diff --git a/make/autoconf/lib-alsa.m4 b/make/autoconf/lib-alsa.m4 index 19a91f94809..8d0fb324cd0 100644 --- a/make/autoconf/lib-alsa.m4 +++ b/make/autoconf/lib-alsa.m4 @@ -70,6 +70,25 @@ AC_DEFUN_ONCE([LIB_SETUP_ALSA], PKG_CHECK_MODULES(ALSA, alsa, [ALSA_FOUND=yes], [ALSA_FOUND=no]) fi fi + if test "x$ALSA_FOUND" = xno; then + # If we have sysroot set, and no explicit library location is set, + # look at known locations in sysroot. + if test "x$SYSROOT" != "x" && test "x${with_alsa_lib}" == x; then + if test -f "$SYSROOT/usr/lib64/libasound.so" && test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + ALSA_LIBS="-L$SYSROOT/usr/lib64 -lasound" + ALSA_FOUND=yes + elif test -f "$SYSROOT/usr/lib/libasound.so"; then + ALSA_LIBS="-L$SYSROOT/usr/lib -lasound" + ALSA_FOUND=yes + elif test -f "$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libasound.so"; then + ALSA_LIBS="-L$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI -lasound" + ALSA_FOUND=yes + elif test -f "$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libasound.so"; then + ALSA_LIBS="-L$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI -lasound" + ALSA_FOUND=yes + fi + fi + fi if test "x$ALSA_FOUND" = xno; then AC_CHECK_HEADERS([alsa/asoundlib.h], [ diff --git a/make/autoconf/lib-x11.m4 b/make/autoconf/lib-x11.m4 index 412eadaf6a1..3494fa8acfa 100644 --- a/make/autoconf/lib-x11.m4 +++ b/make/autoconf/lib-x11.m4 @@ -71,9 +71,9 @@ AC_DEFUN_ONCE([LIB_SETUP_X11], elif test -f "$SYSROOT/usr/lib/libX11.so"; then x_libraries="$SYSROOT/usr/lib" elif test -f "$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libX11.so"; then - x_libraries="$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libX11.so" + x_libraries="$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI" elif test -f "$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libX11.so"; then - x_libraries="$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libX11.so" + x_libraries="$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI" fi fi fi diff --git a/make/autoconf/version-numbers b/make/autoconf/version-numbers index d77db625100..4937deee8d3 100644 --- a/make/autoconf/version-numbers +++ b/make/autoconf/version-numbers @@ -37,7 +37,7 @@ DEFAULT_VERSION_DATE=2026-04-21 DEFAULT_VERSION_CLASSFILE_MAJOR=55 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_ACCEPTABLE_BOOT_VERSIONS="10 11" -DEFAULT_PROMOTED_VERSION_PRE=ea +DEFAULT_PROMOTED_VERSION_PRE= LAUNCHER_NAME=openjdk PRODUCT_NAME=OpenJDK diff --git a/make/data/tzdata/VERSION b/make/data/tzdata/VERSION index 4bd54efbcdc..a2974d757c8 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. # -tzdata2025b +tzdata2026a diff --git a/make/data/tzdata/africa b/make/data/tzdata/africa index 8098f4bea9d..cf1247ee3ab 100644 --- a/make/data/tzdata/africa +++ b/make/data/tzdata/africa @@ -27,9 +27,9 @@ # 2009-05-17 by Arthur David Olson. # This file is by no means authoritative; if you think you know better, -# go ahead and edit the file (and please send any changes to -# tz@iana.org for general use in the future). For more, please see -# the file CONTRIBUTING in the tz distribution. +# go ahead and edit the file, and please send any changes to +# the public mailing list tz@iana.org for general use in the future. +# For more, please see the file CONTRIBUTING in the tz distribution. # From Paul Eggert (2018-05-27): # @@ -138,8 +138,9 @@ Zone Atlantic/Cape_Verde -1:34:04 - LMT 1912 Jan 01 2:00u # Praia -1:00 - %z # Chad +# Fort-Lamy was renamed to N’Djamena on 1973-04-06. # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Africa/Ndjamena 1:00:12 - LMT 1912 Jan 1 # N'Djamena +Zone Africa/Ndjamena 1:00:12 - LMT 1912 Jan 1 # Fort-Lamy 1:00 - WAT 1979 Oct 14 1:00 1:00 WAST 1980 Mar 8 1:00 - WAT diff --git a/make/data/tzdata/antarctica b/make/data/tzdata/antarctica index 87787d31cfe..b3c186851f1 100644 --- a/make/data/tzdata/antarctica +++ b/make/data/tzdata/antarctica @@ -26,13 +26,10 @@ # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. -# From Paul Eggert (1999-11-15): -# To keep things manageable, we list only locations occupied year-round; see -# COMNAP - Stations and Bases -# http://www.comnap.aq/comnap/comnap.nsf/P/Stations/ -# and -# Summary of the Peri-Antarctic Islands (1998-07-23) -# http://www.spri.cam.ac.uk/bob/periant.htm +# From Paul Eggert (2025-08-16): +# To keep things manageable, list only locations occupied year-round; see +# Antarctic Facilities Information +# https://www.comnap.aq/antarctic-facilities-information # for information. # Unless otherwise specified, we have no time zone information. @@ -167,6 +164,7 @@ Zone Antarctica/Mawson 0 - -00 1954 Feb 13 # China - year-round bases # Great Wall, King George Island, -6213-05858, since 1985-02-20 # Zhongshan, Larsemann Hills, Prydz Bay, -6922+07623, since 1989-02-26 +# Qinling, Inexpressible I, Terra Nova Bay, -7456+16343, since 2024-02-07 # France - year-round bases (also see "France & Italy") # diff --git a/make/data/tzdata/asia b/make/data/tzdata/asia index 55b13134f9c..005abd01793 100644 --- a/make/data/tzdata/asia +++ b/make/data/tzdata/asia @@ -27,9 +27,9 @@ # 2009-05-17 by Arthur David Olson. # This file is by no means authoritative; if you think you know better, -# go ahead and edit the file (and please send any changes to -# tz@iana.org for general use in the future). For more, please see -# the file CONTRIBUTING in the tz distribution. +# go ahead and edit the file, and please send any changes to +# the public mailing list tz@iana.org for general use in the future. +# For more, please see the file CONTRIBUTING in the tz distribution. # From Paul Eggert (2019-07-11): # diff --git a/make/data/tzdata/australasia b/make/data/tzdata/australasia index d659d1fb4b1..638789f42da 100644 --- a/make/data/tzdata/australasia +++ b/make/data/tzdata/australasia @@ -960,9 +960,9 @@ Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila # NOTES # This file is by no means authoritative; if you think you know better, -# go ahead and edit the file (and please send any changes to -# tz@iana.org for general use in the future). For more, please see -# the file CONTRIBUTING in the tz distribution. +# go ahead and edit the file, and please send any changes to +# the public mailing list tz@iana.org for general use in the future. +# For more, please see the file CONTRIBUTING in the tz distribution. # From Paul Eggert (2018-11-18): # @@ -2011,6 +2011,7 @@ Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila # From Paul Eggert (2018-11-19): # The 1921-01-15 introduction of standard time is in Shanks; it is also in # "Standard Time Throughout the World", US National Bureau of Standards (1935), +# https://nvlpubs.nist.gov/nistpubs/Legacy/circ/nbscircular406.pdf # page 3, which does not give the UT offset. In response to a comment by # Phake Nick I set the Nauru time of occupation by Japan to # 1942-08-29/1945-09-08 by using dates from: @@ -2078,9 +2079,10 @@ Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila # https://webspace.science.uu.nl/~gent0113/idl/idl_alaska_samoa.htm # Although Shanks & Pottenger says they both switched to UT -11:30 -# in 1911, and to -11 in 1950. many earlier sources give -11 +# in 1911, and to -11 in 1950, many earlier sources give -11 # for American Samoa, e.g., the US National Bureau of Standards # circular "Standard Time Throughout the World", 1932. +# https://nvlpubs.nist.gov/nistpubs/Legacy/circ/nbscircular399.pdf # Assume American Samoa switched to -11 in 1911, not 1950, # and that after 1950 they agreed until (western) Samoa skipped a # day in 2011. Assume also that the Samoas follow the US and New diff --git a/make/data/tzdata/etcetera b/make/data/tzdata/etcetera index 41660b05dba..9b030fdb8d4 100644 --- a/make/data/tzdata/etcetera +++ b/make/data/tzdata/etcetera @@ -43,7 +43,8 @@ # which load the "UTC" file to handle seconds properly. Zone Etc/UTC 0 - UTC -# Functions like gmtime load the "GMT" file to handle leap seconds properly. +# If leap second support is enabled, functions like gmtime +# load the "GMT" file to handle leap seconds properly. # Vanguard section, which works with most .zi parsers. #Zone GMT 0 - GMT # Rearguard section, for TZUpdater 2.3.2 and earlier. diff --git a/make/data/tzdata/europe b/make/data/tzdata/europe index 7ba6c679609..a66d40834cd 100644 --- a/make/data/tzdata/europe +++ b/make/data/tzdata/europe @@ -27,9 +27,9 @@ # 2009-05-17 by Arthur David Olson. # This file is by no means authoritative; if you think you know better, -# go ahead and edit the file (and please send any changes to -# tz@iana.org for general use in the future). For more, please see -# the file CONTRIBUTING in the tz distribution. +# go ahead and edit the file, and please send any changes to +# the public mailing list tz@iana.org for general use in the future. +# For more, please see the file CONTRIBUTING in the tz distribution. # From Paul Eggert (2017-02-10): # @@ -65,7 +65,7 @@ # . He writes: # "It is requested that corrections and additions to these tables # may be sent to Mr. John Milne, Royal Geographical Society, -# Savile Row, London." Nowadays please email them to tz@iana.org. +# Savile Row, London." Nowadays please see the file CONTRIBUTING. # # Byalokoz EL. New Counting of Time in Russia since July 1, 1919. # This Russian-language source was consulted by Vladimir Karpinsky; see @@ -77,7 +77,7 @@ # Десятая гос. тип., 1919. # http://resolver.gpntb.ru/purl?docushare/dsweb/Get/Resource-2011/Byalokoz__E.L.__Novyy__schet__vremeni__v__techenie__sutok__izd__2(1).pdf # -# Brazil's Divisão Serviço da Hora (DSHO), +# Brazil's Divisão de Serviços da Hora (DISHO) # History of Summer Time # # (1998-09-21, in Portuguese) @@ -937,7 +937,7 @@ Rule Belgium 1922 1927 - Oct Sat>=1 23:00s 0 - Rule Belgium 1923 only - Apr 21 23:00s 1:00 S Rule Belgium 1924 only - Mar 29 23:00s 1:00 S Rule Belgium 1925 only - Apr 4 23:00s 1:00 S -# DSH writes that a royal decree of 1926-02-22 specified the Sun following 3rd +# DISHO writes that a royal decree of 1926-02-22 specified the Sun following 3rd # Sat in Apr (except if it's Easter, in which case it's one Sunday earlier), # to Sun following 1st Sat in Oct, and that a royal decree of 1928-09-15 # changed the transition times to 02:00 GMT. @@ -1064,9 +1064,19 @@ Zone Atlantic/Faroe -0:27:04 - LMT 1908 Jan 11 # Tórshavn # Greenland # -# From Paul Eggert (2004-10-31): +# From Paul Eggert (2026-01-22): +# During World War II, Greenland was effectively independent of Denmark and +# observed daylight saving time. TIME, volume 37, page 23 (1941-04-21) +# says, +# "Penfield and West made their way to the U.S.'s most northerly consulate. +# They were astonished to find that Greenlanders, with almost 24 hours of +# sunlight a day during the summer, have daylight saving time." +# As the details are unknown they are omitted from the data for now. +# # During World War II, Germany maintained secret manned weather stations in # East Greenland and Franz Josef Land, but we don't know their time zones. +# Also, they're likely out of scope for the database +# as we lack resources to track every bit of military activity. # My source for this is Wilhelm Dege's book mentioned under Svalbard. # # From Paul Eggert (2017-12-10): @@ -1333,6 +1343,13 @@ Zone Europe/Helsinki 1:39:49 - LMT 1878 May 31 # France # Monaco +# From Robert H. van Gent (2025-07-21): +# The most recent issue of the Annuaire [par le Bureau des Longitudes] +# on Gallica (2021) ... lists information for France +# https://gallica.bnf.fr/ark:/12148/bpt6k9127672b/f52.item +# From Paul Eggert (2025-07-21): +# Go with the 2020 Annuaire (published 2021) except as noted below. + # From Ciro Discepolo (2000-12-20): # # Henri Le Corre, Régimes horaires pour le monde entier, Éditions @@ -1394,7 +1411,6 @@ Zone Europe/Helsinki 1:39:49 - LMT 1878 May 31 # problems in Algiers, Monaco and Tunis. # -# Shank & Pottenger seem to use '24:00' ambiguously; resolve it with Whitman. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule France 1916 only - Jun 14 23:00s 1:00 S Rule France 1916 1919 - Oct Sun>=1 23:00s 0 - @@ -1406,9 +1422,25 @@ Rule France 1920 only - Oct 23 23:00s 0 - Rule France 1921 only - Mar 14 23:00s 1:00 S Rule France 1921 only - Oct 25 23:00s 0 - Rule France 1922 only - Mar 25 23:00s 1:00 S -# DSH writes that a law of 1923-05-24 specified 3rd Sat in Apr at 23:00 to 1st -# Sat in Oct at 24:00; and that in 1930, because of Easter, the transitions -# were Apr 12 and Oct 5. Go with Shanks & Pottenger. +# From Robert H. van Gent (2025-07-22): +# There is a curious history behind the erroneous date for the start of +# daylight saving in France in 1923 as listed in the current issues of +# the Annuaire du Bureau des Longitudes. [See:] +# https://lists.iana.org/hyperkitty/list/tz@iana.org/message/MYQEJMSXO2AIEZ3UIXZKMTTAIPY7KNT2/ +# From Brian Inglis (2025-07-23): +# Légifrance JORF No. 0073 du 15 mars 1922 +# https://www.legifrance.gouv.fr/jorf/jo/id/JORFCONT000000008324 +# Légifrance JORF No. 0139 du 25 mai 1923 +# https://www.legifrance.gouv.fr/jorf/jo/id/JORFCONT000000008416 +# From Paul Eggert (2025-07-23): +# The latter specifies March's last Saturday at 23:00 to October's first +# Saturday at 24:00, except that if neighboring allies agree the dates +# can be moved to April's third Saturday and September's third Saturday. +# Apparently spring 1923 was tricky. DISHO writes that in 1930, +# because of Easter, the transitions were Apr 12 and Oct 5. +# Use the 2020 Annuaire dates, except for spring 1923 where +# Shanks & Pottenger's May 26 matches the dates given in the 1924 and +# 1961-2001 issues of the Annuaire. Rule France 1922 1938 - Oct Sat>=1 23:00s 0 - Rule France 1923 only - May 26 23:00s 1:00 S Rule France 1924 only - Mar 29 23:00s 1:00 S @@ -1958,7 +1990,6 @@ Zone Europe/Malta 0:58:04 - LMT 1893 Nov 2 # Valletta # From Stepan Golosunov (2016-03-07): # the act of the government of the Republic of Moldova Nr. 132 from 1990-05-04 -# http://lex.justice.md/viewdoc.php?action=view&view=doc&id=298782&lang=2 # ... says that since 1990-05-06 on the territory of the Moldavian SSR # time would be calculated as the standard time of the second time belt # plus one hour of the "summer" time. To implement that clocks would be @@ -2013,9 +2044,61 @@ Zone Europe/Malta 0:58:04 - LMT 1893 Nov 2 # Valletta # says the 2014-03-30 spring-forward transition was at 02:00 local time. # Guess that since 1997 Moldova has switched one hour before the EU. +# From Heitor David Pinto (2026-02-22): +# Soviet Moldovan resolution 132 of 1990 defined the summer time period from +# the last Sunday in March at 2:00 to the last Sunday in September at 3:00, +# matching the dates used in most of Europe at the time: +# https://web.archive.org/web/20211107050832/http://lex.justice.md/viewdoc.php?action=view&view=doc&id=298782&lang=1 +# +# It seems that in 1996 Moldova changed the end date to October like most of +# Europe, but kept the transitions at 2:00 and 3:00 rather than 1:00 UTC, +# which would have been locally 3:00 and 4:00.... +# +# The notices in the Moldovan government website and broadcaster showed the +# transitions at 2:00 and 3:00 until 2021: +# 2015 https://old.gov.md/en/node/7304 +# 2016 https://old.gov.md/en/node/12587 +# 2017 https://old.gov.md/en/node/20654 +# 2017 https://old.gov.md/en/content/moldova-upholds-winter-time-night-28-29-october +# 2018 https://old.gov.md/en/content/moldova-switch-summer-time +# 2018 https://old.gov.md/en/content/cabinet-ministers-informs-about-switch-winter-time-28-october +# 2019 https://old.gov.md/en/content/moldova-switch-summer-time-31-march +# 2019 https://old.gov.md/en/node/31122 +# 2020 https://old.gov.md/en/node/32771 +# 2020 https://old.gov.md/en/node/34497 +# 2021 https://trm.md/ro/social/moldova-trece-in-aceasta-noapte-la-ora-de-vara +# 2021 https://trm.md/en/social/republica-moldova-trece-la-ora-de-iarna1 +# +# However, since 2022, the notices showed the transitions at 3:00 and 4:00, +# matching the EU rule at 1:00 UTC: +# 2022 https://trm.md/en/social/in-acest-weekend-republica-moldova-trece-la-ora-de-vara +# 2022 https://old.gov.md/en/content/moldova-switch-winter-time +# 2023 https://moldova1.md/p/6587/ora-de-vara-2023-cum-schimbam-acele-ceasornicelor-si-cand-trecem-la-ora-de-vara +# 2023 https://old.gov.md/en/node/46662 +# 2024 https://moldova1.md/p/26535/republica-moldova-trece-la-ora-de-vara-in-acest-weekend +# 2024 https://moldova1.md/p/37768/republica-moldova-trece-in-aceasta-noapte-la-ora-de-iarna +# 2025 https://moldova1.md/p/46349/republica-moldova-trece-la-ora-de-vara-pe-30-martie-cum-ne-afecteaza-si-ce-recomanda-medicii +# 2025 https://moldova1.md/p/60469/republica-moldova-trece-la-ora-de-iarna-ceasurile-se-dau-inapoi-cu-o-ora +# +# It seems that the changes to the end date and transition times were just +# done in practice without formally changing the resolution. In late 2025, the +# government said that the Soviet resolution was still in force, and proposed +# a new resolution to replace it and formally establish the EU rule: +# ... based on the notices, it seems that in practice Moldova already +# uses the EU rule since 2022. This was also the year when Moldova applied to +# join the EU. +# +# From Robert Bastian (2026-02-26): +# This has been approved and published in the government gazette: +# https://monitorul.gov.md/ro/monitorul/view/pdf/3234/part/2#page=27 +# +# From Paul Eggert (2026-02-24): +# Also see Svetlana Rudenko, "Moldova abandons the 'Soviet era'", Logos Press, +# 2026-02-21 . + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S -Rule Moldova 1997 max - Mar lastSun 2:00 1:00 S -Rule Moldova 1997 max - Oct lastSun 3:00 0 - +Rule Moldova 1997 2021 - Mar lastSun 2:00 1:00 S +Rule Moldova 1997 2021 - Oct lastSun 3:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Europe/Chisinau 1:55:20 - LMT 1880 @@ -2028,7 +2111,8 @@ Zone Europe/Chisinau 1:55:20 - LMT 1880 2:00 Russia EE%sT 1992 2:00 E-Eur EE%sT 1997 # See Romania commentary for the guessed 1997 transition to EU rules. - 2:00 Moldova EE%sT + 2:00 Moldova EE%sT 2022 + 2:00 EU EE%sT # Poland @@ -2119,12 +2203,10 @@ Zone Europe/Warsaw 1:24:00 - LMT 1880 # all clocks therefore having to be advanced or set back correspondingly ... # Rule NAME FROM TO - IN ON AT SAVE LETTER/S -# From Tim Parenti (2024-07-01), per Paul Eggert (1999-01-30): -# DSH writes in their history that Decreto 1469 of 1915-03-30 established -# summer time and that, "despite" this, the change to the clocks was not done -# every year, depending on what Spain did, because of railroad schedules. -# In fact, that decree had nothing to do with DST; rather, it regulated the -# sending of time signals. But we do see linkage to Spain in the 1920s below. +# From Tim Parenti (2024-07-01): +# Decreto 1469 of 1915-03-30 ... had nothing to do with DST; +# rather it regulated the sending of time signals. +# But we do see linkage to Spain in the 1920s below. # https://dre.pt/dr/detalhe/decreto/1469-1915-285721 # https://dre.pt/application/conteudo/285721 # @@ -2416,7 +2498,7 @@ Zone Atlantic/Madeira -1:07:36 - LMT 1884 # Funchal # Nine O'clock # (1998-10-23) reports that the switch occurred at # 04:00 local time in fall 1998. For lack of better info, -# assume that Romania and Moldova switched to EU rules in 1997, +# assume that Romania switched to EU rules in 1997, # the same year as Bulgaria. # # Rule NAME FROM TO - IN ON AT SAVE LETTER/S diff --git a/make/data/tzdata/iso3166.tab b/make/data/tzdata/iso3166.tab index 7fa350ecbe3..ddcc841fe97 100644 --- a/make/data/tzdata/iso3166.tab +++ b/make/data/tzdata/iso3166.tab @@ -26,22 +26,22 @@ # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. # -# From Paul Eggert (2023-09-06): +# From Paul Eggert (2025-07-01): # This file contains a table of two-letter country codes. Columns are -# separated by a single tab. Lines beginning with '#' are comments. +# separated by a single tab. Lines beginning with ‘#’ are comments. # All text uses UTF-8 encoding. The columns of the table are as follows: # # 1. ISO 3166-1 alpha-2 country code, current as of -# ISO/TC 46 N1108 (2023-04-05). See: ISO/TC 46 Documents +# ISO/TC 46 N1127 (2024-02-29). See: ISO/TC 46 Documents # https://www.iso.org/committee/48750.html?view=documents # 2. The usual English name for the coded region. This sometimes # departs from ISO-listed names, sometimes so that sorted subsets -# of names are useful (e.g., "Samoa (American)" and "Samoa -# (western)" rather than "American Samoa" and "Samoa"), +# of names are useful (e.g., “Samoa (American)” and “Samoa +# (western)” rather than “American Samoa” and “Samoa”), # sometimes to avoid confusion among non-experts (e.g., -# "Czech Republic" and "Turkey" rather than "Czechia" and "Türkiye"), -# and sometimes to omit needless detail or churn (e.g., "Netherlands" -# rather than "Netherlands (the)" or "Netherlands (Kingdom of the)"). +# “Czech Republic” and “Turkey” rather than “Czechia” and “Türkiye”), +# and sometimes to omit needless detail or churn (e.g., “Netherlands” +# rather than “Netherlands (the)” or “Netherlands (Kingdom of the)”). # # The table is sorted by country code. # @@ -94,7 +94,7 @@ CD Congo (Dem. Rep.) CF Central African Rep. CG Congo (Rep.) CH Switzerland -CI Côte d'Ivoire +CI Côte d’Ivoire CK Cook Islands CL Chile CM Cameroon diff --git a/make/data/tzdata/leapseconds b/make/data/tzdata/leapseconds index 042a32b052c..d431a7d3607 100644 --- a/make/data/tzdata/leapseconds +++ b/make/data/tzdata/leapseconds @@ -28,7 +28,8 @@ # This file is generated automatically from the data in the public-domain # NIST/IERS format leap-seconds.list file, which can be copied from # -# or, in a variant with different comments, from +# or via a less-secure protocol and with different comments and +# less volatile last-modified and expiration timestamps, from # . # For more about leap-seconds.list, please see # The NTP Timescale and Leap Seconds @@ -92,11 +93,17 @@ Leap 2016 Dec 31 23:59:60 + S # Any additional leap seconds will come after this. # This Expires line is commented out for now, # so that pre-2020a zic implementations do not reject this file. -#Expires 2025 Dec 28 00:00:00 +#Expires 2026 Dec 28 00:00:00 -# POSIX timestamps for the data in this file: -#updated 1736208000 (2025-01-07 00:00:00 UTC) -#expires 1766880000 (2025-12-28 00:00:00 UTC) +# Here are POSIX timestamps for the data in this file. +# "#updated" gives the last time the leap seconds data changed +# or, if this file was derived from the IERS leap-seconds.list, +# the last time that file changed in any way. +# "#expires" gives the first time this file might be wrong; +# if this file was derived from the IERS leap-seconds.list, +# this is typically a bit less than one year after "updated". +#updated 1767698058 (2026-01-06 11:14:18 UTC) +#expires 1798416000 (2026-12-28 00:00:00 UTC) # Updated through IERS Bulletin C (https://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat) -# File expires on 28 December 2025 +# File expires on 28 December 2026 diff --git a/make/data/tzdata/northamerica b/make/data/tzdata/northamerica index 21f178ee8cb..f20879e9063 100644 --- a/make/data/tzdata/northamerica +++ b/make/data/tzdata/northamerica @@ -29,9 +29,9 @@ # also includes Central America and the Caribbean # This file is by no means authoritative; if you think you know better, -# go ahead and edit the file (and please send any changes to -# tz@iana.org for general use in the future). For more, please see -# the file CONTRIBUTING in the tz distribution. +# go ahead and edit the file, and please send any changes to +# the public mailing list tz@iana.org for general use in the future. +# For more, please see the file CONTRIBUTING in the tz distribution. # From Paul Eggert (1999-03-22): # A reliable and entertaining source about time zones is @@ -1241,6 +1241,16 @@ Zone America/Menominee -5:50:27 - LMT 1885 Sep 18 12:00 # _Los Angeles Times_ (1998-11-10), A1, A10; it cites # Jimmy Skaggs, _The Great Guano Rush_ (1994). +# From Rob van Gent (2025-07-23): +# Another useful source for historical time zone information appears to be +# a series of circulars with the title "Standard Time Throughout the World" +# issued between 1925 and 1950 by the U.S. Bureau of Standards. +# I found the following issues online: +# https://nvlpubs.nist.gov/nistpubs/Legacy/circ/nbscircular280.pdf (1925) +# https://nvlpubs.nist.gov/nistpubs/Legacy/circ/nbscircular399.pdf (1932) +# https://nvlpubs.nist.gov/nistpubs/Legacy/circ/nbscircular406.pdf (1935) +# https://nvlpubs.nist.gov/nistpubs/Legacy/circ/nbscircular496.pdf (1950) + ################################################################################ @@ -2457,12 +2467,35 @@ Zone America/Dawson -9:17:40 - LMT 1900 Aug 20 # on the same dates or with a difference of one day. # So it may be easier to implement these changes as DST with rule CA # during this whole period. -# -# From Paul Eggert (2024-08-18): -# For now, maintain the slightly-different history for Baja California, + +# From Alois Treindl (2025-07-29): +# I did a quick newspaper archive research on https://hndm.iib.unam.mx/ +# and found that Periódico Oficial del Estado de Baja California Norte +# (1973-04-20) states clearly that DST was observed from last Sunday +# in April to last Sunday in October.... I have a few more data from the +# official bulletin for DST begin or end in Baja California 1964 1967 1969 +# 1972 1973 (already sent) 1974 1975 1976 I do not know whether it is safe to +# assume that it also applied in the years where I did not yet find proof. +# The 1974 end of DST contains a reference to an Acuerdo of 1973-dec-20 which +# I could not find.... One might assume that Baja California, which followed +# US-CA in all these other yours, did the same. +# +# From Paul Eggert (2025-08-04): +# Assume that Tijuana agreed with San Diego from 1953 through 1996, +# as this agrees with Alois Treindl's data and with Shanks. +# For now, keep the slightly-different 1948/1952 history for Baja California, # as we have no information on whether 1948/1952 clocks in Tijuana followed # the decrees or followed San Diego. +# From Mark Schapiro, writing in The Nation (2002-10-28): +# https://www.thenation.com/article/archive/sowing-disaster/ +# When Mexican clocks were turned back for daylight saving time in the spring, +# the Zapotecs refused to make the adjustment, insisting that they live in +# "God's time," not in what they derisively call "Fox time," referring to +# President Vicente Fox in far-off Mexico City. +# From Paul Eggert (2025-08-04): +# Unfortunately we have no data to track this informal practice. + # From Alan Perry (1996-02-15): # A guy from our Mexico subsidiary finally found the Presidential Decree # outlining the timezone changes in Mexico. @@ -2728,7 +2761,7 @@ Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 7:00u # Chihuahua (near US border - western side) # This includes the municipios of Janos, Ascensión, Juárez, Guadalupe, and # Práxedis G Guerrero. -# http://gaceta.diputados.gob.mx/PDF/65/2a022/nov/20221124-VII.pdf +# https://gaceta.diputados.gob.mx/PDF/65/2022/nov/20221124-VII.pdf Zone America/Ciudad_Juarez -7:05:56 - LMT 1922 Jan 1 7:00u -7:00 - MST 1927 Jun 10 -6:00 - CST 1930 Nov 15 @@ -2743,7 +2776,7 @@ Zone America/Ciudad_Juarez -7:05:56 - LMT 1922 Jan 1 7:00u # Chihuahua (near US border - eastern side) # This includes the municipios of Coyame del Sotol, Ojinaga, and Manuel # Benavides. -# http://gaceta.diputados.gob.mx/PDF/65/2a022/nov/20221124-VII.pdf +# https://gaceta.diputados.gob.mx/PDF/65/2022/nov/20221124-VII.pdf Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 7:00u -7:00 - MST 1927 Jun 10 -6:00 - CST 1930 Nov 15 @@ -2840,9 +2873,7 @@ Zone America/Tijuana -7:48:04 - LMT 1922 Jan 1 7:00u -8:00 1:00 PDT 1951 Sep 30 2:00 -8:00 - PST 1952 Apr 27 2:00 -8:00 1:00 PDT 1952 Sep 28 2:00 - -8:00 - PST 1954 - -8:00 CA P%sT 1961 - -8:00 - PST 1976 + -8:00 CA P%sT 1967 -8:00 US P%sT 1996 -8:00 Mexico P%sT 2001 -8:00 US P%sT 2002 Feb 20 diff --git a/make/data/tzdata/southamerica b/make/data/tzdata/southamerica index 06fee598baf..bcd4abdfa42 100644 --- a/make/data/tzdata/southamerica +++ b/make/data/tzdata/southamerica @@ -4,9 +4,9 @@ # 2009-05-17 by Arthur David Olson. # This file is by no means authoritative; if you think you know better, -# go ahead and edit the file (and please send any changes to -# tz@iana.org for general use in the future). For more, please see -# the file CONTRIBUTING in the tz distribution. +# go ahead and edit the file, and please send any changes to +# the public mailing list tz@iana.org for general use in the future. +# For more, please see the file CONTRIBUTING in the tz distribution. # From Paul Eggert (2016-12-05): # diff --git a/make/hotspot/lib/JvmMapfile.gmk b/make/hotspot/lib/JvmMapfile.gmk index ba44e579832..cb9e3ff7f2a 100644 --- a/make/hotspot/lib/JvmMapfile.gmk +++ b/make/hotspot/lib/JvmMapfile.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. # 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,26 @@ else ifeq ($(call isTargetOs, aix), true) else ifeq ($(call isTargetOs, windows), true) DUMP_SYMBOLS_CMD := $(DUMPBIN) -symbols *.obj + + # The following lines create a list of vftable symbols to be filtered out of + # the mapfile. Removing this line causes the linker to complain about too many + # (> 64K) symbols, so the _guess_ is that this line is here to keep down the + # number of exported symbols below that limit. + # + # Some usages of C++ lambdas require the vftable symbol of classes that use + # the lambda type as a template parameter. The usage of those classes won't + # link if their vftable symbols are removed. That's why there's an exception + # for vftable symbols containing the string 'lambda'. + # + # A very simple example of a lambda usage that fails if the lambda vftable + # symbols are missing in the mapfile: + # + # #include + # std::function f = [](){} + FILTER_SYMBOLS_AWK_SCRIPT := \ '{ \ - if ($$7 ~ /??_7.*@@6B@/ && $$7 !~ /type_info/) print $$7; \ + if ($$7 ~ /\?\?_7.*@@6B@/ && $$7 !~ /type_info/ && $$7 !~ /lambda/) print $$7; \ }' else diff --git a/make/lib/Awt2dLibraries.gmk b/make/lib/Awt2dLibraries.gmk index eaa582b343e..e4ee6ce9efb 100644 --- a/make/lib/Awt2dLibraries.gmk +++ b/make/lib/Awt2dLibraries.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -895,7 +895,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) unused-function $(LIBZ_DISABLED_WARNINGS_CLANG), \ DISABLED_WARNINGS_solstudio := E_NEWLINE_NOT_LAST E_DECLARATION_IN_CODE \ E_STATEMENT_NOT_REACHED, \ - DISABLED_WARNINGS_microsoft := 4018 4244 4267, \ + DISABLED_WARNINGS_microsoft := 4018 4146 4244 4267, \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LDFLAGS_macosx := -L$(INSTALL_LIBRARIES_HERE), \ diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 259851a8424..0de3adc1a91 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -8028,10 +8028,11 @@ instruct bytes_reverse_unsigned_short(iRegINoSp dst, iRegIorL2I src) %{ match(Set dst (ReverseBytesUS src)); ins_cost(INSN_COST); - format %{ "rev16w $dst, $src" %} + format %{ "rev16w $dst, $src\t# $dst -> unsigned short" %} ins_encode %{ __ rev16w(as_Register($dst$$reg), as_Register($src$$reg)); + __ narrow_subword_type(as_Register($dst$$reg), T_CHAR); %} ins_pipe(ialu_reg); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 9aa29b7f944..db1d50fbc40 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -2339,6 +2339,17 @@ void MacroAssembler::store_sized_value(Address dst, Register src, size_t size_in } } +void MacroAssembler::narrow_subword_type(Register reg, BasicType bt) { + assert(is_subword_type(bt), "required"); + switch (bt) { + case T_BOOLEAN: andw(reg, reg, 1); break; + case T_BYTE: sxtbw(reg, reg); break; + case T_CHAR: uxthw(reg, reg); break; + case T_SHORT: sxthw(reg, reg); break; + default: ShouldNotReachHere(); + } +} + void MacroAssembler::decrementw(Register reg, int value) { if (value < 0) { incrementw(reg, -value); return; } diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 22abfb7f9ca..fbc8ac9012c 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -29,6 +29,7 @@ #include "asm/assembler.inline.hpp" #include "runtime/vm_version.hpp" +#include "utilities/globalDefinitions.hpp" // MacroAssembler extends Assembler by frequently used macros. // @@ -646,6 +647,9 @@ class MacroAssembler: public Assembler { // Support for sign-extension (hi:lo = extend_sign(lo)) void extend_sign(Register hi, Register lo); + // Clean up a subword typed value to the representation in compliance with JVMS §2.3 + void narrow_subword_type(Register reg, BasicType bt); + // Load and store values by size and signed-ness void load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed, Register dst2 = noreg); void store_sized_value(Address dst, Register src, size_t size_in_bytes, Register src2 = noreg); diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 8714349365e..912e0993ef0 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -12445,10 +12445,12 @@ instruct bytes_reverse_unsigned_short(iRegI dst, iRegI src) %{ // high 32 bits zeroed %} #else - size(4); - format %{ "REV16 $dst,$src" %} + size(8); + format %{ "REV32 $dst,$src\n\t" + "LSR $dst,$dst,#16" %} ins_encode %{ - __ rev16($dst$$Register, $src$$Register); + __ rev($dst$$Register, $src$$Register); + __ mov($dst$$Register, AsmOperand($dst$$Register, lsr, 16)); %} #endif ins_pipe( iload_mem ); // FIXME diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 2a8cfcf0465..1cee06cf6bf 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -13632,6 +13632,19 @@ instruct countTrailingZerosL_cnttzd(iRegIdst dst, iRegLsrc src) %{ ins_pipe(pipe_class_default); %} +// Expand nodes for byte_reverse_int/ushort/short. +instruct rlwinm(iRegIdst dst, iRegIsrc src, immI16 shift, immI16 mb, immI16 me) %{ + effect(DEF dst, USE src, USE shift, USE mb, USE me); + predicate(false); + + format %{ "RLWINM $dst, $src, $shift, $mb, $me" %} + size(4); + ins_encode %{ + __ rlwinm($dst$$Register, $src$$Register, $shift$$constant, $mb$$constant, $me$$constant); + %} + ins_pipe(pipe_class_default); +%} + // Expand nodes for byte_reverse_int. instruct insrwi_a(iRegIdst dst, iRegIsrc src, immI16 pos, immI16 shift) %{ effect(DEF dst, USE src, USE pos, USE shift); @@ -13754,34 +13767,22 @@ instruct bytes_reverse_long(iRegLdst dst, iRegLsrc src) %{ ins_pipe(pipe_class_default); %} +// Need zero extend. Must not use brh only. instruct bytes_reverse_ushort_Ex(iRegIdst dst, iRegIsrc src) %{ match(Set dst (ReverseBytesUS src)); - predicate(!UseByteReverseInstructions); ins_cost(2*DEFAULT_COST); expand %{ + immI16 imm31 %{ (int) 31 %} + immI16 imm24 %{ (int) 24 %} immI16 imm16 %{ (int) 16 %} immI16 imm8 %{ (int) 8 %} - urShiftI_reg_imm(dst, src, imm8); + rlwinm(dst, src, imm24, imm24, imm31); insrwi(dst, src, imm16, imm8); %} %} -instruct bytes_reverse_ushort(iRegIdst dst, iRegIsrc src) %{ - match(Set dst (ReverseBytesUS src)); - predicate(UseByteReverseInstructions); - ins_cost(DEFAULT_COST); - size(4); - - format %{ "BRH $dst, $src" %} - - ins_encode %{ - __ brh($dst$$Register, $src$$Register); - %} - ins_pipe(pipe_class_default); -%} - instruct bytes_reverse_short_Ex(iRegIdst dst, iRegIsrc src) %{ match(Set dst (ReverseBytesS src)); predicate(!UseByteReverseInstructions); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index f1404c234e8..94644e02236 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -47,6 +47,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/thread.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "crc32c.h" #ifdef COMPILER2 @@ -3983,6 +3984,17 @@ void MacroAssembler::sign_extend_short(Register reg) { } } +void MacroAssembler::narrow_subword_type(Register reg, BasicType bt) { + assert(is_subword_type(bt), "required"); + switch (bt) { + case T_BOOLEAN: andl(reg, 1); break; + case T_BYTE: movsbl(reg, reg); break; + case T_CHAR: movzwl(reg, reg); break; + case T_SHORT: movswl(reg, reg); break; + default: ShouldNotReachHere(); + } +} + void MacroAssembler::testl(Register dst, AddressLiteral src) { assert(reachable(src), "Address should be reachable"); testl(dst, as_Address(src)); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 515ed093286..d28e124f31c 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -425,6 +425,9 @@ class MacroAssembler: public Assembler { void sign_extend_short(Register reg); void sign_extend_byte(Register reg); + // Clean up a subword typed value to the representation in compliance with JVMS §2.3 + void narrow_subword_type(Register reg, BasicType bt); + // Division by power of 2, rounding towards 0 void division_with_shift(Register reg, int shift_value); diff --git a/src/hotspot/cpu/x86/x86_32.ad b/src/hotspot/cpu/x86/x86_32.ad index 1a1275b0de9..2e998782587 100644 --- a/src/hotspot/cpu/x86/x86_32.ad +++ b/src/hotspot/cpu/x86/x86_32.ad @@ -7546,10 +7546,11 @@ instruct xaddB_no_res( memory mem, Universe dummy, immI add, eFlagsReg cr) %{ instruct xaddB( memory mem, xRegI newval, eFlagsReg cr) %{ match(Set newval (GetAndAddB mem newval)); effect(KILL cr); - format %{ "XADDB [$mem],$newval" %} + format %{ "XADDB [$mem],$newval\t# $newval -> byte" %} ins_encode %{ if (os::is_MP()) { __ lock(); } __ xaddb($mem$$Address, $newval$$Register); + __ narrow_subword_type($newval$$Register, T_BYTE); %} ins_pipe( pipe_cmpxchg ); %} @@ -7569,10 +7570,11 @@ instruct xaddS_no_res( memory mem, Universe dummy, immI add, eFlagsReg cr) %{ instruct xaddS( memory mem, rRegI newval, eFlagsReg cr) %{ match(Set newval (GetAndAddS mem newval)); effect(KILL cr); - format %{ "XADDS [$mem],$newval" %} + format %{ "XADDS [$mem],$newval\t# $newval -> short" %} ins_encode %{ if (os::is_MP()) { __ lock(); } __ xaddw($mem$$Address, $newval$$Register); + __ narrow_subword_type($newval$$Register, T_SHORT); %} ins_pipe( pipe_cmpxchg ); %} @@ -7603,18 +7605,20 @@ instruct xaddI( memory mem, rRegI newval, eFlagsReg cr) %{ // Important to match to xRegI: only 8-bit regs. instruct xchgB( memory mem, xRegI newval) %{ match(Set newval (GetAndSetB mem newval)); - format %{ "XCHGB $newval,[$mem]" %} + format %{ "XCHGB $newval,[$mem]\t# $newval -> byte" %} ins_encode %{ __ xchgb($newval$$Register, $mem$$Address); + __ narrow_subword_type($newval$$Register, T_BYTE); %} ins_pipe( pipe_cmpxchg ); %} instruct xchgS( memory mem, rRegI newval) %{ match(Set newval (GetAndSetS mem newval)); - format %{ "XCHGW $newval,[$mem]" %} + format %{ "XCHGW $newval,[$mem]\t# $newval -> short" %} ins_encode %{ __ xchgw($newval$$Register, $mem$$Address); + __ narrow_subword_type($newval$$Register, T_SHORT); %} ins_pipe( pipe_cmpxchg ); %} diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 5054a5647a9..383b925f604 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -8000,10 +8000,11 @@ instruct xaddB_no_res( memory mem, Universe dummy, immI add, rFlagsReg cr) %{ instruct xaddB( memory mem, rRegI newval, rFlagsReg cr) %{ match(Set newval (GetAndAddB mem newval)); effect(KILL cr); - format %{ "XADDB [$mem],$newval" %} + format %{ "XADDB [$mem],$newval\t# $newval -> byte" %} ins_encode %{ if (os::is_MP()) { __ lock(); } __ xaddb($mem$$Address, $newval$$Register); + __ narrow_subword_type($newval$$Register, T_BYTE); %} ins_pipe( pipe_cmpxchg ); %} @@ -8023,10 +8024,11 @@ instruct xaddS_no_res( memory mem, Universe dummy, immI add, rFlagsReg cr) %{ instruct xaddS( memory mem, rRegI newval, rFlagsReg cr) %{ match(Set newval (GetAndAddS mem newval)); effect(KILL cr); - format %{ "XADDW [$mem],$newval" %} + format %{ "XADDW [$mem],$newval\t# $newval -> short" %} ins_encode %{ if (os::is_MP()) { __ lock(); } __ xaddw($mem$$Address, $newval$$Register); + __ narrow_subword_type($newval$$Register, T_SHORT); %} ins_pipe( pipe_cmpxchg ); %} @@ -8079,18 +8081,20 @@ instruct xaddL( memory mem, rRegL newval, rFlagsReg cr) %{ instruct xchgB( memory mem, rRegI newval) %{ match(Set newval (GetAndSetB mem newval)); - format %{ "XCHGB $newval,[$mem]" %} + format %{ "XCHGB $newval,[$mem]\t# $newval -> byte" %} ins_encode %{ __ xchgb($newval$$Register, $mem$$Address); + __ narrow_subword_type($newval$$Register, T_BYTE); %} ins_pipe( pipe_cmpxchg ); %} instruct xchgS( memory mem, rRegI newval) %{ match(Set newval (GetAndSetS mem newval)); - format %{ "XCHGW $newval,[$mem]" %} + format %{ "XCHGW $newval,[$mem]\t# $newval -> short" %} ins_encode %{ __ xchgw($newval$$Register, $mem$$Address); + __ narrow_subword_type($newval$$Register, T_SHORT); %} ins_pipe( pipe_cmpxchg ); %} diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index c75e140e50b..063d3a3e0f7 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -958,6 +958,7 @@ ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const str if (throw_exception && is_init_completed()) { THROW_MSG_(vmSymbols::java_lang_ClassNotFoundException(), msg, NULL); } else { + log_info(class, path)("failed: %s, err: %s", path, error_msg); return NULL; } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java index f634a639c19..0d09cecf703 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,38 @@ final class PBES1Core { private int blkSize; private String algo = null; private byte[] salt = null; - private int iCount = 10; + // RFC 8018 and NIST SP 800-132 sec 5.2 recommend 1000 as the minimum + private int iCount = PKCS12PBECipherCore.DEFAULT_COUNT; + + // utility method for checking weak salts of PBEWithMD5AndTripleDES cipher + private static boolean isWeak(byte[] s) { + // consider salts weak if it met both of the following conditions: + // 1) s[0...3] == s[4...7] + // 2) s[0] == s[3] && s[1] == s[2] + if (Arrays.equals(s, 0, 4, s, 4, 8)) { + return (s[0] == s[3]) && (s[1] == s[2]); + } + return false; + } + + // utility method for generating 8-byte salts + private static byte[] generateSalt(String algo, SecureRandom sr) { + byte[] salt = new byte[8]; + sr.nextBytes(salt); + // check and re-generate for DESede if necessary + if (algo.equals("DESede")) { + // prevent an infinite-loop in case of a rigged SecureRandom + int numAttempts = 50; + while (isWeak(salt)) { + sr.nextBytes(salt); + if (numAttempts-- < 0) { + throw new ProviderException( + "Unable to find salts after 50 attempts"); + } + } + } + return salt; + } /** * Creates an instance of PBE Cipher using the specified CipherSpi @@ -164,8 +195,7 @@ byte[] getIV() { AlgorithmParameters getParameters() { AlgorithmParameters params = null; if (salt == null) { - salt = new byte[8]; - SunJCE.getRandom().nextBytes(salt); + salt = generateSalt(algo, SunJCE.getRandom()); } PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount); try { @@ -228,8 +258,7 @@ void init(int opmode, Key key, AlgorithmParameterSpec params, if (params == null) { // create random salt and use default iteration count - salt = new byte[8]; - random.nextBytes(salt); + salt = generateSalt(algo, random); } else { if (!(params instanceof PBEParameterSpec)) { throw new InvalidAlgorithmParameterException @@ -241,6 +270,15 @@ void init(int opmode, Key key, AlgorithmParameterSpec params, throw new InvalidAlgorithmParameterException ("Salt must be 8 bytes long"); } + // for DESede, reject weak salts for encryption + if (algo.equals("DESede") && + (opmode == Cipher.ENCRYPT_MODE || + opmode == Cipher.WRAP_MODE) && + isWeak(salt)) { + throw new InvalidAlgorithmParameterException( + "Weak salts cannot be used for encryption"); + } + iCount = ((PBEParameterSpec) params).getIterationCount(); if (iCount <= 0) { throw new InvalidAlgorithmParameterException diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java b/src/java.base/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java index 6aaac223edb..282535dda75 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ final class PKCS12PBECipherCore { private int iCount = 0; private static final int DEFAULT_SALT_LENGTH = 20; - private static final int DEFAULT_COUNT = 1024; + static final int DEFAULT_COUNT = 1024; static final int CIPHER_KEY = 1; static final int CIPHER_IV = 2; diff --git a/src/java.base/share/classes/sun/security/provider/MD4.java b/src/java.base/share/classes/sun/security/provider/MD4.java index b1c45ab90ec..01e799a9749 100644 --- a/src/java.base/share/classes/sun/security/provider/MD4.java +++ b/src/java.base/share/classes/sun/security/provider/MD4.java @@ -79,13 +79,8 @@ public Void run() { }); } - public static MessageDigest getInstance() { - try { - return MessageDigest.getInstance("MD4", md4Provider); - } catch (NoSuchAlgorithmException e) { - // should never occur - throw new ProviderException(e); - } + public static MessageDigest getInstance() throws NoSuchAlgorithmException { + return MessageDigest.getInstance("MD4", md4Provider); } // Standard constructor, creates a new MD4 instance. diff --git a/src/java.base/share/classes/sun/security/provider/X509Factory.java b/src/java.base/share/classes/sun/security/provider/X509Factory.java index f30647126f4..ca278ba9403 100644 --- a/src/java.base/share/classes/sun/security/provider/X509Factory.java +++ b/src/java.base/share/classes/sun/security/provider/X509Factory.java @@ -65,6 +65,7 @@ public class X509Factory extends CertificateFactorySpi { public static final String END_CERT = "-----END CERTIFICATE-----"; private static final int ENC_MAX_LENGTH = 4096 * 1024; // 4 MB MAX + public static final int BER_ITERATION_COUNT = 128; // Limit nested depth private static final Cache certCache = Cache.newSoftMemoryCache(750); @@ -549,7 +550,7 @@ private static byte[] readOneBlock(InputStream is) throws IOException { if (c == DerValue.tag_Sequence) { ByteArrayOutputStream bout = new ByteArrayOutputStream(2048); bout.write(c); - readBERInternal(is, bout, c); + readBERInternal(is, bout, c, BER_ITERATION_COUNT); return bout.toByteArray(); } else { // Read BASE64 encoded data, might skip info at the beginning @@ -670,12 +671,16 @@ private static void checkHeaderFooter(String header, * @param is Read from this InputStream * @param bout Write into this OutputStream * @param tag Tag already read (-1 mean not read) + * @param depth nesting depth limit * @return The current tag, used to check EOC in indefinite-length BER * @throws IOException Any parsing error */ private static int readBERInternal(InputStream is, - ByteArrayOutputStream bout, int tag) throws IOException { + ByteArrayOutputStream bout, int tag, int depth) throws IOException { + if (depth-- == 0) { + throw new IOException("Nesting sequence depth limit reached."); + } if (tag == -1) { // Not read before the call, read now tag = is.read(); if (tag == -1) { @@ -701,7 +706,7 @@ private static int readBERInternal(InputStream is, "Non constructed encoding must have definite length"); } while (true) { - int subTag = readBERInternal(is, bout, -1); + int subTag = readBERInternal(is, bout, -1, depth); if (subTag == 0) { // EOC, end of indefinite-length section break; } diff --git a/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java b/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java index b1a26498143..186b441f2a7 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * 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,9 +39,7 @@ /** * Class to obtain CRLs via the CRLDistributionPoints extension. - * Note that the functionality of this class must be explicitly enabled - * via a system property, see the USE_CRLDP variable below. - * + *

* This class uses the URICertStore class to fetch CRLs. The URICertStore * class also implements CRL caching: see the class description for more * information. diff --git a/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java b/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java index 6d8e842419a..835d6b562d7 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * 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,6 +39,7 @@ import java.security.cert.Extension; import java.security.cert.*; import java.util.*; +import java.util.stream.Collectors; import javax.security.auth.x500.X500Principal; import static sun.security.provider.certpath.OCSP.*; @@ -988,13 +989,17 @@ private void buildToNewKey(X509Certificate currCert, // any way to convey them back to the application. // That's the default, so no need to write code. builderParams.setDate(params.date()); - builderParams.setCertPathCheckers(params.certPathCheckers()); builderParams.setSigProvider(params.sigProvider()); // Skip revocation during this build to detect circular // references. But check revocation afterwards, using the // key (or any other that works). builderParams.setRevocationEnabled(false); + // Remove itself from params to avoid circular reference. + builderParams.setCertPathCheckers(params.certPathCheckers() + .stream() + .filter(checker -> checker != this) + .collect(Collectors.toUnmodifiableList())); // check for AuthorityInformationAccess extension if (Builder.USE_AIA == true) { diff --git a/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java b/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java index 753c8213a59..8f219586dba 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package sun.security.ssl; +import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE; + import java.io.IOException; import java.nio.ByteBuffer; import java.util.List; @@ -96,26 +98,27 @@ public byte[] produce(ConnectionContext context, } // Produce the extension. - if (chc.localSupportedSignAlgs == null) { - chc.localSupportedSignAlgs = - SignatureScheme.getSupportedAlgorithms( - chc.sslConfig, - chc.algorithmConstraints, chc.activeProtocols); + if (chc.localSupportedCertSignAlgs == null) { + chc.localSupportedCertSignAlgs = + SignatureScheme.getSupportedAlgorithms( + chc.sslConfig, + chc.algorithmConstraints, chc.activeProtocols, + CERTIFICATE_SCOPE); } int vectorLen = SignatureScheme.sizeInRecord() * - chc.localSupportedSignAlgs.size(); + chc.localSupportedCertSignAlgs.size(); byte[] extData = new byte[vectorLen + 2]; ByteBuffer m = ByteBuffer.wrap(extData); Record.putInt16(m, vectorLen); - for (SignatureScheme ss : chc.localSupportedSignAlgs) { + for (SignatureScheme ss : chc.localSupportedCertSignAlgs) { Record.putInt16(m, ss.id); } // Update the context. chc.handshakeExtensions.put( SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT, - new SignatureSchemesSpec(chc.localSupportedSignAlgs)); + new SignatureSchemesSpec(chc.localSupportedCertSignAlgs)); return extData; } @@ -195,7 +198,9 @@ public void consume(ConnectionContext context, SignatureScheme.getSupportedAlgorithms( shc.sslConfig, shc.algorithmConstraints, shc.negotiatedProtocol, - spec.signatureSchemes); + spec.signatureSchemes, + CERTIFICATE_SCOPE); + shc.peerRequestedCertSignSchemes = schemes; shc.handshakeSession.setPeerSupportedSignatureAlgorithms(schemes); @@ -244,24 +249,28 @@ public byte[] produce(ConnectionContext context, } // Produce the extension. - List sigAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, - List.of(shc.negotiatedProtocol)); + if (shc.localSupportedCertSignAlgs == null) { + shc.localSupportedCertSignAlgs = + SignatureScheme.getSupportedAlgorithms( + shc.sslConfig, + shc.algorithmConstraints, + List.of(shc.negotiatedProtocol), + CERTIFICATE_SCOPE); + } - int vectorLen = SignatureScheme.sizeInRecord() * sigAlgs.size(); + int vectorLen = SignatureScheme.sizeInRecord() + * shc.localSupportedCertSignAlgs.size(); byte[] extData = new byte[vectorLen + 2]; ByteBuffer m = ByteBuffer.wrap(extData); Record.putInt16(m, vectorLen); - for (SignatureScheme ss : sigAlgs) { + for (SignatureScheme ss : shc.localSupportedCertSignAlgs) { Record.putInt16(m, ss.id); } // Update the context. shc.handshakeExtensions.put( SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT, - new SignatureSchemesSpec(shc.localSupportedSignAlgs)); + new SignatureSchemesSpec(shc.localSupportedCertSignAlgs)); return extData; } @@ -340,7 +349,9 @@ public void consume(ConnectionContext context, SignatureScheme.getSupportedAlgorithms( chc.sslConfig, chc.algorithmConstraints, chc.negotiatedProtocol, - spec.signatureSchemes); + spec.signatureSchemes, + CERTIFICATE_SCOPE); + chc.peerRequestedCertSignSchemes = schemes; chc.handshakeSession.setPeerSupportedSignatureAlgorithms(schemes); } diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java index 753219f4590..2647672c1a5 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,9 @@ package sun.security.ssl; +import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE; +import static sun.security.ssl.SignatureScheme.HANDSHAKE_SCOPE; + import java.io.IOException; import java.nio.ByteBuffer; import java.security.PrivateKey; @@ -380,7 +383,6 @@ public void consume(ConnectionContext context, crm.getAuthorities(), (SSLEngine)chc.conContext.transport); } - if (clientAlias == null) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("No available client authentication"); @@ -607,16 +609,33 @@ private T12CertificateRequestProducer() { public byte[] produce(ConnectionContext context, HandshakeMessage message) throws IOException { // The producing happens in server side only. - ServerHandshakeContext shc = (ServerHandshakeContext)context; + ServerHandshakeContext shc = (ServerHandshakeContext) context; + if (shc.localSupportedSignAlgs == null) { shc.localSupportedSignAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols); + SignatureScheme.getSupportedAlgorithms( + shc.sslConfig, + shc.algorithmConstraints, shc.activeProtocols, + HANDSHAKE_SCOPE); + } + + if (shc.localSupportedCertSignAlgs == null) { + shc.localSupportedCertSignAlgs = + SignatureScheme.getSupportedAlgorithms( + shc.sslConfig, + shc.algorithmConstraints, shc.activeProtocols, + CERTIFICATE_SCOPE); } - if (shc.localSupportedSignAlgs == null || - shc.localSupportedSignAlgs.isEmpty()) { + // According to TLSv1.2 RFC, CertificateRequest message must + // contain signature schemes supported for both: + // handshake signatures and certificate signatures. + List certReqSignAlgs = + new ArrayList<>(shc.localSupportedSignAlgs); + certReqSignAlgs.retainAll(shc.localSupportedCertSignAlgs); + + if (certReqSignAlgs == null || + certReqSignAlgs.isEmpty()) { throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, "No supported signature algorithm"); } @@ -625,7 +644,7 @@ public byte[] produce(ConnectionContext context, shc.sslContext.getX509TrustManager().getAcceptedIssuers(); T12CertificateRequestMessage crm = new T12CertificateRequestMessage( shc, caCerts, shc.negotiatedCipherSuite.keyExchange, - shc.localSupportedSignAlgs); + certReqSignAlgs); if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced CertificateRequest handshake message", crm); @@ -706,19 +725,28 @@ public void consume(ConnectionContext context, chc.handshakeProducers.put(SSLHandshake.CERTIFICATE.id, SSLHandshake.CERTIFICATE); - List sss = + List signAlgs = + SignatureScheme.getSupportedAlgorithms( + chc.sslConfig, + chc.algorithmConstraints, chc.negotiatedProtocol, + crm.algorithmIds, + HANDSHAKE_SCOPE); + + List signCertAlgs = SignatureScheme.getSupportedAlgorithms( chc.sslConfig, chc.algorithmConstraints, chc.negotiatedProtocol, - crm.algorithmIds); - if (sss == null || sss.isEmpty()) { + crm.algorithmIds, + CERTIFICATE_SCOPE); + + if (signAlgs == null || signAlgs.isEmpty() || signCertAlgs.isEmpty()) { throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, "No supported signature algorithm"); } - chc.peerRequestedSignatureSchemes = sss; - chc.peerRequestedCertSignSchemes = sss; // use the same schemes - chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss); + chc.peerRequestedSignatureSchemes = signAlgs; + chc.peerRequestedCertSignSchemes = signCertAlgs; + chc.handshakeSession.setPeerSupportedSignatureAlgorithms(signCertAlgs); chc.peerSupportedAuthorities = crm.getAuthorities(); // For TLS 1.2, we need to use a combination of the CR message's diff --git a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java index 44a3cc38ef0..55b3a3dacb6 100644 --- a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java +++ b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,7 +82,7 @@ abstract class HandshakeContext implements ConnectionContext { // consolidated parameters final List activeProtocols; final List activeCipherSuites; - final AlgorithmConstraints algorithmConstraints; + final SSLAlgorithmConstraints algorithmConstraints; final ProtocolVersion maximumActiveProtocol; // output stream @@ -135,6 +135,7 @@ abstract class HandshakeContext implements ConnectionContext { // SignatureScheme List localSupportedSignAlgs; + List localSupportedCertSignAlgs; List peerRequestedSignatureSchemes; List peerRequestedCertSignSchemes; diff --git a/src/java.base/share/classes/sun/security/ssl/PostHandshakeContext.java b/src/java.base/share/classes/sun/security/ssl/PostHandshakeContext.java index 692fd74ba10..a5f9c8c5491 100644 --- a/src/java.base/share/classes/sun/security/ssl/PostHandshakeContext.java +++ b/src/java.base/share/classes/sun/security/ssl/PostHandshakeContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ final class PostHandshakeContext extends HandshakeContext { "Post-handshake not supported in " + negotiatedProtocol.name); } - this.localSupportedSignAlgs = new ArrayList<>( + this.localSupportedCertSignAlgs = new ArrayList<>( context.conSession.getLocalSupportedSignatureSchemes()); // Add the potential post-handshake consumers. diff --git a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java index 4bcf8dce262..9f0b6716624 100644 --- a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import sun.security.ssl.SSLExtension.SSLExtensionSpec; import sun.security.ssl.SSLHandshake.HandshakeMessage; import static sun.security.ssl.SSLExtension.*; +import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE; /** * Pack of the "pre_shared_key" extension. @@ -414,15 +415,16 @@ private static boolean canRejoin(ClientHelloMessage clientHello, result = false; } - // Make sure that the server handshake context's localSupportedSignAlgs - // field is populated. This is particularly important when - // client authentication was used in an initial session and it is - // now being resumed. - if (shc.localSupportedSignAlgs == null) { - shc.localSupportedSignAlgs = + // Make sure that the server handshake context's + // localSupportedCertSignAlgs field is populated. This is particularly + // important when client authentication was used in an initial session, + // and it is now being resumed. + if (shc.localSupportedCertSignAlgs == null) { + shc.localSupportedCertSignAlgs = SignatureScheme.getSupportedAlgorithms( shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols); + shc.algorithmConstraints, shc.activeProtocols, + CERTIFICATE_SCOPE); } // Validate the required client authentication. @@ -444,7 +446,7 @@ private static boolean canRejoin(ClientHelloMessage clientHello, Collection sessionSigAlgs = s.getLocalSupportedSignatureSchemes(); if (result && - !shc.localSupportedSignAlgs.containsAll(sessionSigAlgs)) { + !shc.localSupportedCertSignAlgs.containsAll(sessionSigAlgs)) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Can't resume. Session uses different " + @@ -638,7 +640,7 @@ public byte[] produce(ConnectionContext context, // Make sure the list of supported signature algorithms matches Collection sessionSigAlgs = chc.resumingSession.getLocalSupportedSignatureSchemes(); - if (!chc.localSupportedSignAlgs.containsAll(sessionSigAlgs)) { + if (!chc.localSupportedCertSignAlgs.containsAll(sessionSigAlgs)) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Existing session uses different " + "signature algorithms"); diff --git a/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java index 59662ab8fd2..171026f1a93 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * 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,11 +42,11 @@ */ final class SSLAlgorithmConstraints implements AlgorithmConstraints { - private static final AlgorithmConstraints tlsDisabledAlgConstraints = + private static final DisabledAlgorithmConstraints tlsDisabledAlgConstraints = new DisabledAlgorithmConstraints(PROPERTY_TLS_DISABLED_ALGS, new SSLAlgorithmDecomposer()); - private static final AlgorithmConstraints x509DisabledAlgConstraints = + private static final DisabledAlgorithmConstraints x509DisabledAlgConstraints = new DisabledAlgorithmConstraints(PROPERTY_CERTPATH_DISABLED_ALGS, new SSLAlgorithmDecomposer(true)); @@ -56,11 +56,11 @@ final class SSLAlgorithmConstraints implements AlgorithmConstraints { private final boolean enabledX509DisabledAlgConstraints; // the default algorithm constraints - static final AlgorithmConstraints DEFAULT = + static final SSLAlgorithmConstraints DEFAULT = new SSLAlgorithmConstraints(null, true); // the default SSL only algorithm constraints - static final AlgorithmConstraints DEFAULT_SSL_ONLY = + static final SSLAlgorithmConstraints DEFAULT_SSL_ONLY = new SSLAlgorithmConstraints(null, false); private SSLAlgorithmConstraints(AlgorithmConstraints userSpecifiedConstraints, @@ -84,11 +84,11 @@ private SSLAlgorithmConstraints( * @param userSpecifiedConstraints additional constraints to check * @return a SSLAlgorithmConstraints instance */ - static AlgorithmConstraints wrap(AlgorithmConstraints userSpecifiedConstraints) { + static SSLAlgorithmConstraints wrap(AlgorithmConstraints userSpecifiedConstraints) { return wrap(userSpecifiedConstraints, true); } - private static AlgorithmConstraints wrap( + private static SSLAlgorithmConstraints wrap( AlgorithmConstraints userSpecifiedConstraints, boolean withDefaultCertPathConstraints) { if (nullIfDefault(userSpecifiedConstraints) == null) { @@ -199,22 +199,22 @@ public boolean permits(Set primitives, if (peerSpecifiedConstraints != null) { permitted = peerSpecifiedConstraints.permits( - primitives, algorithm, parameters); + primitives, algorithm, parameters); } if (permitted && userSpecifiedConstraints != null) { permitted = userSpecifiedConstraints.permits( - primitives, algorithm, parameters); + primitives, algorithm, parameters); } if (permitted) { permitted = tlsDisabledAlgConstraints.permits( - primitives, algorithm, parameters); + primitives, algorithm, parameters); } if (permitted && enabledX509DisabledAlgConstraints) { permitted = x509DisabledAlgConstraints.permits( - primitives, algorithm, parameters); + primitives, algorithm, parameters); } return permitted; @@ -252,27 +252,31 @@ public boolean permits(Set primitives, if (peerSpecifiedConstraints != null) { permitted = peerSpecifiedConstraints.permits( - primitives, algorithm, key, parameters); + primitives, algorithm, key, parameters); } if (permitted && userSpecifiedConstraints != null) { permitted = userSpecifiedConstraints.permits( - primitives, algorithm, key, parameters); + primitives, algorithm, key, parameters); } if (permitted) { permitted = tlsDisabledAlgConstraints.permits( - primitives, algorithm, key, parameters); + primitives, algorithm, key, parameters); } if (permitted && enabledX509DisabledAlgConstraints) { permitted = x509DisabledAlgConstraints.permits( - primitives, algorithm, key, parameters); + primitives, algorithm, key, parameters); } return permitted; } + // Checks if algorithm is disabled for the given TLS scopes. + boolean permits(String algorithm, Set scopes) { + return tlsDisabledAlgConstraints.permits(algorithm, scopes); + } private static class SupportedSignatureAlgorithmConstraints implements AlgorithmConstraints { diff --git a/src/java.base/share/classes/sun/security/ssl/SSLScope.java b/src/java.base/share/classes/sun/security/ssl/SSLScope.java new file mode 100644 index 00000000000..d2f4dfc14a3 --- /dev/null +++ b/src/java.base/share/classes/sun/security/ssl/SSLScope.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +/* + * Scopes defining different parts of TLS protocol. + */ + +public enum SSLScope { + // Handshake signature scope as in signature_algorithms extension. + HANDSHAKE_SIGNATURE("HandshakeSignature"), + + // Certificate signature scope as in signature_algorithms_cert extension. + CERTIFICATE_SIGNATURE("CertificateSignature"); + + private final String name; + + SSLScope(String name) { + this.name = name; + } + + // Note: the SSLScope name is case-insensitive. + public static SSLScope nameOf(String scopeName) { + for (SSLScope scope : SSLScope.values()) { + if (scope.name.equalsIgnoreCase(scopeName)) { + return scope; + } + } + + return null; + } +} diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java index 8ab7b7917b5..263313b9f8a 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -183,10 +183,10 @@ final class SSLSessionImpl extends ExtendedSSLSession { this.sessionId = id; this.host = hc.conContext.transport.getPeerHost(); this.port = hc.conContext.transport.getPeerPort(); - this.localSupportedSignAlgs = hc.localSupportedSignAlgs == null ? + this.localSupportedSignAlgs = hc.localSupportedCertSignAlgs == null ? Collections.emptySet() : Collections.unmodifiableCollection( - new ArrayList<>(hc.localSupportedSignAlgs)); + new ArrayList<>(hc.localSupportedCertSignAlgs)); this.serverNameIndication = hc.negotiatedServerName; this.requestedServerNames = Collections.unmodifiableList( new ArrayList<>(hc.getRequestedServerNames())); diff --git a/src/java.base/share/classes/sun/security/ssl/ServerHello.java b/src/java.base/share/classes/sun/security/ssl/ServerHello.java index 812ec896d28..1c9076b3811 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerHello.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,9 @@ package sun.security.ssl; +import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE; +import static sun.security.ssl.SignatureScheme.HANDSHAKE_SCOPE; + import java.io.IOException; import java.nio.ByteBuffer; import java.security.AlgorithmConstraints; @@ -276,7 +279,16 @@ public byte[] produce(ConnectionContext context, shc.localSupportedSignAlgs = SignatureScheme.getSupportedAlgorithms( shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols); + shc.algorithmConstraints, shc.activeProtocols, + HANDSHAKE_SCOPE); + } + + if (shc.localSupportedCertSignAlgs == null) { + shc.localSupportedCertSignAlgs = + SignatureScheme.getSupportedAlgorithms( + shc.sslConfig, + shc.algorithmConstraints, shc.activeProtocols, + CERTIFICATE_SCOPE); } SSLSessionImpl session = @@ -505,7 +517,16 @@ public byte[] produce(ConnectionContext context, shc.localSupportedSignAlgs = SignatureScheme.getSupportedAlgorithms( shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols); + shc.algorithmConstraints, shc.activeProtocols, + HANDSHAKE_SCOPE); + } + + if (shc.localSupportedCertSignAlgs == null) { + shc.localSupportedCertSignAlgs = + SignatureScheme.getSupportedAlgorithms( + shc.sslConfig, + shc.algorithmConstraints, shc.activeProtocols, + CERTIFICATE_SCOPE); } SSLSessionImpl session = diff --git a/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java b/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java index 541c51d2c64..01dbc41acaf 100644 --- a/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,9 @@ package sun.security.ssl; +import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE; +import static sun.security.ssl.SignatureScheme.HANDSHAKE_SCOPE; + import java.io.IOException; import java.nio.ByteBuffer; import java.text.MessageFormat; @@ -32,6 +35,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Locale; +import javax.net.ssl.SSLException; import javax.net.ssl.SSLProtocolException; import sun.security.ssl.SSLExtension.ExtensionConsumer; import sun.security.ssl.SSLExtension.SSLExtensionSpec; @@ -186,7 +190,8 @@ public byte[] produce(ConnectionContext context, chc.localSupportedSignAlgs = SignatureScheme.getSupportedAlgorithms( chc.sslConfig, - chc.algorithmConstraints, chc.activeProtocols); + chc.algorithmConstraints, chc.activeProtocols, + HANDSHAKE_SCOPE); } int vectorLen = SignatureScheme.sizeInRecord() * @@ -275,28 +280,8 @@ public void consume(ConnectionContext context, return; } - // update the context - List sss = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, shc.negotiatedProtocol, - spec.signatureSchemes); - if (sss == null || sss.isEmpty()) { - throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, - "No supported signature algorithm"); - } - shc.peerRequestedSignatureSchemes = sss; - - // If no "signature_algorithms_cert" extension is present, then - // the "signature_algorithms" extension also applies to - // signatures appearing in certificates. - SignatureSchemesSpec certSpec = - (SignatureSchemesSpec)shc.handshakeExtensions.get( - SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT); - if (certSpec == null) { - shc.peerRequestedCertSignSchemes = sss; - shc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss); - } + updateHandshakeContext(shc, spec.signatureSchemes, + SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT); if (!shc.isResumption && shc.negotiatedProtocol.useTLS13PlusSpec()) { @@ -418,7 +403,8 @@ public byte[] produce(ConnectionContext context, SignatureScheme.getSupportedAlgorithms( shc.sslConfig, shc.algorithmConstraints, - List.of(shc.negotiatedProtocol)); + List.of(shc.negotiatedProtocol), + HANDSHAKE_SCOPE); int vectorLen = SignatureScheme.sizeInRecord() * sigAlgs.size(); byte[] extData = new byte[vectorLen + 2]; @@ -514,28 +500,8 @@ public void consume(ConnectionContext context, return; } - // update the context - List sss = - SignatureScheme.getSupportedAlgorithms( - chc.sslConfig, - chc.algorithmConstraints, chc.negotiatedProtocol, - spec.signatureSchemes); - if (sss == null || sss.isEmpty()) { - throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, - "No supported signature algorithm"); - } - chc.peerRequestedSignatureSchemes = sss; - - // If no "signature_algorithms_cert" extension is present, then - // the "signature_algorithms" extension also applies to - // signatures appearing in certificates. - SignatureSchemesSpec certSpec = - (SignatureSchemesSpec)chc.handshakeExtensions.get( - SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT); - if (certSpec == null) { - chc.peerRequestedCertSignSchemes = sss; - chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss); - } + updateHandshakeContext(chc, spec.signatureSchemes, + SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT); } } @@ -558,4 +524,49 @@ public void absent(ConnectionContext context, "received CertificateRequest handshake message"); } } + + // Updates given HandshakeContext with peer signature schemes. + private static void updateHandshakeContext(HandshakeContext hc, + int[] signatureSchemes, SSLExtension signatureAlgorithmsCertExt) + throws SSLException { + List handshakeSS = + SignatureScheme.getSupportedAlgorithms( + hc.sslConfig, + hc.algorithmConstraints, + hc.negotiatedProtocol, + signatureSchemes, + HANDSHAKE_SCOPE); + + if (handshakeSS.isEmpty()) { + throw hc.conContext.fatal(Alert.HANDSHAKE_FAILURE, + "No supported signature algorithm"); + } + + hc.peerRequestedSignatureSchemes = handshakeSS; + + // If no "signature_algorithms_cert" extension is present, then + // the "signature_algorithms" extension also applies to + // signatures appearing in certificates. + SignatureSchemesSpec certSpec = + (SignatureSchemesSpec) hc.handshakeExtensions.get( + signatureAlgorithmsCertExt); + + if (certSpec == null) { + List certSS = + SignatureScheme.getSupportedAlgorithms( + hc.sslConfig, + hc.algorithmConstraints, + hc.negotiatedProtocol, + signatureSchemes, + CERTIFICATE_SCOPE); + + if (certSS.isEmpty()) { + throw hc.conContext.fatal(Alert.HANDSHAKE_FAILURE, + "No supported signature algorithm"); + } + + hc.peerRequestedCertSignSchemes = certSS; + hc.handshakeSession.setPeerSupportedSignatureAlgorithms(certSS); + } + } } diff --git a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java index b6003816eda..f80ec9d7c3d 100644 --- a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java +++ b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.EnumSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -134,8 +133,9 @@ enum SignatureScheme { "DSA", ProtocolVersion.PROTOCOLS_TO_12), ECDSA_SHA1 (0x0203, "ecdsa_sha1", "SHA1withECDSA", - "EC", - ProtocolVersion.PROTOCOLS_TO_13), + "EC", null, null, -1, + ProtocolVersion.PROTOCOLS_TO_13, + ProtocolVersion.PROTOCOLS_TO_12), RSA_PKCS1_SHA1 (0x0201, "rsa_pkcs1_sha1", "SHA1withRSA", "RSA", null, null, 511, ProtocolVersion.PROTOCOLS_TO_13, @@ -219,10 +219,17 @@ static enum SigAlgParamSpec { // support RSASSA-PSS only now } } - // performance optimization - private static final Set SIGNATURE_PRIMITIVE_SET = - Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); + // Handshake signature scope. + static final Set HANDSHAKE_SCOPE = + Set.of(SSLScope.HANDSHAKE_SIGNATURE); + + // Certificate signature scope. + static final Set CERTIFICATE_SCOPE = + Set.of(SSLScope.CERTIFICATE_SIGNATURE); + // Non-TLS specific SIGNATURE CryptoPrimitive. + private static final Set SIGNATURE_PRIMITIVE_SET = + Set.of(CryptoPrimitive.SIGNATURE); private SignatureScheme(int id, String name, String algorithm, String keyAlgorithm, @@ -355,24 +362,25 @@ static int sizeInRecord() { return 2; } - private boolean isPermitted(AlgorithmConstraints constraints) { - return constraints.permits(SIGNATURE_PRIMITIVE_SET, - this.name, null) && - constraints.permits(SIGNATURE_PRIMITIVE_SET, - this.keyAlgorithm, null) && - constraints.permits(SIGNATURE_PRIMITIVE_SET, - this.algorithm, (signAlgParams != null ? - signAlgParams.parameters : null)) && - (namedGroup != null ? - namedGroup.isPermitted(constraints) : true); + private boolean isPermitted( + SSLAlgorithmConstraints constraints, Set scopes) { + return constraints.permits(this.name, scopes) + && constraints.permits(this.keyAlgorithm, scopes) + && constraints.permits(this.algorithm, scopes) + && constraints.permits(SIGNATURE_PRIMITIVE_SET, this.name, null) + && constraints.permits(SIGNATURE_PRIMITIVE_SET, this.keyAlgorithm, null) + && constraints.permits(SIGNATURE_PRIMITIVE_SET, this.algorithm, + (signAlgParams != null ? signAlgParams.parameters : null)) + && (namedGroup == null || namedGroup.isPermitted(constraints)); } // Get local supported algorithm collection complying to algorithm - // constraints. + // constraints and SSL scopes. static List getSupportedAlgorithms( SSLConfiguration config, - AlgorithmConstraints constraints, - List activeProtocols) { + SSLAlgorithmConstraints constraints, + List activeProtocols, + Set scopes) { List supported = new LinkedList<>(); for (SignatureScheme ss: SignatureScheme.values()) { if (!ss.isAvailable || @@ -388,14 +396,14 @@ static List getSupportedAlgorithms( boolean isMatch = false; for (ProtocolVersion pv : activeProtocols) { - if (ss.supportedProtocols.contains(pv)) { + if (ss.isSupportedProtocol(pv, scopes)) { isMatch = true; break; } } if (isMatch) { - if (ss.isPermitted(constraints)) { + if (ss.isPermitted(constraints, scopes)) { supported.add(ss); } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) { @@ -414,8 +422,10 @@ static List getSupportedAlgorithms( static List getSupportedAlgorithms( SSLConfiguration config, - AlgorithmConstraints constraints, - ProtocolVersion protocolVersion, int[] algorithmIds) { + SSLAlgorithmConstraints constraints, + ProtocolVersion protocolVersion, + int[] algorithmIds, + Set scopes) { List supported = new LinkedList<>(); for (int ssid : algorithmIds) { SignatureScheme ss = SignatureScheme.valueOf(ssid); @@ -425,11 +435,9 @@ static List getSupportedAlgorithms( "Unsupported signature scheme: " + SignatureScheme.nameOf(ssid)); } - } else if (ss.isAvailable && - ss.supportedProtocols.contains(protocolVersion) && - (config.signatureSchemes.isEmpty() || - config.signatureSchemes.contains(ss)) && - ss.isPermitted(constraints)) { + } else if ((config.signatureSchemes.isEmpty() + || config.signatureSchemes.contains(ss)) + && ss.isAllowed(constraints, protocolVersion, scopes)) { supported.add(ss); } else { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { @@ -443,16 +451,14 @@ static List getSupportedAlgorithms( } static SignatureScheme getPreferableAlgorithm( - AlgorithmConstraints constraints, + SSLAlgorithmConstraints constraints, List schemes, SignatureScheme certScheme, ProtocolVersion version) { for (SignatureScheme ss : schemes) { - if (ss.isAvailable && - ss.handshakeSupportedProtocols.contains(version) && - certScheme.keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm) && - ss.isPermitted(constraints)) { + if (certScheme.keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm) + && ss.isAllowed(constraints, version, HANDSHAKE_SCOPE)) { return ss; } } @@ -461,7 +467,7 @@ static SignatureScheme getPreferableAlgorithm( } static Map.Entry getSignerOfPreferableAlgorithm( - AlgorithmConstraints constraints, + SSLAlgorithmConstraints constraints, List schemes, X509Possession x509Possession, ProtocolVersion version) { @@ -477,10 +483,9 @@ static Map.Entry getSignerOfPreferableAlgorithm( keySize = Integer.MAX_VALUE; } for (SignatureScheme ss : schemes) { - if (ss.isAvailable && (keySize >= ss.minimalKeySize) && - ss.handshakeSupportedProtocols.contains(version) && + if (keySize >= ss.minimalKeySize && keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm) && - ss.isPermitted(constraints)) { + ss.isAllowed(constraints, version, HANDSHAKE_SCOPE)) { if ((ss.namedGroup != null) && (ss.namedGroup.spec == NamedGroupSpec.NAMED_GROUP_ECDHE)) { ECParameterSpec params = @@ -540,6 +545,26 @@ static Map.Entry getSignerOfPreferableAlgorithm( return null; } + // Returns true if this signature scheme is supported for the given + // protocol version and SSL scopes. + private boolean isSupportedProtocol( + ProtocolVersion version, Set scopes) { + if (scopes != null && scopes.equals(HANDSHAKE_SCOPE)) { + return this.handshakeSupportedProtocols.contains(version); + } else { + return this.supportedProtocols.contains(version); + } + } + + // Returns true if this signature scheme is available, supported and + // permitted for the given constraints, protocol version and SSL scopes. + private boolean isAllowed(SSLAlgorithmConstraints constraints, + ProtocolVersion version, Set scopes) { + return isAvailable + && isSupportedProtocol(version, scopes) + && isPermitted(constraints, scopes); + } + static String[] getAlgorithmNames(Collection schemes) { if (schemes != null) { ArrayList names = new ArrayList<>(schemes.size()); diff --git a/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java index 00e4031921f..ce8c845fe01 100644 --- a/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java +++ b/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java @@ -25,6 +25,7 @@ package sun.security.util; +import sun.security.ssl.SSLScope; import sun.security.validator.Validator; import java.lang.ref.SoftReference; @@ -47,6 +48,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -179,6 +181,12 @@ public final boolean permits(Set primitives, return true; } + // Checks if algorithm is disabled for the given TLS scopes. + public boolean permits(String algorithm, Set scopes) { + List list = algorithmConstraints.getConstraints(algorithm); + return list == null || list.stream().allMatch(c -> c.permits(scopes)); + } + /* * Checks if the key algorithm has been disabled or constraints have been * placed on the key. @@ -431,7 +439,7 @@ public Constraints(String propertyName, Set constraintSet) { denyAfterLimit = true; } else if (entry.startsWith("usage")) { String s[] = (entry.substring(5)).trim().split(" "); - c = new UsageConstraint(algorithm, s); + c = new UsageConstraint(algorithm, s, propertyName); if (debug != null) { debug.println("Constraints usage length is " + s.length); } @@ -602,6 +610,17 @@ public boolean permits(AlgorithmParameters parameters) { return true; } + /** + * Check if the algorithm constraint permits the given TLS scopes. + * + * @param scopes TLS scopes + * @return 'true' if TLS scopes are allowed, + * 'false' otherwise. + */ + public boolean permits(Set scopes) { + return true; + } + /** * Check if an algorithm constraint is permitted with a given * ConstraintsParameters. @@ -779,14 +798,49 @@ public boolean permits(Key key) { /* * The usage constraint is for the "usage" keyword. It checks against the - * variant value in ConstraintsParameters. + * variant value in ConstraintsParameters and against TLS scopes. */ private static class UsageConstraint extends Constraint { String[] usages; + Set scopes; - UsageConstraint(String algorithm, String[] usages) { + UsageConstraint( + String algorithm, String[] usages, String propertyName) { this.algorithm = algorithm; - this.usages = usages; + + // Support TLS scopes only for jdk.tls.disabledAlgorithms property. + if (PROPERTY_TLS_DISABLED_ALGS.equals(propertyName)) { + for (String usage : usages) { + SSLScope scope = SSLScope.nameOf(usage); + + if (scope != null) { + if (this.scopes == null) { + this.scopes = new HashSet<>(usages.length); + } + this.scopes.add(scope); + } else { + this.usages = usages; + } + } + + if (this.scopes != null && this.usages != null) { + throw new IllegalArgumentException( + "Can't mix TLS protocol specific constraints" + + " with other usage constraints"); + } + + } else { + this.usages = usages; + } + } + + @Override + public boolean permits(Set scopes) { + if (this.scopes == null || scopes == null) { + return true; + } + + return Collections.disjoint(this.scopes, scopes); } @Override diff --git a/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java b/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java index 36837c60e4d..2c7d93a5a84 100644 --- a/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java +++ b/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,6 +85,22 @@ void checkDistrust(String variant, X509Certificate[] chain) } CamerfirmaTLSPolicy.checkDistrust(chain); } + }, + + /** + * Distrust TLS Server certificates anchored by the Chunghwa ePKI root CA + * and issued after March 17, 2026. If enabled, this policy is currently + * enforced by the PKIX and SunX509 TrustManager implementations + * of the SunJSSE provider implementation. + */ + CHUNGHWA_TLS { + void checkDistrust(String variant, X509Certificate[] chain) + throws ValidatorException { + if (!variant.equals(Validator.VAR_TLS_SERVER)) { + return; + } + ChunghwaTLSPolicy.checkDistrust(chain); + } }; /** diff --git a/src/java.base/share/classes/sun/security/validator/ChunghwaTLSPolicy.java b/src/java.base/share/classes/sun/security/validator/ChunghwaTLSPolicy.java new file mode 100644 index 00000000000..ed377011b45 --- /dev/null +++ b/src/java.base/share/classes/sun/security/validator/ChunghwaTLSPolicy.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.security.validator; + +import java.security.cert.X509Certificate; +import java.time.LocalDate; +import java.time.Month; +import java.time.ZoneOffset; +import java.util.Date; +import java.util.Map; +import java.util.Set; + +import sun.security.util.Debug; +import sun.security.x509.X509CertImpl; + +/** + * This class checks if Chunghwa issued TLS Server certificates should be + * restricted. + */ +final class ChunghwaTLSPolicy { + + private static final Debug debug = Debug.getInstance("certpath"); + + // SHA-256 certificate fingerprint of distrusted root for TLS + // cacerts alias: chunghwaepkirootca + // DN: OU=ePKI Root Certification Authority, + // O="Chunghwa Telecom Co., Ltd.", C=TW + private static final String FINGERPRINT = + "C0A6F4DC63A24BFDCF54EF2A6A082A0A72DE35803E2FF5FF527AE5D87206DFD5"; + + // Any TLS Server certificate that is anchored by the Chunghwa + // root above and is issued after this date will be distrusted. + private static final LocalDate MARCH_17_2026 = + LocalDate.of(2026, Month.MARCH, 17); + + /** + * This method assumes the eeCert is a TLS Server Cert and chains back to + * the anchor. + * + * @param chain the end-entity's certificate chain. The end entity cert + * is at index 0, the trust anchor at index n-1. + * @throws ValidatorException if the certificate is distrusted + */ + static void checkDistrust(X509Certificate[] chain) + throws ValidatorException { + X509Certificate anchor = chain[chain.length-1]; + String fp = fingerprint(anchor); + if (fp == null) { + throw new ValidatorException("Cannot generate fingerprint for " + + "trust anchor of TLS server certificate"); + } + if (FINGERPRINT.equalsIgnoreCase(fp)) { + Date notBefore = chain[0].getNotBefore(); + LocalDate ldNotBefore = LocalDate.ofInstant(notBefore.toInstant(), + ZoneOffset.UTC); + // reject if certificate is issued after March 17, 2026 + checkNotBefore(ldNotBefore, MARCH_17_2026, anchor); + } + } + + private static String fingerprint(X509Certificate cert) { + return X509CertImpl.getFingerprint("SHA-256", cert); + } + + // Check whether the certificate's notBeforeDate is after the + // distrust date for the anchor (root CA). Throw ValidatorException + // if it is after the distrust date. + private static void checkNotBefore(LocalDate notBeforeDate, + LocalDate distrustDate, X509Certificate anchor) + throws ValidatorException { + if (notBeforeDate.isAfter(distrustDate)) { + throw new ValidatorException + ("TLS Server certificate issued after " + distrustDate + + " and anchored by a distrusted legacy Chunghwa root CA: " + + anchor.getSubjectX500Principal(), + ValidatorException.T_UNTRUSTED_CERT, anchor); + } + } + + private ChunghwaTLSPolicy() {} +} diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index ea098a494d0..2a7e58df1f7 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -745,11 +745,30 @@ jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \ # This is in addition to the jdk.certpath.disabledAlgorithms property above. # # See the specification of "jdk.certpath.disabledAlgorithms" for the -# syntax of the disabled algorithm string. Additionally, TLS cipher suites -# can be disabled with this property using one or more "*" wildcard characters. -# For example, "TLS_RSA_*" disables all cipher suites that start with -# "TLS_RSA_". Only cipher suites starting with "TLS_" are allowed to have -# wildcard characters. +# syntax of the disabled algorithm string. +# +# Additional TLS-specific syntax supported by this property: +# +# - TLS cipher suites can be disabled with this property using one or more +# "*" wildcard characters. For example, "TLS_RSA_*" disables all cipher +# suites that start with "TLS_RSA_". Only cipher suites starting with +# "TLS_" are allowed to have wildcard characters. +# +# - TLS protocol specific usage constraints are supported by this property: +# +# UsageConstraint: +# usage UsageType { UsageType } +# +# UsageType: +# HandshakeSignature | CertificateSignature +# +# HandshakeSignature restricts the use of the algorithm in TLS handshake +# signatures. CertificateSignature restricts the use of the algorithm in +# certificate signatures. An algorithm with this constraint cannot include +# other usage types defined in the jdk.certpath.disabledAlgorithms +# property. The usage type follows the keyword and more than one usage type +# can be specified with a whitespace delimiter. +# Example: "rsa_pkcs1_sha1 usage HandshakeSignature" # # Note: The algorithm restrictions do not apply to trust anchors or # self-signed certificates. @@ -762,7 +781,8 @@ jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \ # rsa_pkcs1_sha1, secp224r1, TLS_RSA_* jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, \ MD5withRSA, DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \ - ECDH, TLS_RSA_*, \ + ECDH, TLS_RSA_*, rsa_pkcs1_sha1 usage HandshakeSignature, \ + ecdsa_sha1 usage HandshakeSignature, dsa_sha1 usage HandshakeSignature, \ include jdk.disabled.namedCurves # @@ -1297,6 +1317,9 @@ jdk.sasl.disabledMechanisms= # CAMERFIRMA_TLS : Distrust TLS Server certificates anchored by # a Camerfirma root CA and issued after April 15, 2025. # +# CHUNGHWA_TLS : Distrust TLS Server certificates anchored by +# a Chunghwa root CA and issued after March 17, 2026. +# # Leading and trailing whitespace surrounding each value are ignored. # Unknown values are ignored. If the property is commented out or set to the # empty String, no policies are enforced. @@ -1308,7 +1331,8 @@ jdk.sasl.disabledMechanisms= # jdk.certpath.disabledAlgorithms; those restrictions are still enforced even # if this property is not enabled. # -jdk.security.caDistrustPolicies=SYMANTEC_TLS,ENTRUST_TLS,CAMERFIRMA_TLS +jdk.security.caDistrustPolicies=SYMANTEC_TLS,ENTRUST_TLS,CAMERFIRMA_TLS,\ + CHUNGHWA_TLS # # FilePermission path canonicalization diff --git a/src/java.base/share/native/libzip/zip_util.c b/src/java.base/share/native/libzip/zip_util.c index 41dbd273380..5aa3242766a 100644 --- a/src/java.base/share/native/libzip/zip_util.c +++ b/src/java.base/share/native/libzip/zip_util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -568,7 +568,7 @@ static jlong readCEN(jzfile *zip, jint knownTotal) { /* Following are unsigned 32-bit */ - jlong endpos, end64pos, cenpos, cenlen, cenoff; + jlong endpos, end64pos, cenpos, cenlen, cenoff, total64; /* Following are unsigned 16-bit */ jint total, tablelen, i, j; unsigned char *cenbuf = NULL; @@ -602,7 +602,16 @@ readCEN(jzfile *zip, jint knownTotal) if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) { cenlen = ZIP64_ENDSIZ(end64buf); cenoff = ZIP64_ENDOFF(end64buf); - total = (jint)ZIP64_ENDTOT(end64buf); + total64 = ZIP64_ENDTOT(end64buf); + /* ZIP64 size, offset and total-count fields are unsigned 64-bit + * values. Sizes and offsets that do not fit in signed jlong + * (i.e., >= 2^63), or total values that do not fit in jint, are + * not supported and indicate a corrupt or invalid zip file. + */ + if (cenlen < 0 || cenoff < 0 || total64 < 0 || total64 > INT_MAX) { + ZIP_FORMAT_ERROR("Zip64 END values exceed supported size"); + } + total = (jint)total64; endpos = end64pos; endhdrlen = ZIP64_ENDHDR; } @@ -1137,20 +1146,8 @@ ZIP_FreeEntry(jzfile *jz, jzentry *ze) } } -/* - * Returns the zip entry corresponding to the specified name, or - * NULL if not found. - */ -jzentry * -ZIP_GetEntry(jzfile *zip, char *name, jint ulen) -{ - if (ulen == 0) { - return ZIP_GetEntry2(zip, name, (jint)strlen(name), JNI_FALSE); - } - return ZIP_GetEntry2(zip, name, ulen, JNI_TRUE); -} - -jboolean equals(char* name1, int len1, char* name2, int len2) { +static jboolean +equals(const char* name1, int len1, const char* name2, int len2) { if (len1 != len2) { return JNI_FALSE; } @@ -1162,16 +1159,12 @@ jboolean equals(char* name1, int len1, char* name2, int len2) { return JNI_TRUE; } -/* - * Returns the zip entry corresponding to the specified name, or - * NULL if not found. - * This method supports embedded null character in "name", use ulen - * for the length of "name". - */ jzentry * -ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash) +ZIP_GetEntry(jzfile *zip, const char *name) { - unsigned int hsh = hashN(name, ulen); + // length of the entry name being searched for + const jint name_len = (jint) strlen(name); + const unsigned int hsh = hashN(name, name_len); jint idx; jzentry *ze = 0; @@ -1182,79 +1175,47 @@ ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash) idx = zip->table[hsh % zip->tablelen]; + /* Check the cached entry first */ + ze = zip->cache; + if (ze && equals(ze->name, ze->nlen, name, name_len)) { + /* Cache hit! Remove and return the cached entry. */ + zip->cache = 0; + ZIP_Unlock(zip); + return ze; + } + ze = 0; + /* - * This while loop is an optimization where a double lookup - * for name and name+/ is being performed. The name char - * array has enough room at the end to try again with a - * slash appended if the first table lookup does not succeed. + * Search down the target hash chain for a cell whose + * 32 bit hash matches the hashed name. */ - while(1) { - - /* Check the cached entry first */ - ze = zip->cache; - if (ze && equals(ze->name, ze->nlen, name, ulen)) { - /* Cache hit! Remove and return the cached entry. */ - zip->cache = 0; - ZIP_Unlock(zip); - return ze; - } - ze = 0; - - /* - * Search down the target hash chain for a cell whose - * 32 bit hash matches the hashed name. - */ - while (idx != ZIP_ENDCHAIN) { - jzcell *zc = &zip->entries[idx]; - - if (zc->hash == hsh) { - /* - * OK, we've found a ZIP entry whose 32 bit hashcode - * matches the name we're looking for. Try to read - * its entry information from the CEN. If the CEN - * name matches the name we're looking for, we're - * done. - * If the names don't match (which should be very rare) - * we keep searching. - */ - ze = newEntry(zip, zc, ACCESS_RANDOM); - if (ze && equals(ze->name, ze->nlen, name, ulen)) { - break; - } - if (ze != 0) { - /* We need to release the lock across the free call */ - ZIP_Unlock(zip); - ZIP_FreeEntry(zip, ze); - ZIP_Lock(zip); - } - ze = 0; + while (idx != ZIP_ENDCHAIN) { + jzcell *zc = &zip->entries[idx]; + + if (zc->hash == hsh) { + /* + * OK, we've found a ZIP entry whose 32 bit hashcode + * matches the name we're looking for. Try to read + * its entry information from the CEN. If the CEN + * name matches the name we're looking for, we're + * done. + * If the names don't match (which should be very rare) + * we keep searching. + */ + ze = newEntry(zip, zc, ACCESS_RANDOM); + if (ze && equals(ze->name, ze->nlen, name, name_len)) { + break; } - idx = zc->next; - } - - /* Entry found, return it */ - if (ze != 0) { - break; - } - - /* If no need to try appending slash, we are done */ - if (!addSlash) { - break; - } - - /* Slash is already there? */ - if (ulen > 0 && name[ulen - 1] == '/') { - break; + if (ze != 0) { + /* We need to release the lock across the free call */ + ZIP_Unlock(zip); + ZIP_FreeEntry(zip, ze); + ZIP_Lock(zip); + } + ze = 0; } - - /* Add slash and try once more */ - name[ulen++] = '/'; - name[ulen] = '\0'; - hsh = hash_append(hsh, '/'); - idx = zip->table[hsh % zip->tablelen]; - addSlash = JNI_FALSE; + idx = zc->next; } - Finally: ZIP_Unlock(zip); return ze; @@ -1466,9 +1427,9 @@ InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg) * has the size bigger than 2**32 bytes in ONE invocation. */ JNIEXPORT jzentry * -ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP) +ZIP_FindEntry(jzfile *zip, const char *name, jint *sizeP, jint *nameLenP) { - jzentry *entry = ZIP_GetEntry(zip, name, 0); + jzentry *entry = ZIP_GetEntry(zip, name); if (entry) { *sizeP = (jint)entry->size; *nameLenP = (jint)strlen(entry->name); diff --git a/src/java.base/share/native/libzip/zip_util.h b/src/java.base/share/native/libzip/zip_util.h index a0d925a654a..7847e8f872f 100644 --- a/src/java.base/share/native/libzip/zip_util.h +++ b/src/java.base/share/native/libzip/zip_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +241,15 @@ typedef struct jzfile { /* Zip file */ */ #define ZIP_ENDCHAIN ((jint)-1) +/* + * Returns the ZIP entry corresponding to the given (NULL terminated) + * entry name. Returns NULL if no entry is found by that name. + * If the entry is found, then the value of the given sizeP will be + * updated to the ZIP entry's size and the value of nameLenP will be + * updated to the ZIP entry name's length. + */ JNIEXPORT jzentry * -ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP); +ZIP_FindEntry(jzfile *zip, const char *name, jint *sizeP, jint *nameLenP); JNIEXPORT jboolean ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entrynm); @@ -268,8 +275,12 @@ ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, JNIEXPORT void ZIP_Close(jzfile *zip); +/* + * Returns the ZIP entry corresponding to the given (NULL terminated) + * entry name. Returns NULL if no entry is found by that name. + */ jzentry * -ZIP_GetEntry(jzfile *zip, char *name, jint ulen); +ZIP_GetEntry(jzfile *zip, const char *name); void ZIP_Lock(jzfile *zip); void @@ -279,7 +290,6 @@ ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len); void ZIP_FreeEntry(jzfile *zip, jzentry *ze); jlong ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry); -jzentry * ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash); JNIEXPORT jboolean ZIP_InflateFully(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pmsg); diff --git a/src/java.desktop/share/classes/sun/awt/geom/AreaOp.java b/src/java.desktop/share/classes/sun/awt/geom/AreaOp.java index 785ffb2331c..70109ed43e8 100644 --- a/src/java.desktop/share/classes/sun/awt/geom/AreaOp.java +++ b/src/java.desktop/share/classes/sun/awt/geom/AreaOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -146,6 +146,8 @@ private AreaOp() { public static final int RSTAG_INSIDE = 1; public static final int RSTAG_OUTSIDE = -1; + public static final int MAX_LINK_COUNT = 1024; + public abstract void newRow(); public abstract int classify(Edge e); @@ -195,6 +197,25 @@ public int compare(Edge o1, Edge o2) { } }; + private void consumeSubCurves(Vector subcurves, + Vector chains, + Vector curve) { + finalizeSubCurves(subcurves, chains); + Enumeration enum_ = subcurves.elements(); + while (enum_.hasMoreElements()) { + CurveLink link = enum_.nextElement(); + curve.add(link.getMoveto()); + CurveLink nextlink = link; + while ((nextlink = nextlink.getNext()) != null) { + if (!link.absorb(nextlink)) { + curve.add(link.getSubCurve()); + link = nextlink; + } + } + curve.add(link.getSubCurve()); + } + } + private Vector pruneEdges(Vector edges) { int numedges = edges.size(); if (numedges < 2) { @@ -218,6 +239,8 @@ private Vector pruneEdges(Vector edges) { Vector subcurves = new Vector<>(); Vector chains = new Vector<>(); Vector links = new Vector<>(); + Vector ret = new Vector<>(); + int linkCount = 0; // Active edges are between left (inclusive) and right (exclusive) while (left < numedges) { double y = yrange[0]; @@ -390,27 +413,22 @@ private Vector pruneEdges(Vector edges) { System.out.println(" "+link.getSubCurve()); } } + // If we have complex area calculation, we should consume the + // intermediate subcurves to optimize memory footprint + if (linkCount >= MAX_LINK_COUNT) { + consumeSubCurves(subcurves, chains, ret); + linkCount = 0; + chains.clear(); + subcurves.clear(); + } + linkCount += links.size(); resolveLinks(subcurves, chains, links); links.clear(); // Finally capture the bottom of the valid Y range as the top // of the next Y range. yrange[0] = yend; } - finalizeSubCurves(subcurves, chains); - Vector ret = new Vector<>(); - Enumeration enum_ = subcurves.elements(); - while (enum_.hasMoreElements()) { - CurveLink link = enum_.nextElement(); - ret.add(link.getMoveto()); - CurveLink nextlink = link; - while ((nextlink = nextlink.getNext()) != null) { - if (!link.absorb(nextlink)) { - ret.add(link.getSubCurve()); - link = nextlink; - } - } - ret.add(link.getSubCurve()); - } + consumeSubCurves(subcurves, chains, ret); return ret; } diff --git a/src/java.desktop/share/classes/sun/awt/geom/Curve.java b/src/java.desktop/share/classes/sun/awt/geom/Curve.java index bc478da02b3..7f2a9ecc9f0 100644 --- a/src/java.desktop/share/classes/sun/awt/geom/Curve.java +++ b/src/java.desktop/share/classes/sun/awt/geom/Curve.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -926,6 +926,9 @@ public int compareTo(Curve that, double yrange[]) { double bump = ymin; double maxbump = Math.min(ymin * 1E13, (y1 - y0) * .1); double y = y0 + bump; + if (!Double.isFinite(y1)) { + return 0; + } while (y <= y1) { if (fairlyClose(this.XforY(y), that.XforY(y))) { if ((bump *= 2) > maxbump) { @@ -1199,7 +1202,7 @@ public double refineTforY(double t0, double yt0, double y0) { public boolean fairlyClose(double v1, double v2) { return (Math.abs(v1 - v2) < - Math.max(Math.abs(v1), Math.abs(v2)) * 1E-10); + Math.max(Math.abs(v1), Math.abs(v2)) * 1E-8); } public abstract int getSegment(double coords[]); diff --git a/src/java.desktop/share/legal/freetype.md b/src/java.desktop/share/legal/freetype.md index 2c654e154ba..0c99e79209d 100644 --- a/src/java.desktop/share/legal/freetype.md +++ b/src/java.desktop/share/legal/freetype.md @@ -1,4 +1,4 @@ -## The FreeType Project: Freetype v2.13.3 +## The FreeType Project: Freetype v2.14.2 ### FreeType Notice @@ -21,25 +21,24 @@ which fits your needs best. ### FreeType License ``` -Copyright (C) 1996-2024 by David Turner, Robert Wilhelm, and Werner Lemberg. -Copyright (C) 2007-2024 by Dereg Clegg and Michael Toftdal. -Copyright (C) 1996-2024 by Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. -Copyright (C) 2022-2024 by David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and -Copyright (C) 2004-2024 by Masatake YAMATO and Redhat K.K. -Copyright (C) 2007-2024 by Derek Clegg and Michael Toftdal. -Copyright (C) 2003-2024 by Masatake YAMATO, Red Hat K.K., -Copyright (C) 1996-2024 by David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. -Copyright (C) 2007-2024 by David Turner. -Copyright (C) 2022-2024 by David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. -Copyright (C) 2007-2024 by Rahul Bhalerao , . -Copyright (C) 2008-2024 by David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya. -Copyright (C) 2013-2024 by Google, Inc. -Copyright (C) 2019-2024 by Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. -Copyright (C) 2009-2024 by Oran Agra and Mickey Gabel. -Copyright (C) 2018-2024 by David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg. -Copyright (C) 2004-2024 by David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. - - +Copyright (C) 1996-2025 by David Turner, Robert Wilhelm, and Werner Lemberg. +Copyright (C) 2007-2025 by Dereg Clegg and Michael Toftdal. +Copyright (C) 1996-2025 by Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. +Copyright (C) 2022-2025 by David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and +Copyright (C) 2004-2025 by Masatake YAMATO and Redhat K.K. +Copyright (C) 2007-2025 by Derek Clegg and Michael Toftdal. +Copyright (C) 2003-2025 by Masatake YAMATO, Red Hat K.K., +Copyright (C) 1996-2025 by David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. +Copyright (C) 2007-2025 by David Turner. +Copyright (C) 2022-2025 by David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. +Copyright (C) 2007-2025 by Rahul Bhalerao , . +Copyright (C) 2025 by Behdad Esfahbod. +Copyright (C) 2008-2025 by David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya. +Copyright (C) 2013-2025 by Google, Inc. +Copyright (C) 2019-2025 by Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. +Copyright (C) 2009-2025 by Oran Agra and Mickey Gabel. +Copyright (C) 2018-2025 by David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg. +Copyright (C) 2004-2025 by David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. The FreeType Project LICENSE ---------------------------- @@ -207,6 +206,7 @@ Legal Terms https://www.freetype.org + ``` ### GPL v2 diff --git a/src/java.desktop/share/legal/giflib.md b/src/java.desktop/share/legal/giflib.md index 8b8fde8706d..781023dd334 100644 --- a/src/java.desktop/share/legal/giflib.md +++ b/src/java.desktop/share/legal/giflib.md @@ -1,9 +1,9 @@ -## GIFLIB v5.2.2 +## GIFLIB v6.1.2 ### GIFLIB License ``` -The GIFLIB distribution is Copyright (c) 1997 Eric S. Raymond += MIT LICENSE Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -23,8 +23,19 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +--------------------------------- +The below applies to the following file(s): +giflib/dgif_lib.c +giflib/gifalloc.c +giflib/gif_err.c +giflib/openbsd-reallocarray.c + +Copyright (C) 1989 Gershon Elber +Copyright (C) 2008 Otto Moerbeek +Copyright (C) Eric S. Raymond + +SPDX-License-Identifier: MIT -tree/README == Authors == @@ -38,13 +49,4 @@ former maintainer Eric Raymond current as well as long time former maintainer of giflib code -There have been many other contributors; see the attributions in the -version-control history to learn more. - - -tree/openbsd-reallocarray.c - -Copyright (C) 2008 Otto Moerbeek -SPDX-License-Identifier: MIT - ``` diff --git a/src/java.desktop/share/legal/harfbuzz.md b/src/java.desktop/share/legal/harfbuzz.md index e0c40705ed6..3aa5ca841d6 100644 --- a/src/java.desktop/share/legal/harfbuzz.md +++ b/src/java.desktop/share/legal/harfbuzz.md @@ -1,4 +1,4 @@ -## Harfbuzz 11.2.0 +## Harfbuzz 12.3.2 ### Harfbuzz License diff --git a/src/java.desktop/share/legal/libpng.md b/src/java.desktop/share/legal/libpng.md index 80d12248ec4..7783fc7ff03 100644 --- a/src/java.desktop/share/legal/libpng.md +++ b/src/java.desktop/share/legal/libpng.md @@ -1,4 +1,4 @@ -## libpng v1.6.54 +## libpng v1.6.57 ### libpng License

@@ -168,8 +168,10 @@ Authors, for copyright and licensing purposes.
  * Glenn Randers-Pehrson
  * Greg Roelofs
  * Guy Eric Schalnat
+ * Halil Oktay
  * James Yu
  * John Bowler
+ * Joshua Inscoe
  * Kevin Bracey
  * Lucas Chollet
  * Magnus Holmgren
@@ -178,6 +180,7 @@ Authors, for copyright and licensing purposes.
  * Mans Rullgard
  * Matt Sarett
  * Mike Klein
+ * Mohammad Seet
  * Pascal Massimino
  * Paul Schmidt
  * Petr Simecek
@@ -186,12 +189,14 @@ Authors, for copyright and licensing purposes.
  * Sam Bushell
  * Samuel Williams
  * Simon-Pierre Cadieux
+ * Taegu Ha (하태구)
  * Tim Wegner
  * Tobias Stoeckmann
  * Tom Lane
  * Tom Tanner
  * Vadim Barkov
  * Willem van Schaik
+ * Yuelin Wang (王跃林)
  * Zhijie Liang
  * Apple Inc.
     - Zixu Wang (王子旭)
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftconfig.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftconfig.h
index 0667493fec6..d66c5df9976 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftconfig.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftconfig.h
@@ -4,7 +4,7 @@
  *
  *   ANSI-specific configuration file (specification only).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftheader.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftheader.h
index f6ef2618ded..16eab9048fc 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftheader.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftheader.h
@@ -4,7 +4,7 @@
  *
  *   Build macros of the FreeType 2 library.
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h
index d29a0a7cefb..a0a1a410b68 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h
@@ -4,7 +4,7 @@
  *
  *   User-selectable configuration macros (specification only).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -158,12 +158,12 @@ FT_BEGIN_HEADER
 
   /**************************************************************************
    *
-   * If this macro is defined, try to use an inlined assembler version of the
-   * @FT_MulFix function, which is a 'hotspot' when loading and hinting
-   * glyphs, and which should be executed as fast as possible.
+   * If this macro is defined, try to use an inlined 64-bit or assembler
+   * version of the @FT_MulFix function, which is a 'hotspot' when loading
+   * and hinting glyphs, and which should be executed as fast as possible.
    *
-   * Note that if your compiler or CPU is not supported, this will default to
-   * the standard and portable implementation found in `ftcalc.c`.
+   * If your compiler is not C99-compliant or CPU assembly is not supported,
+   * you can disable this option.
    */
 #define FT_CONFIG_OPTION_INLINE_MULFIX
 
@@ -293,6 +293,31 @@ FT_BEGIN_HEADER
 /* #define FT_CONFIG_OPTION_USE_HARFBUZZ */
 
 
+  /**************************************************************************
+   *
+   * HarfBuzz dynamic support.
+   *
+   *   Define this macro if you want the HarfBuzz library to be loaded at
+   *   runtime instead of being linked to FreeType.
+   *
+   *   This option has no effect if `FT_CONFIG_OPTION_USE_HARFBUZZ` is not
+   *   defined.
+   *
+   *   When this option is enabled, FreeType will try to load the HarfBuzz
+   *   library at runtime, using `dlopen` or `LoadLibrary`, depending on the
+   *   platform.  On Microsoft platforms, the library name looked up is
+   *   `libharfbuzz-0.dll`.  On Apple platforms, the library name looked up
+   *   is `libharfbuzz.0.dylib`.  On all other platforms, the library name
+   *   looked up is `libharfbuzz.so.0`.  This name can be overridden by
+   *   defining the macro `FT_LIBHARFBUZZ` at FreeType compilation time.
+   *
+   *   If you use a build system like cmake or the `configure` script,
+   *   options set by those programs have precedence, overwriting the value
+   *   here with the configured one.
+   */
+/* #define FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */
+
+
   /**************************************************************************
    *
    * Brotli support.
@@ -679,7 +704,7 @@ FT_BEGIN_HEADER
    * defined.
    *
    * [1]
-   * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx
+   * https://learn.microsoft.com/typography/cleartype/truetypecleartype
    */
 #define TT_CONFIG_OPTION_SUBPIXEL_HINTING
 
@@ -697,7 +722,7 @@ FT_BEGIN_HEADER
    * flags array which can be used to disambiguate, but old fonts will not
    * have them.
    *
-   *   https://www.microsoft.com/typography/otspec/glyf.htm
+   *   https://learn.microsoft.com/typography/opentype/spec/glyf
    *   https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html
    */
 #undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED
@@ -734,7 +759,13 @@ FT_BEGIN_HEADER
   /**************************************************************************
    *
    * Define `TT_CONFIG_OPTION_BDF` if you want to include support for an
-   * embedded 'BDF~' table within SFNT-based bitmap formats.
+   * embedded 'BDF~' table within an SFNT-based `.otb` font file.  This table
+   * is an extension used by X11 to preserve BDF properties after conversion
+   * to SFNT containers.  See
+   *
+   *   https://fontforge.org/docs/techref/non-standard.html#non-standard-bdf
+   *
+   * for more details.
    */
 /* #define TT_CONFIG_OPTION_BDF */
 
@@ -760,10 +791,10 @@ FT_BEGIN_HEADER
   /**************************************************************************
    *
    * Option `TT_CONFIG_OPTION_GPOS_KERNING` enables a basic GPOS kerning
-   * implementation (for TrueType fonts only).  With this defined, FreeType
-   * is able to get kerning pair data from the GPOS 'kern' feature as well as
-   * legacy 'kern' tables; without this defined, FreeType will only be able
-   * to use legacy 'kern' tables.
+   * implementation (for TrueType and OpenType fonts only).  With this
+   * defined, FreeType is able to get kerning pair data from the GPOS 'kern'
+   * feature as well as legacy 'kern' tables; without this defined, FreeType
+   * will only be able to use legacy 'kern' tables.
    *
    * Note that FreeType does not support more advanced GPOS layout features;
    * even the 'kern' feature implemented here doesn't handle more
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h
index e17aa7b89d5..f846b4456c1 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h
@@ -5,7 +5,7 @@
  *   ANSI-specific library and header configuration file (specification
  *   only).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/integer-types.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/integer-types.h
index c27505ffc4b..a0b892ece4b 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/config/integer-types.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/integer-types.h
@@ -4,7 +4,7 @@
  *
  *   FreeType integer types definitions.
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -17,6 +17,8 @@
 #ifndef FREETYPE_CONFIG_INTEGER_TYPES_H_
 #define FREETYPE_CONFIG_INTEGER_TYPES_H_
 
+FT_BEGIN_HEADER
+
   /* There are systems (like the Texas Instruments 'C54x) where a `char`  */
   /* has 16~bits.  ANSI~C says that `sizeof(char)` is always~1.  Since an */
   /* `int` has 16~bits also for this system, `sizeof(int)` gives~1 which  */
@@ -242,9 +244,34 @@
 #endif /* FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) */
 
 #ifdef FT_INT64
+
   typedef FT_INT64   FT_Int64;
   typedef FT_UINT64  FT_UInt64;
-#endif
 
+#  define FT_INT64_ZERO  0
+
+#else  /* !FT_INT64 */
+
+  /* we need to emulate 64-bit data types if none are available */
+
+  typedef struct  FT_Int64_
+  {
+    FT_UInt32  lo;
+    FT_UInt32  hi;
+
+  } FT_Int64;
+
+  typedef struct  FT_UInt64_
+  {
+    FT_UInt32  lo;
+    FT_UInt32  hi;
+
+  } FT_UInt64;
+
+#  define FT_INT64_ZERO  { 0, 0 }
+
+#endif /* !FT_INT64 */
+
+FT_END_HEADER
 
 #endif  /* FREETYPE_CONFIG_INTEGER_TYPES_H_ */
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/mac-support.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/mac-support.h
index 07b6f915bd8..bd350851d56 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/config/mac-support.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/mac-support.h
@@ -4,7 +4,7 @@
  *
  *   Mac/OS X support configuration header.
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -24,6 +24,7 @@
    *   This is the only necessary change, so it is defined here instead
    *   providing a new configuration file.
    */
+#ifdef FT_MACINTOSH
 #if defined( __APPLE__ ) || ( defined( __MWERKS__ ) && defined( macintosh ) )
   /* No Carbon frameworks for 64bit 10.4.x.                         */
   /* `AvailabilityMacros.h` is available since Mac OS X 10.2,       */
@@ -36,6 +37,7 @@
     ( MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 )
 #undef FT_MACINTOSH
 #endif
+#endif  /* __APPLE__ ... */
 
 #elif defined( __SC__ ) || defined( __MRC__ )
   /* Classic MacOS compilers */
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/public-macros.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/public-macros.h
index f56581a6ee7..9f28b394737 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/config/public-macros.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/public-macros.h
@@ -4,7 +4,7 @@
  *
  *   Define a set of compiler macros used in public FreeType headers.
  *
- * Copyright (C) 2020-2024 by
+ * Copyright (C) 2020-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -62,8 +62,8 @@ FT_BEGIN_HEADER
    * because it is needed by `FT_EXPORT`.
    */
 
-  /* Visual C, mingw */
-#if defined( _WIN32 )
+  /* Visual C, MinGW, Cygwin */
+#if defined( _WIN32 ) || defined( __CYGWIN__ )
 
 #if defined( FT2_BUILD_LIBRARY ) && defined( DLL_EXPORT )
 #define FT_PUBLIC_FUNCTION_ATTRIBUTE  __declspec( dllexport )
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h b/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h
index 58fc33dfe60..e8a1b1e2f3e 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h
@@ -4,7 +4,7 @@
  *
  *   FreeType high-level API and common types (specification only).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -811,7 +811,7 @@ FT_BEGIN_HEADER
    *   FT_ENCODING_MS_SYMBOL ::
    *     Microsoft Symbol encoding, used to encode mathematical symbols and
    *     wingdings.  For more information, see
-   *     'https://www.microsoft.com/typography/otspec/recom.htm#non-standard-symbol-fonts',
+   *     'https://learn.microsoft.com/typography/opentype/spec/recom#non-standard-symbol-fonts',
    *     'http://www.kostis.net/charsets/symbol.htm', and
    *     'http://www.kostis.net/charsets/wingding.htm'.
    *
@@ -1068,12 +1068,12 @@ FT_BEGIN_HEADER
    *     the face in the font file (starting with value~0).  They are set
    *     to~0 if there is only one face in the font file.
    *
-   *     [Since 2.6.1] Bits 16-30 are relevant to GX and OpenType variation
-   *     fonts only, holding the named instance index for the current face
-   *     index (starting with value~1; value~0 indicates font access without
-   *     a named instance).  For non-variation fonts, bits 16-30 are ignored.
-   *     If we have the third named instance of face~4, say, `face_index` is
-   *     set to 0x00030004.
+   *     [Since 2.6.1] Bits 16-30 are relevant to TrueType GX and OpenType
+   *     Font Variations only, holding the named instance index for the
+   *     current face index (starting with value~1; value~0 indicates font
+   *     access without a named instance).  For non-variation fonts, bits
+   *     16-30 are ignored.  If we have the third named instance of face~4,
+   *     say, `face_index` is set to 0x00030004.
    *
    *     Bit 31 is always zero (that is, `face_index` is always a positive
    *     value).
@@ -1092,10 +1092,10 @@ FT_BEGIN_HEADER
    *     the face; see @FT_STYLE_FLAG_XXX for the details.
    *
    *     [Since 2.6.1] Bits 16-30 hold the number of named instances
-   *     available for the current face if we have a GX or OpenType variation
-   *     (sub)font.  Bit 31 is always zero (that is, `style_flags` is always
-   *     a positive value).  Note that a variation font has always at least
-   *     one named instance, namely the default instance.
+   *     available for the current face if we have a TrueType GX or OpenType
+   *     Font Variation.  Bit 31 is always zero (that is, `style_flags` is
+   *     always a positive value).  Note that a variation font has always at
+   *     least one named instance, namely the default instance.
    *
    *   num_glyphs ::
    *     The number of glyphs in the face.  If the face is scalable and has
@@ -1159,7 +1159,7 @@ FT_BEGIN_HEADER
    *     Note that the bounding box might be off by (at least) one pixel for
    *     hinted fonts.  See @FT_Size_Metrics for further discussion.
    *
-   *     Note that the bounding box does not vary in OpenType variation fonts
+   *     Note that the bounding box does not vary in OpenType Font Variations
    *     and should only be used in relation to the default instance.
    *
    *   units_per_EM ::
@@ -1218,7 +1218,7 @@ FT_BEGIN_HEADER
    *   Fields may be changed after a call to @FT_Attach_File or
    *   @FT_Attach_Stream.
    *
-   *   For an OpenType variation font, the values of the following fields can
+   *   For OpenType Font Variations, the values of the following fields can
    *   change after a call to @FT_Set_Var_Design_Coordinates (and friends) if
    *   the font contains an 'MVAR' table: `ascender`, `descender`, `height`,
    *   `underline_position`, and `underline_thickness`.
@@ -1336,7 +1336,7 @@ FT_BEGIN_HEADER
    *   FT_FACE_FLAG_MULTIPLE_MASTERS ::
    *     The face contains multiple masters and is capable of interpolating
    *     between them.  Supported formats are Adobe MM, TrueType GX, and
-   *     OpenType variation fonts.
+   *     OpenType Font Variations.
    *
    *     See section @multiple_masters for API details.
    *
@@ -1609,7 +1609,7 @@ FT_BEGIN_HEADER
    *
    * @description:
    *   A macro that returns true whenever a face object is a named instance
-   *   of a GX or OpenType variation font.
+   *   of a TrueType GX or OpenType Font Variations.
    *
    *   [Since 2.9] Changing the design coordinates with
    *   @FT_Set_Var_Design_Coordinates or @FT_Set_Var_Blend_Coordinates does
@@ -2147,7 +2147,7 @@ FT_BEGIN_HEADER
    *     freed.
    *
    *     [Since 2.10.1] If @FT_LOAD_NO_SCALE is set, outline coordinates of
-   *     OpenType variation fonts for a selected instance are internally
+   *     OpenType Font Variations for a selected instance are internally
    *     handled as 26.6 fractional font units but returned as (rounded)
    *     integers, as expected.  To get unrounded font units, don't use
    *     @FT_LOAD_NO_SCALE but load the glyph with @FT_LOAD_NO_HINTING and
@@ -2640,14 +2640,14 @@ FT_BEGIN_HEADER
    *     the face in the font file (starting with value~0).  Set it to~0 if
    *     there is only one face in the font file.
    *
-   *     [Since 2.6.1] Bits 16-30 are relevant to GX and OpenType variation
-   *     fonts only, specifying the named instance index for the current face
-   *     index (starting with value~1; value~0 makes FreeType ignore named
-   *     instances).  For non-variation fonts, bits 16-30 are ignored.
-   *     Assuming that you want to access the third named instance in face~4,
-   *     `face_index` should be set to 0x00030004.  If you want to access
-   *     face~4 without variation handling, simply set `face_index` to
-   *     value~4.
+   *     [Since 2.6.1] Bits 16-30 are relevant to TrueType GX and OpenType
+   *     Font Variations only, specifying the named instance index for the
+   *     current face index (starting with value~1; value~0 makes FreeType
+   *     ignore named instances).  For non-variation fonts, bits 16-30 are
+   *     ignored.  Assuming that you want to access the third named instance
+   *     in face~4, `face_index` should be set to 0x00030004.  If you want
+   *     to access face~4 without variation handling, simply set
+   *     `face_index` to value~4.
    *
    *     `FT_Open_Face` and its siblings can be used to quickly check whether
    *     the font format of a given font resource is supported by FreeType.
@@ -2914,11 +2914,11 @@ FT_BEGIN_HEADER
    *   of the available glyphs at a given ppem value is available.  FreeType
    *   silently uses outlines if there is no bitmap for a given glyph index.
    *
-   *   For GX and OpenType variation fonts, a bitmap strike makes sense only
-   *   if the default instance is active (that is, no glyph variation takes
-   *   place); otherwise, FreeType simply ignores bitmap strikes.  The same
-   *   is true for all named instances that are different from the default
-   *   instance.
+   *   For TrueType GX and OpenType Font Variations, a bitmap strike makes
+   *   sense only if the default instance is active (that is, no glyph
+   *   variation takes place); otherwise, FreeType simply ignores bitmap
+   *   strikes.  The same is true for all named instances that are different
+   *   from the default instance.
    *
    *   Don't use this function if you are using the FreeType cache API.
    */
@@ -3078,7 +3078,7 @@ FT_BEGIN_HEADER
    *   is dependent entirely on how the size is defined in the source face.
    *   The font designer chooses the final size of each glyph relative to
    *   this size.  For more information refer to
-   *   'https://www.freetype.org/freetype2/docs/glyphs/glyphs-2.html'.
+   *   'https://freetype.org/freetype2/docs/glyphs/glyphs-2.html'.
    *
    *   Contrary to @FT_Set_Char_Size, this function doesn't have special code
    *   to normalize zero-valued widths, heights, or resolutions, which are
@@ -3441,8 +3441,10 @@ FT_BEGIN_HEADER
    *     blending of the color glyph layers associated with the glyph index,
    *     using the same bitmap format as embedded color bitmap images.  This
    *     is mainly for convenience and works only for glyphs in 'COLR' v0
-   *     tables (or glyphs in 'COLR' v1 tables that exclusively use v0
-   *     features).  For full control of color layers use
+   *     tables.  **There is no rendering support for 'COLR' v1** (with the
+   *     exception of v1 tables that exclusively use v0 features)!  You need
+   *     a graphics library like Skia or Cairo to interpret the graphics
+   *     commands stored in v1 tables.  For full control of color layers use
    *     @FT_Get_Color_Glyph_Layer and FreeType's color functions like
    *     @FT_Palette_Select instead of setting @FT_LOAD_COLOR for rendering
    *     so that the client application can handle blending by itself.
@@ -3895,8 +3897,10 @@ FT_BEGIN_HEADER
    *
    *   This process can cost performance.  There is an approximation that
    *   does not need to know about the background color; see
-   *   https://bel.fi/alankila/lcd/ and
-   *   https://bel.fi/alankila/lcd/alpcor.html for details.
+   *   https://web.archive.org/web/20211019204945/https://bel.fi/alankila/lcd/
+   *   and
+   *   https://web.archive.org/web/20210211002939/https://bel.fi/alankila/lcd/alpcor.html
+   *   for details.
    *
    *   **ATTENTION**: Linear blending is even more important when dealing
    *   with subpixel-rendered glyphs to prevent color-fringing!  A
@@ -3993,13 +3997,13 @@ FT_BEGIN_HEADER
    *   out of the scope of this API function -- they can be implemented
    *   through format-specific interfaces.
    *
-   *   Note that, for TrueType fonts only, this can extract data from both
-   *   the 'kern' table and the basic, pair-wise kerning feature from the
-   *   GPOS table (with `TT_CONFIG_OPTION_GPOS_KERNING` enabled), though
-   *   FreeType does not support the more advanced GPOS layout features; use
-   *   a library like HarfBuzz for those instead.  If a font has both a
-   *   'kern' table and kern features of a GPOS table, the 'kern' table will
-   *   be used.
+   *   Note that, for TrueType and OpenType fonts only, this can extract data
+   *   from both the 'kern' table and the basic, pair-wise kerning feature
+   *   from the GPOS table (with `TT_CONFIG_OPTION_GPOS_KERNING` enabled),
+   *   though FreeType does not support the more advanced GPOS layout
+   *   features; use a library like HarfBuzz for those instead.  If a font
+   *   has both a 'kern' table and kern features of a GPOS table, the 'kern'
+   *   table will be used.
    *
    *   Also note for right-to-left scripts, the functionality may differ for
    *   fonts with GPOS tables vs. 'kern' tables.  For GPOS, right-to-left
@@ -4314,14 +4318,13 @@ FT_BEGIN_HEADER
    *     property `no-stem-darkening` provided by the 'autofit', 'cff',
    *     'type1', and 't1cid' modules; see @no-stem-darkening).
    *
-   *   * @FT_PARAM_TAG_LCD_FILTER_WEIGHTS (LCD filter weights, corresponding
-   *     to function @FT_Library_SetLcdFilterWeights).
-   *
    *   * @FT_PARAM_TAG_RANDOM_SEED (seed value for the CFF, Type~1, and CID
    *     'random' operator, corresponding to the `random-seed` property
    *     provided by the 'cff', 'type1', and 't1cid' modules; see
    *     @random-seed).
    *
+   *   * @FT_PARAM_TAG_LCD_FILTER_WEIGHTS (no longer supported).
+   *
    *   Pass `NULL` as `data` in @FT_Parameter for a given tag to reset the
    *   option and use the library or module default again.
    *
@@ -4348,25 +4351,17 @@ FT_BEGIN_HEADER
    *     FT_Bool              darken_stems = 1;
    *
    *     FT_Parameter         property2;
-   *     FT_LcdFiveTapFilter  custom_weight =
-   *                            { 0x11, 0x44, 0x56, 0x44, 0x11 };
-   *
-   *     FT_Parameter         property3;
    *     FT_Int32             random_seed = 314159265;
    *
-   *     FT_Parameter         properties[3] = { property1,
-   *                                            property2,
-   *                                            property3 };
+   *     FT_Parameter         properties[2] = { property1,
+   *                                            property2 };
    *
    *
    *     property1.tag  = FT_PARAM_TAG_STEM_DARKENING;
    *     property1.data = &darken_stems;
    *
-   *     property2.tag  = FT_PARAM_TAG_LCD_FILTER_WEIGHTS;
-   *     property2.data = custom_weight;
-   *
-   *     property3.tag  = FT_PARAM_TAG_RANDOM_SEED;
-   *     property3.data = &random_seed;
+   *     property2.tag  = FT_PARAM_TAG_RANDOM_SEED;
+   *     property2.data = &random_seed;
    *
    *     FT_Face_Properties( face, 3, properties );
    *   ```
@@ -4377,7 +4372,7 @@ FT_BEGIN_HEADER
    *     FT_Parameter  property;
    *
    *
-   *     property.tag  = FT_PARAM_TAG_LCD_FILTER_WEIGHTS;
+   *     property.tag  = FT_PARAM_TAG_STEM_DARKENING;
    *     property.data = NULL;
    *
    *     FT_Face_Properties( face, 1, &property );
@@ -4530,7 +4525,7 @@ FT_BEGIN_HEADER
    *   table description in the OpenType specification for the meaning of the
    *   various flags (which get synthesized for non-OpenType subglyphs).
    *
-   *     https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description
+   *     https://learn.microsoft.com/typography/opentype/spec/glyf#composite-glyph-description
    *
    * @values:
    *   FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS ::
@@ -4593,7 +4588,7 @@ FT_BEGIN_HEADER
    *   interpreted depending on the flags returned in `*p_flags`.  See the
    *   OpenType specification for details.
    *
-   *     https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description
+   *     https://learn.microsoft.com/typography/opentype/spec/glyf#composite-glyph-description
    *
    */
   FT_EXPORT( FT_Error )
@@ -4619,7 +4614,7 @@ FT_BEGIN_HEADER
    *   associated with a font.
    *
    *   See
-   *   https://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/FontPolicies.pdf
+   *   https://adobe-type-tools.github.io/font-tech-notes/pdfs/AcrobatDC_FontPolicies.pdf
    *   for more details.
    *
    * @values:
@@ -5173,8 +5168,8 @@ FT_BEGIN_HEADER
    *
    */
 #define FREETYPE_MAJOR  2
-#define FREETYPE_MINOR  13
-#define FREETYPE_PATCH  3
+#define FREETYPE_MINOR  14
+#define FREETYPE_PATCH  2
 
 
   /**************************************************************************
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftadvanc.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftadvanc.h
index 85b8ba2554b..62a856ccbd7 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftadvanc.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftadvanc.h
@@ -4,7 +4,7 @@
  *
  *   Quick computation of advance widths (specification only).
  *
- * Copyright (C) 2008-2024 by
+ * Copyright (C) 2008-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftbbox.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftbbox.h
index 12bbfa63a62..348b4b3a268 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftbbox.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftbbox.h
@@ -4,7 +4,7 @@
  *
  *   FreeType exact bbox computation (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftbdf.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftbdf.h
index 6f63b0b1e78..ab142249217 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftbdf.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftbdf.h
@@ -4,7 +4,7 @@
  *
  *   FreeType API for accessing BDF-specific strings (specification).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -44,7 +44,8 @@ FT_BEGIN_HEADER
    *
    * @description:
    *   This section contains the declaration of functions specific to BDF and
-   *   PCF fonts.
+   *   PCF fonts.  They also work for SFNT bitmap fonts that contain a 'BDF~'
+   *   table like X11's `.otb` fonts.
    *
    */
 
@@ -151,7 +152,9 @@ FT_BEGIN_HEADER
    *   FreeType error code.  0~means success.
    *
    * @note:
-   *   This function only works with BDF faces, returning an error otherwise.
+   *   This function only works with BDF faces and SFNT fonts that have a
+   *   'BDF~' table, returning an error otherwise.  For the latter, a bitmap
+   *   strike size must be selected first.
    */
   FT_EXPORT( FT_Error )
   FT_Get_BDF_Charset_ID( FT_Face       face,
@@ -165,7 +168,7 @@ FT_BEGIN_HEADER
    *    FT_Get_BDF_Property
    *
    * @description:
-   *    Retrieve a BDF property from a BDF or PCF font file.
+   *    Retrieve a BDF property from a BDF or PCF font.
    *
    * @input:
    *    face ::
@@ -196,6 +199,9 @@ FT_BEGIN_HEADER
    *
    *   In case of error, `aproperty->type` is always set to
    *   @BDF_PROPERTY_TYPE_NONE.
+   *
+   *   This also works with SFNT fonts that have a 'BDF~' table, after a
+   *   bitmap strike size has been selected.
    */
   FT_EXPORT( FT_Error )
   FT_Get_BDF_Property( FT_Face           face,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftbitmap.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftbitmap.h
index df9d462652e..a22d43adf14 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftbitmap.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftbitmap.h
@@ -4,7 +4,7 @@
  *
  *   FreeType utility functions for bitmaps (specification).
  *
- * Copyright (C) 2004-2024 by
+ * Copyright (C) 2004-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftcid.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftcid.h
index 96b2a90fc59..7cda8ff3f39 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftcid.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftcid.h
@@ -4,7 +4,7 @@
  *
  *   FreeType API for accessing CID font information (specification).
  *
- * Copyright (C) 2007-2024 by
+ * Copyright (C) 2007-2025 by
  * Dereg Clegg and Michael Toftdal.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftcolor.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftcolor.h
index 420720ddf22..129b1a23fb0 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftcolor.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftcolor.h
@@ -4,7 +4,7 @@
  *
  *   FreeType's glyph color management (specification).
  *
- * Copyright (C) 2018-2024 by
+ * Copyright (C) 2018-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -317,6 +317,15 @@ FT_BEGIN_HEADER
    * @description:
    *   The functions described here allow access of colored glyph layer data
    *   in OpenType's 'COLR' tables.
+   *
+   *   Note that FreeType does *not* provide rendering in general of glyphs
+   *   that use a 'COLR' table!  While FreeType has very limited rendering
+   *   support for 'COLR' v0 tables (without a possibility to change the
+   *   color palette) via @FT_Render_Glyph, there is no such convenience
+   *   code for 'COLR' v1 tables -- while it appears that v1 is simply an
+   *   'improved' version of v0, this is not the case: it is a completely
+   *   different color font format, and you need a dedicated graphics
+   *   library like Skia or Cairo to handle a v1 table's drawing commands.
    */
 
 
@@ -359,7 +368,7 @@ FT_BEGIN_HEADER
    *   iteratively retrieve the colored glyph layers associated with the
    *   current glyph slot.
    *
-   *     https://docs.microsoft.com/en-us/typography/opentype/spec/colr
+   *     https://learn.microsoft.com/typography/opentype/spec/colr
    *
    *   The glyph layer data for a given glyph index, if present, provides an
    *   alternative, multi-color glyph representation: Instead of rendering
@@ -1518,7 +1527,7 @@ FT_BEGIN_HEADER
    *
    * @return:
    *   Value~1 if a clip box is found.  If no clip box is found or an error
-   *   occured, value~0 is returned.
+   *   occurred, value~0 is returned.
    *
    * @note:
    *   To retrieve the clip box in font units, reset scale to units-per-em
@@ -1646,7 +1655,7 @@ FT_BEGIN_HEADER
    *
    * @return:
    *   Value~1 if everything is OK.  Value~0 if no details can be found for
-   *   this paint or any other error occured.
+   *   this paint or any other error occurred.
    *
    * @since:
    *   2.13
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h
index 1b7f539f5e2..b65a06ab69b 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h
@@ -4,7 +4,7 @@
  *
  *   FreeType API for controlling driver modules (specification only).
  *
- * Copyright (C) 2017-2024 by
+ * Copyright (C) 2017-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -282,7 +282,7 @@ FT_BEGIN_HEADER
    *   minimize hinting techniques that were problematic with the extra
    *   resolution of ClearType; see
    *   http://rastertragedy.com/RTRCh4.htm#Sec1 and
-   *   https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx.
+   *   https://learn.microsoft.com/typography/cleartype/truetypecleartype.
    *   This technique is not to be confused with ClearType compatible widths.
    *   ClearType backward compatibility has no direct impact on changing
    *   advance widths, but there might be an indirect impact on disabling
@@ -784,7 +784,7 @@ FT_BEGIN_HEADER
    *
    *   Details on subpixel hinting and some of the necessary tweaks can be
    *   found in Greg Hitchcock's whitepaper at
-   *   'https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx'.
+   *   'https://learn.microsoft.com/typography/cleartype/truetypecleartype'.
    *   Note that FreeType currently doesn't really 'subpixel hint' (6x1, 6x2,
    *   or 6x5 supersampling) like discussed in the paper.  Depending on the
    *   chosen interpreter, it simply ignores instructions on vertical stems
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/fterrdef.h b/src/java.desktop/share/native/libfreetype/include/freetype/fterrdef.h
index 710ca91bbdd..3e591bede8d 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/fterrdef.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/fterrdef.h
@@ -4,7 +4,7 @@
  *
  *   FreeType error codes (specification).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/fterrors.h b/src/java.desktop/share/native/libfreetype/include/freetype/fterrors.h
index 27c0ece5c1c..eca494f90c0 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/fterrors.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/fterrors.h
@@ -4,7 +4,7 @@
  *
  *   FreeType error code handling (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftfntfmt.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftfntfmt.h
index 7c8b0874a81..5df82447d0e 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftfntfmt.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftfntfmt.h
@@ -4,7 +4,7 @@
  *
  *   Support functions for font formats.
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftgasp.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftgasp.h
index 30e5a9bf82b..77e5a7e7bfd 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftgasp.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftgasp.h
@@ -4,7 +4,7 @@
  *
  *   Access of TrueType's 'gasp' table (specification).
  *
- * Copyright (C) 2007-2024 by
+ * Copyright (C) 2007-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftglyph.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftglyph.h
index dc1eb8873ae..3691781cf52 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftglyph.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftglyph.h
@@ -4,7 +4,7 @@
  *
  *   FreeType convenience functions to handle glyphs (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftgzip.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftgzip.h
index 9516dc030ac..e26c334c11a 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftgzip.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftgzip.h
@@ -4,7 +4,7 @@
  *
  *   Gzip-compressed stream support.
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h
index 2b4b4ac60ae..a4dc724f349 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h
@@ -5,7 +5,7 @@
  *   FreeType glyph image formats and default raster interface
  *   (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -267,6 +267,10 @@ FT_BEGIN_HEADER
    *   *logical* one.  For example, if @FT_Pixel_Mode is set to
    *   `FT_PIXEL_MODE_LCD`, the logical width is a just a third of the
    *   physical one.
+   *
+   *   An empty bitmap with a NULL `buffer` is valid, with `rows` and/or
+   *   `pitch` also set to 0.  Such bitmaps might be produced while rendering
+   *   empty or degenerate outlines.
    */
   typedef struct  FT_Bitmap_
   {
@@ -439,7 +443,7 @@ FT_BEGIN_HEADER
    *   rasterizer; see the `tags` field in @FT_Outline.
    *
    *   Please refer to the description of the 'SCANTYPE' instruction in the
-   *   [OpenType specification](https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#scantype)
+   *   [OpenType specification](https://learn.microsoft.com/typography/opentype/spec/tt_instructions#scantype)
    *   how simple drop-outs, smart drop-outs, and stubs are defined.
    */
 #define FT_OUTLINE_NONE             0x0
@@ -871,7 +875,7 @@ FT_BEGIN_HEADER
    */
   typedef struct  FT_Span_
   {
-    short           x;
+    unsigned short  x;
     unsigned short  len;
     unsigned char   coverage;
 
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftincrem.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftincrem.h
index 816581b78eb..2233044754e 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftincrem.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftincrem.h
@@ -4,7 +4,7 @@
  *
  *   FreeType incremental loading (specification).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftlcdfil.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftlcdfil.h
index 25274dc4ac2..37bb5e1b8fb 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftlcdfil.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftlcdfil.h
@@ -5,7 +5,7 @@
  *   FreeType API for color filtering of subpixel bitmap glyphs
  *   (specification).
  *
- * Copyright (C) 2006-2024 by
+ * Copyright (C) 2006-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -145,16 +145,10 @@ FT_BEGIN_HEADER
    *
    *   FT_LCD_FILTER_LEGACY ::
    *   FT_LCD_FILTER_LEGACY1 ::
-   *     This filter corresponds to the original libXft color filter.  It
-   *     provides high contrast output but can exhibit really bad color
-   *     fringes if glyphs are not extremely well hinted to the pixel grid.
-   *     This filter is only provided for comparison purposes, and might be
-   *     disabled or stay unsupported in the future. The second value is
-   *     provided for compatibility with FontConfig, which historically used
-   *     different enumeration, sometimes incorrectly forwarded to FreeType.
+   *     The legacy libXft color filter is no longer supported and ignored.
    *
    * @since:
-   *   2.3.0 (`FT_LCD_FILTER_LEGACY1` since 2.6.2)
+   *   2.3.0
    */
   typedef enum  FT_LcdFilter_
   {
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftlist.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftlist.h
index 972fbfa2fe4..14958b0ff37 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftlist.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftlist.h
@@ -4,7 +4,7 @@
  *
  *   Generic list support for FreeType (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h
index 1813cfc2c27..d155171136c 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h
@@ -4,7 +4,7 @@
  *
  *   Additional debugging APIs.
  *
- * Copyright (C) 2020-2024 by
+ * Copyright (C) 2020-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftmac.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftmac.h
index e4efde33dd8..c5ac49101a4 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftmac.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftmac.h
@@ -4,7 +4,7 @@
  *
  *   Additional Mac-specific API.
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h
index 35ed039c89b..ff0bbab59f9 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h
@@ -2,9 +2,9 @@
  *
  * ftmm.h
  *
- *   FreeType Multiple Master font interface (specification).
+ *   FreeType variation font interface (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -37,24 +37,79 @@ FT_BEGIN_HEADER
    *   multiple_masters
    *
    * @title:
-   *   Multiple Masters
+   *   OpenType Font Variations, TrueType GX, and Adobe MM Fonts
    *
    * @abstract:
-   *   How to manage Multiple Masters fonts.
+   *   How to manage variable fonts with multiple design axes.
    *
    * @description:
-   *   The following types and functions are used to manage Multiple Master
-   *   fonts, i.e., the selection of specific design instances by setting
-   *   design axis coordinates.
-   *
-   *   Besides Adobe MM fonts, the interface supports Apple's TrueType GX and
-   *   OpenType variation fonts.  Some of the routines only work with Adobe
-   *   MM fonts, others will work with all three types.  They are similar
-   *   enough that a consistent interface makes sense.
-   *
-   *   For Adobe MM fonts, macro @FT_IS_SFNT returns false.  For GX and
-   *   OpenType variation fonts, it returns true.
-   *
+   *   The following types and functions manage OpenType Font Variations,
+   *   Adobe Multiple Master (MM) fonts, and Apple TrueType GX fonts.  These
+   *   formats have in common that they allow the selection of specific
+   *   design instances by setting design coordinates for one or more axes
+   *   like font weight or width.
+   *
+   *   For historical reasons there are two interfaces.  The first, older one
+   *   can be used with Adobe MM fonts only, and the second, newer one is a
+   *   unified interface that handles all three font formats.  However, some
+   *   differences remain and are documented accordingly; in particular,
+   *   Adobe MM fonts don't have named instances (see below).
+   *
+   *   For Adobe MM fonts, macro @FT_IS_SFNT returns false.  For TrueType GX
+   *   and OpenType Font Variations, it returns true.
+   *
+   *   We use mostly the terminology of the OpenType standard.  Here are some
+   *   important technical terms.
+   *
+   *   * A 'named instance' is a tuple of design coordinates that has a
+   *     string ID (i.e., an index into the font's 'name' table) associated
+   *     with it.  The font can tell the user that, for example,
+   *     [Weight=700,Width=110] is 'Bold'.  Another name for 'named instance'
+   *     is 'named style'.
+   *
+   *       Adobe MM fonts don't have named instances.
+   *
+   *   * The 'default instance' of a variation font is that instance for
+   *     which the nth axis coordinate is equal to the nth default axis
+   *     coordinate (i.e., `axis[n].def` as specified in the @FT_MM_Var
+   *     structure), with~n covering all axes.  In TrueType GX and OpenType
+   *     Font Variations, the default instance is explicitly given.  In Adobe
+   *     MM fonts, the `WeightVector` entry as found in the font file is
+   *     taken as the default instance.
+   *
+   *       For TrueType GX and OpenType Font Variations, FreeType synthesizes
+   *       a named instance for the default instance if the font does not
+   *       contain such an entry.
+   *
+   *   * 'Design coordinates' are the axis values found in a variation font
+   *      file.  Their meaning is specified by the font designer and the
+   *      values are rather arbitrary.
+   *
+   *       For example, the 'weight' axis in design coordinates might vary
+   *       between 100 (thin) and 900 (heavy) in font~A, while font~B
+   *       contains values between 400 (normal) and 800 (extra bold).
+   *
+   *   * 'Normalized coordinates' are design coordinates mapped to a standard
+   *     range; they are also called 'blend coordinates'.
+   *
+   *       For TrueType GX and OpenType Font Variations, the range is [-1;1],
+   *       with the minimum mapped to value~-1, the default mapped to
+   *       value~0, and the maximum mapped to value~1, and all other
+   *       coordinates mapped to intervening points.  Please look up the
+   *       [OpenType
+   *       specification](https://learn.microsoft.com/en-us/typography/opentype/spec/otvaroverview)
+   *       on how this mapping works in detail.
+   *
+   *       For Adobe MM fonts, this standard range is [0;1], with the minimum
+   *       mapped to value~0 and the maximum mapped to value~1, and all other
+   *       coordinates mapped to intervening points.  Please look up [Adobe
+   *       TechNote
+   *       #5015](https://adobe-type-tools.github.io/font-tech-notes/pdfs/5015.Type1_Supp.pdf)
+   *       on how this mapping works in detail.
+   *
+   *       Assuming that the two fonts in the previous example are OpenType
+   *       Font Variations, both font~A's [100;900] and font~B's [400;800]
+   *       coordinate ranges get mapped to [-1;1].
    */
 
 
@@ -64,14 +119,14 @@ FT_BEGIN_HEADER
    *   T1_MAX_MM_XXX
    *
    * @description:
-   *   Multiple Masters limits as defined in their specifications.
+   *   Adobe MM font limits as defined in their specifications.
    *
    * @values:
    *   T1_MAX_MM_AXIS ::
-   *     The maximum number of Multiple Masters axes.
+   *     The maximum number of Adobe MM font axes.
    *
    *   T1_MAX_MM_DESIGNS ::
-   *     The maximum number of Multiple Masters designs.
+   *     The maximum number of Adobe MM font designs.
    *
    *   T1_MAX_MM_MAP_POINTS ::
    *     The maximum number of elements in a design map.
@@ -88,11 +143,10 @@ FT_BEGIN_HEADER
    *   FT_MM_Axis
    *
    * @description:
-   *   A structure to model a given axis in design space for Multiple Masters
-   *   fonts.
+   *   A structure to model a given axis in design space for Adobe MM fonts.
    *
-   *   This structure can't be used for TrueType GX or OpenType variation
-   *   fonts.
+   *   This structure can't be used with TrueType GX or OpenType Font
+   *   Variations.
    *
    * @fields:
    *   name ::
@@ -119,17 +173,17 @@ FT_BEGIN_HEADER
    *   FT_Multi_Master
    *
    * @description:
-   *   A structure to model the axes and space of a Multiple Masters font.
+   *   A structure to model the axes and space of an Adobe MM font.
    *
-   *   This structure can't be used for TrueType GX or OpenType variation
-   *   fonts.
+   *   This structure can't be used with TrueType GX or OpenType Font
+   *   Variations.
    *
    * @fields:
    *   num_axis ::
    *     Number of axes.  Cannot exceed~4.
    *
    *   num_designs ::
-   *     Number of designs; should be normally 2^num_axis even though the
+   *     Number of designs; should be normally `2^num_axis` even though the
    *     Type~1 specification strangely allows for intermediate designs to be
    *     present.  This number cannot exceed~16.
    *
@@ -151,13 +205,13 @@ FT_BEGIN_HEADER
    *   FT_Var_Axis
    *
    * @description:
-   *   A structure to model a given axis in design space for Multiple
-   *   Masters, TrueType GX, and OpenType variation fonts.
+   *   A structure to model a given axis in design space for Adobe MM fonts,
+   *   TrueType GX, and OpenType Font Variations.
    *
    * @fields:
    *   name ::
    *     The axis's name.  Not always meaningful for TrueType GX or OpenType
-   *     variation fonts.
+   *     Font Variations.
    *
    *   minimum ::
    *     The axis's minimum design coordinate.
@@ -171,17 +225,17 @@ FT_BEGIN_HEADER
    *
    *   tag ::
    *     The axis's tag (the equivalent to 'name' for TrueType GX and
-   *     OpenType variation fonts).  FreeType provides default values for
+   *     OpenType Font Variations).  FreeType provides default values for
    *     Adobe MM fonts if possible.
    *
    *   strid ::
    *     The axis name entry in the font's 'name' table.  This is another
    *     (and often better) version of the 'name' field for TrueType GX or
-   *     OpenType variation fonts.  Not meaningful for Adobe MM fonts.
+   *     OpenType Font Variations.  Not meaningful for Adobe MM fonts.
    *
    * @note:
    *   The fields `minimum`, `def`, and `maximum` are 16.16 fractional values
-   *   for TrueType GX and OpenType variation fonts.  For Adobe MM fonts, the
+   *   for TrueType GX and OpenType Font Variations.  For Adobe MM fonts, the
    *   values are whole numbers (i.e., the fractional part is zero).
    */
   typedef struct  FT_Var_Axis_
@@ -205,7 +259,7 @@ FT_BEGIN_HEADER
    *
    * @description:
    *   A structure to model a named instance in a TrueType GX or OpenType
-   *   variation font.
+   *   Font Variations.
    *
    *   This structure can't be used for Adobe MM fonts.
    *
@@ -215,11 +269,11 @@ FT_BEGIN_HEADER
    *     entry for each axis.
    *
    *   strid ::
-   *     The entry in 'name' table identifying this instance.
+   *     An index into the 'name' table identifying this instance.
    *
    *   psid ::
-   *     The entry in 'name' table identifying a PostScript name for this
-   *     instance.  Value 0xFFFF indicates a missing entry.
+   *     An index into the 'name' table identifying a PostScript name for
+   *     this instance.  Value 0xFFFF indicates a missing entry.
    */
   typedef struct  FT_Var_Named_Style_
   {
@@ -236,39 +290,33 @@ FT_BEGIN_HEADER
    *   FT_MM_Var
    *
    * @description:
-   *   A structure to model the axes and space of an Adobe MM, TrueType GX,
-   *   or OpenType variation font.
+   *   A structure to model the axes and space of Adobe MM fonts, TrueType
+   *   GX, or OpenType Font Variations.
    *
    *   Some fields are specific to one format and not to the others.
    *
    * @fields:
    *   num_axis ::
    *     The number of axes.  The maximum value is~4 for Adobe MM fonts; no
-   *     limit in TrueType GX or OpenType variation fonts.
+   *     limit in TrueType GX or OpenType Font Variations.
    *
    *   num_designs ::
-   *     The number of designs; should be normally 2^num_axis for Adobe MM
-   *     fonts.  Not meaningful for TrueType GX or OpenType variation fonts
+   *     The number of designs; should be normally `2^num_axis` for Adobe MM
+   *     fonts.  Not meaningful for TrueType GX or OpenType Font Variations
    *     (where every glyph could have a different number of designs).
    *
    *   num_namedstyles ::
-   *     The number of named styles; a 'named style' is a tuple of design
-   *     coordinates that has a string ID (in the 'name' table) associated
-   *     with it.  The font can tell the user that, for example,
-   *     [Weight=1.5,Width=1.1] is 'Bold'.  Another name for 'named style' is
-   *     'named instance'.
-   *
-   *     For Adobe Multiple Masters fonts, this value is always zero because
-   *     the format does not support named styles.
+   *     The number of named instances.  For Adobe MM fonts, this value is
+   *     always zero.
    *
    *   axis ::
-   *     An axis descriptor table.  TrueType GX and OpenType variation fonts
+   *     An axis descriptor table.  TrueType GX and OpenType Font Variations
    *     contain slightly more data than Adobe MM fonts.  Memory management
    *     of this pointer is done internally by FreeType.
    *
    *   namedstyle ::
-   *     A named style (instance) table.  Only meaningful for TrueType GX and
-   *     OpenType variation fonts.  Memory management of this pointer is done
+   *     An array of named instances.  Only meaningful for TrueType GX and
+   *     OpenType Font Variations.  Memory management of this pointer is done
    *     internally by FreeType.
    */
   typedef struct  FT_MM_Var_
@@ -290,8 +338,8 @@ FT_BEGIN_HEADER
    * @description:
    *   Retrieve a variation descriptor of a given Adobe MM font.
    *
-   *   This function can't be used with TrueType GX or OpenType variation
-   *   fonts.
+   *   This function can't be used with TrueType GX or OpenType Font
+   *   Variations.
    *
    * @input:
    *   face ::
@@ -299,7 +347,7 @@ FT_BEGIN_HEADER
    *
    * @output:
    *   amaster ::
-   *     The Multiple Masters descriptor.
+   *     The Adobe MM font's variation descriptor.
    *
    * @return:
    *   FreeType error code.  0~means success.
@@ -366,8 +414,8 @@ FT_BEGIN_HEADER
    *   For Adobe MM fonts, choose an interpolated font design through design
    *   coordinates.
    *
-   *   This function can't be used with TrueType GX or OpenType variation
-   *   fonts.
+   *   This function can't be used with TrueType GX or OpenType Font
+   *   Variations.
    *
    * @inout:
    *   face ::
@@ -391,8 +439,8 @@ FT_BEGIN_HEADER
    *
    *   [Since 2.9] If `num_coords` is larger than zero, this function sets
    *   the @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field
-   *   (i.e., @FT_IS_VARIATION will return true).  If `num_coords` is zero,
-   *   this bit flag gets unset.
+   *   (i.e., @FT_IS_VARIATION returns true).  If `num_coords` is zero, this
+   *   bit flag gets unset.
    */
   FT_EXPORT( FT_Error )
   FT_Set_MM_Design_Coordinates( FT_Face   face,
@@ -428,7 +476,7 @@ FT_BEGIN_HEADER
    *
    * @note:
    *   The design coordinates are 16.16 fractional values for TrueType GX and
-   *   OpenType variation fonts.  For Adobe MM fonts, the values are supposed
+   *   OpenType Font Variations.  For Adobe MM fonts, the values are supposed
    *   to be whole numbers (i.e., the fractional part is zero).
    *
    *   [Since 2.8.1] To reset all axes to the default values, call the
@@ -438,8 +486,14 @@ FT_BEGIN_HEADER
    *
    *   [Since 2.9] If `num_coords` is larger than zero, this function sets
    *   the @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field
-   *   (i.e., @FT_IS_VARIATION will return true).  If `num_coords` is zero,
-   *   this bit flag gets unset.
+   *   (i.e., @FT_IS_VARIATION returns true).  If `num_coords` is zero, this
+   *   bit flag gets unset.
+   *
+   *   [Since 2.14] This function also sets the @FT_FACE_FLAG_VARIATION bit
+   *   in @FT_Face's `face_flags` field (i.e., @FT_IS_VARIATION returns
+   *   true) if any of the provided coordinates is different from the face's
+   *   default value for the corresponding axis, that is, the set up face is
+   *   not at its default position.
    */
   FT_EXPORT( FT_Error )
   FT_Set_Var_Design_Coordinates( FT_Face    face,
@@ -468,14 +522,14 @@ FT_BEGIN_HEADER
    *
    * @output:
    *   coords ::
-   *     The design coordinates array.
+   *     The design coordinates array, which must be allocated by the user.
    *
    * @return:
    *   FreeType error code.  0~means success.
    *
    * @note:
    *   The design coordinates are 16.16 fractional values for TrueType GX and
-   *   OpenType variation fonts.  For Adobe MM fonts, the values are whole
+   *   OpenType Font Variations.  For Adobe MM fonts, the values are whole
    *   numbers (i.e., the fractional part is zero).
    *
    * @since:
@@ -493,8 +547,7 @@ FT_BEGIN_HEADER
    *   FT_Set_MM_Blend_Coordinates
    *
    * @description:
-   *   Choose an interpolated font design through normalized blend
-   *   coordinates.
+   *   Choose an interpolated font design through normalized coordinates.
    *
    *   This function works with all supported variation formats.
    *
@@ -509,9 +562,10 @@ FT_BEGIN_HEADER
    *     the number of axes, use default values for the remaining axes.
    *
    *   coords ::
-   *     The design coordinates array.  Each element is a 16.16 fractional
-   *     value and must be between 0 and 1.0 for Adobe MM fonts, and between
-   *     -1.0 and 1.0 for TrueType GX and OpenType variation fonts.
+   *     The normalized coordinates array.  Each element is a 16.16
+   *     fractional value and must be between 0 and 1.0 for Adobe MM fonts,
+   *     and between -1.0 and 1.0 for TrueType GX and OpenType Font
+   *     Variations.
    *
    * @return:
    *   FreeType error code.  0~means success.
@@ -524,8 +578,14 @@ FT_BEGIN_HEADER
    *
    *   [Since 2.9] If `num_coords` is larger than zero, this function sets
    *   the @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field
-   *   (i.e., @FT_IS_VARIATION will return true).  If `num_coords` is zero,
-   *   this bit flag gets unset.
+   *   (i.e., @FT_IS_VARIATION returns true).  If `num_coords` is zero, this
+   *   bit flag gets unset.
+   *
+   *   [Since 2.14] This function also sets the @FT_FACE_FLAG_VARIATION bit
+   *   in @FT_Face's `face_flags` field (i.e., @FT_IS_VARIATION returns
+   *   true) if any of the provided coordinates is different from the face's
+   *   default value for the corresponding axis, that is, the set up face is
+   *   not at its default position.
    */
   FT_EXPORT( FT_Error )
   FT_Set_MM_Blend_Coordinates( FT_Face    face,
@@ -539,8 +599,8 @@ FT_BEGIN_HEADER
    *   FT_Get_MM_Blend_Coordinates
    *
    * @description:
-   *   Get the normalized blend coordinates of the currently selected
-   *   interpolated font.
+   *   Get the normalized coordinates of the currently selected interpolated
+   *   font.
    *
    *   This function works with all supported variation formats.
    *
@@ -549,14 +609,14 @@ FT_BEGIN_HEADER
    *     A handle to the source face.
    *
    *   num_coords ::
-   *     The number of normalized blend coordinates to retrieve.  If it is
-   *     larger than the number of axes, set the excess values to~0.5 for
-   *     Adobe MM fonts, and to~0 for TrueType GX and OpenType variation
-   *     fonts.
+   *     The number of normalized coordinates to retrieve.  If it is larger
+   *     than the number of axes, set the excess values to~0.5 for Adobe MM
+   *     fonts, and to~0 for TrueType GX and OpenType Font Variations.
    *
    * @output:
    *   coords ::
-   *     The normalized blend coordinates array (as 16.16 fractional values).
+   *     The normalized coordinates array (as 16.16 fractional values), which
+   *     must be allocated by the user.
    *
    * @return:
    *   FreeType error code.  0~means success.
@@ -610,8 +670,8 @@ FT_BEGIN_HEADER
    *   For Adobe MM fonts, choose an interpolated font design by directly
    *   setting the weight vector.
    *
-   *   This function can't be used with TrueType GX or OpenType variation
-   *   fonts.
+   *   This function can't be used with TrueType GX or OpenType Font
+   *   Variations.
    *
    * @inout:
    *   face ::
@@ -630,16 +690,16 @@ FT_BEGIN_HEADER
    *   FreeType error code.  0~means success.
    *
    * @note:
-   *   Adobe Multiple Master fonts limit the number of designs, and thus the
-   *   length of the weight vector to 16~elements.
+   *   Adobe MM fonts limit the number of designs, and thus the length of the
+   *   weight vector, to 16~elements.
    *
    *   If `len` is larger than zero, this function sets the
    *   @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field (i.e.,
-   *   @FT_IS_VARIATION will return true).  If `len` is zero, this bit flag
-   *   is unset and the weight vector array is reset to the default values.
+   *   @FT_IS_VARIATION returns true).  If `len` is zero, this bit flag is
+   *   unset and the weight vector array is reset to the default values.
    *
    *   The Adobe documentation also states that the values in the
-   *   WeightVector array must total 1.0 +/-~0.001.  In practice this does
+   *   `WeightVector` array must total 1.0 +/-~0.001.  In practice this does
    *   not seem to be enforced, so is not enforced here, either.
    *
    * @since:
@@ -659,8 +719,8 @@ FT_BEGIN_HEADER
    * @description:
    *   For Adobe MM fonts, retrieve the current weight vector of the font.
    *
-   *   This function can't be used with TrueType GX or OpenType variation
-   *   fonts.
+   *   This function can't be used with TrueType GX or OpenType Font
+   *   Variations.
    *
    * @inout:
    *   face ::
@@ -677,14 +737,14 @@ FT_BEGIN_HEADER
    *
    * @output:
    *   weightvector ::
-   *     An array to be filled.
+   *     An array to be filled; it must be allocated by the user.
    *
    * @return:
    *   FreeType error code.  0~means success.
    *
    * @note:
-   *   Adobe Multiple Master fonts limit the number of designs, and thus the
-   *   length of the WeightVector to~16.
+   *   Adobe MM fonts limit the number of designs, and thus the length of the
+   *   weight vector, to~16 elements.
    *
    * @since:
    *   2.10
@@ -760,8 +820,8 @@ FT_BEGIN_HEADER
    *     A handle to the source face.
    *
    *   instance_index ::
-   *     The index of the requested instance, starting with value 1.  If set
-   *     to value 0, FreeType switches to font access without a named
+   *     The index of the requested instance, starting with value~1.  If set
+   *     to value~0, FreeType switches to font access without a named
    *     instance.
    *
    * @return:
@@ -771,11 +831,11 @@ FT_BEGIN_HEADER
    *   The function uses the value of `instance_index` to set bits 16-30 of
    *   the face's `face_index` field.  It also resets any variation applied
    *   to the font, and the @FT_FACE_FLAG_VARIATION bit of the face's
-   *   `face_flags` field gets reset to zero (i.e., @FT_IS_VARIATION will
-   *   return false).
+   *   `face_flags` field gets reset to zero (i.e., @FT_IS_VARIATION returns
+   *   false).
    *
-   *   For Adobe MM fonts (which don't have named instances) this function
-   *   simply resets the current face to the default instance.
+   *   For Adobe MM fonts, this function resets the current face to the
+   *   default instance.
    *
    * @since:
    *   2.9
@@ -794,10 +854,6 @@ FT_BEGIN_HEADER
    *   Retrieve the index of the default named instance, to be used with
    *   @FT_Set_Named_Instance.
    *
-   *   The default instance of a variation font is that instance for which
-   *   the nth axis coordinate is equal to `axis[n].def` (as specified in the
-   *   @FT_MM_Var structure), with~n covering all axes.
-   *
    *   FreeType synthesizes a named instance for the default instance if the
    *   font does not contain such an entry.
    *
@@ -813,8 +869,8 @@ FT_BEGIN_HEADER
    *   FreeType error code.  0~means success.
    *
    * @note:
-   *   For Adobe MM fonts (which don't have named instances) this function
-   *   always returns zero for `instance_index`.
+   *   For Adobe MM fonts, this function always returns zero for
+   *   `instance_index`.
    *
    * @since:
    *   2.13.1
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftmodapi.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftmodapi.h
index 0ee715898f7..2669e4a03b3 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftmodapi.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftmodapi.h
@@ -4,7 +4,7 @@
  *
  *   FreeType modules public interface (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h
index 6722fbf8b70..8e2ef2f01f8 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h
@@ -4,7 +4,7 @@
  *
  *   FreeType module error offsets (specification).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h
index 44e94b4f5bb..2545ca8486b 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h
@@ -5,7 +5,7 @@
  *   Support for the FT_Outline type used to store glyph shapes of
  *   most scalable font formats (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftparams.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftparams.h
index 43bf69c202f..94dcd6399a6 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftparams.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftparams.h
@@ -4,7 +4,7 @@
  *
  *   FreeType API for possible FT_Parameter tags (specification only).
  *
- * Copyright (C) 2017-2024 by
+ * Copyright (C) 2017-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -133,11 +133,8 @@ FT_BEGIN_HEADER
    *   FT_PARAM_TAG_LCD_FILTER_WEIGHTS
    *
    * @description:
-   *   An @FT_Parameter tag to be used with @FT_Face_Properties.  The
-   *   corresponding argument specifies the five LCD filter weights for a
-   *   given face (if using @FT_LOAD_TARGET_LCD, for example), overriding the
-   *   global default values or the values set up with
-   *   @FT_Library_SetLcdFilterWeights.
+   *   Overriding global LCD filter weights with custom values for a given
+   *   face is no longer supported and ignored.
    *
    * @since:
    *   2.8
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h
index dc5018a1b54..cc3102073b1 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h
@@ -4,7 +4,7 @@
  *
  *   FreeType renderer modules public interface (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftsizes.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftsizes.h
index 4ef5c7955df..fdb89f24ccc 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftsizes.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftsizes.h
@@ -4,7 +4,7 @@
  *
  *   FreeType size objects management (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftsnames.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftsnames.h
index d5d5cd93103..99728574db6 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftsnames.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftsnames.h
@@ -7,7 +7,7 @@
  *
  *   This is _not_ used to retrieve glyph names!
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftstroke.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftstroke.h
index 41626dc9d7b..2c4761c768d 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftstroke.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftstroke.h
@@ -4,7 +4,7 @@
  *
  *   FreeType path stroker (specification).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h
index 43081b6c330..93499a4b4f1 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h
@@ -5,7 +5,7 @@
  *   FreeType synthesizing code for emboldening and slanting
  *   (specification).
  *
- * Copyright (C) 2000-2024 by
+ * Copyright (C) 2000-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h
index 1eacb3af398..1de9f8e603d 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h
@@ -4,7 +4,7 @@
  *
  *   FreeType low-level system interface definition (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/fttrigon.h b/src/java.desktop/share/native/libfreetype/include/freetype/fttrigon.h
index a5299e938d4..ed7bd06a78f 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/fttrigon.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/fttrigon.h
@@ -4,7 +4,7 @@
  *
  *   FreeType trigonometric functions (specification).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h
index 27815143a64..e207c5ebe09 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h
@@ -4,7 +4,7 @@
  *
  *   FreeType simple types definitions (specification only).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/autohint.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/autohint.h
index 8865d53b389..987e704e9b0 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/autohint.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/autohint.h
@@ -4,7 +4,7 @@
  *
  *   High-level 'autohint' module-specific interface (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/cffotypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/cffotypes.h
index 36b0390a5a5..26ee43bb9a9 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/cffotypes.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/cffotypes.h
@@ -4,7 +4,7 @@
  *
  *   Basic OpenType/CFF object type definitions (specification).
  *
- * Copyright (C) 2017-2024 by
+ * Copyright (C) 2017-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/cfftypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/cfftypes.h
index ef2e8e7569c..754122fa646 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/cfftypes.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/cfftypes.h
@@ -5,7 +5,7 @@
  *   Basic OpenType/CFF type definitions and interface (specification
  *   only).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -191,8 +191,8 @@ FT_BEGIN_HEADER
     FT_UInt    weight;
     FT_Bool    is_fixed_pitch;
     FT_Fixed   italic_angle;
-    FT_Fixed   underline_position;
-    FT_Fixed   underline_thickness;
+    FT_Short   underline_position;
+    FT_UShort  underline_thickness;
     FT_Int     paint_type;
     FT_Int     charstring_type;
     FT_Matrix  font_matrix;
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h
index 876f66e2561..e6d0166d888 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h
@@ -4,7 +4,7 @@
  *
  *   Compiler-specific macro definitions used internally by FreeType.
  *
- * Copyright (C) 2020-2024 by
+ * Copyright (C) 2020-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -128,8 +128,8 @@ FT_BEGIN_HEADER
    * before a function declaration.
    */
 
-  /* Visual C, mingw */
-#if defined( _WIN32 )
+  /* Visual C, MinGW, Cygwin */
+#if defined( _WIN32 ) || defined( __CYGWIN__ )
 #define FT_INTERNAL_FUNCTION_ATTRIBUTE  /* empty */
 
   /* gcc, clang */
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h
index 71128a2df90..16a732224ef 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h
@@ -4,7 +4,7 @@
  *
  *   Arithmetic computations (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -27,17 +27,87 @@
 FT_BEGIN_HEADER
 
 
+  /*
+   * The following macros have two purposes.
+   *
+   * - Tag places where overflow is expected and harmless.
+   *
+   * - Avoid run-time undefined behavior sanitizer errors.
+   *
+   * Use with care!
+   */
+#define ADD_INT( a, b )                           \
+          (FT_Int)( (FT_UInt)(a) + (FT_UInt)(b) )
+#define SUB_INT( a, b )                           \
+          (FT_Int)( (FT_UInt)(a) - (FT_UInt)(b) )
+#define MUL_INT( a, b )                           \
+          (FT_Int)( (FT_UInt)(a) * (FT_UInt)(b) )
+#define NEG_INT( a )                              \
+          (FT_Int)( (FT_UInt)0 - (FT_UInt)(a) )
+
+#define ADD_LONG( a, b )                             \
+          (FT_Long)( (FT_ULong)(a) + (FT_ULong)(b) )
+#define SUB_LONG( a, b )                             \
+          (FT_Long)( (FT_ULong)(a) - (FT_ULong)(b) )
+#define MUL_LONG( a, b )                             \
+          (FT_Long)( (FT_ULong)(a) * (FT_ULong)(b) )
+#define NEG_LONG( a )                                \
+          (FT_Long)( (FT_ULong)0 - (FT_ULong)(a) )
+
+#define ADD_INT32( a, b )                               \
+          (FT_Int32)( (FT_UInt32)(a) + (FT_UInt32)(b) )
+#define SUB_INT32( a, b )                               \
+          (FT_Int32)( (FT_UInt32)(a) - (FT_UInt32)(b) )
+#define MUL_INT32( a, b )                               \
+          (FT_Int32)( (FT_UInt32)(a) * (FT_UInt32)(b) )
+#define NEG_INT32( a )                                  \
+          (FT_Int32)( (FT_UInt32)0 - (FT_UInt32)(a) )
+
+#ifdef FT_INT64
+
+#define ADD_INT64( a, b )                               \
+          (FT_Int64)( (FT_UInt64)(a) + (FT_UInt64)(b) )
+#define SUB_INT64( a, b )                               \
+          (FT_Int64)( (FT_UInt64)(a) - (FT_UInt64)(b) )
+#define MUL_INT64( a, b )                               \
+          (FT_Int64)( (FT_UInt64)(a) * (FT_UInt64)(b) )
+#define NEG_INT64( a )                                  \
+          (FT_Int64)( (FT_UInt64)0 - (FT_UInt64)(a) )
+
+#endif /* FT_INT64 */
+
+
   /**************************************************************************
    *
    * FT_MulDiv() and FT_MulFix() are declared in freetype.h.
    *
    */
 
-#ifndef  FT_CONFIG_OPTION_NO_ASSEMBLER
-  /* Provide assembler fragments for performance-critical functions. */
-  /* These must be defined `static __inline__' with GCC.             */
+#ifdef FT_CONFIG_OPTION_INLINE_MULFIX
 
-#if defined( __CC_ARM ) || defined( __ARMCC__ )  /* RVCT */
+#ifdef FT_INT64
+
+  static inline FT_Long
+  FT_MulFix_64( FT_Long  a,
+                FT_Long  b )
+  {
+    FT_Int64  ab = MUL_INT64( a, b );
+
+
+    ab = ADD_INT64( ab, 0x8000 + ( ab >> 63 ) );  /* rounding phase */
+
+    return (FT_Long)( ab >> 16 );
+  }
+
+
+#define FT_MulFix( a, b )  FT_MulFix_64( a, b )
+
+#elif !defined( FT_CONFIG_OPTION_NO_ASSEMBLER )
+  /* Provide 32-bit assembler fragments for optimized FT_MulFix. */
+  /* These must be defined `static __inline__' or similar.       */
+
+#if defined( __arm__ )                                 && \
+    ( defined( __thumb2__ ) || !defined( __thumb__ ) )
 
 #define FT_MULFIX_ASSEMBLER  FT_MulFix_arm
 
@@ -49,6 +119,7 @@ FT_BEGIN_HEADER
   {
     FT_Int32  t, t2;
 
+#if defined( __CC_ARM ) || defined( __ARMCC__ )  /* RVCT */
 
     __asm
     {
@@ -60,28 +131,8 @@ FT_BEGIN_HEADER
       mov   a,  t2, lsr #16         /* a   = t2 >> 16 */
       orr   a,  a,  t,  lsl #16     /* a  |= t << 16 */
     }
-    return a;
-  }
-
-#endif /* __CC_ARM || __ARMCC__ */
-
-
-#ifdef __GNUC__
-
-#if defined( __arm__ )                                 && \
-    ( !defined( __thumb__ ) || defined( __thumb2__ ) ) && \
-    !( defined( __CC_ARM ) || defined( __ARMCC__ ) )
-
-#define FT_MULFIX_ASSEMBLER  FT_MulFix_arm
-
-  /* documentation is in freetype.h */
-
-  static __inline__ FT_Int32
-  FT_MulFix_arm( FT_Int32  a,
-                 FT_Int32  b )
-  {
-    FT_Int32  t, t2;
 
+#elif defined( __GNUC__ )
 
     __asm__ __volatile__ (
       "smull  %1, %2, %4, %3\n\t"       /* (lo=%1,hi=%2) = a*b */
@@ -98,26 +149,25 @@ FT_BEGIN_HEADER
       : "=r"(a), "=&r"(t2), "=&r"(t)
       : "r"(a), "r"(b)
       : "cc" );
-    return a;
-  }
 
-#endif /* __arm__                      && */
-       /* ( __thumb2__ || !__thumb__ ) && */
-       /* !( __CC_ARM || __ARMCC__ )      */
+#endif
 
+    return a;
+  }
 
-#if defined( __i386__ )
+#elif defined( __i386__ ) || defined( _M_IX86 )
 
 #define FT_MULFIX_ASSEMBLER  FT_MulFix_i386
 
   /* documentation is in freetype.h */
 
-  static __inline__ FT_Int32
+  static __inline FT_Int32
   FT_MulFix_i386( FT_Int32  a,
                   FT_Int32  b )
   {
     FT_Int32  result;
 
+#if defined( __GNUC__ )
 
     __asm__ __volatile__ (
       "imul  %%edx\n"
@@ -132,27 +182,8 @@ FT_BEGIN_HEADER
       : "=a"(result), "=d"(b)
       : "a"(a), "d"(b)
       : "%ecx", "cc" );
-    return result;
-  }
-
-#endif /* i386 */
-
-#endif /* __GNUC__ */
-
-
-#ifdef _MSC_VER /* Visual C++ */
 
-#ifdef _M_IX86
-
-#define FT_MULFIX_ASSEMBLER  FT_MulFix_i386
-
-  /* documentation is in freetype.h */
-
-  static __inline FT_Int32
-  FT_MulFix_i386( FT_Int32  a,
-                  FT_Int32  b )
-  {
-    FT_Int32  result;
+#elif defined( _MSC_VER )
 
     __asm
     {
@@ -169,82 +200,22 @@ FT_BEGIN_HEADER
       add eax, edx
       mov result, eax
     }
-    return result;
-  }
-
-#endif /* _M_IX86 */
 
-#endif /* _MSC_VER */
-
-
-#if defined( __GNUC__ ) && defined( __x86_64__ )
-
-#define FT_MULFIX_ASSEMBLER  FT_MulFix_x86_64
-
-  static __inline__ FT_Int32
-  FT_MulFix_x86_64( FT_Int32  a,
-                    FT_Int32  b )
-  {
-    /* Temporarily disable the warning that C90 doesn't support */
-    /* `long long'.                                             */
-#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 6 )
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlong-long"
 #endif
 
-#if 1
-    /* Technically not an assembly fragment, but GCC does a really good */
-    /* job at inlining it and generating good machine code for it.      */
-    long long  ret, tmp;
-
-
-    ret  = (long long)a * b;
-    tmp  = ret >> 63;
-    ret += 0x8000 + tmp;
-
-    return (FT_Int32)( ret >> 16 );
-#else
-
-    /* For some reason, GCC 4.6 on Ubuntu 12.04 generates invalid machine  */
-    /* code from the lines below.  The main issue is that `wide_a' is not  */
-    /* properly initialized by sign-extending `a'.  Instead, the generated */
-    /* machine code assumes that the register that contains `a' on input   */
-    /* can be used directly as a 64-bit value, which is wrong most of the  */
-    /* time.                                                               */
-    long long  wide_a = (long long)a;
-    long long  wide_b = (long long)b;
-    long long  result;
-
-
-    __asm__ __volatile__ (
-      "imul %2, %1\n"
-      "mov %1, %0\n"
-      "sar $63, %0\n"
-      "lea 0x8000(%1, %0), %0\n"
-      "sar $16, %0\n"
-      : "=&r"(result), "=&r"(wide_a)
-      : "r"(wide_b)
-      : "cc" );
-
-    return (FT_Int32)result;
-#endif
-
-#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 6 )
-#pragma GCC diagnostic pop
-#endif
+    return result;
   }
 
-#endif /* __GNUC__ && __x86_64__ */
-
-#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */
-
+#endif /* __i386__ || _M_IX86 */
 
-#ifdef FT_CONFIG_OPTION_INLINE_MULFIX
 #ifdef FT_MULFIX_ASSEMBLER
 #define FT_MulFix( a, b )  FT_MULFIX_ASSEMBLER( (FT_Int32)(a), (FT_Int32)(b) )
-#endif
 #endif
 
+#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */
+
+#endif /* FT_CONFIG_OPTION_INLINE_MULFIX */
+
 
   /**************************************************************************
    *
@@ -278,40 +249,6 @@ FT_BEGIN_HEADER
                       FT_Long  c );
 
 
-  /**************************************************************************
-   *
-   * @function:
-   *   FT_MulAddFix
-   *
-   * @description:
-   *   Compute `(s[0] * f[0] + s[1] * f[1] + ...) / 0x10000`, where `s[n]` is
-   *   usually a 16.16 scalar.
-   *
-   * @input:
-   *   s ::
-   *     The array of scalars.
-   *   f ::
-   *     The array of factors.
-   *   count ::
-   *     The number of entries in the array.
-   *
-   * @return:
-   *   The result of `(s[0] * f[0] + s[1] * f[1] + ...) / 0x10000`.
-   *
-   * @note:
-   *   This function is currently used for the scaled delta computation of
-   *   variation stores.  It internally uses 64-bit data types when
-   *   available, otherwise it emulates 64-bit math by using 32-bit
-   *   operations, which produce a correct result but most likely at a slower
-   *   performance in comparison to the implementation base on `int64_t`.
-   *
-   */
-  FT_BASE( FT_Int32 )
-  FT_MulAddFix( FT_Fixed*  s,
-                FT_Int32*  f,
-                FT_UInt    count );
-
-
   /*
    * A variant of FT_Matrix_Multiply which scales its result afterwards.  The
    * idea is that both `a' and `b' are scaled by factors of 10 so that the
@@ -455,6 +392,10 @@ FT_BEGIN_HEADER
 
 #define FT_MSB( x )  FT_MSB_i386( x )
 
+#elif defined( __CC_ARM )
+
+#define FT_MSB( x )  ( 31 - __clz( x ) )
+
 #elif defined( __SunOS_5_11 )
 
 #include 
@@ -526,55 +467,6 @@ FT_BEGIN_HEADER
 
 #define ROUND_F26DOT6( x )     ( ( (x) + 32 - ( x < 0 ) ) & -64 )
 
-  /*
-   * The following macros have two purposes.
-   *
-   * - Tag places where overflow is expected and harmless.
-   *
-   * - Avoid run-time sanitizer errors.
-   *
-   * Use with care!
-   */
-#define ADD_INT( a, b )                           \
-          (FT_Int)( (FT_UInt)(a) + (FT_UInt)(b) )
-#define SUB_INT( a, b )                           \
-          (FT_Int)( (FT_UInt)(a) - (FT_UInt)(b) )
-#define MUL_INT( a, b )                           \
-          (FT_Int)( (FT_UInt)(a) * (FT_UInt)(b) )
-#define NEG_INT( a )                              \
-          (FT_Int)( (FT_UInt)0 - (FT_UInt)(a) )
-
-#define ADD_LONG( a, b )                             \
-          (FT_Long)( (FT_ULong)(a) + (FT_ULong)(b) )
-#define SUB_LONG( a, b )                             \
-          (FT_Long)( (FT_ULong)(a) - (FT_ULong)(b) )
-#define MUL_LONG( a, b )                             \
-          (FT_Long)( (FT_ULong)(a) * (FT_ULong)(b) )
-#define NEG_LONG( a )                                \
-          (FT_Long)( (FT_ULong)0 - (FT_ULong)(a) )
-
-#define ADD_INT32( a, b )                               \
-          (FT_Int32)( (FT_UInt32)(a) + (FT_UInt32)(b) )
-#define SUB_INT32( a, b )                               \
-          (FT_Int32)( (FT_UInt32)(a) - (FT_UInt32)(b) )
-#define MUL_INT32( a, b )                               \
-          (FT_Int32)( (FT_UInt32)(a) * (FT_UInt32)(b) )
-#define NEG_INT32( a )                                  \
-          (FT_Int32)( (FT_UInt32)0 - (FT_UInt32)(a) )
-
-#ifdef FT_INT64
-
-#define ADD_INT64( a, b )                               \
-          (FT_Int64)( (FT_UInt64)(a) + (FT_UInt64)(b) )
-#define SUB_INT64( a, b )                               \
-          (FT_Int64)( (FT_UInt64)(a) - (FT_UInt64)(b) )
-#define MUL_INT64( a, b )                               \
-          (FT_Int64)( (FT_UInt64)(a) * (FT_UInt64)(b) )
-#define NEG_INT64( a )                                  \
-          (FT_Int64)( (FT_UInt64)0 - (FT_UInt64)(a) )
-
-#endif /* FT_INT64 */
-
 
 FT_END_HEADER
 
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h
index d7fa8dc93cf..d7facf40d12 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h
@@ -4,7 +4,7 @@
  *
  *   Debugging and logging component (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h
index 5609b3ef12b..24be4dad36b 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h
@@ -4,7 +4,7 @@
  *
  *   FreeType internal font driver interface (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftgloadr.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftgloadr.h
index f1c155b162c..8f2a54c015b 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftgloadr.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftgloadr.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType glyph loader (specification).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/fthash.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/fthash.h
index 622ec76bb9a..642d21e21c6 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/fthash.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/fthash.h
@@ -117,6 +117,18 @@ FT_BEGIN_HEADER
                       FT_Hash    hash,
                       FT_Memory  memory );
 
+  FT_Error
+  ft_hash_str_insert_no_overwrite( const char*  key,
+                                   size_t       data,
+                                   FT_Hash      hash,
+                                   FT_Memory    memory );
+
+  FT_Error
+  ft_hash_num_insert_no_overwrite( FT_Int     num,
+                                   size_t     data,
+                                   FT_Hash    hash,
+                                   FT_Memory  memory );
+
   size_t*
   ft_hash_str_lookup( const char*  key,
                       FT_Hash      hash );
@@ -125,6 +137,17 @@ FT_BEGIN_HEADER
   ft_hash_num_lookup( FT_Int   num,
                       FT_Hash  hash );
 
+  FT_Bool
+  ft_hash_num_iterator( FT_UInt  *idx,
+                        FT_Int   *key,
+                        size_t   *value,
+                        FT_Hash   hash );
+
+  FT_Bool
+  ft_hash_str_iterator( FT_UInt      *idx,
+                        const char*  *key,
+                        size_t       *value,
+                        FT_Hash       hash );
 
 FT_END_HEADER
 
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmemory.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmemory.h
index 4e05a29f13a..c75c33f2895 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmemory.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmemory.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType memory management macros (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h
index 8449e7a010d..be3747bbf94 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h
@@ -5,7 +5,7 @@
  *   OpenType Variations type definitions for internal use
  *   with the multi-masters service (specification).
  *
- * Copyright (C) 2022-2024 by
+ * Copyright (C) 2022-2025 by
  * David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and
  * Dominik Röttsches.
  *
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h
index a1e93298fdb..d4d7bc00fe9 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType private base classes (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -275,6 +275,28 @@ FT_BEGIN_HEADER
                   FT_GlyphSlot    slot,
                   FT_Render_Mode  mode );
 
+
+  /**************************************************************************
+   *
+   * @Function:
+   *   find_unicode_charmap
+   *
+   * @Description:
+   *   This function finds a Unicode charmap, if there is one.  And if there
+   *   is more than one, it tries to favour the more extensive one, i.e., one
+   *   that supports UCS-4 against those which are limited to the BMP (UCS-2
+   *   encoding.)
+   *
+   *   If a unicode charmap is found, `face->charmap` is set to it.
+   *
+   *   This function is called from `open_face`, from `FT_Select_Charmap(...,
+   *   FT_ENCODING_UNICODE)`, and also from `afadjust.c` in the 'autofit'
+   *   module.
+   */
+  FT_BASE( FT_Error )
+  find_unicode_charmap( FT_Face  face );
+
+
 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
 
   typedef void  (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap*      bitmap,
@@ -343,11 +365,6 @@ FT_BEGIN_HEADER
    *     Value~0 means to use the font's value.  Value~-1 means to use the
    *     CFF driver's default.
    *
-   *   lcd_weights ::
-   *   lcd_filter_func ::
-   *     These fields specify the LCD filtering weights and callback function
-   *     for ClearType-style subpixel rendering.
-   *
    *   refcount ::
    *     A counter initialized to~1 at the time an @FT_Face structure is
    *     created.  @FT_Reference_Face increments this counter, and
@@ -369,11 +386,6 @@ FT_BEGIN_HEADER
     FT_Char              no_stem_darkening;
     FT_Int32             random_seed;
 
-#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
-    FT_LcdFiveTapFilter      lcd_weights;      /* filter weights, if any */
-    FT_Bitmap_LcdFilterFunc  lcd_filter_func;  /* filtering callback     */
-#endif
-
     FT_Int  refcount;
 
   } FT_Face_InternalRec;
@@ -498,9 +510,9 @@ FT_BEGIN_HEADER
    */
   typedef struct  FT_ModuleRec_
   {
-    FT_Module_Class*  clazz;
-    FT_Library        library;
-    FT_Memory         memory;
+    const FT_Module_Class*  clazz;
+    FT_Library              library;
+    FT_Memory               memory;
 
   } FT_ModuleRec;
 
@@ -702,9 +714,9 @@ FT_BEGIN_HEADER
                               const FT_Vector*  origin );
 
   /* Allocate a new bitmap buffer in a glyph slot. */
+  /* Dimensions must be preset in advance.         */
   FT_BASE( FT_Error )
-  ft_glyphslot_alloc_bitmap( FT_GlyphSlot  slot,
-                             FT_ULong      size );
+  ft_glyphslot_alloc_bitmap( FT_GlyphSlot  slot );
 
 
   /* Set the bitmap buffer in a glyph slot to a given pointer.  The buffer */
@@ -867,10 +879,6 @@ FT_BEGIN_HEADER
    *   lcd_weights ::
    *     The LCD filter weights for ClearType-style subpixel rendering.
    *
-   *   lcd_filter_func ::
-   *     The LCD filtering callback function for for ClearType-style subpixel
-   *     rendering.
-   *
    *   lcd_geometry ::
    *     This array specifies LCD subpixel geometry and controls Harmony LCD
    *     rendering technique, alternative to ClearType.
@@ -904,7 +912,6 @@ FT_BEGIN_HEADER
 
 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
     FT_LcdFiveTapFilter      lcd_weights;      /* filter weights, if any */
-    FT_Bitmap_LcdFilterFunc  lcd_filter_func;  /* filtering callback     */
 #else
     FT_Vector                lcd_geometry[3];  /* RGB subpixel positions */
 #endif
@@ -973,17 +980,6 @@ FT_BEGIN_HEADER
 #endif /* !FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM */
 
 
-  /* Define default raster's interface.  The default raster is located in  */
-  /* `src/base/ftraster.c'.                                                */
-  /*                                                                       */
-  /* Client applications can register new rasters through the              */
-  /* FT_Set_Raster() API.                                                  */
-
-#ifndef FT_NO_DEFAULT_RASTER
-  FT_EXPORT_VAR( FT_Raster_Funcs )  ft_default_raster;
-#endif
-
-
   /**************************************************************************
    *
    * @macro:
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftpsprop.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftpsprop.h
index 4f11aa16ba1..18a954d22f5 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftpsprop.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftpsprop.h
@@ -4,7 +4,7 @@
  *
  *   Get and set properties of PostScript drivers (specification).
  *
- * Copyright (C) 2017-2024 by
+ * Copyright (C) 2017-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftrfork.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftrfork.h
index 05c1d6c48b5..e077f98bfb9 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftrfork.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftrfork.h
@@ -4,7 +4,7 @@
  *
  *   Embedded resource forks accessor (specification).
  *
- * Copyright (C) 2004-2024 by
+ * Copyright (C) 2004-2025 by
  * Masatake YAMATO and Redhat K.K.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h
index 8c35dbd7139..ce11bba19b2 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType services (specification only).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftstream.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftstream.h
index fd52f767ef7..20c1dd7c4b0 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftstream.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftstream.h
@@ -4,7 +4,7 @@
  *
  *   Stream handling (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h
index 42595a29ff3..3fd592800e2 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h
@@ -4,7 +4,7 @@
  *
  *   Tracing handling (specification only).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -19,7 +19,7 @@
   /* definitions of trace levels for FreeType 2 */
 
   /* the maximum string length (if the argument to `FT_TRACE_DEF` */
-  /* gets used as a string) plus one charachter for ':' plus      */
+  /* gets used as a string) plus one character for ':' plus       */
   /* another one for the trace level                              */
 #define FT_MAX_TRACE_LEVEL_LENGTH  (9 + 1 + 1)
 
@@ -159,6 +159,7 @@ FT_TRACE_DEF( gxvprop )
 FT_TRACE_DEF( gxvtrak )
 
   /* autofit components */
+FT_TRACE_DEF( afadjust )
 FT_TRACE_DEF( afcjk )
 FT_TRACE_DEF( afglobal )
 FT_TRACE_DEF( afhints )
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftvalid.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftvalid.h
index a1312f2aba6..03a726c82cb 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftvalid.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftvalid.h
@@ -4,7 +4,7 @@
  *
  *   FreeType validation support (specification).
  *
- * Copyright (C) 2004-2024 by
+ * Copyright (C) 2004-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/psaux.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/psaux.h
index 745d2cb56b7..344be0f19a7 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/psaux.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/psaux.h
@@ -5,7 +5,7 @@
  *   Auxiliary functions and data structures related to PostScript fonts
  *   (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/pshints.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/pshints.h
index dba6c7303fd..96c5d84f058 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/pshints.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/pshints.h
@@ -6,7 +6,7 @@
  *   recorders (specification only).  These are used to support native
  *   T1/T2 hints in the 'type1', 'cid', and 'cff' font drivers.
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svbdf.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svbdf.h
index 89e9c2e5de8..5bd51da23f4 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svbdf.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svbdf.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType BDF services (specification).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcfftl.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcfftl.h
index 3cb483c344f..c97bf84fb2e 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcfftl.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcfftl.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType CFF tables loader service (specification).
  *
- * Copyright (C) 2017-2024 by
+ * Copyright (C) 2017-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcid.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcid.h
index 8362cb8724d..748a8caf887 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcid.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcid.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType CID font services (specification).
  *
- * Copyright (C) 2007-2024 by
+ * Copyright (C) 2007-2025 by
  * Derek Clegg and Michael Toftdal.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h
index 6b837e79fcd..690fdc2a24f 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType font format service (specification only).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgldict.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgldict.h
index 6126ec9ada4..7128d6f3d7a 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgldict.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgldict.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType glyph dictionary services (specification).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgxval.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgxval.h
index 29cf5528189..1ca3e0a031b 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgxval.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgxval.h
@@ -4,7 +4,7 @@
  *
  *   FreeType API for validating TrueTypeGX/AAT tables (specification).
  *
- * Copyright (C) 2004-2024 by
+ * Copyright (C) 2004-2025 by
  * Masatake YAMATO, Red Hat K.K.,
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svkern.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svkern.h
index ac1bc30c412..8a3d59bec6d 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svkern.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svkern.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType Kerning service (specification).
  *
- * Copyright (C) 2006-2024 by
+ * Copyright (C) 2006-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h
index 8b3563b25ca..4dde3a8151a 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType services for metrics variations (specification).
  *
- * Copyright (C) 2016-2024 by
+ * Copyright (C) 2016-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -77,7 +77,7 @@ FT_BEGIN_HEADER
   typedef void
   (*FT_Metrics_Adjust_Func)( FT_Face  face );
 
-  typedef FT_Error
+  typedef void
   (*FT_Size_Reset_Func)( FT_Size  size );
 
 
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h
index 5288fadf375..9be133e2db0 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType Multiple Masters and GX var services (specification).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svotval.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svotval.h
index 7aea7ec11f0..933e5de98da 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svotval.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svotval.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType OpenType validation service (specification).
  *
- * Copyright (C) 2004-2024 by
+ * Copyright (C) 2004-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpfr.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpfr.h
index b2fac6d086b..c81b6a68a8b 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpfr.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpfr.h
@@ -4,7 +4,7 @@
  *
  *   Internal PFR service functions (specification).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpostnm.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpostnm.h
index d19f3adc6d5..33864ebc344 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpostnm.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpostnm.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType PostScript name services (specification).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svprop.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svprop.h
index ba39c0dd4da..0eb79c885d8 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svprop.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svprop.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType property service (specification).
  *
- * Copyright (C) 2012-2024 by
+ * Copyright (C) 2012-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h
index d4908ee41aa..8f85d12157c 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType PostScript charmap service (specification).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpsinfo.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpsinfo.h
index 2aadcdd02a1..83de04478df 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpsinfo.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpsinfo.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType PostScript info service (specification).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svsfnt.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svsfnt.h
index 9e0f4ff202e..9bf5e3473c4 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svsfnt.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svsfnt.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType SFNT table loading service (specification).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h
index 250886bcc5d..fc9b0aeb8e3 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType TrueType/sfnt cmap extra information service.
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * Masatake YAMATO, Redhat K.K.,
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svtteng.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svtteng.h
index 14967529a9a..979e9ea102e 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svtteng.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svtteng.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType TrueType engine query service (specification).
  *
- * Copyright (C) 2006-2024 by
+ * Copyright (C) 2006-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttglyf.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttglyf.h
index f190b3985d0..e4f54c10037 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttglyf.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttglyf.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType TrueType glyph service.
  *
- * Copyright (C) 2007-2024 by
+ * Copyright (C) 2007-2025 by
  * David Turner.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svwinfnt.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svwinfnt.h
index 49f3fb7f775..ff887ffdc03 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svwinfnt.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svwinfnt.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType Windows FNT/FONT service (specification).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/sfnt.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/sfnt.h
index 35e4e73af02..adba2178877 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/sfnt.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/sfnt.h
@@ -4,7 +4,7 @@
  *
  *   High-level 'sfnt' driver interface (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -612,7 +612,7 @@ FT_BEGIN_HEADER
    *
    * @return:
    *   Value~1 if a ClipBox is found.  If no clip box is found or an
-   *   error occured, value~0 is returned.
+   *   error occurred, value~0 is returned.
    */
   typedef FT_Bool
   ( *TT_Get_Color_Glyph_ClipBox_Func )( TT_Face      face,
@@ -707,7 +707,7 @@ FT_BEGIN_HEADER
    *
    * @return:
    *   Value~1 if everything is OK.  Value~0 if no details can be found for
-   *   this paint or any other error occured.
+   *   this paint or any other error occurred.
    */
   typedef FT_Bool
   ( *TT_Get_Paint_Func )( TT_Face         face,
@@ -808,7 +808,7 @@ FT_BEGIN_HEADER
    *     corresponding (1,0) Apple entry.
    *
    * @return:
-   *   1 if there is either a win or apple entry (or both), 0 otheriwse.
+   *   1 if there is either a win or apple entry (or both), 0 otherwise.
    */
   typedef FT_Bool
   (*TT_Get_Name_ID_Func)( TT_Face    face,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/svginterface.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/svginterface.h
index 68c99efb10a..20c73b2fbd2 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/svginterface.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/svginterface.h
@@ -4,7 +4,7 @@
  *
  *   Interface of ot-svg module (specification only).
  *
- * Copyright (C) 2022-2024 by
+ * Copyright (C) 2022-2025 by
  * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h
index 1821ae5cc83..5b26e4620d0 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h
@@ -5,7 +5,7 @@
  *   Basic Type1/Type2 type definitions and interface (specification
  *   only).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h
index 7053e656a7e..d0e5eee89bc 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h
@@ -5,7 +5,7 @@
  *   Basic SFNT/TrueType type definitions and interface (specification
  *   only).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -930,8 +930,8 @@ FT_BEGIN_HEADER
    *   resolution and scaling independent parts of a TrueType font resource.
    *
    * @note:
-   *   The TT_Face structure is also used as a 'parent class' for the
-   *   OpenType-CFF class (T2_Face).
+   *   The TT_Face structure is also used for CFF support; see file
+   *   `cffotypes.h`.
    */
   typedef struct TT_FaceRec_*  TT_Face;
 
@@ -1276,10 +1276,6 @@ FT_BEGIN_HEADER
    *
    *     If varied by the `CVAR' table, non-integer values are possible.
    *
-   *   interpreter ::
-   *     A pointer to the TrueType bytecode interpreters field is also used
-   *     to hook the debugger in 'ttdebug'.
-   *
    *   extra ::
    *     Reserved for third-party font drivers.
    *
@@ -1521,10 +1517,6 @@ FT_BEGIN_HEADER
     FT_ULong              cvt_size;
     FT_Int32*             cvt;
 
-    /* A pointer to the bytecode interpreter to use.  This is also */
-    /* used to hook the debugger for the `ttdebug' utility.        */
-    TT_Interpreter        interpreter;
-
 
     /************************************************************************
      *
@@ -1582,11 +1574,6 @@ FT_BEGIN_HEADER
     FT_UInt32             kern_avail_bits;
     FT_UInt32             kern_order_bits;
 
-#ifdef TT_CONFIG_OPTION_GPOS_KERNING
-    FT_Byte*              gpos_table;
-    FT_Bool               gpos_kerning_available;
-#endif
-
 #ifdef TT_CONFIG_OPTION_BDF
     TT_BDFRec             bdf;
 #endif /* TT_CONFIG_OPTION_BDF */
@@ -1608,6 +1595,15 @@ FT_BEGIN_HEADER
     /* since 2.12 */
     void*                 svg;
 
+#ifdef TT_CONFIG_OPTION_GPOS_KERNING
+    /* since 2.13.3 */
+    FT_Byte*              gpos_table;
+    /* since 2.14 */
+    /* This is actually an array of GPOS lookup subtables. */
+    FT_UInt32*            gpos_lookups_kerning;
+    FT_UInt               num_gpos_lookups_kerning;
+#endif
+
   } TT_FaceRec;
 
 
@@ -1621,15 +1617,6 @@ FT_BEGIN_HEADER
    *   coordinates.
    *
    * @fields:
-   *   memory ::
-   *     A handle to the memory manager.
-   *
-   *   max_points ::
-   *     The maximum size in points of the zone.
-   *
-   *   max_contours ::
-   *     Max size in links contours of the zone.
-   *
    *   n_points ::
    *     The current number of points in the zone.
    *
@@ -1653,9 +1640,6 @@ FT_BEGIN_HEADER
    */
   typedef struct  TT_GlyphZoneRec_
   {
-    FT_Memory   memory;
-    FT_UShort   max_points;
-    FT_UShort   max_contours;
     FT_UShort   n_points;    /* number of points in zone    */
     FT_UShort   n_contours;  /* number of contours          */
 
@@ -1714,7 +1698,6 @@ FT_BEGIN_HEADER
     TT_GlyphZoneRec  zone;
 
     TT_ExecContext   exec;
-    FT_Byte*         instructions;
     FT_ULong         ins_pos;
 
     /* for possible extensibility in other formats */
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/wofftypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/wofftypes.h
index 4a169d12f57..7d5b7df0fa1 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/wofftypes.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/wofftypes.h
@@ -5,7 +5,7 @@
  *   Basic WOFF/WOFF2 type definitions and interface (specification
  *   only).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/otsvg.h b/src/java.desktop/share/native/libfreetype/include/freetype/otsvg.h
index 9d356938cc7..326bbcd0153 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/otsvg.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/otsvg.h
@@ -4,7 +4,7 @@
  *
  *   Interface for OT-SVG support related things (specification).
  *
- * Copyright (C) 2022-2024 by
+ * Copyright (C) 2022-2025 by
  * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/t1tables.h b/src/java.desktop/share/native/libfreetype/include/freetype/t1tables.h
index fbd558aa34d..fe769f607fa 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/t1tables.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/t1tables.h
@@ -5,7 +5,7 @@
  *   Basic Type 1/Type 2 tables definitions and interface (specification
  *   only).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -92,7 +92,7 @@ FT_BEGIN_HEADER
     FT_String*  full_name;
     FT_String*  family_name;
     FT_String*  weight;
-    FT_Long     italic_angle;
+    FT_Fixed    italic_angle;
     FT_Bool     is_fixed_pitch;
     FT_Short    underline_position;
     FT_UShort   underline_thickness;
@@ -645,7 +645,7 @@ FT_BEGIN_HEADER
     PS_DICT_UNDERLINE_POSITION,     /* FT_Short   */
     PS_DICT_UNDERLINE_THICKNESS,    /* FT_UShort  */
     PS_DICT_FS_TYPE,                /* FT_UShort  */
-    PS_DICT_ITALIC_ANGLE,           /* FT_Long    */
+    PS_DICT_ITALIC_ANGLE,           /* FT_Fixed   */
 
     PS_DICT_MAX = PS_DICT_ITALIC_ANGLE
 
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ttnameid.h b/src/java.desktop/share/native/libfreetype/include/freetype/ttnameid.h
index d5d470e380f..3ef61091cc9 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ttnameid.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ttnameid.h
@@ -4,7 +4,7 @@
  *
  *   TrueType name ID definitions (specification only).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -436,7 +436,7 @@ FT_BEGIN_HEADER
    *
    *   The canonical source for Microsoft's IDs is
    *
-   *     https://docs.microsoft.com/en-us/windows/desktop/Intl/language-identifier-constants-and-strings ,
+   *     https://learn.microsoft.com/windows/win32/intl/language-identifier-constants-and-strings ,
    *
    *   however, we only provide macros for language identifiers present in
    *   the OpenType specification: Microsoft has abandoned the concept of
@@ -847,113 +847,113 @@ FT_BEGIN_HEADER
   /* --------------- */
 
   /* Bit  0   Basic Latin */
-#define TT_UCR_BASIC_LATIN                     (1L <<  0) /* U+0020-U+007E */
+#define TT_UCR_BASIC_LATIN                    (1UL <<  0) /* U+0020-U+007E */
   /* Bit  1   C1 Controls and Latin-1 Supplement */
-#define TT_UCR_LATIN1_SUPPLEMENT               (1L <<  1) /* U+0080-U+00FF */
+#define TT_UCR_LATIN1_SUPPLEMENT              (1UL <<  1) /* U+0080-U+00FF */
   /* Bit  2   Latin Extended-A */
-#define TT_UCR_LATIN_EXTENDED_A                (1L <<  2) /* U+0100-U+017F */
+#define TT_UCR_LATIN_EXTENDED_A               (1UL <<  2) /* U+0100-U+017F */
   /* Bit  3   Latin Extended-B */
-#define TT_UCR_LATIN_EXTENDED_B                (1L <<  3) /* U+0180-U+024F */
+#define TT_UCR_LATIN_EXTENDED_B               (1UL <<  3) /* U+0180-U+024F */
   /* Bit  4   IPA Extensions                 */
   /*          Phonetic Extensions            */
   /*          Phonetic Extensions Supplement */
-#define TT_UCR_IPA_EXTENSIONS                  (1L <<  4) /* U+0250-U+02AF */
+#define TT_UCR_IPA_EXTENSIONS                 (1UL <<  4) /* U+0250-U+02AF */
                                                           /* U+1D00-U+1D7F */
                                                           /* U+1D80-U+1DBF */
   /* Bit  5   Spacing Modifier Letters */
   /*          Modifier Tone Letters    */
-#define TT_UCR_SPACING_MODIFIER                (1L <<  5) /* U+02B0-U+02FF */
+#define TT_UCR_SPACING_MODIFIER               (1UL <<  5) /* U+02B0-U+02FF */
                                                           /* U+A700-U+A71F */
   /* Bit  6   Combining Diacritical Marks            */
   /*          Combining Diacritical Marks Supplement */
-#define TT_UCR_COMBINING_DIACRITICAL_MARKS     (1L <<  6) /* U+0300-U+036F */
+#define TT_UCR_COMBINING_DIACRITICAL_MARKS    (1UL <<  6) /* U+0300-U+036F */
                                                           /* U+1DC0-U+1DFF */
   /* Bit  7   Greek and Coptic */
-#define TT_UCR_GREEK                           (1L <<  7) /* U+0370-U+03FF */
+#define TT_UCR_GREEK                          (1UL <<  7) /* U+0370-U+03FF */
   /* Bit  8   Coptic */
-#define TT_UCR_COPTIC                          (1L <<  8) /* U+2C80-U+2CFF */
+#define TT_UCR_COPTIC                         (1UL <<  8) /* U+2C80-U+2CFF */
   /* Bit  9   Cyrillic            */
   /*          Cyrillic Supplement */
   /*          Cyrillic Extended-A */
   /*          Cyrillic Extended-B */
-#define TT_UCR_CYRILLIC                        (1L <<  9) /* U+0400-U+04FF */
+#define TT_UCR_CYRILLIC                       (1UL <<  9) /* U+0400-U+04FF */
                                                           /* U+0500-U+052F */
                                                           /* U+2DE0-U+2DFF */
                                                           /* U+A640-U+A69F */
   /* Bit 10   Armenian */
-#define TT_UCR_ARMENIAN                        (1L << 10) /* U+0530-U+058F */
+#define TT_UCR_ARMENIAN                       (1UL << 10) /* U+0530-U+058F */
   /* Bit 11   Hebrew */
-#define TT_UCR_HEBREW                          (1L << 11) /* U+0590-U+05FF */
+#define TT_UCR_HEBREW                         (1UL << 11) /* U+0590-U+05FF */
   /* Bit 12   Vai */
-#define TT_UCR_VAI                             (1L << 12) /* U+A500-U+A63F */
+#define TT_UCR_VAI                            (1UL << 12) /* U+A500-U+A63F */
   /* Bit 13   Arabic            */
   /*          Arabic Supplement */
-#define TT_UCR_ARABIC                          (1L << 13) /* U+0600-U+06FF */
+#define TT_UCR_ARABIC                         (1UL << 13) /* U+0600-U+06FF */
                                                           /* U+0750-U+077F */
   /* Bit 14   NKo */
-#define TT_UCR_NKO                             (1L << 14) /* U+07C0-U+07FF */
+#define TT_UCR_NKO                            (1UL << 14) /* U+07C0-U+07FF */
   /* Bit 15   Devanagari */
-#define TT_UCR_DEVANAGARI                      (1L << 15) /* U+0900-U+097F */
-  /* Bit 16   Bengali */
-#define TT_UCR_BENGALI                         (1L << 16) /* U+0980-U+09FF */
+#define TT_UCR_DEVANAGARI                     (1UL << 15) /* U+0900-U+097F */
+  /* Bit 16   Bangla (Bengali) */
+#define TT_UCR_BENGALI                        (1UL << 16) /* U+0980-U+09FF */
   /* Bit 17   Gurmukhi */
-#define TT_UCR_GURMUKHI                        (1L << 17) /* U+0A00-U+0A7F */
+#define TT_UCR_GURMUKHI                       (1UL << 17) /* U+0A00-U+0A7F */
   /* Bit 18   Gujarati */
-#define TT_UCR_GUJARATI                        (1L << 18) /* U+0A80-U+0AFF */
-  /* Bit 19   Oriya */
-#define TT_UCR_ORIYA                           (1L << 19) /* U+0B00-U+0B7F */
+#define TT_UCR_GUJARATI                       (1UL << 18) /* U+0A80-U+0AFF */
+  /* Bit 19   Oriya (Odia) */
+#define TT_UCR_ORIYA                          (1UL << 19) /* U+0B00-U+0B7F */
   /* Bit 20   Tamil */
-#define TT_UCR_TAMIL                           (1L << 20) /* U+0B80-U+0BFF */
+#define TT_UCR_TAMIL                          (1UL << 20) /* U+0B80-U+0BFF */
   /* Bit 21   Telugu */
-#define TT_UCR_TELUGU                          (1L << 21) /* U+0C00-U+0C7F */
+#define TT_UCR_TELUGU                         (1UL << 21) /* U+0C00-U+0C7F */
   /* Bit 22   Kannada */
-#define TT_UCR_KANNADA                         (1L << 22) /* U+0C80-U+0CFF */
+#define TT_UCR_KANNADA                        (1UL << 22) /* U+0C80-U+0CFF */
   /* Bit 23   Malayalam */
-#define TT_UCR_MALAYALAM                       (1L << 23) /* U+0D00-U+0D7F */
+#define TT_UCR_MALAYALAM                      (1UL << 23) /* U+0D00-U+0D7F */
   /* Bit 24   Thai */
-#define TT_UCR_THAI                            (1L << 24) /* U+0E00-U+0E7F */
+#define TT_UCR_THAI                           (1UL << 24) /* U+0E00-U+0E7F */
   /* Bit 25   Lao */
-#define TT_UCR_LAO                             (1L << 25) /* U+0E80-U+0EFF */
+#define TT_UCR_LAO                            (1UL << 25) /* U+0E80-U+0EFF */
   /* Bit 26   Georgian            */
   /*          Georgian Supplement */
-#define TT_UCR_GEORGIAN                        (1L << 26) /* U+10A0-U+10FF */
+#define TT_UCR_GEORGIAN                       (1UL << 26) /* U+10A0-U+10FF */
                                                           /* U+2D00-U+2D2F */
   /* Bit 27   Balinese */
-#define TT_UCR_BALINESE                        (1L << 27) /* U+1B00-U+1B7F */
+#define TT_UCR_BALINESE                       (1UL << 27) /* U+1B00-U+1B7F */
   /* Bit 28   Hangul Jamo */
-#define TT_UCR_HANGUL_JAMO                     (1L << 28) /* U+1100-U+11FF */
+#define TT_UCR_HANGUL_JAMO                    (1UL << 28) /* U+1100-U+11FF */
   /* Bit 29   Latin Extended Additional */
   /*          Latin Extended-C          */
   /*          Latin Extended-D          */
-#define TT_UCR_LATIN_EXTENDED_ADDITIONAL       (1L << 29) /* U+1E00-U+1EFF */
+#define TT_UCR_LATIN_EXTENDED_ADDITIONAL      (1UL << 29) /* U+1E00-U+1EFF */
                                                           /* U+2C60-U+2C7F */
                                                           /* U+A720-U+A7FF */
   /* Bit 30   Greek Extended */
-#define TT_UCR_GREEK_EXTENDED                  (1L << 30) /* U+1F00-U+1FFF */
+#define TT_UCR_GREEK_EXTENDED                 (1UL << 30) /* U+1F00-U+1FFF */
   /* Bit 31   General Punctuation      */
   /*          Supplemental Punctuation */
-#define TT_UCR_GENERAL_PUNCTUATION             (1L << 31) /* U+2000-U+206F */
+#define TT_UCR_GENERAL_PUNCTUATION            (1UL << 31) /* U+2000-U+206F */
                                                           /* U+2E00-U+2E7F */
 
   /* ulUnicodeRange2 */
   /* --------------- */
 
   /* Bit 32   Superscripts And Subscripts */
-#define TT_UCR_SUPERSCRIPTS_SUBSCRIPTS         (1L <<  0) /* U+2070-U+209F */
+#define TT_UCR_SUPERSCRIPTS_SUBSCRIPTS        (1UL <<  0) /* U+2070-U+209F */
   /* Bit 33   Currency Symbols */
-#define TT_UCR_CURRENCY_SYMBOLS                (1L <<  1) /* U+20A0-U+20CF */
+#define TT_UCR_CURRENCY_SYMBOLS               (1UL <<  1) /* U+20A0-U+20CF */
   /* Bit 34   Combining Diacritical Marks For Symbols */
 #define TT_UCR_COMBINING_DIACRITICAL_MARKS_SYMB \
-                                               (1L <<  2) /* U+20D0-U+20FF */
+                                              (1UL <<  2) /* U+20D0-U+20FF */
   /* Bit 35   Letterlike Symbols */
-#define TT_UCR_LETTERLIKE_SYMBOLS              (1L <<  3) /* U+2100-U+214F */
+#define TT_UCR_LETTERLIKE_SYMBOLS             (1UL <<  3) /* U+2100-U+214F */
   /* Bit 36   Number Forms */
-#define TT_UCR_NUMBER_FORMS                    (1L <<  4) /* U+2150-U+218F */
+#define TT_UCR_NUMBER_FORMS                   (1UL <<  4) /* U+2150-U+218F */
   /* Bit 37   Arrows                           */
   /*          Supplemental Arrows-A            */
   /*          Supplemental Arrows-B            */
   /*          Miscellaneous Symbols and Arrows */
-#define TT_UCR_ARROWS                          (1L <<  5) /* U+2190-U+21FF */
+#define TT_UCR_ARROWS                         (1UL <<  5) /* U+2190-U+21FF */
                                                           /* U+27F0-U+27FF */
                                                           /* U+2900-U+297F */
                                                           /* U+2B00-U+2BFF */
@@ -961,52 +961,52 @@ FT_BEGIN_HEADER
   /*          Supplemental Mathematical Operators  */
   /*          Miscellaneous Mathematical Symbols-A */
   /*          Miscellaneous Mathematical Symbols-B */
-#define TT_UCR_MATHEMATICAL_OPERATORS          (1L <<  6) /* U+2200-U+22FF */
+#define TT_UCR_MATHEMATICAL_OPERATORS         (1UL <<  6) /* U+2200-U+22FF */
                                                           /* U+2A00-U+2AFF */
                                                           /* U+27C0-U+27EF */
                                                           /* U+2980-U+29FF */
   /* Bit 39 Miscellaneous Technical */
-#define TT_UCR_MISCELLANEOUS_TECHNICAL         (1L <<  7) /* U+2300-U+23FF */
+#define TT_UCR_MISCELLANEOUS_TECHNICAL        (1UL <<  7) /* U+2300-U+23FF */
   /* Bit 40   Control Pictures */
-#define TT_UCR_CONTROL_PICTURES                (1L <<  8) /* U+2400-U+243F */
+#define TT_UCR_CONTROL_PICTURES               (1UL <<  8) /* U+2400-U+243F */
   /* Bit 41   Optical Character Recognition */
-#define TT_UCR_OCR                             (1L <<  9) /* U+2440-U+245F */
+#define TT_UCR_OCR                            (1UL <<  9) /* U+2440-U+245F */
   /* Bit 42   Enclosed Alphanumerics */
-#define TT_UCR_ENCLOSED_ALPHANUMERICS          (1L << 10) /* U+2460-U+24FF */
+#define TT_UCR_ENCLOSED_ALPHANUMERICS         (1UL << 10) /* U+2460-U+24FF */
   /* Bit 43   Box Drawing */
-#define TT_UCR_BOX_DRAWING                     (1L << 11) /* U+2500-U+257F */
+#define TT_UCR_BOX_DRAWING                    (1UL << 11) /* U+2500-U+257F */
   /* Bit 44   Block Elements */
-#define TT_UCR_BLOCK_ELEMENTS                  (1L << 12) /* U+2580-U+259F */
+#define TT_UCR_BLOCK_ELEMENTS                 (1UL << 12) /* U+2580-U+259F */
   /* Bit 45   Geometric Shapes */
-#define TT_UCR_GEOMETRIC_SHAPES                (1L << 13) /* U+25A0-U+25FF */
+#define TT_UCR_GEOMETRIC_SHAPES               (1UL << 13) /* U+25A0-U+25FF */
   /* Bit 46   Miscellaneous Symbols */
-#define TT_UCR_MISCELLANEOUS_SYMBOLS           (1L << 14) /* U+2600-U+26FF */
+#define TT_UCR_MISCELLANEOUS_SYMBOLS          (1UL << 14) /* U+2600-U+26FF */
   /* Bit 47   Dingbats */
-#define TT_UCR_DINGBATS                        (1L << 15) /* U+2700-U+27BF */
+#define TT_UCR_DINGBATS                       (1UL << 15) /* U+2700-U+27BF */
   /* Bit 48   CJK Symbols and Punctuation */
-#define TT_UCR_CJK_SYMBOLS                     (1L << 16) /* U+3000-U+303F */
+#define TT_UCR_CJK_SYMBOLS                    (1UL << 16) /* U+3000-U+303F */
   /* Bit 49   Hiragana */
-#define TT_UCR_HIRAGANA                        (1L << 17) /* U+3040-U+309F */
+#define TT_UCR_HIRAGANA                       (1UL << 17) /* U+3040-U+309F */
   /* Bit 50   Katakana                     */
   /*          Katakana Phonetic Extensions */
-#define TT_UCR_KATAKANA                        (1L << 18) /* U+30A0-U+30FF */
+#define TT_UCR_KATAKANA                       (1UL << 18) /* U+30A0-U+30FF */
                                                           /* U+31F0-U+31FF */
   /* Bit 51   Bopomofo          */
   /*          Bopomofo Extended */
-#define TT_UCR_BOPOMOFO                        (1L << 19) /* U+3100-U+312F */
+#define TT_UCR_BOPOMOFO                       (1UL << 19) /* U+3100-U+312F */
                                                           /* U+31A0-U+31BF */
   /* Bit 52   Hangul Compatibility Jamo */
-#define TT_UCR_HANGUL_COMPATIBILITY_JAMO       (1L << 20) /* U+3130-U+318F */
+#define TT_UCR_HANGUL_COMPATIBILITY_JAMO      (1UL << 20) /* U+3130-U+318F */
   /* Bit 53   Phags-Pa */
-#define TT_UCR_CJK_MISC                        (1L << 21) /* U+A840-U+A87F */
-#define TT_UCR_KANBUN  TT_UCR_CJK_MISC /* deprecated */
-#define TT_UCR_PHAGSPA
+#define TT_UCR_PHAGSPA                        (1UL << 21) /* U+A840-U+A87F */
+#define TT_UCR_KANBUN    TT_UCR_PHAGSPA  /* deprecated */
+#define TT_UCR_CJK_MISC  TT_UCR_PHAGSPA  /* deprecated */
   /* Bit 54   Enclosed CJK Letters and Months */
-#define TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS     (1L << 22) /* U+3200-U+32FF */
+#define TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS    (1UL << 22) /* U+3200-U+32FF */
   /* Bit 55   CJK Compatibility */
-#define TT_UCR_CJK_COMPATIBILITY               (1L << 23) /* U+3300-U+33FF */
+#define TT_UCR_CJK_COMPATIBILITY              (1UL << 23) /* U+3300-U+33FF */
   /* Bit 56   Hangul Syllables */
-#define TT_UCR_HANGUL                          (1L << 24) /* U+AC00-U+D7A3 */
+#define TT_UCR_HANGUL                         (1UL << 24) /* U+AC00-U+D7A3 */
   /* Bit 57   High Surrogates              */
   /*          High Private Use Surrogates  */
   /*          Low Surrogates               */
@@ -1017,12 +1017,12 @@ FT_BEGIN_HEADER
   /* Basic Multilingual Plane that is      */
   /* supported by this font.  So it really */
   /* means >= U+10000.                     */
-#define TT_UCR_SURROGATES                      (1L << 25) /* U+D800-U+DB7F */
+#define TT_UCR_SURROGATES                     (1UL << 25) /* U+D800-U+DB7F */
                                                           /* U+DB80-U+DBFF */
                                                           /* U+DC00-U+DFFF */
 #define TT_UCR_NON_PLANE_0  TT_UCR_SURROGATES
   /* Bit 58  Phoenician */
-#define TT_UCR_PHOENICIAN                      (1L << 26) /*U+10900-U+1091F*/
+#define TT_UCR_PHOENICIAN                     (1UL << 26) /*U+10900-U+1091F*/
   /* Bit 59   CJK Unified Ideographs             */
   /*          CJK Radicals Supplement            */
   /*          Kangxi Radicals                    */
@@ -1030,7 +1030,7 @@ FT_BEGIN_HEADER
   /*          CJK Unified Ideographs Extension A */
   /*          CJK Unified Ideographs Extension B */
   /*          Kanbun                             */
-#define TT_UCR_CJK_UNIFIED_IDEOGRAPHS          (1L << 27) /* U+4E00-U+9FFF */
+#define TT_UCR_CJK_UNIFIED_IDEOGRAPHS         (1UL << 27) /* U+4E00-U+9FFF */
                                                           /* U+2E80-U+2EFF */
                                                           /* U+2F00-U+2FDF */
                                                           /* U+2FF0-U+2FFF */
@@ -1038,178 +1038,178 @@ FT_BEGIN_HEADER
                                                           /*U+20000-U+2A6DF*/
                                                           /* U+3190-U+319F */
   /* Bit 60   Private Use */
-#define TT_UCR_PRIVATE_USE                     (1L << 28) /* U+E000-U+F8FF */
+#define TT_UCR_PRIVATE_USE                    (1UL << 28) /* U+E000-U+F8FF */
   /* Bit 61   CJK Strokes                             */
   /*          CJK Compatibility Ideographs            */
   /*          CJK Compatibility Ideographs Supplement */
-#define TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS    (1L << 29) /* U+31C0-U+31EF */
+#define TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS   (1UL << 29) /* U+31C0-U+31EF */
                                                           /* U+F900-U+FAFF */
                                                           /*U+2F800-U+2FA1F*/
   /* Bit 62   Alphabetic Presentation Forms */
-#define TT_UCR_ALPHABETIC_PRESENTATION_FORMS   (1L << 30) /* U+FB00-U+FB4F */
+#define TT_UCR_ALPHABETIC_PRESENTATION_FORMS  (1UL << 30) /* U+FB00-U+FB4F */
   /* Bit 63   Arabic Presentation Forms-A */
-#define TT_UCR_ARABIC_PRESENTATION_FORMS_A     (1L << 31) /* U+FB50-U+FDFF */
+#define TT_UCR_ARABIC_PRESENTATION_FORMS_A    (1UL << 31) /* U+FB50-U+FDFF */
 
   /* ulUnicodeRange3 */
   /* --------------- */
 
   /* Bit 64   Combining Half Marks */
-#define TT_UCR_COMBINING_HALF_MARKS            (1L <<  0) /* U+FE20-U+FE2F */
+#define TT_UCR_COMBINING_HALF_MARKS           (1UL <<  0) /* U+FE20-U+FE2F */
   /* Bit 65   Vertical forms          */
   /*          CJK Compatibility Forms */
-#define TT_UCR_CJK_COMPATIBILITY_FORMS         (1L <<  1) /* U+FE10-U+FE1F */
+#define TT_UCR_CJK_COMPATIBILITY_FORMS        (1UL <<  1) /* U+FE10-U+FE1F */
                                                           /* U+FE30-U+FE4F */
   /* Bit 66   Small Form Variants */
-#define TT_UCR_SMALL_FORM_VARIANTS             (1L <<  2) /* U+FE50-U+FE6F */
+#define TT_UCR_SMALL_FORM_VARIANTS            (1UL <<  2) /* U+FE50-U+FE6F */
   /* Bit 67   Arabic Presentation Forms-B */
-#define TT_UCR_ARABIC_PRESENTATION_FORMS_B     (1L <<  3) /* U+FE70-U+FEFE */
+#define TT_UCR_ARABIC_PRESENTATION_FORMS_B    (1UL <<  3) /* U+FE70-U+FEFF */
   /* Bit 68   Halfwidth and Fullwidth Forms */
-#define TT_UCR_HALFWIDTH_FULLWIDTH_FORMS       (1L <<  4) /* U+FF00-U+FFEF */
+#define TT_UCR_HALFWIDTH_FULLWIDTH_FORMS      (1UL <<  4) /* U+FF00-U+FFEF */
   /* Bit 69   Specials */
-#define TT_UCR_SPECIALS                        (1L <<  5) /* U+FFF0-U+FFFD */
+#define TT_UCR_SPECIALS                       (1UL <<  5) /* U+FFF0-U+FFFF */
   /* Bit 70   Tibetan */
-#define TT_UCR_TIBETAN                         (1L <<  6) /* U+0F00-U+0FFF */
+#define TT_UCR_TIBETAN                        (1UL <<  6) /* U+0F00-U+0FFF */
   /* Bit 71   Syriac */
-#define TT_UCR_SYRIAC                          (1L <<  7) /* U+0700-U+074F */
+#define TT_UCR_SYRIAC                         (1UL <<  7) /* U+0700-U+074F */
   /* Bit 72   Thaana */
-#define TT_UCR_THAANA                          (1L <<  8) /* U+0780-U+07BF */
+#define TT_UCR_THAANA                         (1UL <<  8) /* U+0780-U+07BF */
   /* Bit 73   Sinhala */
-#define TT_UCR_SINHALA                         (1L <<  9) /* U+0D80-U+0DFF */
+#define TT_UCR_SINHALA                        (1UL <<  9) /* U+0D80-U+0DFF */
   /* Bit 74   Myanmar */
-#define TT_UCR_MYANMAR                         (1L << 10) /* U+1000-U+109F */
+#define TT_UCR_MYANMAR                        (1UL << 10) /* U+1000-U+109F */
   /* Bit 75   Ethiopic            */
   /*          Ethiopic Supplement */
   /*          Ethiopic Extended   */
-#define TT_UCR_ETHIOPIC                        (1L << 11) /* U+1200-U+137F */
+#define TT_UCR_ETHIOPIC                       (1UL << 11) /* U+1200-U+137F */
                                                           /* U+1380-U+139F */
                                                           /* U+2D80-U+2DDF */
   /* Bit 76   Cherokee */
-#define TT_UCR_CHEROKEE                        (1L << 12) /* U+13A0-U+13FF */
+#define TT_UCR_CHEROKEE                       (1UL << 12) /* U+13A0-U+13FF */
   /* Bit 77   Unified Canadian Aboriginal Syllabics */
-#define TT_UCR_CANADIAN_ABORIGINAL_SYLLABICS   (1L << 13) /* U+1400-U+167F */
+#define TT_UCR_CANADIAN_ABORIGINAL_SYLLABICS  (1UL << 13) /* U+1400-U+167F */
   /* Bit 78   Ogham */
-#define TT_UCR_OGHAM                           (1L << 14) /* U+1680-U+169F */
+#define TT_UCR_OGHAM                          (1UL << 14) /* U+1680-U+169F */
   /* Bit 79   Runic */
-#define TT_UCR_RUNIC                           (1L << 15) /* U+16A0-U+16FF */
+#define TT_UCR_RUNIC                          (1UL << 15) /* U+16A0-U+16FF */
   /* Bit 80   Khmer         */
   /*          Khmer Symbols */
-#define TT_UCR_KHMER                           (1L << 16) /* U+1780-U+17FF */
+#define TT_UCR_KHMER                          (1UL << 16) /* U+1780-U+17FF */
                                                           /* U+19E0-U+19FF */
   /* Bit 81   Mongolian */
-#define TT_UCR_MONGOLIAN                       (1L << 17) /* U+1800-U+18AF */
+#define TT_UCR_MONGOLIAN                      (1UL << 17) /* U+1800-U+18AF */
   /* Bit 82   Braille Patterns */
-#define TT_UCR_BRAILLE                         (1L << 18) /* U+2800-U+28FF */
+#define TT_UCR_BRAILLE                        (1UL << 18) /* U+2800-U+28FF */
   /* Bit 83   Yi Syllables */
   /*          Yi Radicals  */
-#define TT_UCR_YI                              (1L << 19) /* U+A000-U+A48F */
+#define TT_UCR_YI                             (1UL << 19) /* U+A000-U+A48F */
                                                           /* U+A490-U+A4CF */
   /* Bit 84   Tagalog  */
   /*          Hanunoo  */
   /*          Buhid    */
   /*          Tagbanwa */
-#define TT_UCR_PHILIPPINE                      (1L << 20) /* U+1700-U+171F */
+#define TT_UCR_PHILIPPINE                     (1UL << 20) /* U+1700-U+171F */
                                                           /* U+1720-U+173F */
                                                           /* U+1740-U+175F */
                                                           /* U+1760-U+177F */
   /* Bit 85   Old Italic */
-#define TT_UCR_OLD_ITALIC                      (1L << 21) /*U+10300-U+1032F*/
+#define TT_UCR_OLD_ITALIC                     (1UL << 21) /*U+10300-U+1032F*/
   /* Bit 86   Gothic */
-#define TT_UCR_GOTHIC                          (1L << 22) /*U+10330-U+1034F*/
+#define TT_UCR_GOTHIC                         (1UL << 22) /*U+10330-U+1034F*/
   /* Bit 87   Deseret */
-#define TT_UCR_DESERET                         (1L << 23) /*U+10400-U+1044F*/
+#define TT_UCR_DESERET                        (1UL << 23) /*U+10400-U+1044F*/
   /* Bit 88   Byzantine Musical Symbols      */
   /*          Musical Symbols                */
   /*          Ancient Greek Musical Notation */
-#define TT_UCR_MUSICAL_SYMBOLS                 (1L << 24) /*U+1D000-U+1D0FF*/
+#define TT_UCR_MUSICAL_SYMBOLS                (1UL << 24) /*U+1D000-U+1D0FF*/
                                                           /*U+1D100-U+1D1FF*/
                                                           /*U+1D200-U+1D24F*/
   /* Bit 89   Mathematical Alphanumeric Symbols */
-#define TT_UCR_MATH_ALPHANUMERIC_SYMBOLS       (1L << 25) /*U+1D400-U+1D7FF*/
+#define TT_UCR_MATH_ALPHANUMERIC_SYMBOLS      (1UL << 25) /*U+1D400-U+1D7FF*/
   /* Bit 90   Private Use (plane 15) */
   /*          Private Use (plane 16) */
-#define TT_UCR_PRIVATE_USE_SUPPLEMENTARY       (1L << 26) /*U+F0000-U+FFFFD*/
+#define TT_UCR_PRIVATE_USE_SUPPLEMENTARY      (1UL << 26) /*U+F0000-U+FFFFD*/
                                                         /*U+100000-U+10FFFD*/
   /* Bit 91   Variation Selectors            */
   /*          Variation Selectors Supplement */
-#define TT_UCR_VARIATION_SELECTORS             (1L << 27) /* U+FE00-U+FE0F */
+#define TT_UCR_VARIATION_SELECTORS            (1UL << 27) /* U+FE00-U+FE0F */
                                                           /*U+E0100-U+E01EF*/
   /* Bit 92   Tags */
-#define TT_UCR_TAGS                            (1L << 28) /*U+E0000-U+E007F*/
+#define TT_UCR_TAGS                           (1UL << 28) /*U+E0000-U+E007F*/
   /* Bit 93   Limbu */
-#define TT_UCR_LIMBU                           (1L << 29) /* U+1900-U+194F */
+#define TT_UCR_LIMBU                          (1UL << 29) /* U+1900-U+194F */
   /* Bit 94   Tai Le */
-#define TT_UCR_TAI_LE                          (1L << 30) /* U+1950-U+197F */
+#define TT_UCR_TAI_LE                         (1UL << 30) /* U+1950-U+197F */
   /* Bit 95   New Tai Lue */
-#define TT_UCR_NEW_TAI_LUE                     (1L << 31) /* U+1980-U+19DF */
+#define TT_UCR_NEW_TAI_LUE                    (1UL << 31) /* U+1980-U+19DF */
 
   /* ulUnicodeRange4 */
   /* --------------- */
 
   /* Bit 96   Buginese */
-#define TT_UCR_BUGINESE                        (1L <<  0) /* U+1A00-U+1A1F */
+#define TT_UCR_BUGINESE                       (1UL <<  0) /* U+1A00-U+1A1F */
   /* Bit 97   Glagolitic */
-#define TT_UCR_GLAGOLITIC                      (1L <<  1) /* U+2C00-U+2C5F */
+#define TT_UCR_GLAGOLITIC                     (1UL <<  1) /* U+2C00-U+2C5F */
   /* Bit 98   Tifinagh */
-#define TT_UCR_TIFINAGH                        (1L <<  2) /* U+2D30-U+2D7F */
+#define TT_UCR_TIFINAGH                       (1UL <<  2) /* U+2D30-U+2D7F */
   /* Bit 99   Yijing Hexagram Symbols */
-#define TT_UCR_YIJING                          (1L <<  3) /* U+4DC0-U+4DFF */
+#define TT_UCR_YIJING                         (1UL <<  3) /* U+4DC0-U+4DFF */
   /* Bit 100  Syloti Nagri */
-#define TT_UCR_SYLOTI_NAGRI                    (1L <<  4) /* U+A800-U+A82F */
+#define TT_UCR_SYLOTI_NAGRI                   (1UL <<  4) /* U+A800-U+A82F */
   /* Bit 101  Linear B Syllabary */
   /*          Linear B Ideograms */
   /*          Aegean Numbers     */
-#define TT_UCR_LINEAR_B                        (1L <<  5) /*U+10000-U+1007F*/
+#define TT_UCR_LINEAR_B                       (1UL <<  5) /*U+10000-U+1007F*/
                                                           /*U+10080-U+100FF*/
                                                           /*U+10100-U+1013F*/
   /* Bit 102  Ancient Greek Numbers */
-#define TT_UCR_ANCIENT_GREEK_NUMBERS           (1L <<  6) /*U+10140-U+1018F*/
+#define TT_UCR_ANCIENT_GREEK_NUMBERS          (1UL <<  6) /*U+10140-U+1018F*/
   /* Bit 103  Ugaritic */
-#define TT_UCR_UGARITIC                        (1L <<  7) /*U+10380-U+1039F*/
+#define TT_UCR_UGARITIC                       (1UL <<  7) /*U+10380-U+1039F*/
   /* Bit 104  Old Persian */
-#define TT_UCR_OLD_PERSIAN                     (1L <<  8) /*U+103A0-U+103DF*/
+#define TT_UCR_OLD_PERSIAN                    (1UL <<  8) /*U+103A0-U+103DF*/
   /* Bit 105  Shavian */
-#define TT_UCR_SHAVIAN                         (1L <<  9) /*U+10450-U+1047F*/
+#define TT_UCR_SHAVIAN                        (1UL <<  9) /*U+10450-U+1047F*/
   /* Bit 106  Osmanya */
-#define TT_UCR_OSMANYA                         (1L << 10) /*U+10480-U+104AF*/
+#define TT_UCR_OSMANYA                        (1UL << 10) /*U+10480-U+104AF*/
   /* Bit 107  Cypriot Syllabary */
-#define TT_UCR_CYPRIOT_SYLLABARY               (1L << 11) /*U+10800-U+1083F*/
+#define TT_UCR_CYPRIOT_SYLLABARY              (1UL << 11) /*U+10800-U+1083F*/
   /* Bit 108  Kharoshthi */
-#define TT_UCR_KHAROSHTHI                      (1L << 12) /*U+10A00-U+10A5F*/
+#define TT_UCR_KHAROSHTHI                     (1UL << 12) /*U+10A00-U+10A5F*/
   /* Bit 109  Tai Xuan Jing Symbols */
-#define TT_UCR_TAI_XUAN_JING                   (1L << 13) /*U+1D300-U+1D35F*/
+#define TT_UCR_TAI_XUAN_JING                  (1UL << 13) /*U+1D300-U+1D35F*/
   /* Bit 110  Cuneiform                         */
   /*          Cuneiform Numbers and Punctuation */
-#define TT_UCR_CUNEIFORM                       (1L << 14) /*U+12000-U+123FF*/
+#define TT_UCR_CUNEIFORM                      (1UL << 14) /*U+12000-U+123FF*/
                                                           /*U+12400-U+1247F*/
   /* Bit 111  Counting Rod Numerals */
-#define TT_UCR_COUNTING_ROD_NUMERALS           (1L << 15) /*U+1D360-U+1D37F*/
+#define TT_UCR_COUNTING_ROD_NUMERALS          (1UL << 15) /*U+1D360-U+1D37F*/
   /* Bit 112  Sundanese */
-#define TT_UCR_SUNDANESE                       (1L << 16) /* U+1B80-U+1BBF */
+#define TT_UCR_SUNDANESE                      (1UL << 16) /* U+1B80-U+1BBF */
   /* Bit 113  Lepcha */
-#define TT_UCR_LEPCHA                          (1L << 17) /* U+1C00-U+1C4F */
+#define TT_UCR_LEPCHA                         (1UL << 17) /* U+1C00-U+1C4F */
   /* Bit 114  Ol Chiki */
-#define TT_UCR_OL_CHIKI                        (1L << 18) /* U+1C50-U+1C7F */
+#define TT_UCR_OL_CHIKI                       (1UL << 18) /* U+1C50-U+1C7F */
   /* Bit 115  Saurashtra */
-#define TT_UCR_SAURASHTRA                      (1L << 19) /* U+A880-U+A8DF */
+#define TT_UCR_SAURASHTRA                     (1UL << 19) /* U+A880-U+A8DF */
   /* Bit 116  Kayah Li */
-#define TT_UCR_KAYAH_LI                        (1L << 20) /* U+A900-U+A92F */
+#define TT_UCR_KAYAH_LI                       (1UL << 20) /* U+A900-U+A92F */
   /* Bit 117  Rejang */
-#define TT_UCR_REJANG                          (1L << 21) /* U+A930-U+A95F */
+#define TT_UCR_REJANG                         (1UL << 21) /* U+A930-U+A95F */
   /* Bit 118  Cham */
-#define TT_UCR_CHAM                            (1L << 22) /* U+AA00-U+AA5F */
+#define TT_UCR_CHAM                           (1UL << 22) /* U+AA00-U+AA5F */
   /* Bit 119  Ancient Symbols */
-#define TT_UCR_ANCIENT_SYMBOLS                 (1L << 23) /*U+10190-U+101CF*/
+#define TT_UCR_ANCIENT_SYMBOLS                (1UL << 23) /*U+10190-U+101CF*/
   /* Bit 120  Phaistos Disc */
-#define TT_UCR_PHAISTOS_DISC                   (1L << 24) /*U+101D0-U+101FF*/
+#define TT_UCR_PHAISTOS_DISC                  (1UL << 24) /*U+101D0-U+101FF*/
   /* Bit 121  Carian */
   /*          Lycian */
   /*          Lydian */
-#define TT_UCR_OLD_ANATOLIAN                   (1L << 25) /*U+102A0-U+102DF*/
+#define TT_UCR_OLD_ANATOLIAN                  (1UL << 25) /*U+102A0-U+102DF*/
                                                           /*U+10280-U+1029F*/
                                                           /*U+10920-U+1093F*/
   /* Bit 122  Domino Tiles  */
   /*          Mahjong Tiles */
-#define TT_UCR_GAME_TILES                      (1L << 26) /*U+1F030-U+1F09F*/
+#define TT_UCR_GAME_TILES                     (1UL << 26) /*U+1F030-U+1F09F*/
                                                           /*U+1F000-U+1F02F*/
   /* Bit 123-127 Reserved for process-internal usage */
 
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/tttables.h b/src/java.desktop/share/native/libfreetype/include/freetype/tttables.h
index 2cf0ff1bc61..aa4336435d9 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/tttables.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/tttables.h
@@ -5,7 +5,7 @@
  *   Basic SFNT/TrueType tables definitions and interface
  *   (specification only).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -192,7 +192,7 @@ FT_BEGIN_HEADER
    *     A pointer into the 'hmtx' table.
    *
    * @note:
-   *   For an OpenType variation font, the values of the following fields can
+   *   For OpenType Font Variations, the values of the following fields can
    *   change after a call to @FT_Set_Var_Design_Coordinates (and friends) if
    *   the font contains an 'MVAR' table: `caret_Slope_Rise`,
    *   `caret_Slope_Run`, and `caret_Offset`.
@@ -310,7 +310,7 @@ FT_BEGIN_HEADER
    *     A pointer into the 'vmtx' table.
    *
    * @note:
-   *   For an OpenType variation font, the values of the following fields can
+   *   For OpenType Font Variations, the values of the following fields can
    *   change after a call to @FT_Set_Var_Design_Coordinates (and friends) if
    *   the font contains an 'MVAR' table: `Ascender`, `Descender`,
    *   `Line_Gap`, `caret_Slope_Rise`, `caret_Slope_Run`, and `caret_Offset`.
@@ -359,7 +359,7 @@ FT_BEGIN_HEADER
    *   table.  In this case, the `version` field is always set to 0xFFFF.
    *
    * @note:
-   *   For an OpenType variation font, the values of the following fields can
+   *   For OpenType Font Variations, the values of the following fields can
    *   change after a call to @FT_Set_Var_Design_Coordinates (and friends) if
    *   the font contains an 'MVAR' table: `sCapHeight`, `sTypoAscender`,
    *   `sTypoDescender`, `sTypoLineGap`, `sxHeight`, `usWinAscent`,
@@ -442,7 +442,7 @@ FT_BEGIN_HEADER
    *   them.
    *
    * @note:
-   *   For an OpenType variation font, the values of the following fields can
+   *   For OpenType Font Variations, the values of the following fields can
    *   change after a call to @FT_Set_Var_Design_Coordinates (and friends) if
    *   the font contains an 'MVAR' table: `underlinePosition` and
    *   `underlineThickness`.
@@ -705,6 +705,9 @@ FT_BEGIN_HEADER
    *     definitions found in the @FT_TRUETYPE_TAGS_H file, or forge a new
    *     one with @FT_MAKE_TAG.
    *
+   *     [Since 2.14] Use value~1 if you want to access the table directory
+   *     of the (currently selected) font.
+   *
    *   offset ::
    *     The starting offset in the table (or file if tag~==~0).
    *
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h b/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h
index da0af5d3f23..56bb0a3ee5e 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h
@@ -4,7 +4,7 @@
  *
  *   Tags for TrueType and OpenType tables (specification only).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/include/ft2build.h b/src/java.desktop/share/native/libfreetype/include/ft2build.h
index d3d7685039c..3008aea7cf5 100644
--- a/src/java.desktop/share/native/libfreetype/include/ft2build.h
+++ b/src/java.desktop/share/native/libfreetype/include/ft2build.h
@@ -4,7 +4,7 @@
  *
  *   FreeType 2 build and setup macros.
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afadjust.c b/src/java.desktop/share/native/libfreetype/src/autofit/afadjust.c
new file mode 100644
index 00000000000..a1aa45914d0
--- /dev/null
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afadjust.c
@@ -0,0 +1,1621 @@
+/****************************************************************************
+ *
+ * afadjust.c
+ *
+ *   Auto-fitter routines to adjust components based on charcode (body).
+ *
+ * Copyright (C) 2023-2025 by
+ * David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ * Written by Craig White .
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT.  By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+#include "afadjust.h"
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
+#  include "afgsub.h"
+#endif
+
+#include 
+#include 
+#include 
+#include 
+
+#define AF_ADJUSTMENT_DATABASE_LENGTH           \
+          ( sizeof ( adjustment_database ) /    \
+            sizeof ( adjustment_database[0] ) )
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  afadjust
+
+
+  typedef struct  AF_AdjustmentDatabaseEntry_
+  {
+    FT_UInt32  codepoint;
+    FT_UInt32  flags;
+
+  } AF_AdjustmentDatabaseEntry;
+
+
+  /*
+    All entries in this list must be sorted by ascending Unicode code
+    points.  The table entries are 3 numbers consisting of:
+
+    - Unicode code point.
+    - The vertical adjustment type.  This should be a combination of the
+      AF_ADJUST_XXX and AF_IGNORE_XXX macros.
+  */
+  static AF_AdjustmentDatabaseEntry  adjustment_database[] =
+  {
+    /* C0 Controls and Basic Latin */
+    { 0x21,  AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ! */
+    { 0x51,  AF_IGNORE_CAPITAL_BOTTOM } , /* Q */
+    { 0x3F,  AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ? */
+    { 0x69,  AF_ADJUST_UP }, /* i */
+    { 0x6A,  AF_ADJUST_UP }, /* j */
+#if 0
+    /* XXX TODO */
+    { 0x7E,  AF_ADJUST_TILDE_TOP }, /* ~ */
+#endif
+
+    /* C1 Controls and Latin-1 Supplement */
+    { 0xA1,  AF_ADJUST_UP }, /* ¡ */
+    { 0xA6,  AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ¦ */
+    { 0xAA,  AF_ADJUST_UP }, /* ª */
+    { 0xBA,  AF_ADJUST_UP }, /* º */
+    { 0xBF,  AF_ADJUST_UP }, /* ¿ */
+
+    { 0xC0,  AF_ADJUST_UP }, /* À */
+    { 0xC1,  AF_ADJUST_UP }, /* Á */
+    { 0xC2,  AF_ADJUST_UP }, /* Â */
+    { 0xC3,  AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ã */
+    { 0xC4,  AF_ADJUST_UP }, /* Ä */
+    { 0xC5,  AF_ADJUST_UP }, /* Å */
+    { 0xC7,  AF_IGNORE_CAPITAL_BOTTOM }, /* Ç */
+    { 0xC8,  AF_ADJUST_UP }, /* È */
+    { 0xC9,  AF_ADJUST_UP }, /* É */
+    { 0xCA,  AF_ADJUST_UP }, /* Ê */
+    { 0xCB,  AF_ADJUST_UP }, /* Ë */
+    { 0xCC,  AF_ADJUST_UP }, /* Ì */
+    { 0xCD,  AF_ADJUST_UP }, /* Í */
+    { 0xCE,  AF_ADJUST_UP }, /* Î */
+    { 0xCF,  AF_ADJUST_UP }, /* Ï */
+
+    { 0xD1,  AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ñ */
+    { 0xD2,  AF_ADJUST_UP }, /* Ò */
+    { 0xD3,  AF_ADJUST_UP }, /* Ó */
+    { 0xD4,  AF_ADJUST_UP }, /* Ô */
+    { 0xD5,  AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Õ */
+    { 0xD6,  AF_ADJUST_UP }, /* Ö */
+    { 0xD8,  AF_IGNORE_CAPITAL_TOP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ø */
+    { 0xD9,  AF_ADJUST_UP }, /* Ù */
+    { 0xDA,  AF_ADJUST_UP }, /* Ú */
+    { 0xDB,  AF_ADJUST_UP }, /* Û */
+    { 0xDC,  AF_ADJUST_UP }, /* Ü */
+    { 0xDD,  AF_ADJUST_UP }, /* Ý */
+
+    { 0xE0,  AF_ADJUST_UP }, /* à */
+    { 0xE1,  AF_ADJUST_UP }, /* á */
+    { 0xE2,  AF_ADJUST_UP }, /* â */
+    { 0xE3,  AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ã */
+    { 0xE4,  AF_ADJUST_UP }, /* ä */
+    { 0xE5,  AF_ADJUST_UP }, /* å */
+    { 0xE7,  AF_IGNORE_SMALL_BOTTOM }, /* ç */
+    { 0xE8,  AF_ADJUST_UP }, /* è */
+    { 0xE9,  AF_ADJUST_UP }, /* é */
+    { 0xEA,  AF_ADJUST_UP }, /* ê */
+    { 0xEB,  AF_ADJUST_UP }, /* ë */
+    { 0xEC,  AF_ADJUST_UP }, /* ì */
+    { 0xED,  AF_ADJUST_UP }, /* í */
+    { 0xEE,  AF_ADJUST_UP }, /* î */
+    { 0xEF,  AF_ADJUST_UP }, /* ï */
+
+    { 0xF1,  AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ñ */
+    { 0xF2,  AF_ADJUST_UP }, /* ò */
+    { 0xF3,  AF_ADJUST_UP }, /* ó */
+    { 0xF4,  AF_ADJUST_UP }, /* ô */
+    { 0xF5,  AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* õ */
+    { 0xF6,  AF_ADJUST_UP }, /* ö */
+    { 0xF8,  AF_IGNORE_SMALL_TOP | AF_IGNORE_SMALL_BOTTOM }, /* ø */
+    { 0xF9,  AF_ADJUST_UP }, /* ù */
+    { 0xFA,  AF_ADJUST_UP }, /* ú */
+    { 0xFB,  AF_ADJUST_UP }, /* û */
+    { 0xFC,  AF_ADJUST_UP }, /* ü */
+    { 0xFD,  AF_ADJUST_UP }, /* ý */
+    { 0xFF,  AF_ADJUST_UP }, /* ÿ */
+
+    /* Latin Extended-A */
+    { 0x100, AF_ADJUST_UP }, /* Ā */
+    { 0x101, AF_ADJUST_UP }, /* ā */
+    { 0x102, AF_ADJUST_UP }, /* Ă */
+    { 0x103, AF_ADJUST_UP }, /* ă */
+    { 0x104, AF_IGNORE_CAPITAL_BOTTOM }, /* Ą */
+    { 0x105, AF_IGNORE_SMALL_BOTTOM }, /* ą */
+    { 0x106, AF_ADJUST_UP }, /* Ć */
+    { 0x107, AF_ADJUST_UP }, /* ć */
+    { 0x108, AF_ADJUST_UP }, /* Ĉ */
+    { 0x109, AF_ADJUST_UP }, /* ĉ */
+    { 0x10A, AF_ADJUST_UP }, /* Ċ */
+    { 0x10B, AF_ADJUST_UP }, /* ċ */
+    { 0x10C, AF_ADJUST_UP }, /* Č */
+    { 0x10D, AF_ADJUST_UP }, /* č */
+    { 0x10E, AF_ADJUST_UP }, /* Ď */
+
+    { 0x112, AF_ADJUST_UP }, /* Ē */
+    { 0x113, AF_ADJUST_UP }, /* ē */
+    { 0x114, AF_ADJUST_UP }, /* Ĕ */
+    { 0x115, AF_ADJUST_UP }, /* ĕ */
+    { 0x116, AF_ADJUST_UP }, /* Ė */
+    { 0x117, AF_ADJUST_UP }, /* ė */
+    { 0x118, AF_IGNORE_CAPITAL_BOTTOM }, /* Ę */
+    { 0x119, AF_IGNORE_SMALL_BOTTOM }, /* ę */
+    { 0x11A, AF_ADJUST_UP }, /* Ě */
+    { 0x11B, AF_ADJUST_UP }, /* ě */
+    { 0x11C, AF_ADJUST_UP }, /* Ĝ */
+    { 0x11D, AF_ADJUST_UP }, /* ĝ */
+    { 0x11E, AF_ADJUST_UP }, /* Ğ */
+    { 0x11F, AF_ADJUST_UP }, /* ğ */
+
+    { 0x120, AF_ADJUST_UP }, /* Ġ */
+    { 0x121, AF_ADJUST_UP }, /* ġ */
+    { 0x122, AF_ADJUST_DOWN }, /* Ģ */
+    { 0x123, AF_ADJUST_UP }, /* ģ */
+    { 0x124, AF_ADJUST_UP }, /* Ĥ */
+    { 0x125, AF_ADJUST_UP }, /* ĥ */
+    { 0x128, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ĩ */
+    { 0x129, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ĩ */
+    { 0x12A, AF_ADJUST_UP }, /* Ī */
+    { 0x12B, AF_ADJUST_UP }, /* ī */
+    { 0x12C, AF_ADJUST_UP }, /* Ĭ */
+    { 0x12D, AF_ADJUST_UP }, /* ĭ */
+    { 0x12E, AF_IGNORE_CAPITAL_BOTTOM }, /* Į */
+    { 0x12F, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* į */
+
+    { 0x130, AF_ADJUST_UP }, /* İ */
+    { 0x133, AF_ADJUST_UP }, /* ij */
+    { 0x134, AF_ADJUST_UP }, /* Ĵ */
+    { 0x135, AF_ADJUST_UP }, /* ĵ */
+    { 0x136, AF_ADJUST_DOWN }, /* Ķ */
+    { 0x137, AF_ADJUST_DOWN }, /* ķ */
+    { 0x139, AF_ADJUST_UP }, /* Ĺ */
+    { 0x13A, AF_ADJUST_UP }, /* ĺ */
+    { 0x13B, AF_ADJUST_DOWN }, /* Ļ */
+    { 0x13C, AF_ADJUST_DOWN }, /* ļ */
+
+    { 0x143, AF_ADJUST_UP }, /* Ń */
+    { 0x144, AF_ADJUST_UP }, /* ń */
+    { 0x145, AF_ADJUST_DOWN }, /* Ņ */
+    { 0x146, AF_ADJUST_DOWN }, /* ņ */
+    { 0x147, AF_ADJUST_UP }, /* Ň */
+    { 0x148, AF_ADJUST_UP }, /* ň */
+    { 0x14C, AF_ADJUST_UP }, /* Ō */
+    { 0x14D, AF_ADJUST_UP }, /* ō */
+    { 0x14E, AF_ADJUST_UP }, /* Ŏ */
+    { 0x14F, AF_ADJUST_UP }, /* ŏ */
+
+    { 0x150, AF_ADJUST_UP }, /* Ő */
+    { 0x151, AF_ADJUST_UP }, /* ő */
+    { 0x154, AF_ADJUST_UP }, /* Ŕ */
+    { 0x155, AF_ADJUST_UP }, /* ŕ */
+    { 0x156, AF_ADJUST_DOWN }, /* Ŗ */
+    { 0x157, AF_ADJUST_DOWN }, /* ŗ */
+    { 0x158, AF_ADJUST_UP }, /* Ř */
+    { 0x159, AF_ADJUST_UP }, /* ř */
+    { 0x15A, AF_ADJUST_UP }, /* Ś */
+    { 0x15B, AF_ADJUST_UP }, /* ś */
+    { 0x15C, AF_ADJUST_UP }, /* Ŝ */
+    { 0x15D, AF_ADJUST_UP }, /* ŝ */
+    { 0x15E, AF_IGNORE_CAPITAL_BOTTOM }, /* Ş */
+    { 0x15F, AF_IGNORE_SMALL_BOTTOM }, /* ş */
+
+    { 0x160, AF_ADJUST_UP }, /* Š */
+    { 0x161, AF_ADJUST_UP }, /* š */
+    { 0x162, AF_IGNORE_CAPITAL_BOTTOM }, /* Ţ */
+    { 0x163, AF_IGNORE_SMALL_BOTTOM }, /* ţ */
+    { 0x164, AF_ADJUST_UP }, /* Ť */
+    { 0x168, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ũ */
+    { 0x169, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ũ */
+    { 0x16A, AF_ADJUST_UP }, /* Ū */
+    { 0x16B, AF_ADJUST_UP }, /* ū */
+    { 0x16C, AF_ADJUST_UP }, /* Ŭ */
+    { 0x16D, AF_ADJUST_UP }, /* ŭ */
+    { 0x16E, AF_ADJUST_UP }, /* Ů */
+    { 0x16F, AF_ADJUST_UP }, /* ů */
+
+    { 0x170, AF_ADJUST_UP }, /* Ű */
+    { 0x171, AF_ADJUST_UP }, /* ű */
+    { 0x172, AF_IGNORE_CAPITAL_BOTTOM }, /* Ų */
+    { 0x173, AF_IGNORE_SMALL_BOTTOM }, /* ų */
+    { 0x174, AF_ADJUST_UP }, /* Ŵ */
+    { 0x175, AF_ADJUST_UP }, /* ŵ */
+    { 0x176, AF_ADJUST_UP }, /* Ŷ */
+    { 0x177, AF_ADJUST_UP }, /* ŷ */
+    { 0x178, AF_ADJUST_UP }, /* Ÿ */
+    { 0x179, AF_ADJUST_UP }, /* Ź */
+    { 0x17A, AF_ADJUST_UP }, /* ź */
+    { 0x17B, AF_ADJUST_UP }, /* Ż */
+    { 0x17C, AF_ADJUST_UP }, /* ż */
+    { 0x17D, AF_ADJUST_UP }, /* Ž */
+    { 0x17E, AF_ADJUST_UP }, /* ž */
+
+    /* Latin Extended-B */
+    { 0x187, AF_IGNORE_CAPITAL_TOP }, /* Ƈ */
+    { 0x188, AF_IGNORE_SMALL_TOP }, /* ƈ */
+
+    { 0x1A0, AF_IGNORE_CAPITAL_TOP }, /* Ơ */
+    { 0x1A1, AF_IGNORE_SMALL_TOP }, /* ơ */
+    { 0x1A5, AF_IGNORE_SMALL_TOP }, /* ƥ */
+    { 0x1AB, AF_IGNORE_SMALL_BOTTOM }, /* ƫ */
+    { 0x1AE, AF_IGNORE_CAPITAL_BOTTOM }, /* Ʈ */
+    { 0x1AF, AF_IGNORE_CAPITAL_TOP }, /* Ư */
+
+    { 0x1B0, AF_IGNORE_SMALL_TOP }, /* ư */
+    { 0x1B4, AF_IGNORE_SMALL_TOP }, /* ƴ */
+
+    { 0x1C3, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ǃ */
+    { 0x1C4, AF_ADJUST_UP }, /* DŽ */
+#if 0
+    { 0x1C5, AF_ADJUST_UP }, /* Dž */
+    { 0x1C6, AF_ADJUST_UP }, /* dž */
+    { 0x1C8, AF_ADJUST_UP }, /* Lj */
+    { 0x1C9, AF_ADJUST_UP }, /* lj */
+    { 0x1CB, AF_ADJUST_UP }, /* Nj */
+#endif
+    { 0x1CC, AF_ADJUST_UP }, /* nj */
+    { 0x1CD, AF_ADJUST_UP }, /* Ǎ */
+    { 0x1CE, AF_ADJUST_UP }, /* ǎ */
+    { 0x1CF, AF_ADJUST_UP }, /* Ǐ */
+
+    { 0x1D0, AF_ADJUST_UP }, /* ǐ */
+    { 0x1D1, AF_ADJUST_UP }, /* Ǒ */
+    { 0x1D2, AF_ADJUST_UP }, /* ǒ */
+    { 0x1D3, AF_ADJUST_UP }, /* Ǔ */
+    { 0x1D4, AF_ADJUST_UP }, /* ǔ */
+    { 0x1D5, AF_ADJUST_UP2 }, /* Ǖ */
+    { 0x1D6, AF_ADJUST_UP2 }, /* ǖ */
+    { 0x1D7, AF_ADJUST_UP2 }, /* Ǘ */
+    { 0x1D8, AF_ADJUST_UP2 }, /* ǘ */
+    { 0x1D9, AF_ADJUST_UP2 }, /* Ǚ */
+    { 0x1DA, AF_ADJUST_UP2 }, /* ǚ */
+    { 0x1DB, AF_ADJUST_UP2 }, /* Ǜ */
+    { 0x1DC, AF_ADJUST_UP2 }, /* ǜ */
+    { 0x1DE, AF_ADJUST_UP2 }, /* Ǟ */
+    { 0x1DF, AF_ADJUST_UP2 }, /* ǟ */
+
+    { 0x1E0, AF_ADJUST_UP2 }, /* Ǡ */
+    { 0x1E1, AF_ADJUST_UP2 }, /* ǡ */
+    { 0x1E2, AF_ADJUST_UP }, /* Ǣ */
+    { 0x1E3, AF_ADJUST_UP }, /* ǣ */
+    { 0x1E6, AF_ADJUST_UP }, /* Ǧ */
+    { 0x1E7, AF_ADJUST_UP }, /* ǧ */
+    { 0x1E8, AF_ADJUST_UP }, /* Ǩ */
+    { 0x1E9, AF_ADJUST_UP }, /* ǩ */
+    { 0x1EA, AF_IGNORE_CAPITAL_BOTTOM }, /* Ǫ */
+    { 0x1EB, AF_IGNORE_SMALL_BOTTOM }, /* ǫ */
+    { 0x1EC, AF_ADJUST_UP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ǭ */
+    { 0x1ED, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* ǭ */
+    { 0x1EE, AF_ADJUST_UP }, /* Ǯ */
+    { 0x1EF, AF_ADJUST_UP }, /* ǯ */
+
+    { 0x1F0, AF_ADJUST_UP }, /* ǰ */
+    { 0x1F4, AF_ADJUST_UP }, /* Ǵ */
+    { 0x1F5, AF_ADJUST_UP }, /* ǵ */
+    { 0x1F8, AF_ADJUST_UP }, /* Ǹ */
+    { 0x1F9, AF_ADJUST_UP }, /* ǹ */
+    { 0x1FA, AF_ADJUST_UP2 }, /* Ǻ */
+    { 0x1FB, AF_ADJUST_UP2 }, /* ǻ */
+    { 0x1FC, AF_ADJUST_UP }, /* Ǽ */
+    { 0x1FD, AF_ADJUST_UP }, /* ǽ */
+    { 0x1FE, AF_ADJUST_UP }, /* Ǿ */
+    { 0x1FF, AF_ADJUST_UP }, /* ǿ */
+
+    { 0x200, AF_ADJUST_UP }, /* Ȁ */
+    { 0x201, AF_ADJUST_UP }, /* ȁ */
+    { 0x202, AF_ADJUST_UP }, /* Ȃ */
+    { 0x203, AF_ADJUST_UP }, /* ȃ */
+    { 0x204, AF_ADJUST_UP }, /* Ȅ */
+    { 0x205, AF_ADJUST_UP }, /* ȅ */
+    { 0x206, AF_ADJUST_UP }, /* Ȇ */
+    { 0x207, AF_ADJUST_UP }, /* ȇ */
+    { 0x208, AF_ADJUST_UP }, /* Ȉ */
+    { 0x209, AF_ADJUST_UP }, /* ȉ */
+    { 0x20A, AF_ADJUST_UP }, /* Ȋ */
+    { 0x20B, AF_ADJUST_UP }, /* ȋ */
+    { 0x20C, AF_ADJUST_UP }, /* Ȍ */
+    { 0x20D, AF_ADJUST_UP }, /* ȍ */
+    { 0x20E, AF_ADJUST_UP }, /* Ȏ */
+    { 0x20F, AF_ADJUST_UP }, /* ȏ */
+
+    { 0x210, AF_ADJUST_UP }, /* Ȑ */
+    { 0x211, AF_ADJUST_UP }, /* ȑ */
+    { 0x212, AF_ADJUST_UP }, /* Ȓ */
+    { 0x213, AF_ADJUST_UP }, /* ȓ */
+    { 0x214, AF_ADJUST_UP }, /* Ȕ */
+    { 0x215, AF_ADJUST_UP }, /* ȕ */
+    { 0x216, AF_ADJUST_UP }, /* Ȗ */
+    { 0x217, AF_ADJUST_UP }, /* ȗ */
+    { 0x218, AF_ADJUST_DOWN }, /* Ș */
+    { 0x219, AF_ADJUST_DOWN }, /* ș */
+    { 0x21A, AF_ADJUST_DOWN }, /* Ț */
+    { 0x21B, AF_ADJUST_DOWN }, /* ț */
+    { 0x21E, AF_ADJUST_UP }, /* Ȟ */
+    { 0x21F, AF_ADJUST_UP }, /* ȟ */
+
+    { 0x224, AF_IGNORE_CAPITAL_BOTTOM }, /* Ȥ */
+    { 0x225, AF_IGNORE_SMALL_BOTTOM }, /* ȥ */
+    { 0x226, AF_ADJUST_UP }, /* Ȧ */
+    { 0x227, AF_ADJUST_UP }, /* ȧ */
+    { 0x228, AF_IGNORE_CAPITAL_BOTTOM }, /* Ȩ */
+    { 0x229, AF_IGNORE_SMALL_BOTTOM }, /* ȩ */
+    { 0x22A, AF_ADJUST_UP2 }, /* Ȫ */
+    { 0x22B, AF_ADJUST_UP2 }, /* ȫ */
+    { 0x22C, AF_ADJUST_UP2 }, /* Ȭ */
+    { 0x22D, AF_ADJUST_UP2 }, /* ȭ */
+    { 0x22E, AF_ADJUST_UP }, /* Ȯ */
+    { 0x22F, AF_ADJUST_UP }, /* ȯ */
+
+    { 0x230, AF_ADJUST_UP2 }, /* Ȱ */
+    { 0x231, AF_ADJUST_UP2 }, /* ȱ */
+    { 0x232, AF_ADJUST_UP }, /* Ȳ */
+    { 0x233, AF_ADJUST_UP }, /* ȳ */
+    { 0x23A, AF_IGNORE_CAPITAL_TOP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ⱥ */
+    { 0x23B, AF_IGNORE_CAPITAL_TOP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ȼ */
+    { 0x23F, AF_IGNORE_SMALL_BOTTOM }, /* ȿ */
+
+    { 0x240, AF_IGNORE_SMALL_BOTTOM }, /* ɀ */
+    { 0x249, AF_ADJUST_UP }, /* ɉ */
+
+    /* IPA Extensions */
+    { 0x256, AF_IGNORE_SMALL_BOTTOM }, /* ɖ */
+
+    { 0x260, AF_IGNORE_SMALL_TOP }, /* ɠ */
+    { 0x267, AF_IGNORE_SMALL_BOTTOM }, /* ɧ */
+    { 0x268, AF_ADJUST_UP }, /* ɨ */
+
+    { 0x272, AF_IGNORE_SMALL_BOTTOM }, /* ɲ */
+    { 0x273, AF_IGNORE_SMALL_BOTTOM }, /* ɳ */
+    { 0x27B, AF_IGNORE_SMALL_BOTTOM }, /* ɻ */
+    { 0x27D, AF_IGNORE_SMALL_BOTTOM }, /* ɽ */
+
+    { 0x282, AF_IGNORE_SMALL_BOTTOM }, /* ʂ */
+    { 0x288, AF_IGNORE_SMALL_BOTTOM }, /* ʈ */
+
+    { 0x290, AF_IGNORE_SMALL_BOTTOM }, /* ʐ */
+    { 0x29B, AF_IGNORE_SMALL_TOP }, /* ʛ */
+
+    { 0x2A0, AF_IGNORE_SMALL_TOP }, /* ʠ */
+
+    /* Spacing Modifier Letters */
+    { 0x2B2, AF_ADJUST_UP }, /* ʲ */
+    { 0x2B5, AF_IGNORE_SMALL_BOTTOM }, /* ʵ */
+
+    /* Greek and Coptic */
+    { 0x390, AF_ADJUST_UP2 }, /* ΐ */
+
+    { 0x3AA, AF_ADJUST_UP }, /* Ϊ */
+    { 0x3AB, AF_ADJUST_UP }, /* Ϋ */
+    { 0x3AC, AF_ADJUST_UP }, /* ά */
+    { 0x3AD, AF_ADJUST_UP }, /* έ */
+    { 0x3AE, AF_ADJUST_UP }, /* ή */
+    { 0x3AF, AF_ADJUST_UP }, /* ί */
+
+    { 0x3B0, AF_ADJUST_UP2 }, /* ΰ */
+
+    { 0x3CA, AF_ADJUST_UP }, /* ϊ */
+    { 0x3CB, AF_ADJUST_UP }, /* ϋ */
+    { 0x3CC, AF_ADJUST_UP }, /* ό */
+    { 0x3CD, AF_ADJUST_UP }, /* ύ */
+    { 0x3CE, AF_ADJUST_UP }, /* ώ */
+    { 0x3CF, AF_IGNORE_CAPITAL_BOTTOM }, /* Ϗ */
+
+    { 0x3D4, AF_ADJUST_UP }, /* ϔ */
+    { 0x3D7, AF_IGNORE_SMALL_BOTTOM }, /* ϗ */
+    { 0x3D9, AF_IGNORE_SMALL_BOTTOM }, /* ϙ */
+
+    { 0x3E2, AF_IGNORE_CAPITAL_BOTTOM }, /* Ϣ */
+    { 0x3E3, AF_IGNORE_SMALL_BOTTOM }, /* ϣ */
+
+    { 0x3F3, AF_ADJUST_UP }, /* ϳ */
+
+    /* Cyrillic */
+    { 0x400, AF_ADJUST_UP }, /* Ѐ */
+    { 0x401, AF_ADJUST_UP }, /* Ё */
+    { 0x403, AF_ADJUST_UP }, /* Ѓ */
+    { 0x407, AF_ADJUST_UP }, /* Ї */
+    { 0x40C, AF_ADJUST_UP }, /* Ќ */
+    { 0x40D, AF_ADJUST_UP }, /* Ѝ */
+    { 0x40E, AF_ADJUST_UP }, /* Ў */
+    { 0x40F, AF_IGNORE_CAPITAL_BOTTOM }, /* Џ */
+
+    { 0x419, AF_ADJUST_UP }, /* Й */
+
+    { 0x426, AF_IGNORE_CAPITAL_BOTTOM }, /* Ц */
+    { 0x429, AF_IGNORE_CAPITAL_BOTTOM }, /* Щ */
+
+    { 0x439, AF_ADJUST_UP }, /* й */
+
+    { 0x446, AF_IGNORE_SMALL_BOTTOM }, /* ц */
+    { 0x449, AF_IGNORE_SMALL_BOTTOM }, /* щ */
+
+    { 0x450, AF_ADJUST_UP }, /* ѐ */
+    { 0x451, AF_ADJUST_UP }, /* ё */
+    { 0x453, AF_ADJUST_UP }, /* ѓ */
+    { 0x456, AF_ADJUST_UP }, /* і */
+    { 0x457, AF_ADJUST_UP }, /* ї */
+    { 0x458, AF_ADJUST_UP }, /* ј */
+    { 0x45C, AF_ADJUST_UP }, /* ќ */
+    { 0x45D, AF_ADJUST_UP }, /* ѝ */
+    { 0x45E, AF_ADJUST_UP }, /* ў */
+    { 0x45F, AF_IGNORE_SMALL_BOTTOM }, /* џ */
+
+    { 0x476, AF_ADJUST_UP }, /* Ѷ */
+    { 0x477, AF_ADJUST_UP }, /* ѷ */
+    { 0x47C, AF_ADJUST_UP2 }, /* Ѽ */
+    { 0x47D, AF_ADJUST_UP2 }, /* ѽ */
+    { 0x47E, AF_ADJUST_UP }, /* Ѿ */
+    { 0x47F, AF_ADJUST_UP }, /* ѿ */
+
+    { 0x480, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҁ */
+    { 0x481, AF_IGNORE_SMALL_BOTTOM }, /* ҁ */
+    { 0x48A, AF_ADJUST_UP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ҋ */
+    { 0x48B, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* ҋ */
+
+    { 0x490, AF_IGNORE_CAPITAL_TOP }, /* Ґ */
+    { 0x491, AF_IGNORE_SMALL_TOP }, /* ґ */
+    { 0x496, AF_IGNORE_CAPITAL_BOTTOM }, /* Җ */
+    { 0x497, AF_IGNORE_SMALL_BOTTOM }, /* җ */
+    { 0x498, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҙ */
+    { 0x499, AF_IGNORE_SMALL_BOTTOM }, /* ҙ */
+    { 0x49A, AF_IGNORE_CAPITAL_BOTTOM }, /* Қ */
+    { 0x49B, AF_IGNORE_SMALL_BOTTOM }, /* қ */
+
+    { 0x4A2, AF_IGNORE_CAPITAL_BOTTOM }, /* Ң */
+    { 0x4A3, AF_IGNORE_SMALL_BOTTOM }, /* ң */
+    { 0x4AA, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҫ */
+    { 0x4AB, AF_IGNORE_SMALL_BOTTOM }, /* ҫ */
+    { 0x4AC, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҭ */
+    { 0x4AD, AF_IGNORE_SMALL_BOTTOM }, /* ҭ */
+
+    { 0x4B2, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҳ */
+    { 0x4B3, AF_IGNORE_SMALL_BOTTOM }, /* ҳ */
+    { 0x4B4, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҵ */
+    { 0x4B5, AF_IGNORE_SMALL_BOTTOM }, /* ҵ */
+    { 0x4B6, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҷ */
+    { 0x4B7, AF_IGNORE_SMALL_BOTTOM }, /* ҷ */
+    { 0x4BE, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҿ */
+    { 0x4BF, AF_IGNORE_SMALL_BOTTOM }, /* ҿ */
+
+    { 0x4C1, AF_ADJUST_UP }, /* Ӂ */
+    { 0x4C2, AF_ADJUST_UP }, /* ӂ */
+    { 0x4C5, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӆ */
+    { 0x4C6, AF_IGNORE_SMALL_BOTTOM }, /* ӆ */
+    { 0x4C9, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӊ */
+    { 0x4CA, AF_IGNORE_SMALL_BOTTOM }, /* ӊ */
+    { 0x4CB, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӌ */
+    { 0x4CC, AF_IGNORE_SMALL_BOTTOM }, /* ӌ */
+    { 0x4CD, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӎ */
+    { 0x4CE, AF_IGNORE_SMALL_BOTTOM }, /* ӎ */
+
+    { 0x4D0, AF_ADJUST_UP }, /* Ӑ */
+    { 0x4D1, AF_ADJUST_UP }, /* ӑ */
+    { 0x4D2, AF_ADJUST_UP }, /* Ӓ */
+    { 0x4D3, AF_ADJUST_UP }, /* ӓ */
+    { 0x4D6, AF_ADJUST_UP }, /* Ӗ */
+    { 0x4D7, AF_ADJUST_UP }, /* ӗ */
+    { 0x4DA, AF_ADJUST_UP }, /* Ӛ */
+    { 0x4DB, AF_ADJUST_UP }, /* ӛ */
+    { 0x4DC, AF_ADJUST_UP }, /* Ӝ */
+    { 0x4DD, AF_ADJUST_UP }, /* ӝ */
+    { 0x4DE, AF_ADJUST_UP }, /* Ӟ */
+    { 0x4DF, AF_ADJUST_UP }, /* ӟ */
+
+    { 0x4E2, AF_ADJUST_UP }, /* Ӣ */
+    { 0x4E3, AF_ADJUST_UP }, /* ӣ */
+    { 0x4E4, AF_ADJUST_UP }, /* Ӥ */
+    { 0x4E5, AF_ADJUST_UP }, /* ӥ */
+    { 0x4E6, AF_ADJUST_UP }, /* Ӧ */
+    { 0x4E7, AF_ADJUST_UP }, /* ӧ */
+    { 0x4EA, AF_ADJUST_UP }, /* Ӫ */
+    { 0x4EB, AF_ADJUST_UP }, /* ӫ */
+    { 0x4EC, AF_ADJUST_UP }, /* Ӭ */
+    { 0x4ED, AF_ADJUST_UP }, /* ӭ */
+    { 0x4EE, AF_ADJUST_UP }, /* Ӯ */
+    { 0x4EF, AF_ADJUST_UP }, /* ӯ */
+
+    { 0x4F0, AF_ADJUST_UP }, /* Ӱ */
+    { 0x4F1, AF_ADJUST_UP }, /* ӱ */
+    { 0x4F2, AF_ADJUST_UP }, /* Ӳ */
+    { 0x4F3, AF_ADJUST_UP }, /* ӳ */
+    { 0x4F4, AF_ADJUST_UP }, /* Ӵ */
+    { 0x4F5, AF_ADJUST_UP }, /* ӵ */
+    { 0x4F6, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӷ */
+    { 0x4F7, AF_IGNORE_SMALL_BOTTOM }, /* ӷ */
+    { 0x4F8, AF_ADJUST_UP }, /* Ӹ */
+    { 0x4F9, AF_ADJUST_UP }, /* ӹ */
+    { 0x4FA, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӻ */
+    { 0x4FB, AF_IGNORE_SMALL_BOTTOM }, /* ӻ */
+
+    /* Cyrillic Supplement */
+    { 0x506, AF_IGNORE_CAPITAL_BOTTOM }, /* Ԇ */
+    { 0x507, AF_IGNORE_SMALL_BOTTOM }, /* ԇ */
+
+    { 0x524, AF_IGNORE_CAPITAL_BOTTOM }, /* Ԥ */
+    { 0x525, AF_IGNORE_SMALL_BOTTOM }, /* ԥ */
+    { 0x526, AF_IGNORE_CAPITAL_BOTTOM }, /* Ԧ */
+    { 0x527, AF_IGNORE_SMALL_BOTTOM }, /* ԧ */
+    { 0x52E, AF_IGNORE_CAPITAL_BOTTOM }, /* Ԯ */
+    { 0x52F, AF_IGNORE_SMALL_BOTTOM }, /* ԯ */
+
+    /* Cherokee */
+    { 0x13A5, AF_ADJUST_UP }, /* Ꭵ */
+
+    /* Phonetic Extensions */
+    { 0x1D09, AF_ADJUST_DOWN }, /* ᴉ */
+
+    { 0x1D4E, AF_ADJUST_DOWN }, /* ᵎ */
+
+    { 0x1D51, AF_IGNORE_SMALL_BOTTOM }, /* ᵑ */
+
+    { 0x1D62, AF_ADJUST_UP }, /* ᵢ */
+
+    /* Phonetic Extensions Supplement */
+    { 0x1D80, AF_IGNORE_SMALL_BOTTOM }, /* ᶀ */
+    { 0x1D81, AF_IGNORE_SMALL_BOTTOM }, /* ᶁ */
+    { 0x1D82, AF_IGNORE_SMALL_BOTTOM }, /* ᶂ */
+    { 0x1D84, AF_IGNORE_SMALL_BOTTOM }, /* ᶄ */
+    { 0x1D85, AF_IGNORE_SMALL_BOTTOM }, /* ᶅ */
+    { 0x1D86, AF_IGNORE_SMALL_BOTTOM }, /* ᶆ */
+    { 0x1D87, AF_IGNORE_SMALL_BOTTOM }, /* ᶇ */
+    { 0x1D89, AF_IGNORE_SMALL_BOTTOM }, /* ᶉ */
+    { 0x1D8A, AF_IGNORE_SMALL_BOTTOM }, /* ᶊ */
+    { 0x1D8C, AF_IGNORE_SMALL_BOTTOM }, /* ᶌ */
+    { 0x1D8D, AF_IGNORE_SMALL_BOTTOM }, /* ᶍ */
+    { 0x1D8E, AF_IGNORE_SMALL_BOTTOM }, /* ᶎ */
+    { 0x1D8F, AF_IGNORE_SMALL_BOTTOM }, /* ᶏ */
+
+    { 0x1D90, AF_IGNORE_SMALL_BOTTOM }, /* ᶐ */
+    { 0x1D91, AF_IGNORE_SMALL_BOTTOM }, /* ᶑ */
+    { 0x1D92, AF_IGNORE_SMALL_BOTTOM }, /* ᶒ */
+    { 0x1D93, AF_IGNORE_SMALL_BOTTOM }, /* ᶓ */
+    { 0x1D94, AF_IGNORE_SMALL_BOTTOM }, /* ᶔ */
+    { 0x1D95, AF_IGNORE_SMALL_BOTTOM }, /* ᶕ */
+    { 0x1D96, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* ᶖ */
+    { 0x1D97, AF_IGNORE_SMALL_BOTTOM }, /* ᶗ */
+    { 0x1D98, AF_IGNORE_SMALL_BOTTOM }, /* ᶘ */
+    { 0x1D99, AF_IGNORE_SMALL_BOTTOM }, /* ᶙ */
+    { 0x1D9A, AF_IGNORE_SMALL_BOTTOM }, /* ᶚ */
+
+    { 0x1DA4, AF_ADJUST_UP }, /* ᶤ */
+    { 0x1DA8, AF_ADJUST_UP }, /* ᶨ */
+    { 0x1DA9, AF_IGNORE_SMALL_BOTTOM }, /* ᶩ */
+    { 0x1DAA, AF_IGNORE_SMALL_BOTTOM }, /* ᶪ */
+    { 0x1DAC, AF_IGNORE_SMALL_BOTTOM }, /* ᶬ */
+    { 0x1DAE, AF_IGNORE_SMALL_BOTTOM }, /* ᶮ */
+    { 0x1DAF, AF_IGNORE_SMALL_BOTTOM }, /* ᶯ */
+
+    { 0x1DB3, AF_IGNORE_SMALL_BOTTOM }, /* ᶳ */
+    { 0x1DB5, AF_IGNORE_SMALL_BOTTOM }, /* ᶵ */
+    { 0x1DBC, AF_IGNORE_SMALL_BOTTOM }, /* ᶼ */
+
+    /* Latin Extended Additional */
+    { 0x1E00, AF_ADJUST_DOWN }, /* Ḁ */
+    { 0x1E01, AF_ADJUST_DOWN }, /* ḁ */
+    { 0x1E02, AF_ADJUST_UP }, /* Ḃ */
+    { 0x1E03, AF_ADJUST_UP }, /* ḃ */
+    { 0x1E04, AF_ADJUST_DOWN }, /* Ḅ */
+    { 0x1E05, AF_ADJUST_DOWN }, /* ḅ */
+    { 0x1E06, AF_ADJUST_DOWN }, /* Ḇ */
+    { 0x1E07, AF_ADJUST_DOWN }, /* ḇ */
+    { 0x1E08, AF_ADJUST_UP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ḉ */
+    { 0x1E09, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* ḉ */
+    { 0x1E0A, AF_ADJUST_UP }, /* Ḋ */
+    { 0x1E0B, AF_ADJUST_UP }, /* ḋ */
+    { 0x1E0C, AF_ADJUST_DOWN }, /* Ḍ */
+    { 0x1E0D, AF_ADJUST_DOWN }, /* ḍ */
+    { 0x1E0E, AF_ADJUST_DOWN }, /* Ḏ */
+    { 0x1E0F, AF_ADJUST_DOWN }, /* ḏ */
+
+    { 0x1E10, AF_ADJUST_DOWN }, /* Ḑ */
+    { 0x1E11, AF_ADJUST_DOWN }, /* ḑ */
+    { 0x1E12, AF_ADJUST_DOWN }, /* Ḓ */
+    { 0x1E13, AF_ADJUST_DOWN }, /* ḓ */
+    { 0x1E14, AF_ADJUST_UP2 }, /* Ḕ */
+    { 0x1E15, AF_ADJUST_UP2 }, /* ḕ */
+    { 0x1E16, AF_ADJUST_UP2 }, /* Ḗ */
+    { 0x1E17, AF_ADJUST_UP2 }, /* ḗ */
+    { 0x1E18, AF_ADJUST_DOWN }, /* Ḙ */
+    { 0x1E19, AF_ADJUST_DOWN }, /* ḙ */
+    { 0x1E1A, AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* Ḛ */
+    { 0x1E1B, AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* ḛ */
+    { 0x1E1C, AF_ADJUST_UP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ḝ */
+    { 0x1E1D, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* ḝ */
+    { 0x1E1E, AF_ADJUST_UP }, /* Ḟ */
+    { 0x1E1F, AF_ADJUST_UP }, /* ḟ */
+
+    { 0x1E20, AF_ADJUST_UP }, /* Ḡ */
+    { 0x1E21, AF_ADJUST_UP }, /* ḡ */
+    { 0x1E22, AF_ADJUST_UP }, /* Ḣ */
+    { 0x1E23, AF_ADJUST_UP }, /* ḣ */
+    { 0x1E24, AF_ADJUST_DOWN }, /* Ḥ */
+    { 0x1E25, AF_ADJUST_DOWN }, /* ḥ */
+    { 0x1E26, AF_ADJUST_UP }, /* Ḧ */
+    { 0x1E27, AF_ADJUST_UP }, /* ḧ */
+    { 0x1E28, AF_IGNORE_CAPITAL_BOTTOM }, /* Ḩ */
+    { 0x1E29, AF_IGNORE_SMALL_BOTTOM }, /* ḩ */
+    { 0x1E2A, AF_ADJUST_DOWN }, /* Ḫ */
+    { 0x1E2B, AF_ADJUST_DOWN }, /* ḫ */
+    { 0x1E2C, AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* Ḭ */
+    { 0x1E2D, AF_ADJUST_UP | AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* ḭ */
+    { 0x1E2E, AF_ADJUST_UP2 }, /* Ḯ */
+    { 0x1E2F, AF_ADJUST_UP2 }, /* ḯ */
+
+    { 0x1E30, AF_ADJUST_UP }, /* Ḱ */
+    { 0x1E31, AF_ADJUST_UP }, /* ḱ */
+    { 0x1E32, AF_ADJUST_DOWN }, /* Ḳ */
+    { 0x1E33, AF_ADJUST_DOWN }, /* ḳ */
+    { 0x1E34, AF_ADJUST_DOWN }, /* Ḵ */
+    { 0x1E35, AF_ADJUST_DOWN }, /* ḵ */
+    { 0x1E36, AF_ADJUST_DOWN }, /* Ḷ */
+    { 0x1E37, AF_ADJUST_DOWN }, /* ḷ */
+    { 0x1E38, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ḹ */
+    { 0x1E39, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ḹ */
+    { 0x1E3A, AF_ADJUST_DOWN }, /* Ḻ */
+    { 0x1E3B, AF_ADJUST_DOWN }, /* ḻ */
+    { 0x1E3C, AF_ADJUST_DOWN }, /* Ḽ */
+    { 0x1E3D, AF_ADJUST_DOWN }, /* ḽ */
+    { 0x1E3E, AF_ADJUST_UP }, /* Ḿ */
+    { 0x1E3F, AF_ADJUST_UP }, /* ḿ */
+
+    { 0x1E40, AF_ADJUST_UP }, /* Ṁ */
+    { 0x1E41, AF_ADJUST_UP }, /* ṁ */
+    { 0x1E42, AF_ADJUST_DOWN }, /* Ṃ */
+    { 0x1E43, AF_ADJUST_DOWN }, /* ṃ */
+    { 0x1E44, AF_ADJUST_UP }, /* Ṅ */
+    { 0x1E45, AF_ADJUST_UP }, /* ṅ */
+    { 0x1E46, AF_ADJUST_DOWN }, /* Ṇ */
+    { 0x1E47, AF_ADJUST_DOWN }, /* ṇ */
+    { 0x1E48, AF_ADJUST_DOWN }, /* Ṉ */
+    { 0x1E49, AF_ADJUST_DOWN }, /* ṉ */
+    { 0x1E4A, AF_ADJUST_DOWN }, /* Ṋ */
+    { 0x1E4B, AF_ADJUST_DOWN }, /* ṋ */
+    { 0x1E4C, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* Ṍ */
+    { 0x1E4D, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* ṍ */
+    { 0x1E4E, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* Ṏ */
+    { 0x1E4F, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* ṏ */
+
+    { 0x1E50, AF_ADJUST_UP2 }, /* Ṑ */
+    { 0x1E51, AF_ADJUST_UP2 }, /* ṑ */
+    { 0x1E52, AF_ADJUST_UP2 }, /* Ṓ */
+    { 0x1E53, AF_ADJUST_UP2 }, /* ṓ */
+    { 0x1E54, AF_ADJUST_UP }, /* Ṕ */
+    { 0x1E55, AF_ADJUST_UP }, /* ṕ */
+    { 0x1E56, AF_ADJUST_UP }, /* Ṗ */
+    { 0x1E57, AF_ADJUST_UP }, /* ṗ */
+    { 0x1E58, AF_ADJUST_UP }, /* Ṙ */
+    { 0x1E59, AF_ADJUST_UP }, /* ṙ */
+    { 0x1E5A, AF_ADJUST_DOWN }, /* Ṛ */
+    { 0x1E5B, AF_ADJUST_DOWN }, /* ṛ */
+    { 0x1E5C, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ṝ */
+    { 0x1E5D, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ṝ */
+    { 0x1E5E, AF_ADJUST_DOWN }, /* Ṟ */
+    { 0x1E5F, AF_ADJUST_DOWN }, /* ṟ */
+
+    { 0x1E60, AF_ADJUST_UP }, /* Ṡ */
+    { 0x1E61, AF_ADJUST_UP }, /* ṡ */
+    { 0x1E62, AF_ADJUST_DOWN }, /* Ṣ */
+    { 0x1E63, AF_ADJUST_DOWN }, /* ṣ */
+    { 0x1E64, AF_ADJUST_UP }, /* Ṥ */
+    { 0x1E65, AF_ADJUST_UP }, /* ṥ */
+    { 0x1E66, AF_ADJUST_UP }, /* Ṧ */
+    { 0x1E67, AF_ADJUST_UP }, /* ṧ */
+    { 0x1E68, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ṩ */
+    { 0x1E69, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ṩ */
+    { 0x1E6A, AF_ADJUST_UP }, /* Ṫ */
+    { 0x1E6B, AF_ADJUST_UP }, /* ṫ */
+    { 0x1E6C, AF_ADJUST_DOWN }, /* Ṭ */
+    { 0x1E6D, AF_ADJUST_DOWN }, /* ṭ */
+    { 0x1E6E, AF_ADJUST_DOWN }, /* Ṯ */
+    { 0x1E6F, AF_ADJUST_DOWN }, /* ṯ */
+
+    { 0x1E70, AF_ADJUST_DOWN }, /* Ṱ */
+    { 0x1E71, AF_ADJUST_DOWN }, /* ṱ */
+    { 0x1E72, AF_ADJUST_DOWN }, /* Ṳ */
+    { 0x1E73, AF_ADJUST_DOWN }, /* ṳ */
+    { 0x1E74, AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* Ṵ */
+    { 0x1E75, AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* ṵ */
+    { 0x1E76, AF_ADJUST_DOWN }, /* Ṷ */
+    { 0x1E77, AF_ADJUST_DOWN }, /* ṷ */
+    { 0x1E78, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* Ṹ */
+    { 0x1E79, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* ṹ */
+    { 0x1E7A, AF_ADJUST_UP2 }, /* Ṻ */
+    { 0x1E7B, AF_ADJUST_UP2 }, /* ṻ */
+    { 0x1E7C, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ṽ */
+    { 0x1E7D, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ṽ */
+    { 0x1E7E, AF_ADJUST_DOWN }, /* Ṿ */
+    { 0x1E7F, AF_ADJUST_DOWN }, /* ṿ */
+
+    { 0x1E80, AF_ADJUST_UP }, /* Ẁ */
+    { 0x1E81, AF_ADJUST_UP }, /* ẁ */
+    { 0x1E82, AF_ADJUST_UP }, /* Ẃ */
+    { 0x1E83, AF_ADJUST_UP }, /* ẃ */
+    { 0x1E84, AF_ADJUST_UP }, /* Ẅ */
+    { 0x1E85, AF_ADJUST_UP }, /* ẅ */
+    { 0x1E86, AF_ADJUST_UP }, /* Ẇ */
+    { 0x1E87, AF_ADJUST_UP }, /* ẇ */
+    { 0x1E88, AF_ADJUST_DOWN }, /* Ẉ */
+    { 0x1E89, AF_ADJUST_DOWN }, /* ẉ */
+    { 0x1E8A, AF_ADJUST_UP }, /* Ẋ */
+    { 0x1E8B, AF_ADJUST_UP }, /* ẋ */
+    { 0x1E8C, AF_ADJUST_UP }, /* Ẍ */
+    { 0x1E8D, AF_ADJUST_UP }, /* ẍ */
+    { 0x1E8E, AF_ADJUST_UP }, /* Ẏ */
+    { 0x1E8F, AF_ADJUST_UP }, /* ẏ */
+
+    { 0x1E90, AF_ADJUST_UP }, /* Ẑ */
+    { 0x1E91, AF_ADJUST_UP }, /* ẑ */
+    { 0x1E92, AF_ADJUST_DOWN }, /* Ẓ */
+    { 0x1E93, AF_ADJUST_DOWN }, /* ẓ */
+    { 0x1E94, AF_ADJUST_DOWN }, /* Ẕ */
+    { 0x1E95, AF_ADJUST_DOWN }, /* ẕ */
+    { 0x1E96, AF_ADJUST_DOWN }, /* ẖ */
+    { 0x1E97, AF_ADJUST_UP }, /* ẗ */
+    { 0x1E98, AF_ADJUST_UP }, /* ẘ */
+    { 0x1E99, AF_ADJUST_UP }, /* ẙ */
+    { 0x1E9A, AF_ADJUST_UP }, /* ẚ */
+    { 0x1E9B, AF_ADJUST_UP }, /* ẛ */
+
+    { 0x1EA0, AF_ADJUST_DOWN }, /* Ạ */
+    { 0x1EA1, AF_ADJUST_DOWN }, /* ạ */
+    { 0x1EA2, AF_ADJUST_UP }, /* Ả */
+    { 0x1EA3, AF_ADJUST_UP }, /* ả */
+    { 0x1EA4, AF_ADJUST_UP2 }, /* Ấ */
+    { 0x1EA5, AF_ADJUST_UP2 }, /* ấ */
+    { 0x1EA6, AF_ADJUST_UP2 }, /* Ầ */
+    { 0x1EA7, AF_ADJUST_UP2 }, /* ầ */
+    { 0x1EA8, AF_ADJUST_UP2 }, /* Ẩ */
+    { 0x1EA9, AF_ADJUST_UP2 }, /* ẩ */
+    { 0x1EAA, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* Ẫ */
+    { 0x1EAB, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ẫ */
+    { 0x1EAC, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ậ */
+    { 0x1EAD, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ậ */
+    { 0x1EAE, AF_ADJUST_UP2 }, /* Ắ */
+    { 0x1EAF, AF_ADJUST_UP2 }, /* ắ */
+
+    { 0x1EB0, AF_ADJUST_UP2 }, /* Ằ */
+    { 0x1EB1, AF_ADJUST_UP2 }, /* ằ */
+    { 0x1EB2, AF_ADJUST_UP2 }, /* Ẳ */
+    { 0x1EB3, AF_ADJUST_UP2 }, /* ẳ */
+    { 0x1EB4, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* Ẵ */
+    { 0x1EB5, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ẵ */
+    { 0x1EB6, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ặ */
+    { 0x1EB7, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ặ */
+    { 0x1EB8, AF_ADJUST_DOWN }, /* Ẹ */
+    { 0x1EB9, AF_ADJUST_DOWN }, /* ẹ */
+    { 0x1EBA, AF_ADJUST_UP }, /* Ẻ */
+    { 0x1EBB, AF_ADJUST_UP }, /* ẻ */
+    { 0x1EBC, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ẽ */
+    { 0x1EBD, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ẽ */
+    { 0x1EBE, AF_ADJUST_UP2 }, /* Ế */
+    { 0x1EBF, AF_ADJUST_UP2 }, /* ế */
+
+    { 0x1EC0, AF_ADJUST_UP2 }, /* Ề */
+    { 0x1EC1, AF_ADJUST_UP2 }, /* ề */
+    { 0x1EC2, AF_ADJUST_UP2 }, /* Ể */
+    { 0x1EC3, AF_ADJUST_UP2 }, /* ể */
+    { 0x1EC4, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* Ễ */
+    { 0x1EC5, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ễ */
+    { 0x1EC6, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ệ */
+    { 0x1EC7, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ệ */
+    { 0x1EC8, AF_ADJUST_UP }, /* Ỉ */
+    { 0x1EC9, AF_ADJUST_UP }, /* ỉ */
+    { 0x1ECA, AF_ADJUST_DOWN }, /* Ị */
+    { 0x1ECB, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ị */
+    { 0x1ECC, AF_ADJUST_DOWN }, /* Ọ */
+    { 0x1ECD, AF_ADJUST_DOWN }, /* ọ */
+    { 0x1ECE, AF_ADJUST_UP }, /* Ỏ */
+    { 0x1ECF, AF_ADJUST_UP }, /* ỏ */
+
+    { 0x1ED0, AF_ADJUST_UP2 }, /* Ố */
+    { 0x1ED1, AF_ADJUST_UP2 }, /* ố */
+    { 0x1ED2, AF_ADJUST_UP2 }, /* Ồ */
+    { 0x1ED3, AF_ADJUST_UP2 }, /* ồ */
+    { 0x1ED4, AF_ADJUST_UP2 }, /* Ổ */
+    { 0x1ED5, AF_ADJUST_UP2 }, /* ổ */
+    { 0x1ED6, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* Ỗ */
+    { 0x1ED7, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ỗ */
+    { 0x1ED8, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ộ */
+    { 0x1ED9, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ộ */
+    { 0x1EDA, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ớ */
+    { 0x1EDB, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ớ */
+    { 0x1EDC, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ờ */
+    { 0x1EDD, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ờ */
+    { 0x1EDE, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ở */
+    { 0x1EDF, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ở */
+
+    { 0x1EE0, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_IGNORE_CAPITAL_TOP }, /* Ỡ */
+    { 0x1EE1, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_IGNORE_SMALL_TOP }, /* ỡ */
+    { 0x1EE2, AF_ADJUST_DOWN | AF_IGNORE_CAPITAL_TOP }, /* Ợ */
+    { 0x1EE3, AF_ADJUST_DOWN | AF_IGNORE_SMALL_TOP }, /* ợ */
+    { 0x1EE4, AF_ADJUST_DOWN }, /* Ụ */
+    { 0x1EE5, AF_ADJUST_DOWN }, /* ụ */
+    { 0x1EE6, AF_ADJUST_UP }, /* Ủ */
+    { 0x1EE7, AF_ADJUST_UP }, /* ủ */
+    { 0x1EE8, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ứ */
+    { 0x1EE9, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ứ */
+    { 0x1EEA, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ừ */
+    { 0x1EEB, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ừ */
+    { 0x1EEC, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ử */
+    { 0x1EED, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ử */
+    { 0x1EEE, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_IGNORE_CAPITAL_TOP }, /* Ữ */
+    { 0x1EEF, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_IGNORE_SMALL_TOP }, /* ữ */
+
+    { 0x1EF0, AF_ADJUST_DOWN | AF_IGNORE_CAPITAL_TOP }, /* Ự */
+    { 0x1EF1, AF_ADJUST_DOWN | AF_IGNORE_SMALL_TOP }, /* ự */
+    { 0x1EF2, AF_ADJUST_UP }, /* Ỳ */
+    { 0x1EF3, AF_ADJUST_UP }, /* ỳ */
+    { 0x1EF4, AF_ADJUST_DOWN }, /* Ỵ */
+    { 0x1EF5, AF_ADJUST_DOWN }, /* ỵ */
+    { 0x1EF6, AF_ADJUST_UP }, /* Ỷ */
+    { 0x1EF7, AF_ADJUST_UP }, /* ỷ */
+    { 0x1EF8, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ỹ */
+    { 0x1EF9, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ỹ */
+
+    /* Greek Extended */
+    { 0x1F00, AF_ADJUST_UP }, /* ἀ */
+    { 0x1F01, AF_ADJUST_UP }, /* ἁ */
+    { 0x1F02, AF_ADJUST_UP }, /* ἂ */
+    { 0x1F03, AF_ADJUST_UP }, /* ἃ */
+    { 0x1F04, AF_ADJUST_UP }, /* ἄ */
+    { 0x1F05, AF_ADJUST_UP }, /* ἅ */
+    { 0x1F06, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἆ */
+    { 0x1F07, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἇ */
+
+    { 0x1F10, AF_ADJUST_UP }, /* ἐ */
+    { 0x1F11, AF_ADJUST_UP }, /* ἑ */
+    { 0x1F12, AF_ADJUST_UP }, /* ἒ */
+    { 0x1F13, AF_ADJUST_UP }, /* ἓ */
+    { 0x1F14, AF_ADJUST_UP }, /* ἔ */
+    { 0x1F15, AF_ADJUST_UP }, /* ἕ */
+
+    { 0x1F20, AF_ADJUST_UP }, /* ἠ */
+    { 0x1F21, AF_ADJUST_UP }, /* ἡ */
+    { 0x1F22, AF_ADJUST_UP }, /* ἢ */
+    { 0x1F23, AF_ADJUST_UP }, /* ἣ */
+    { 0x1F24, AF_ADJUST_UP }, /* ἤ */
+    { 0x1F25, AF_ADJUST_UP }, /* ἥ */
+    { 0x1F26, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἦ */
+    { 0x1F27, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἧ */
+
+    { 0x1F30, AF_ADJUST_UP }, /* ἰ */
+    { 0x1F31, AF_ADJUST_UP }, /* ἱ */
+    { 0x1F32, AF_ADJUST_UP }, /* ἲ */
+    { 0x1F33, AF_ADJUST_UP }, /* ἳ */
+    { 0x1F34, AF_ADJUST_UP }, /* ἴ */
+    { 0x1F35, AF_ADJUST_UP }, /* ἵ */
+    { 0x1F36, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἶ */
+    { 0x1F37, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἷ */
+
+    { 0x1F40, AF_ADJUST_UP }, /* ὀ */
+    { 0x1F41, AF_ADJUST_UP }, /* ὁ */
+    { 0x1F42, AF_ADJUST_UP }, /* ὂ */
+    { 0x1F43, AF_ADJUST_UP }, /* ὃ */
+    { 0x1F44, AF_ADJUST_UP }, /* ὄ */
+    { 0x1F45, AF_ADJUST_UP }, /* ὅ */
+
+    { 0x1F50, AF_ADJUST_UP }, /* ὐ */
+    { 0x1F51, AF_ADJUST_UP }, /* ὑ */
+    { 0x1F52, AF_ADJUST_UP }, /* ὒ */
+    { 0x1F53, AF_ADJUST_UP }, /* ὓ */
+    { 0x1F54, AF_ADJUST_UP }, /* ὔ */
+    { 0x1F55, AF_ADJUST_UP }, /* ὕ */
+    { 0x1F56, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ὖ */
+    { 0x1F57, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ὗ */
+
+    { 0x1F60, AF_ADJUST_UP }, /* ὠ */
+    { 0x1F61, AF_ADJUST_UP }, /* ὡ */
+    { 0x1F62, AF_ADJUST_UP }, /* ὢ */
+    { 0x1F63, AF_ADJUST_UP }, /* ὣ */
+    { 0x1F64, AF_ADJUST_UP }, /* ὤ */
+    { 0x1F65, AF_ADJUST_UP }, /* ὥ */
+    { 0x1F66, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ὦ */
+    { 0x1F67, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ὧ */
+
+    { 0x1F70, AF_ADJUST_UP }, /* ὰ */
+    { 0x1F71, AF_ADJUST_UP }, /* ά */
+    { 0x1F72, AF_ADJUST_UP }, /* ὲ */
+    { 0x1F73, AF_ADJUST_UP }, /* έ */
+    { 0x1F74, AF_ADJUST_UP }, /* ὴ */
+    { 0x1F75, AF_ADJUST_UP }, /* ή */
+    { 0x1F76, AF_ADJUST_UP }, /* ὶ */
+    { 0x1F77, AF_ADJUST_UP }, /* ί */
+    { 0x1F78, AF_ADJUST_UP }, /* ὸ */
+    { 0x1F79, AF_ADJUST_UP }, /* ό */
+    { 0x1F7A, AF_ADJUST_UP }, /* ὺ */
+    { 0x1F7B, AF_ADJUST_UP }, /* ύ */
+    { 0x1F7C, AF_ADJUST_UP }, /* ὼ */
+    { 0x1F7D, AF_ADJUST_UP }, /* ώ */
+
+    { 0x1F80, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾀ */
+    { 0x1F81, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾁ */
+    { 0x1F82, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾂ */
+    { 0x1F83, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾃ */
+    { 0x1F84, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾄ */
+    { 0x1F85, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾅ */
+    { 0x1F86, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾆ */
+    { 0x1F87, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾇ */
+    { 0x1F88, AF_ADJUST_DOWN }, /* ᾈ */
+    { 0x1F89, AF_ADJUST_DOWN }, /* ᾉ */
+    { 0x1F8A, AF_ADJUST_DOWN }, /* ᾊ */
+    { 0x1F8B, AF_ADJUST_DOWN }, /* ᾋ */
+    { 0x1F8C, AF_ADJUST_DOWN }, /* ᾌ */
+    { 0x1F8D, AF_ADJUST_DOWN }, /* ᾍ */
+    { 0x1F8E, AF_ADJUST_DOWN }, /* ᾎ */
+    { 0x1F8F, AF_ADJUST_DOWN }, /* ᾏ */
+
+    { 0x1F90, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾐ */
+    { 0x1F91, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾑ */
+    { 0x1F92, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾒ */
+    { 0x1F93, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾓ */
+    { 0x1F94, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾔ */
+    { 0x1F95, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾕ */
+    { 0x1F96, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾖ */
+    { 0x1F97, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾗ */
+    { 0x1F98, AF_ADJUST_DOWN }, /* ᾘ */
+    { 0x1F99, AF_ADJUST_DOWN }, /* ᾙ */
+    { 0x1F9A, AF_ADJUST_DOWN }, /* ᾚ */
+    { 0x1F9B, AF_ADJUST_DOWN }, /* ᾛ */
+    { 0x1F9C, AF_ADJUST_DOWN }, /* ᾜ */
+    { 0x1F9D, AF_ADJUST_DOWN }, /* ᾝ */
+    { 0x1F9E, AF_ADJUST_DOWN }, /* ᾞ */
+    { 0x1F9F, AF_ADJUST_DOWN }, /* ᾟ */
+
+    { 0x1FA0, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾠ */
+    { 0x1FA1, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾡ */
+    { 0x1FA2, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾢ */
+    { 0x1FA3, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾣ */
+    { 0x1FA4, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾤ */
+    { 0x1FA5, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾥ */
+    { 0x1FA6, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾦ */
+    { 0x1FA7, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾧ */
+    { 0x1FA8, AF_ADJUST_DOWN }, /* ᾨ */
+    { 0x1FA9, AF_ADJUST_DOWN }, /* ᾩ */
+    { 0x1FAA, AF_ADJUST_DOWN }, /* ᾪ */
+    { 0x1FAB, AF_ADJUST_DOWN }, /* ᾫ */
+    { 0x1FAC, AF_ADJUST_DOWN }, /* ᾬ */
+    { 0x1FAD, AF_ADJUST_DOWN }, /* ᾭ */
+    { 0x1FAE, AF_ADJUST_DOWN }, /* ᾮ */
+    { 0x1FAF, AF_ADJUST_DOWN }, /* ᾯ */
+
+    { 0x1FB0, AF_ADJUST_UP }, /* ᾰ */
+    { 0x1FB1, AF_ADJUST_UP }, /* ᾱ */
+    { 0x1FB2, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾲ */
+    { 0x1FB3, AF_ADJUST_DOWN }, /* ᾳ */
+    { 0x1FB4, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾴ */
+    { 0x1FB6, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ᾶ */
+    { 0x1FB7, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾷ */
+    { 0x1FB8, AF_ADJUST_UP }, /* Ᾰ */
+    { 0x1FB9, AF_ADJUST_UP }, /* Ᾱ */
+    { 0x1FBC, AF_ADJUST_DOWN }, /* ᾼ */
+
+    { 0x1FC2, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ῂ */
+    { 0x1FC3, AF_ADJUST_DOWN }, /* ῃ */
+    { 0x1FC4, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ῄ */
+    { 0x1FC6, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ῆ */
+    { 0x1FC7, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ῇ */
+    { 0x1FCC, AF_ADJUST_DOWN }, /* ῌ */
+
+    { 0x1FD0, AF_ADJUST_UP }, /* ῐ */
+    { 0x1FD1, AF_ADJUST_UP }, /* ῑ */
+    { 0x1FD2, AF_ADJUST_UP2 }, /* ῒ */
+    { 0x1FD3, AF_ADJUST_UP2 }, /* ΐ */
+    { 0x1FD6, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ῖ */
+    { 0x1FD7, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ῗ */
+    { 0x1FD8, AF_ADJUST_UP }, /* Ῐ */
+    { 0x1FD9, AF_ADJUST_UP }, /* Ῑ */
+
+    { 0x1FE0, AF_ADJUST_UP }, /* ῠ */
+    { 0x1FE1, AF_ADJUST_UP }, /* ῡ */
+    { 0x1FE2, AF_ADJUST_UP2 }, /* ῢ */
+    { 0x1FE3, AF_ADJUST_UP2 }, /* ΰ */
+    { 0x1FE4, AF_ADJUST_UP }, /* ῤ */
+    { 0x1FE5, AF_ADJUST_UP }, /* ῥ */
+    { 0x1FE6, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ῦ */
+    { 0x1FE7, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ῧ */
+    { 0x1FE8, AF_ADJUST_UP }, /* Ῠ */
+    { 0x1FE9, AF_ADJUST_UP }, /* Ῡ */
+    { 0x1FF2, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ῲ */
+    { 0x1FF3, AF_ADJUST_DOWN }, /* ῳ */
+    { 0x1FF4, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ῴ */
+    { 0x1FF6, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ῶ */
+    { 0x1FF7, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ῷ */
+    { 0x1FFC, AF_ADJUST_DOWN }, /* ῼ */
+
+    /* General Punctuation */
+    { 0x203C, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ‼ */
+    { 0x203D, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ‽ */
+
+    { 0x2047, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ⁇ */
+    { 0x2048, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ⁈ */
+    { 0x2049, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ⁉ */
+
+    /* Superscripts and Subscripts */
+    { 0x2071, AF_ADJUST_UP }, /* ⁱ */
+
+    /* Currency Symbols */
+    { 0x20AB, AF_ADJUST_DOWN }, /* ₫ */
+
+    { 0x20C0, AF_ADJUST_DOWN }, /* ⃀ */
+
+    /* Number Forms */
+    { 0x2170, AF_ADJUST_UP }, /* ⅰ */
+    { 0x2171, AF_ADJUST_UP }, /* ⅱ */
+    { 0x2172, AF_ADJUST_UP }, /* ⅲ */
+    { 0x2173, AF_ADJUST_UP }, /* ⅳ */
+    { 0x2175, AF_ADJUST_UP }, /* ⅵ */
+    { 0x2176, AF_ADJUST_UP }, /* ⅶ */
+    { 0x2177, AF_ADJUST_UP }, /* ⅷ */
+    { 0x2178, AF_ADJUST_UP }, /* ⅸ */
+    { 0x217A, AF_ADJUST_UP }, /* ⅺ */
+    { 0x217B, AF_ADJUST_UP }, /* ⅻ */
+
+    /* Latin Extended-C */
+    { 0x2C64, AF_IGNORE_CAPITAL_BOTTOM } , /* Ɽ */
+    { 0x2C67, AF_IGNORE_CAPITAL_BOTTOM } , /* Ⱨ */
+    { 0x2C68, AF_IGNORE_SMALL_BOTTOM } , /* ⱨ */
+    { 0x2C69, AF_IGNORE_CAPITAL_BOTTOM } , /* Ⱪ */
+    { 0x2C6A, AF_IGNORE_SMALL_BOTTOM } , /* ⱪ */
+    { 0x2C6B, AF_IGNORE_CAPITAL_BOTTOM } , /* Ⱬ */
+    { 0x2C6C, AF_IGNORE_SMALL_BOTTOM } , /* ⱬ */
+    { 0x2C6E, AF_IGNORE_CAPITAL_BOTTOM } , /* Ɱ */
+
+    { 0x2C7C, AF_ADJUST_UP }, /* ⱼ */
+    { 0x2C7E, AF_IGNORE_CAPITAL_BOTTOM } , /* Ȿ */
+    { 0x2C7F, AF_IGNORE_CAPITAL_BOTTOM } , /* Ɀ */
+
+    /* Coptic */
+    { 0x2CC2, AF_ADJUST_UP }, /* Ⳃ */
+    { 0x2CC3, AF_ADJUST_UP }, /* ⳃ */
+
+    /* Supplemental Punctuation */
+    { 0x2E18, AF_ADJUST_UP }, /* ⸘ */
+
+    { 0x2E2E, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ⸮ */
+
+    /* Cyrillic Extended-B */
+    { 0xA640, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꙁ */
+    { 0xA641, AF_IGNORE_SMALL_BOTTOM } , /* ꙁ */
+    { 0xA642, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꙃ */
+    { 0xA643, AF_IGNORE_SMALL_BOTTOM } , /* ꙃ */
+
+    { 0xA680, AF_IGNORE_CAPITAL_TOP } , /* Ꚁ */
+    { 0xA681, AF_IGNORE_SMALL_TOP } , /* ꚁ */
+    { 0xA688, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꚉ */
+    { 0xA689, AF_IGNORE_SMALL_BOTTOM } , /* ꚉ */
+    { 0xA68A, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꚋ */
+    { 0xA68B, AF_IGNORE_SMALL_BOTTOM } , /* ꚋ */
+    { 0xA68E, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꚏ */
+    { 0xA68F, AF_IGNORE_SMALL_BOTTOM } , /* ꚏ */
+
+    { 0xA690, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꚑ */
+    { 0xA691, AF_IGNORE_SMALL_BOTTOM } , /* ꚑ */
+    { 0xA696, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꚗ */
+    { 0xA697, AF_IGNORE_SMALL_BOTTOM } , /* ꚗ */
+
+    /* Latin Extended-D */
+    { 0xA726, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꜧ */
+    { 0xA727, AF_IGNORE_SMALL_BOTTOM } , /* ꜧ */
+
+    { 0xA756, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꝗ */
+    { 0xA758, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꝙ */
+
+    { 0xA771, AF_IGNORE_SMALL_BOTTOM } , /* ꝱ */
+    { 0xA772, AF_IGNORE_SMALL_BOTTOM } , /* ꝲ */
+    { 0xA773, AF_IGNORE_SMALL_BOTTOM } , /* ꝳ */
+    { 0xA774, AF_IGNORE_SMALL_BOTTOM } , /* ꝴ */
+    { 0xA776, AF_IGNORE_SMALL_BOTTOM } , /* ꝶ */
+
+    { 0xA790, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꞑ */
+    { 0xA791, AF_IGNORE_SMALL_BOTTOM } , /* ꞑ */
+    { 0xA794, AF_IGNORE_SMALL_BOTTOM } , /* ꞔ */
+    { 0xA795, AF_IGNORE_SMALL_BOTTOM } , /* ꞕ */
+
+    { 0xA7C0, AF_IGNORE_CAPITAL_TOP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ꟁ */
+    { 0xA7C1, AF_IGNORE_SMALL_TOP | AF_IGNORE_SMALL_BOTTOM }, /* ꟁ */
+    { 0xA7C4, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꞔ */
+    { 0xA7C5, AF_IGNORE_CAPITAL_BOTTOM } , /* Ʂ */
+    { 0xA7C6, AF_IGNORE_CAPITAL_BOTTOM } , /* Ᶎ */
+    { 0xA7CC, AF_IGNORE_CAPITAL_TOP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ꟍ */
+    { 0xA7CD, AF_IGNORE_SMALL_TOP | AF_IGNORE_SMALL_BOTTOM }, /* ꟍ */
+
+    /* Latin Extended-E */
+    { 0xAB3C, AF_IGNORE_SMALL_BOTTOM } , /* ꬼ */
+
+    { 0xAB46, AF_IGNORE_SMALL_BOTTOM } , /* ꭆ */
+
+    { 0xAB5C, AF_IGNORE_SMALL_BOTTOM } , /* ꭜ */
+
+    { 0xAB66, AF_IGNORE_SMALL_BOTTOM } , /* ꭦ */
+    { 0xAB67, AF_IGNORE_SMALL_BOTTOM } , /* ꭧ */
+  };
+
+
+  FT_LOCAL_DEF( FT_UInt32 )
+  af_adjustment_database_lookup( FT_UInt32  codepoint )
+  {
+    /* Binary search for database entry */
+    FT_Offset  low  = 0;
+    FT_Offset  high = AF_ADJUSTMENT_DATABASE_LENGTH - 1;
+
+
+    while ( high >= low )
+    {
+      FT_Offset  mid           = ( low + high ) / 2;
+      FT_UInt32  mid_codepoint = adjustment_database[mid].codepoint;
+
+
+      if ( mid_codepoint < codepoint )
+        low = mid + 1;
+      else if ( mid_codepoint > codepoint )
+        high = mid - 1;
+      else
+        return adjustment_database[mid].flags;
+    }
+
+    return 0;
+  }
+
+
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
+
+  static FT_Error
+  add_substitute( FT_Int     glyph_idx,
+                  size_t     value,
+                  FT_UInt32  codepoint,
+                  FT_Hash    reverse_map,
+                  FT_Hash    subst_map,
+                  FT_Memory  memory )
+  {
+    FT_Error  error;
+
+    FT_Int  first_substitute = (FT_Int)( value & 0xFFFF );
+
+    FT_UInt  used = reverse_map->used;
+
+
+    /*
+      OpenType features like 'unic' map lowercase letter glyphs to uppercase
+      forms (and vice versa), which could lead to the use of wrong entries
+      in the adjustment database.  For this reason we don't overwrite,
+      prioritizing cmap entries.
+
+      XXX Note, however, that this cannot cover all cases since there might
+      be contradictory entries for glyphs not in the cmap.  A possible
+      solution might be to specially mark pairs of related lowercase and
+      uppercase characters in the adjustment database that have diacritics
+      on different vertical sides (for example, U+0122 'Ģ' and U+0123 'ģ').
+      The auto-hinter could then perform a topological analysis to do the
+      right thing.
+    */
+    error = ft_hash_num_insert_no_overwrite( first_substitute, codepoint,
+                                             reverse_map, memory );
+    if ( error )
+      return error;
+
+    if ( reverse_map->used > used )
+    {
+      size_t*  subst = ft_hash_num_lookup( first_substitute, subst_map );
+
+
+      if ( subst )
+      {
+        error = add_substitute( first_substitute, *subst, codepoint,
+                                reverse_map, subst_map, memory );
+        if ( error )
+          return error;
+      }
+    }
+
+    /* The remaining substitutes. */
+    if ( value & 0xFFFF0000U )
+    {
+      FT_UInt  num_substitutes = value >> 16;
+
+      FT_UInt  i;
+
+
+      for ( i = 1; i <= num_substitutes; i++ )
+      {
+        FT_Int   idx        = glyph_idx + (FT_Int)( i << 16 );
+        size_t*  substitute = ft_hash_num_lookup( idx, subst_map );
+
+
+        used = reverse_map->used;
+
+        error = ft_hash_num_insert_no_overwrite( *substitute,
+                                                 codepoint,
+                                                 reverse_map,
+                                                 memory );
+        if ( error )
+          return error;
+
+        if ( reverse_map->used > used )
+        {
+          size_t*  subst = ft_hash_num_lookup( *substitute, subst_map );
+
+
+          if ( subst )
+          {
+            error = add_substitute( *substitute, *subst, codepoint,
+                                    reverse_map, subst_map, memory );
+            if ( error )
+              return error;
+          }
+        }
+      }
+    }
+
+    return FT_Err_Ok;
+  }
+
+#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */
+
+
+  /* Construct a 'reverse cmap' (i.e., a mapping from glyph indices to   */
+  /* character codes) for all glyphs that an input code point could turn */
+  /* into.                                                               */
+  /*                                                                     */
+  /* If HarfBuzz support is not available, this is the direct inversion  */
+  /* of the cmap table, otherwise the mapping gets extended with data    */
+  /* from the 'GSUB' table.                                              */
+  FT_LOCAL_DEF( FT_Error )
+  af_reverse_character_map_new( FT_Hash         *map,
+                                AF_StyleMetrics  metrics )
+  {
+    FT_Error  error;
+
+    AF_FaceGlobals  globals = metrics->globals;
+    FT_Face         face    = globals->face;
+    FT_Memory       memory  = face->memory;
+
+    FT_CharMap  old_charmap;
+
+    FT_UInt32  codepoint;
+    FT_Offset  i;
+
+
+    FT_TRACE4(( "af_reverse_character_map_new:"
+                " building reverse character map (style `%s')\n",
+                af_style_names[metrics->style_class->style] ));
+
+    /* Search for a unicode charmap.           */
+    /* If there isn't one, create a blank map. */
+
+    /* Back up `face->charmap` because `find_unicode_charmap` sets it. */
+    old_charmap = face->charmap;
+
+    if ( ( error = find_unicode_charmap( face ) ) )
+      goto Exit;
+
+    *map = NULL;
+    if ( FT_QNEW( *map ) )
+      goto Exit;
+
+    error = ft_hash_num_init( *map, memory );
+    if ( error )
+      goto Exit;
+
+    /* Initialize reverse cmap with data directly from the cmap table. */
+    for ( i = 0; i < AF_ADJUSTMENT_DATABASE_LENGTH; i++ )
+    {
+      FT_Int  cmap_glyph;
+
+
+      /*
+        We cannot restrict `codepoint` to character ranges; we have no
+        control what data the script-specific portion of the GSUB table
+        actually holds.
+
+        An example is `arial.ttf` version 7.00; in this font, there are
+        lookups for Cyrillic (lookup 43), Greek (lookup 44), and Latin
+        (lookup 45) that map capital letter glyphs to small capital glyphs.
+        It is tempting to expect that script-specific versions of the 'c2sc'
+        feature only use script-specific lookups.  However, this is not the
+        case in this font: the feature uses all three lookups regardless of
+        the script.
+
+        The auto-hinter, while assigning glyphs to styles, uses the first
+        coverage result it encounters for a particular glyph.  For example,
+        if the coverage for Cyrillic is tested before Latin (as is currently
+        the case), glyphs without a cmap entry that are covered in 'c2sc'
+        are treated as Cyrillic.
+
+        If we now look at glyph 3498, which is a small-caps version of the
+        Latin character 'A grave' (U+00C0, glyph 172), we can see that it is
+        registered as belonging to a Cyrillic style due to the algorithm
+        just described.  As a result, checking only for characters from the
+        Latin range would miss this glyph; we thus have to test all
+        character codes in the database.
+      */
+      codepoint = adjustment_database[i].codepoint;
+
+      cmap_glyph = (FT_Int)FT_Get_Char_Index( face, codepoint );
+      if ( cmap_glyph == 0 )
+        continue;
+
+      error = ft_hash_num_insert( cmap_glyph, codepoint, *map, memory );
+      if ( error )
+        goto Exit;
+    }
+
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
+
+    if ( ft_hb_enabled( globals ) )
+    {
+      hb_font_t  *hb_font;
+      hb_face_t  *hb_face;
+
+      hb_set_t    *gsub_lookups;
+      hb_script_t  script;
+
+      unsigned int  script_count   = 1;
+      hb_tag_t      script_tags[2] = { HB_TAG_NONE, HB_TAG_NONE };
+
+      FT_Hash  subst_map = NULL;
+
+      hb_codepoint_t  idx;
+      FT_UInt         hash_idx;
+      FT_Int          glyph_idx;
+      size_t          value;
+
+
+      /* No need to check whether HarfBuzz has allocation issues; */
+      /* it continues to work in such cases and simply returns    */
+      /* 'empty' objects that do nothing.                         */
+
+      hb_font = globals->hb_font;
+      hb_face = hb( font_get_face )( hb_font );
+
+      gsub_lookups = hb( set_create )();
+
+      script = af_hb_scripts[metrics->style_class->script];
+
+      hb( ot_tags_from_script_and_language )( script, NULL,
+                                              &script_count, script_tags,
+                                              NULL, NULL );
+
+      /* Compute set of all script-specific GSUB lookups. */
+      hb( ot_layout_collect_lookups )( hb_face,
+                                       HB_OT_TAG_GSUB,
+                                       script_tags, NULL, NULL,
+                                       gsub_lookups );
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+      {
+        FT_Bool  have_idx = FALSE;
+
+
+        FT_TRACE4(( "  GSUB lookups to check:\n" ));
+
+        FT_TRACE4(( "  " ));
+        idx = HB_SET_VALUE_INVALID;
+        while ( hb( set_next )( gsub_lookups, &idx ) )
+          if ( idx < globals->gsub_lookup_count            &&
+               globals->gsub_lookups_single_alternate[idx] )
+          {
+            have_idx = TRUE;
+            FT_TRACE4(( "  %u", idx ));
+          }
+        if ( !have_idx )
+          FT_TRACE4(( "  (none)" ));
+        FT_TRACE4(( "\n" ));
+
+        FT_TRACE4(( "\n" ));
+      }
+#endif
+
+      if ( FT_QNEW( subst_map ) )
+        goto Exit_HarfBuzz;
+
+      error = ft_hash_num_init( subst_map, memory );
+      if ( error )
+        goto Exit_HarfBuzz;
+
+      idx = HB_SET_VALUE_INVALID;
+      while ( hb( set_next )( gsub_lookups, &idx ) )
+      {
+        FT_UInt32  offset;
+
+
+        /* HarfBuzz only validates lookup indices while   */
+        /* processing lookups, not while collecting them, */
+        /* so we have to do that by ourselves.            */
+        if ( idx < globals->gsub_lookup_count )
+          offset = globals->gsub_lookups_single_alternate[idx];
+        else
+          offset = 0;
+
+        /* Put all substitutions into a single hash table.  Note that   */
+        /* the hash values usually contain more than a single character */
+        /* code; this can happen if different 'SingleSubst' subtables   */
+        /* map a given glyph index to different substitutions, or if    */
+        /* 'AlternateSubst' subtable entries are present.               */
+        if ( offset )
+          af_map_lookup( globals, subst_map, offset );
+      }
+
+      /*
+        Now iterate over the collected substitution data in `subst_map`
+        (using recursion to resolve one-to-many mappings) and insert the
+        data into the reverse cmap.
+
+        As an example, suppose we have the following cmap and substitution
+        data:
+
+          cmap: X -> a
+                Y -> b
+                Z -> c
+
+          substitutions: a -> b
+                         b -> c, d
+                         d -> e
+
+        The reverse map now becomes as follows.
+
+          a -> X
+          b -> Y
+          c -> Z (via cmap, ignoring mapping from 'b')
+          d -> Y (via 'b')
+          e -> Y (via 'b' and 'd')
+      */
+
+      hash_idx = 0;
+      while ( ft_hash_num_iterator( &hash_idx,
+                                    &glyph_idx,
+                                    &value,
+                                    subst_map ) )
+      {
+        size_t*  val;
+
+
+        /* Ignore keys that do not point to the first substitute. */
+        if ( (FT_UInt)glyph_idx & 0xFFFF0000U )
+          continue;
+
+        /* Ignore glyph indices that are not related to accents. */
+        val = ft_hash_num_lookup( glyph_idx, *map );
+        if ( !val )
+          continue;
+
+        codepoint = *val;
+
+        error = add_substitute( glyph_idx, value, codepoint,
+                                *map, subst_map, memory );
+        if ( error )
+          break;
+      }
+
+    Exit_HarfBuzz:
+      hb( set_destroy )( gsub_lookups );
+
+      ft_hash_num_free( subst_map, memory );
+      FT_FREE( subst_map );
+
+      if ( error )
+        goto Exit;
+    }
+
+#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */
+
+    FT_TRACE4(( "    reverse character map built successfully"
+                " with %u entries\n", ( *map )->used ));
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+    {
+      FT_UInt  cnt;
+
+
+      FT_TRACE7(( "       gidx   code    flags\n" ));
+               /* "      XXXXX  0xXXXX  XXXXXXXXXXX..." */
+      FT_TRACE7(( "     ------------------------------\n" ));
+
+      for ( cnt = 0; cnt < globals->glyph_count; cnt++ )
+      {
+        size_t*    val;
+        FT_UInt32  adj_type;
+
+        const char*  flag_names[] =
+        {
+          "up",          /* AF_ADJUST_UP    */
+          "down",        /* AF_ADJUST_DOWN  */
+          "double up",   /* AF_ADJUST_UP2   */
+          "double down", /* AF_ADJUST_DOWN2 */
+
+          "top tilde",          /* AF_ADJUST_TILDE_TOP     */
+          "bottom tilde",       /* AF_ADJUST_TILDE_BOTTOM  */
+          "below-top tilde",    /* AF_ADJUST_TILDE_TOP2    */
+          "above-bottom tilde", /* AF_ADJUST_TILDE_BOTTOM2 */
+
+          "ignore capital top",    /* AF_IGNORE_CAPITAL_TOP    */
+          "ignore capital bottom", /* AF_IGNORE_CAPITAL_BOTTOM */
+          "ignore small top",      /* AF_IGNORE_SMALL_TOP      */
+          "ignore small bottom",   /* AF_IGNORE_SMALL_BOTTOM   */
+        };
+        size_t  flag_names_size = sizeof ( flag_names ) / sizeof ( char* );
+
+        char  flag_str[256];
+        int   need_comma;
+
+        size_t  j;
+
+
+        val = ft_hash_num_lookup( (FT_Int)cnt, *map );
+        if ( !val )
+          continue;
+        codepoint = *val;
+
+        adj_type = af_adjustment_database_lookup( codepoint );
+        if ( !adj_type )
+          continue;
+
+        flag_str[0] = '\0';
+        need_comma  = 0;
+
+        for ( j = 0; j < flag_names_size; j++ )
+        {
+          if ( adj_type & (1 << j ) )
+          {
+            if ( !need_comma )
+              need_comma = 1;
+            else
+              strcat( flag_str, ", " );
+            strcat( flag_str, flag_names[j] );
+          }
+        }
+
+        FT_TRACE7(( "      %5u  0x%04X  %s\n", cnt, codepoint, flag_str ));
+      }
+    }
+
+#endif /* FT_DEBUG_LEVEL_TRACE */
+
+
+  Exit:
+    face->charmap = old_charmap;
+
+    if ( error )
+    {
+      FT_TRACE4(( "    error while building reverse character map."
+                  " Using blank map.\n" ));
+
+      if ( *map )
+        ft_hash_num_free( *map, memory );
+
+      FT_FREE( *map );
+      *map = NULL;
+      return error;
+    }
+
+    return FT_Err_Ok;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  af_reverse_character_map_done( FT_Hash    map,
+                                 FT_Memory  memory )
+  {
+    if ( map )
+      ft_hash_num_free( map, memory );
+    FT_FREE( map );
+
+    return FT_Err_Ok;
+  }
+
+
+/* END */
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afadjust.h b/src/java.desktop/share/native/libfreetype/src/autofit/afadjust.h
new file mode 100644
index 00000000000..4837451ae4c
--- /dev/null
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afadjust.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+ *
+ * afadjust.h
+ *
+ *   Auto-fitter routines to adjust components based on charcode (header).
+ *
+ * Copyright (C) 2023-2025 by
+ * David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ * Written by Craig White .
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT.  By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+
+#ifndef AFADJUST_H_
+#define AFADJUST_H_
+
+#include 
+
+#include "afglobal.h"
+#include "aftypes.h"
+
+
+FT_BEGIN_HEADER
+
+  /*
+   * Adjustment type flags.
+   *
+   * They also specify topological constraints that the auto-hinter relies
+   * on.  For example, using `AF_ADJUST_UP` implies that we have two
+   * enclosing contours, one for the base glyph and one for the diacritic
+   * above, and no other contour inbetween or above.  With 'enclosing' it is
+   * meant that such a contour can contain more inner contours.
+   *
+   */
+
+  /* Find the topmost contour and push it up until its lowest point is */
+  /* one pixel above the highest point not enclosed by that contour.   */
+#define AF_ADJUST_UP  0x01
+
+  /* Find the bottommost contour and push it down until its highest point */
+  /* is one pixel below the lowest point not enclosed by that contour.    */
+#define AF_ADJUST_DOWN  0x02
+
+  /* Find the contour below the topmost contour and push it up, together */
+  /* with the topmost contour, until its lowest point is one pixel above */
+  /* the highest point not enclosed by that contour.  This flag is       */
+  /* mutually exclusive with `AF_ADJUST_UP`.                             */
+#define AF_ADJUST_UP2  0x04
+
+  /* Find the contour above the bottommost contour and push it down,  */
+  /* together with the bottommost contour, until its highest point is */
+  /* one pixel below the lowest point not enclosed by that contour.   */
+  /* This flag is mutually exclusive with `AF_ADJUST_DOWN`.           */
+#define AF_ADJUST_DOWN2  0x08
+
+  /* The topmost contour is a tilde.  Enlarge it vertically so that it    */
+  /* stays legible at small sizes, not degenerating to a horizontal line. */
+#define AF_ADJUST_TILDE_TOP  0x10
+
+  /* The bottommost contour is a tilde.  Enlarge it vertically so that it */
+  /* stays legible at small sizes, not degenerating to a horizontal line. */
+#define AF_ADJUST_TILDE_BOTTOM  0x20
+
+  /* The contour below the topmost contour is a tilde.  Enlarge it        */
+  /* vertically so that it stays legible at small sizes, not degenerating */
+  /* to a horizontal line.  To be used with `AF_ADJUST_UP2` only.         */
+#define AF_ADJUST_TILDE_TOP2  0x40
+
+  /* The contour above the bottommost contour is a tilde.  Enlarge it     */
+  /* vertically so that it stays legible at small sizes, not degenerating */
+  /* to a horizontal line.  To be used with `AF_ADJUST_DOWN2` only.       */
+#define AF_ADJUST_TILDE_BOTTOM2  0x80
+
+  /* Make the auto-hinter ignore any diacritic (either a separate contour */
+  /* or part of the base character outline) that is attached to the top   */
+  /* of an uppercase base character.                                      */
+#define AF_IGNORE_CAPITAL_TOP  0x100
+
+  /* Make the auto-hinter ignore any diacritic (either a separate contour */
+  /* or part of the base character outline) that is attached to the       */
+  /* bottom of an uppercase base character.                               */
+#define AF_IGNORE_CAPITAL_BOTTOM  0x200
+
+  /* Make the auto-hinter ignore any diacritic (either a separate contour */
+  /* or part of the base character outline) that is attached to the top   */
+  /* of a lowercase base character.                                       */
+#define AF_IGNORE_SMALL_TOP  0x400
+
+  /* Make the auto-hinter ignore any diacritic (either a separate contour */
+  /* or part of the base character outline) that is attached to the       */
+  /* bottom of a lowercase base character.                                */
+#define AF_IGNORE_SMALL_BOTTOM  0x800
+
+  /* By default, the AF_ADJUST_XXX flags are applied only if diacritics */
+  /* have a 'small' height (based on some heuristic checks).  If this   */
+  /* flag is set, no such check is performed.                           */
+#define AF_ADJUST_NO_HEIGHT_CHECK  0x1000
+
+  /* No adjustment, i.e., no flag is set. */
+#define AF_ADJUST_NONE  0x00
+
+
+  FT_LOCAL( FT_UInt32 )
+  af_adjustment_database_lookup( FT_UInt32  codepoint );
+
+  /* Allocate and populate the reverse character map, */
+  /* using the character map within the face.         */
+  FT_LOCAL( FT_Error )
+  af_reverse_character_map_new( FT_Hash         *map,
+                                AF_StyleMetrics  metrics );
+
+  /* Free the reverse character map. */
+  FT_LOCAL( FT_Error )
+  af_reverse_character_map_done( FT_Hash    map,
+                                 FT_Memory  memory );
+
+
+FT_END_HEADER
+
+#endif /* AFADJUST_H_ */
+
+
+/* END */
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.c b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.c
index ea83969cdc9..a6219bdfe41 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.c
@@ -7,7 +7,7 @@
  *
  *   Auto-fitter data for blue strings (body).
  *
- * Copyright (C) 2013-2024 by
+ * Copyright (C) 2013-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -467,24 +467,24 @@
   af_blue_stringsets[] =
   {
     /* */
-    { AF_BLUE_STRING_ADLAM_CAPITAL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP        },
-    { AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, 0                                 },
+    { AF_BLUE_STRING_ADLAM_CAPITAL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP            },
+    { AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM },
     { AF_BLUE_STRING_ADLAM_SMALL_TOP,      AF_BLUE_PROPERTY_LATIN_TOP      |
-                                           AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
-    { AF_BLUE_STRING_ADLAM_SMALL_BOTTOM,   0                                 },
-    { AF_BLUE_STRING_MAX,                  0                                 },
+                                           AF_BLUE_PROPERTY_LATIN_X_HEIGHT       },
+    { AF_BLUE_STRING_ADLAM_SMALL_BOTTOM,   AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM   },
+    { AF_BLUE_STRING_MAX,                  0                                     },
     { AF_BLUE_STRING_ARABIC_TOP,    AF_BLUE_PROPERTY_LATIN_TOP     },
     { AF_BLUE_STRING_ARABIC_BOTTOM, 0                              },
     { AF_BLUE_STRING_ARABIC_JOIN,   AF_BLUE_PROPERTY_LATIN_NEUTRAL },
     { AF_BLUE_STRING_MAX,           0                              },
-    { AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
-    { AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM,  0                                 },
-    { AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER,  AF_BLUE_PROPERTY_LATIN_TOP        },
+    { AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            },
+    { AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM,  AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM },
+    { AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER,  AF_BLUE_PROPERTY_LATIN_TOP            },
     { AF_BLUE_STRING_ARMENIAN_SMALL_TOP,       AF_BLUE_PROPERTY_LATIN_TOP      |
-                                               AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
-    { AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM,    0                                 },
-    { AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0                                 },
-    { AF_BLUE_STRING_MAX,                      0                                 },
+                                               AF_BLUE_PROPERTY_LATIN_X_HEIGHT       },
+    { AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM,    AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM   },
+    { AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0                                     },
+    { AF_BLUE_STRING_MAX,                      0                                     },
     { AF_BLUE_STRING_AVESTAN_TOP,    AF_BLUE_PROPERTY_LATIN_TOP },
     { AF_BLUE_STRING_AVESTAN_BOTTOM, 0                          },
     { AF_BLUE_STRING_MAX,            0                          },
@@ -508,14 +508,14 @@
     { AF_BLUE_STRING_CHAKMA_BOTTOM,    0                          },
     { AF_BLUE_STRING_CHAKMA_DESCENDER, 0                          },
     { AF_BLUE_STRING_MAX,              0                          },
-    { AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP,          AF_BLUE_PROPERTY_LATIN_TOP        },
-    { AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM,       0                                 },
+    { AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP,          AF_BLUE_PROPERTY_LATIN_TOP          },
+    { AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM,       0                                   },
     { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP      |
-                                                      AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
-    { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, 0                                 },
-    { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
-    { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM,  0                                 },
-    { AF_BLUE_STRING_MAX,                             0                                 },
+                                                      AF_BLUE_PROPERTY_LATIN_X_HEIGHT     },
+    { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM },
+    { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP,     AF_BLUE_PROPERTY_LATIN_TOP          },
+    { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM,  0                                   },
+    { AF_BLUE_STRING_MAX,                             0                                   },
     { AF_BLUE_STRING_CARIAN_TOP,    AF_BLUE_PROPERTY_LATIN_TOP },
     { AF_BLUE_STRING_CARIAN_BOTTOM, 0                          },
     { AF_BLUE_STRING_MAX,           0                          },
@@ -527,24 +527,24 @@
     { AF_BLUE_STRING_CHEROKEE_SMALL,           0                                 },
     { AF_BLUE_STRING_CHEROKEE_SMALL_DESCENDER, 0                                 },
     { AF_BLUE_STRING_MAX,                      0                                 },
-    { AF_BLUE_STRING_COPTIC_CAPITAL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP        },
-    { AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, 0                                 },
+    { AF_BLUE_STRING_COPTIC_CAPITAL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP            },
+    { AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM },
     { AF_BLUE_STRING_COPTIC_SMALL_TOP,      AF_BLUE_PROPERTY_LATIN_TOP      |
-                                            AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
-    { AF_BLUE_STRING_COPTIC_SMALL_BOTTOM,   0                                 },
-    { AF_BLUE_STRING_MAX,                   0                                 },
+                                            AF_BLUE_PROPERTY_LATIN_X_HEIGHT       },
+    { AF_BLUE_STRING_COPTIC_SMALL_BOTTOM,   AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM   },
+    { AF_BLUE_STRING_MAX,                   0                                     },
     { AF_BLUE_STRING_CYPRIOT_TOP,    AF_BLUE_PROPERTY_LATIN_TOP },
     { AF_BLUE_STRING_CYPRIOT_BOTTOM, 0                          },
     { AF_BLUE_STRING_CYPRIOT_SMALL,  AF_BLUE_PROPERTY_LATIN_TOP },
     { AF_BLUE_STRING_CYPRIOT_SMALL,  0                          },
     { AF_BLUE_STRING_MAX,            0                          },
-    { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
-    { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM,  0                                 },
+    { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            },
+    { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM,  AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM },
     { AF_BLUE_STRING_CYRILLIC_SMALL,           AF_BLUE_PROPERTY_LATIN_TOP      |
-                                               AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
-    { AF_BLUE_STRING_CYRILLIC_SMALL,           0                                 },
-    { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0                                 },
-    { AF_BLUE_STRING_MAX,                      0                                 },
+                                               AF_BLUE_PROPERTY_LATIN_X_HEIGHT       },
+    { AF_BLUE_STRING_CYRILLIC_SMALL,           0                                     },
+    { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0                                     },
+    { AF_BLUE_STRING_MAX,                      0                                     },
     { AF_BLUE_STRING_DEVANAGARI_TOP,    AF_BLUE_PROPERTY_LATIN_TOP        },
     { AF_BLUE_STRING_DEVANAGARI_HEAD,   AF_BLUE_PROPERTY_LATIN_TOP        },
     { AF_BLUE_STRING_DEVANAGARI_BASE,   AF_BLUE_PROPERTY_LATIN_TOP      |
@@ -553,12 +553,12 @@
     { AF_BLUE_STRING_DEVANAGARI_BASE,   0                                 },
     { AF_BLUE_STRING_DEVANAGARI_BOTTOM, 0                                 },
     { AF_BLUE_STRING_MAX,               0                                 },
-    { AF_BLUE_STRING_DESERET_CAPITAL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP        },
-    { AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, 0                                 },
+    { AF_BLUE_STRING_DESERET_CAPITAL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP            },
+    { AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM },
     { AF_BLUE_STRING_DESERET_SMALL_TOP,      AF_BLUE_PROPERTY_LATIN_TOP      |
-                                             AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
-    { AF_BLUE_STRING_DESERET_SMALL_BOTTOM,   0                                 },
-    { AF_BLUE_STRING_MAX,                    0                                 },
+                                             AF_BLUE_PROPERTY_LATIN_X_HEIGHT       },
+    { AF_BLUE_STRING_DESERET_SMALL_BOTTOM,   AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM   },
+    { AF_BLUE_STRING_MAX,                    0                                     },
     { AF_BLUE_STRING_ETHIOPIC_TOP,    AF_BLUE_PROPERTY_LATIN_TOP },
     { AF_BLUE_STRING_ETHIOPIC_BOTTOM, 0                          },
     { AF_BLUE_STRING_MAX,             0                          },
@@ -578,23 +578,23 @@
     { AF_BLUE_STRING_GEORGIAN_NUSKHURI_ASCENDER,  AF_BLUE_PROPERTY_LATIN_TOP        },
     { AF_BLUE_STRING_GEORGIAN_NUSKHURI_DESCENDER, 0                                 },
     { AF_BLUE_STRING_MAX,                         0                                 },
-    { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP        },
-    { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, 0                                 },
+    { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP            },
+    { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM },
     { AF_BLUE_STRING_GLAGOLITIC_SMALL_TOP,      AF_BLUE_PROPERTY_LATIN_TOP      |
-                                                AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
-    { AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM,   0                                 },
-    { AF_BLUE_STRING_MAX,                       0                                 },
+                                                AF_BLUE_PROPERTY_LATIN_X_HEIGHT       },
+    { AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM,   AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM   },
+    { AF_BLUE_STRING_MAX,                       0                                     },
     { AF_BLUE_STRING_GOTHIC_TOP,    AF_BLUE_PROPERTY_LATIN_TOP },
     { AF_BLUE_STRING_GOTHIC_BOTTOM, 0                          },
     { AF_BLUE_STRING_MAX,           0                          },
-    { AF_BLUE_STRING_GREEK_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
-    { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM,  0                                 },
-    { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP,  AF_BLUE_PROPERTY_LATIN_TOP        },
+    { AF_BLUE_STRING_GREEK_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            },
+    { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM,  AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM },
+    { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP,  AF_BLUE_PROPERTY_LATIN_TOP            },
     { AF_BLUE_STRING_GREEK_SMALL,           AF_BLUE_PROPERTY_LATIN_TOP      |
-                                            AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
-    { AF_BLUE_STRING_GREEK_SMALL,           0                                 },
-    { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0                                 },
-    { AF_BLUE_STRING_MAX,                   0                                 },
+                                            AF_BLUE_PROPERTY_LATIN_X_HEIGHT       },
+    { AF_BLUE_STRING_GREEK_SMALL,           0                                     },
+    { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0                                     },
+    { AF_BLUE_STRING_MAX,                   0                                     },
     { AF_BLUE_STRING_GUJARATI_TOP,       AF_BLUE_PROPERTY_LATIN_TOP      |
                                          AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
     { AF_BLUE_STRING_GUJARATI_BOTTOM,    0                                 },
@@ -643,45 +643,45 @@
     { AF_BLUE_STRING_LAO_LARGE_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP        },
     { AF_BLUE_STRING_LAO_DESCENDER,      0                                 },
     { AF_BLUE_STRING_MAX,                0                                 },
-    { AF_BLUE_STRING_LATIN_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
-    { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM,  0                                 },
-    { AF_BLUE_STRING_LATIN_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
+    { AF_BLUE_STRING_LATIN_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            },
+    { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM,  AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM },
+    { AF_BLUE_STRING_LATIN_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            },
     { AF_BLUE_STRING_LATIN_SMALL_TOP,       AF_BLUE_PROPERTY_LATIN_TOP      |
-                                            AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
-    { AF_BLUE_STRING_LATIN_SMALL_BOTTOM,    0                                 },
-    { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0                                 },
-    { AF_BLUE_STRING_MAX,                   0                                 },
-    { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
-    { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM,  0                                 },
-    { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
+                                            AF_BLUE_PROPERTY_LATIN_X_HEIGHT       },
+    { AF_BLUE_STRING_LATIN_SMALL_BOTTOM,    AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM   },
+    { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0                                     },
+    { AF_BLUE_STRING_MAX,                   0                                     },
+    { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            },
+    { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM,  AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM },
+    { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            },
     { AF_BLUE_STRING_LATIN_SUBS_SMALL,           AF_BLUE_PROPERTY_LATIN_TOP      |
-                                                 AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
-    { AF_BLUE_STRING_LATIN_SUBS_SMALL,           0                                 },
-    { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0                                 },
-    { AF_BLUE_STRING_MAX,                        0                                 },
-    { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
-    { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM,  0                                 },
-    { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
+                                                 AF_BLUE_PROPERTY_LATIN_X_HEIGHT       },
+    { AF_BLUE_STRING_LATIN_SUBS_SMALL,           0                                     },
+    { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0                                     },
+    { AF_BLUE_STRING_MAX,                        0                                     },
+    { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            },
+    { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM,  AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM },
+    { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            },
     { AF_BLUE_STRING_LATIN_SUPS_SMALL,           AF_BLUE_PROPERTY_LATIN_TOP      |
-                                                 AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
-    { AF_BLUE_STRING_LATIN_SUPS_SMALL,           0                                 },
-    { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0                                 },
-    { AF_BLUE_STRING_MAX,                        0                                 },
+                                                 AF_BLUE_PROPERTY_LATIN_X_HEIGHT       },
+    { AF_BLUE_STRING_LATIN_SUPS_SMALL,           0                                     },
+    { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0                                     },
+    { AF_BLUE_STRING_MAX,                        0                                     },
     { AF_BLUE_STRING_LISU_TOP,    AF_BLUE_PROPERTY_LATIN_TOP },
     { AF_BLUE_STRING_LISU_BOTTOM, 0                          },
     { AF_BLUE_STRING_MAX,         0                          },
     { AF_BLUE_STRING_MALAYALAM_TOP,    AF_BLUE_PROPERTY_LATIN_TOP },
     { AF_BLUE_STRING_MALAYALAM_BOTTOM, 0                          },
     { AF_BLUE_STRING_MAX,              0                          },
-    { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
-    { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM,  0                                 },
-    { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
+    { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            },
+    { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM,  AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM },
+    { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            },
     { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP,       AF_BLUE_PROPERTY_LATIN_TOP      |
-                                                  AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
-    { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM,    0                                 },
-    { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER, 0                                 },
-    { AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP,       AF_BLUE_PROPERTY_LATIN_TOP        },
-    { AF_BLUE_STRING_MAX,                         0                                 },
+                                                  AF_BLUE_PROPERTY_LATIN_X_HEIGHT       },
+    { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM,    AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM   },
+    { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER, 0                                     },
+    { AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP,       AF_BLUE_PROPERTY_LATIN_TOP            },
+    { AF_BLUE_STRING_MAX,                         0                                     },
     { AF_BLUE_STRING_MONGOLIAN_TOP_BASE,    AF_BLUE_PROPERTY_LATIN_TOP },
     { AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE, 0                          },
     { AF_BLUE_STRING_MAX,                   0                          },
@@ -691,12 +691,12 @@
     { AF_BLUE_STRING_MYANMAR_ASCENDER,  AF_BLUE_PROPERTY_LATIN_TOP        },
     { AF_BLUE_STRING_MYANMAR_DESCENDER, 0                                 },
     { AF_BLUE_STRING_MAX,               0                                 },
-    { AF_BLUE_STRING_NKO_TOP,          AF_BLUE_PROPERTY_LATIN_TOP        },
-    { AF_BLUE_STRING_NKO_BOTTOM,       0                                 },
+    { AF_BLUE_STRING_NKO_TOP,          AF_BLUE_PROPERTY_LATIN_TOP          },
+    { AF_BLUE_STRING_NKO_BOTTOM,       0                                   },
     { AF_BLUE_STRING_NKO_SMALL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP      |
-                                       AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
-    { AF_BLUE_STRING_NKO_SMALL_BOTTOM, 0                                 },
-    { AF_BLUE_STRING_MAX,              0                                 },
+                                       AF_BLUE_PROPERTY_LATIN_X_HEIGHT     },
+    { AF_BLUE_STRING_NKO_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM },
+    { AF_BLUE_STRING_MAX,              0                                   },
     { AF_BLUE_STRING_MAX, 0 },
     { AF_BLUE_STRING_OL_CHIKI, AF_BLUE_PROPERTY_LATIN_TOP },
     { AF_BLUE_STRING_OL_CHIKI, 0                          },
@@ -704,15 +704,15 @@
     { AF_BLUE_STRING_OLD_TURKIC_TOP,    AF_BLUE_PROPERTY_LATIN_TOP },
     { AF_BLUE_STRING_OLD_TURKIC_BOTTOM, 0                          },
     { AF_BLUE_STRING_MAX,               0                          },
-    { AF_BLUE_STRING_OSAGE_CAPITAL_TOP,       AF_BLUE_PROPERTY_LATIN_TOP       },
-    { AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM,    0                                },
-    { AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0                                },
-    { AF_BLUE_STRING_OSAGE_SMALL_TOP,         AF_BLUE_PROPERTY_LATIN_TOP     |
-                                              AF_BLUE_PROPERTY_LATIN_X_HEIGHT  },
-    { AF_BLUE_STRING_OSAGE_SMALL_BOTTOM,      0                                },
-    { AF_BLUE_STRING_OSAGE_SMALL_ASCENDER,    AF_BLUE_PROPERTY_LATIN_TOP       },
-    { AF_BLUE_STRING_OSAGE_SMALL_DESCENDER,   0                                },
-    { AF_BLUE_STRING_MAX,                     0                                },
+    { AF_BLUE_STRING_OSAGE_CAPITAL_TOP,       AF_BLUE_PROPERTY_LATIN_TOP            },
+    { AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM,    AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM },
+    { AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0                                     },
+    { AF_BLUE_STRING_OSAGE_SMALL_TOP,         AF_BLUE_PROPERTY_LATIN_TOP      |
+                                              AF_BLUE_PROPERTY_LATIN_X_HEIGHT       },
+    { AF_BLUE_STRING_OSAGE_SMALL_BOTTOM,      AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM   },
+    { AF_BLUE_STRING_OSAGE_SMALL_ASCENDER,    AF_BLUE_PROPERTY_LATIN_TOP            },
+    { AF_BLUE_STRING_OSAGE_SMALL_DESCENDER,   0                                     },
+    { AF_BLUE_STRING_MAX,                     0                                     },
     { AF_BLUE_STRING_OSMANYA_TOP,    AF_BLUE_PROPERTY_LATIN_TOP },
     { AF_BLUE_STRING_OSMANYA_BOTTOM, 0                          },
     { AF_BLUE_STRING_MAX,            0                          },
@@ -723,13 +723,13 @@
     { AF_BLUE_STRING_SAURASHTRA_TOP,    AF_BLUE_PROPERTY_LATIN_TOP },
     { AF_BLUE_STRING_SAURASHTRA_BOTTOM, 0                          },
     { AF_BLUE_STRING_MAX,               0                          },
-    { AF_BLUE_STRING_SHAVIAN_TOP,          AF_BLUE_PROPERTY_LATIN_TOP        },
-    { AF_BLUE_STRING_SHAVIAN_BOTTOM,       0                                 },
-    { AF_BLUE_STRING_SHAVIAN_DESCENDER,    0                                 },
+    { AF_BLUE_STRING_SHAVIAN_TOP,          AF_BLUE_PROPERTY_LATIN_TOP          },
+    { AF_BLUE_STRING_SHAVIAN_BOTTOM,       0                                   },
+    { AF_BLUE_STRING_SHAVIAN_DESCENDER,    0                                   },
     { AF_BLUE_STRING_SHAVIAN_SMALL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP      |
-                                           AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
-    { AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, 0                                 },
-    { AF_BLUE_STRING_MAX,                  0                                 },
+                                           AF_BLUE_PROPERTY_LATIN_X_HEIGHT     },
+    { AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM },
+    { AF_BLUE_STRING_MAX,                  0                                   },
     { AF_BLUE_STRING_SINHALA_TOP,       AF_BLUE_PROPERTY_LATIN_TOP },
     { AF_BLUE_STRING_SINHALA_BOTTOM,    0                          },
     { AF_BLUE_STRING_SINHALA_DESCENDER, 0                          },
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.cin b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.cin
index d2270fac744..786c6b3b9e6 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.cin
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.cin
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter data for blue strings (body).
  *
- * Copyright (C) 2013-2024 by
+ * Copyright (C) 2013-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat
index 88bab2632ab..f6e96ff8189 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat
@@ -2,7 +2,7 @@
 //
 //   Auto-fitter data for blue strings.
 //
-// Copyright (C) 2013-2024 by
+// Copyright (C) 2013-2025 by
 // David Turner, Robert Wilhelm, and Werner Lemberg.
 //
 // This file is part of the FreeType project, and may only be used,
@@ -699,12 +699,12 @@ AF_BLUE_STRING_ENUM AF_BLUE_STRINGS_ARRAY AF_BLUE_STRING_MAX_LEN:
 AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN:
 
   AF_BLUE_STRINGSET_ADLM
-    { AF_BLUE_STRING_ADLAM_CAPITAL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP        }
-    { AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, 0                                 }
+    { AF_BLUE_STRING_ADLAM_CAPITAL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP            }
+    { AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }
     { AF_BLUE_STRING_ADLAM_SMALL_TOP,      AF_BLUE_PROPERTY_LATIN_TOP      |
-                                           AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
-    { AF_BLUE_STRING_ADLAM_SMALL_BOTTOM,   0                                 }
-    { AF_BLUE_STRING_MAX,                  0                                 }
+                                           AF_BLUE_PROPERTY_LATIN_X_HEIGHT       }
+    { AF_BLUE_STRING_ADLAM_SMALL_BOTTOM,   AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM   }
+    { AF_BLUE_STRING_MAX,                  0                                     }
 
   AF_BLUE_STRINGSET_ARAB
     { AF_BLUE_STRING_ARABIC_TOP,    AF_BLUE_PROPERTY_LATIN_TOP     }
@@ -713,14 +713,14 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN:
     { AF_BLUE_STRING_MAX,           0                              }
 
   AF_BLUE_STRINGSET_ARMN
-    { AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
-    { AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM,  0                                 }
-    { AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER,  AF_BLUE_PROPERTY_LATIN_TOP        }
+    { AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            }
+    { AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM,  AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }
+    { AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER,  AF_BLUE_PROPERTY_LATIN_TOP            }
     { AF_BLUE_STRING_ARMENIAN_SMALL_TOP,       AF_BLUE_PROPERTY_LATIN_TOP      |
-                                               AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
-    { AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM,    0                                 }
-    { AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0                                 }
-    { AF_BLUE_STRING_MAX,                      0                                 }
+                                               AF_BLUE_PROPERTY_LATIN_X_HEIGHT       }
+    { AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM,    AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM   }
+    { AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0                                     }
+    { AF_BLUE_STRING_MAX,                      0                                     }
 
   AF_BLUE_STRINGSET_AVST
     { AF_BLUE_STRING_AVESTAN_TOP,    AF_BLUE_PROPERTY_LATIN_TOP }
@@ -756,14 +756,14 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN:
     { AF_BLUE_STRING_MAX,              0                          }
 
   AF_BLUE_STRINGSET_CANS
-    { AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP,          AF_BLUE_PROPERTY_LATIN_TOP        }
-    { AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM,       0                                 }
+    { AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP,          AF_BLUE_PROPERTY_LATIN_TOP          }
+    { AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM,       0                                   }
     { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP      |
-                                                      AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
-    { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, 0                                 }
-    { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
-    { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM,  0                                 }
-    { AF_BLUE_STRING_MAX,                             0                                 }
+                                                      AF_BLUE_PROPERTY_LATIN_X_HEIGHT     }
+    { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }
+    { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP,     AF_BLUE_PROPERTY_LATIN_TOP          }
+    { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM,  0                                   }
+    { AF_BLUE_STRING_MAX,                             0                                   }
 
   AF_BLUE_STRINGSET_CARI
     { AF_BLUE_STRING_CARIAN_TOP,    AF_BLUE_PROPERTY_LATIN_TOP }
@@ -781,12 +781,12 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN:
     { AF_BLUE_STRING_MAX,                      0                                 }
 
   AF_BLUE_STRINGSET_COPT
-    { AF_BLUE_STRING_COPTIC_CAPITAL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP        }
-    { AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, 0                                 }
+    { AF_BLUE_STRING_COPTIC_CAPITAL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP            }
+    { AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }
     { AF_BLUE_STRING_COPTIC_SMALL_TOP,      AF_BLUE_PROPERTY_LATIN_TOP      |
-                                            AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
-    { AF_BLUE_STRING_COPTIC_SMALL_BOTTOM,   0                                 }
-    { AF_BLUE_STRING_MAX,                   0                                 }
+                                            AF_BLUE_PROPERTY_LATIN_X_HEIGHT       }
+    { AF_BLUE_STRING_COPTIC_SMALL_BOTTOM,   AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM   }
+    { AF_BLUE_STRING_MAX,                   0                                     }
 
   AF_BLUE_STRINGSET_CPRT
     { AF_BLUE_STRING_CYPRIOT_TOP,    AF_BLUE_PROPERTY_LATIN_TOP }
@@ -796,13 +796,13 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN:
     { AF_BLUE_STRING_MAX,            0                          }
 
   AF_BLUE_STRINGSET_CYRL
-    { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
-    { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM,  0                                 }
+    { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            }
+    { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM,  AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }
     { AF_BLUE_STRING_CYRILLIC_SMALL,           AF_BLUE_PROPERTY_LATIN_TOP      |
-                                               AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
-    { AF_BLUE_STRING_CYRILLIC_SMALL,           0                                 }
-    { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0                                 }
-    { AF_BLUE_STRING_MAX,                      0                                 }
+                                               AF_BLUE_PROPERTY_LATIN_X_HEIGHT       }
+    { AF_BLUE_STRING_CYRILLIC_SMALL,           0                                     }
+    { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0                                     }
+    { AF_BLUE_STRING_MAX,                      0                                     }
 
   AF_BLUE_STRINGSET_DEVA
     { AF_BLUE_STRING_DEVANAGARI_TOP,    AF_BLUE_PROPERTY_LATIN_TOP        }
@@ -815,12 +815,12 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN:
     { AF_BLUE_STRING_MAX,               0                                 }
 
   AF_BLUE_STRINGSET_DSRT
-    { AF_BLUE_STRING_DESERET_CAPITAL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP        }
-    { AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, 0                                 }
+    { AF_BLUE_STRING_DESERET_CAPITAL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP            }
+    { AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }
     { AF_BLUE_STRING_DESERET_SMALL_TOP,      AF_BLUE_PROPERTY_LATIN_TOP      |
-                                             AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
-    { AF_BLUE_STRING_DESERET_SMALL_BOTTOM,   0                                 }
-    { AF_BLUE_STRING_MAX,                    0                                 }
+                                             AF_BLUE_PROPERTY_LATIN_X_HEIGHT       }
+    { AF_BLUE_STRING_DESERET_SMALL_BOTTOM,   AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM   }
+    { AF_BLUE_STRING_MAX,                    0                                     }
 
   AF_BLUE_STRINGSET_ETHI
     { AF_BLUE_STRING_ETHIOPIC_TOP,    AF_BLUE_PROPERTY_LATIN_TOP }
@@ -848,12 +848,12 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN:
     { AF_BLUE_STRING_MAX,                         0                                 }
 
   AF_BLUE_STRINGSET_GLAG
-    { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP        }
-    { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, 0                                 }
+    { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP            }
+    { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }
     { AF_BLUE_STRING_GLAGOLITIC_SMALL_TOP,      AF_BLUE_PROPERTY_LATIN_TOP      |
-                                                AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
-    { AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM,   0                                 }
-    { AF_BLUE_STRING_MAX,                       0                                 }
+                                                AF_BLUE_PROPERTY_LATIN_X_HEIGHT       }
+    { AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM,   AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM   }
+    { AF_BLUE_STRING_MAX,                       0                                     }
 
   AF_BLUE_STRINGSET_GOTH
     { AF_BLUE_STRING_GOTHIC_TOP,    AF_BLUE_PROPERTY_LATIN_TOP }
@@ -861,14 +861,14 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN:
     { AF_BLUE_STRING_MAX,           0                          }
 
   AF_BLUE_STRINGSET_GREK
-    { AF_BLUE_STRING_GREEK_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
-    { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM,  0                                 }
-    { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP,  AF_BLUE_PROPERTY_LATIN_TOP        }
+    { AF_BLUE_STRING_GREEK_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            }
+    { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM,  AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }
+    { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP,  AF_BLUE_PROPERTY_LATIN_TOP            }
     { AF_BLUE_STRING_GREEK_SMALL,           AF_BLUE_PROPERTY_LATIN_TOP      |
-                                            AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
-    { AF_BLUE_STRING_GREEK_SMALL,           0                                 }
-    { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0                                 }
-    { AF_BLUE_STRING_MAX,                   0                                 }
+                                            AF_BLUE_PROPERTY_LATIN_X_HEIGHT       }
+    { AF_BLUE_STRING_GREEK_SMALL,           0                                     }
+    { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0                                     }
+    { AF_BLUE_STRING_MAX,                   0                                     }
 
   AF_BLUE_STRINGSET_GUJR
     { AF_BLUE_STRING_GUJARATI_TOP,       AF_BLUE_PROPERTY_LATIN_TOP      |
@@ -935,34 +935,34 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN:
     { AF_BLUE_STRING_MAX,                0                                 }
 
   AF_BLUE_STRINGSET_LATN
-    { AF_BLUE_STRING_LATIN_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
-    { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM,  0                                 }
-    { AF_BLUE_STRING_LATIN_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
+    { AF_BLUE_STRING_LATIN_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            }
+    { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM,  AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }
+    { AF_BLUE_STRING_LATIN_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            }
     { AF_BLUE_STRING_LATIN_SMALL_TOP,       AF_BLUE_PROPERTY_LATIN_TOP      |
-                                            AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
-    { AF_BLUE_STRING_LATIN_SMALL_BOTTOM,    0                                 }
-    { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0                                 }
-    { AF_BLUE_STRING_MAX,                   0                                 }
+                                            AF_BLUE_PROPERTY_LATIN_X_HEIGHT       }
+    { AF_BLUE_STRING_LATIN_SMALL_BOTTOM,    AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM   }
+    { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0                                     }
+    { AF_BLUE_STRING_MAX,                   0                                     }
 
   AF_BLUE_STRINGSET_LATB
-    { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
-    { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM,  0                                 }
-    { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
+    { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            }
+    { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM,  AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }
+    { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            }
     { AF_BLUE_STRING_LATIN_SUBS_SMALL,           AF_BLUE_PROPERTY_LATIN_TOP      |
-                                                 AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
-    { AF_BLUE_STRING_LATIN_SUBS_SMALL,           0                                 }
-    { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0                                 }
-    { AF_BLUE_STRING_MAX,                        0                                 }
+                                                 AF_BLUE_PROPERTY_LATIN_X_HEIGHT       }
+    { AF_BLUE_STRING_LATIN_SUBS_SMALL,           0                                     }
+    { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0                                     }
+    { AF_BLUE_STRING_MAX,                        0                                     }
 
   AF_BLUE_STRINGSET_LATP
-    { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
-    { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM,  0                                 }
-    { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
+    { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            }
+    { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM,  AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }
+    { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            }
     { AF_BLUE_STRING_LATIN_SUPS_SMALL,           AF_BLUE_PROPERTY_LATIN_TOP      |
-                                                 AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
-    { AF_BLUE_STRING_LATIN_SUPS_SMALL,           0                                 }
-    { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0                                 }
-    { AF_BLUE_STRING_MAX,                        0                                 }
+                                                 AF_BLUE_PROPERTY_LATIN_X_HEIGHT       }
+    { AF_BLUE_STRING_LATIN_SUPS_SMALL,           0                                     }
+    { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0                                     }
+    { AF_BLUE_STRING_MAX,                        0                                     }
 
   AF_BLUE_STRINGSET_LISU
     { AF_BLUE_STRING_LISU_TOP,    AF_BLUE_PROPERTY_LATIN_TOP }
@@ -975,15 +975,15 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN:
     { AF_BLUE_STRING_MAX,              0                          }
 
   AF_BLUE_STRINGSET_MEDF
-    { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
-    { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM,  0                                 }
-    { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
+    { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            }
+    { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM,  AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }
+    { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP            }
     { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP,       AF_BLUE_PROPERTY_LATIN_TOP      |
-                                                  AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
-    { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM,    0                                 }
-    { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER, 0                                 }
-    { AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP,       AF_BLUE_PROPERTY_LATIN_TOP        }
-    { AF_BLUE_STRING_MAX,                         0                                 }
+                                                  AF_BLUE_PROPERTY_LATIN_X_HEIGHT       }
+    { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM,    AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM   }
+    { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER, 0                                     }
+    { AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP,       AF_BLUE_PROPERTY_LATIN_TOP            }
+    { AF_BLUE_STRING_MAX,                         0                                     }
 
   AF_BLUE_STRINGSET_MONG
     { AF_BLUE_STRING_MONGOLIAN_TOP_BASE,    AF_BLUE_PROPERTY_LATIN_TOP }
@@ -999,12 +999,12 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN:
     { AF_BLUE_STRING_MAX,               0                                 }
 
   AF_BLUE_STRINGSET_NKOO
-    { AF_BLUE_STRING_NKO_TOP,          AF_BLUE_PROPERTY_LATIN_TOP        }
-    { AF_BLUE_STRING_NKO_BOTTOM,       0                                 }
+    { AF_BLUE_STRING_NKO_TOP,          AF_BLUE_PROPERTY_LATIN_TOP          }
+    { AF_BLUE_STRING_NKO_BOTTOM,       0                                   }
     { AF_BLUE_STRING_NKO_SMALL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP      |
-                                       AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
-    { AF_BLUE_STRING_NKO_SMALL_BOTTOM, 0                                 }
-    { AF_BLUE_STRING_MAX,              0                                 }
+                                       AF_BLUE_PROPERTY_LATIN_X_HEIGHT     }
+    { AF_BLUE_STRING_NKO_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }
+    { AF_BLUE_STRING_MAX,              0                                   }
 
   AF_BLUE_STRINGSET_NONE
     { AF_BLUE_STRING_MAX, 0 }
@@ -1020,15 +1020,15 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN:
     { AF_BLUE_STRING_MAX,               0                          }
 
   AF_BLUE_STRINGSET_OSGE
-    { AF_BLUE_STRING_OSAGE_CAPITAL_TOP,       AF_BLUE_PROPERTY_LATIN_TOP       }
-    { AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM,    0                                }
-    { AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0                                }
-    { AF_BLUE_STRING_OSAGE_SMALL_TOP,         AF_BLUE_PROPERTY_LATIN_TOP     |
-                                              AF_BLUE_PROPERTY_LATIN_X_HEIGHT  }
-    { AF_BLUE_STRING_OSAGE_SMALL_BOTTOM,      0                                }
-    { AF_BLUE_STRING_OSAGE_SMALL_ASCENDER,    AF_BLUE_PROPERTY_LATIN_TOP       }
-    { AF_BLUE_STRING_OSAGE_SMALL_DESCENDER,   0                                }
-    { AF_BLUE_STRING_MAX,                     0                                }
+    { AF_BLUE_STRING_OSAGE_CAPITAL_TOP,       AF_BLUE_PROPERTY_LATIN_TOP            }
+    { AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM,    AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }
+    { AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0                                     }
+    { AF_BLUE_STRING_OSAGE_SMALL_TOP,         AF_BLUE_PROPERTY_LATIN_TOP      |
+                                              AF_BLUE_PROPERTY_LATIN_X_HEIGHT       }
+    { AF_BLUE_STRING_OSAGE_SMALL_BOTTOM,      AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM   }
+    { AF_BLUE_STRING_OSAGE_SMALL_ASCENDER,    AF_BLUE_PROPERTY_LATIN_TOP            }
+    { AF_BLUE_STRING_OSAGE_SMALL_DESCENDER,   0                                     }
+    { AF_BLUE_STRING_MAX,                     0                                     }
 
   AF_BLUE_STRINGSET_OSMA
     { AF_BLUE_STRING_OSMANYA_TOP,    AF_BLUE_PROPERTY_LATIN_TOP }
@@ -1047,13 +1047,13 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN:
     { AF_BLUE_STRING_MAX,               0                          }
 
   AF_BLUE_STRINGSET_SHAW
-    { AF_BLUE_STRING_SHAVIAN_TOP,          AF_BLUE_PROPERTY_LATIN_TOP        }
-    { AF_BLUE_STRING_SHAVIAN_BOTTOM,       0                                 }
-    { AF_BLUE_STRING_SHAVIAN_DESCENDER,    0                                 }
+    { AF_BLUE_STRING_SHAVIAN_TOP,          AF_BLUE_PROPERTY_LATIN_TOP          }
+    { AF_BLUE_STRING_SHAVIAN_BOTTOM,       0                                   }
+    { AF_BLUE_STRING_SHAVIAN_DESCENDER,    0                                   }
     { AF_BLUE_STRING_SHAVIAN_SMALL_TOP,    AF_BLUE_PROPERTY_LATIN_TOP      |
-                                           AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
-    { AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, 0                                 }
-    { AF_BLUE_STRING_MAX,                  0                                 }
+                                           AF_BLUE_PROPERTY_LATIN_X_HEIGHT     }
+    { AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }
+    { AF_BLUE_STRING_MAX,                  0                                   }
 
   AF_BLUE_STRINGSET_SINH
     { AF_BLUE_STRING_SINHALA_TOP,       AF_BLUE_PROPERTY_LATIN_TOP }
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.h b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.h
index 2aa9d0984ef..5bb8406dc2b 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.h
@@ -7,7 +7,7 @@
  *
  *   Auto-fitter data for blue strings (specification).
  *
- * Copyright (C) 2013-2024 by
+ * Copyright (C) 2013-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -314,14 +314,17 @@ FT_BEGIN_HEADER
   /* Properties are specific to a writing system.  We assume that a given  */
   /* blue string can't be used in more than a single writing system, which */
   /* is a safe bet.                                                        */
-#define AF_BLUE_PROPERTY_LATIN_TOP       ( 1U << 0 )  /* must have value 1 */
+#define AF_BLUE_PROPERTY_LATIN_TOP       ( 1U << 0 )    /* must be value 1 */
 #define AF_BLUE_PROPERTY_LATIN_SUB_TOP   ( 1U << 1 )
 #define AF_BLUE_PROPERTY_LATIN_NEUTRAL   ( 1U << 2 )
 #define AF_BLUE_PROPERTY_LATIN_X_HEIGHT  ( 1U << 3 )
 #define AF_BLUE_PROPERTY_LATIN_LONG      ( 1U << 4 )
 
-#define AF_BLUE_PROPERTY_CJK_TOP    ( 1U << 0 )       /* must have value 1 */
-#define AF_BLUE_PROPERTY_CJK_HORIZ  ( 1U << 1 )       /* must have value 2 */
+#define AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM  ( 1U << 5 )
+#define AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM    ( 1U << 6 )
+
+#define AF_BLUE_PROPERTY_CJK_TOP    ( 1U << 0 )         /* must be value 1 */
+#define AF_BLUE_PROPERTY_CJK_HORIZ  ( 1U << 1 )         /* must be value 2 */
 #define AF_BLUE_PROPERTY_CJK_RIGHT  AF_BLUE_PROPERTY_CJK_TOP
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.hin b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.hin
index 38031505a85..dbac14548d5 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.hin
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.hin
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter data for blue strings (specification).
  *
- * Copyright (C) 2013-2024 by
+ * Copyright (C) 2013-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -99,14 +99,17 @@ FT_BEGIN_HEADER
   /* Properties are specific to a writing system.  We assume that a given  */
   /* blue string can't be used in more than a single writing system, which */
   /* is a safe bet.                                                        */
-#define AF_BLUE_PROPERTY_LATIN_TOP       ( 1U << 0 )  /* must have value 1 */
+#define AF_BLUE_PROPERTY_LATIN_TOP       ( 1U << 0 )    /* must be value 1 */
 #define AF_BLUE_PROPERTY_LATIN_SUB_TOP   ( 1U << 1 )
 #define AF_BLUE_PROPERTY_LATIN_NEUTRAL   ( 1U << 2 )
 #define AF_BLUE_PROPERTY_LATIN_X_HEIGHT  ( 1U << 3 )
 #define AF_BLUE_PROPERTY_LATIN_LONG      ( 1U << 4 )
 
-#define AF_BLUE_PROPERTY_CJK_TOP    ( 1U << 0 )       /* must have value 1 */
-#define AF_BLUE_PROPERTY_CJK_HORIZ  ( 1U << 1 )       /* must have value 2 */
+#define AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM  ( 1U << 5 )
+#define AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM    ( 1U << 6 )
+
+#define AF_BLUE_PROPERTY_CJK_TOP    ( 1U << 0 )         /* must be value 1 */
+#define AF_BLUE_PROPERTY_CJK_HORIZ  ( 1U << 1 )         /* must be value 2 */
 #define AF_BLUE_PROPERTY_CJK_RIGHT  AF_BLUE_PROPERTY_CJK_TOP
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c b/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c
index 869b60487c2..7086601838c 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter hinting routines for CJK writing system (body).
  *
- * Copyright (C) 2006-2024 by
+ * Copyright (C) 2006-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -90,12 +90,8 @@
 
       /* If HarfBuzz is not available, we need a pointer to a single */
       /* unsigned long value.                                        */
-#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
-      void*     shaper_buf;
-#else
       FT_ULong  shaper_buf_;
       void*     shaper_buf = &shaper_buf_;
-#endif
 
       const char*  p;
 
@@ -105,9 +101,8 @@
 
       p = script_class->standard_charstring;
 
-#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
-      shaper_buf = af_shaper_buf_create( face );
-#endif
+      if ( ft_hb_enabled( metrics->root.globals ) )
+        shaper_buf = af_shaper_buf_create( metrics->root.globals );
 
       /* We check a list of standard characters.  The first match wins. */
 
@@ -144,7 +139,7 @@
           break;
       }
 
-      af_shaper_buf_destroy( face, shaper_buf );
+      af_shaper_buf_destroy( metrics->root.globals, shaper_buf );
 
       if ( !glyph_index )
         goto Exit;
@@ -152,7 +147,7 @@
       if ( !glyph_index )
         goto Exit;
 
-      FT_TRACE5(( "standard character: U+%04lX (glyph index %ld)\n",
+      FT_TRACE5(( "standard character: U+%04lX (glyph index %lu)\n",
                   ch, glyph_index ));
 
       error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
@@ -297,12 +292,8 @@
 
     /* If HarfBuzz is not available, we need a pointer to a single */
     /* unsigned long value.                                        */
-#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
-    void*     shaper_buf;
-#else
     FT_ULong  shaper_buf_;
     void*     shaper_buf = &shaper_buf_;
-#endif
 
 
     /* we walk over the blue character strings as specified in the   */
@@ -313,9 +304,8 @@
     FT_TRACE5(( "==========================\n" ));
     FT_TRACE5(( "\n" ));
 
-#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
-    shaper_buf = af_shaper_buf_create( face );
-#endif
+    if ( ft_hb_enabled( metrics->root.globals ) )
+      shaper_buf = af_shaper_buf_create( metrics->root.globals );
 
     for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
     {
@@ -340,7 +330,7 @@
         };
 
 
-        FT_TRACE5(( "blue zone %d (%s):\n",
+        FT_TRACE5(( "blue zone %u (%s):\n",
                     axis->blue_count,
                     cjk_blue_name[AF_CJK_IS_HORIZ_BLUE( bs ) |
                                   AF_CJK_IS_TOP_BLUE( bs )   ] ));
@@ -553,7 +543,7 @@
 
     } /* end for loop */
 
-    af_shaper_buf_destroy( face, shaper_buf );
+    af_shaper_buf_destroy( metrics->root.globals, shaper_buf );
 
     FT_TRACE5(( "\n" ));
 
@@ -572,23 +562,20 @@
 
     /* If HarfBuzz is not available, we need a pointer to a single */
     /* unsigned long value.                                        */
-#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
-    void*     shaper_buf;
-#else
     FT_ULong  shaper_buf_;
     void*     shaper_buf = &shaper_buf_;
-#endif
 
     /* in all supported charmaps, digits have character codes 0x30-0x39 */
     const char   digits[] = "0 1 2 3 4 5 6 7 8 9";
     const char*  p;
 
+    FT_UNUSED( face );
+
 
     p = digits;
 
-#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
-    shaper_buf = af_shaper_buf_create( face );
-#endif
+    if ( ft_hb_enabled( metrics->root.globals ) )
+      shaper_buf = af_shaper_buf_create( metrics->root.globals );
 
     while ( *p )
     {
@@ -624,7 +611,7 @@
       }
     }
 
-    af_shaper_buf_destroy( face, shaper_buf );
+    af_shaper_buf_destroy( metrics->root.globals, shaper_buf );
 
     metrics->root.digits_have_same_width = same_width;
   }
@@ -710,7 +697,7 @@
         FT_Pos  delta1, delta2;
 
 
-        blue->ref.fit  = FT_PIX_ROUND( blue->ref.cur );
+        blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
 
         /* shoot is under shoot for cjk */
         delta1 = FT_DivFix( blue->ref.fit, scale ) - blue->shoot.org;
@@ -736,7 +723,7 @@
 
         blue->shoot.fit = blue->ref.fit - delta2;
 
-        FT_TRACE5(( ">> active cjk blue zone %c%d[%ld/%ld]:\n",
+        FT_TRACE5(( ">> active cjk blue zone %c%u[%ld/%ld]:\n",
                     ( dim == AF_DIMENSION_HORZ ) ? 'H' : 'V',
                     nn, blue->ref.org, blue->shoot.org ));
         FT_TRACE5(( "     ref:   cur=%.2f fit=%.2f\n",
@@ -1378,7 +1365,7 @@
   }
 
 
-  /* Initalize hinting engine. */
+  /* Initialize hinting engine. */
 
   FT_LOCAL_DEF( FT_Error )
   af_cjk_hints_init( AF_GlyphHints    hints,
@@ -2185,7 +2172,7 @@
   af_cjk_align_edge_points( AF_GlyphHints  hints,
                             AF_Dimension   dim )
   {
-    AF_AxisHints  axis       = & hints->axis[dim];
+    AF_AxisHints  axis       = &hints->axis[dim];
     AF_Edge       edges      = axis->edges;
     AF_Edge       edge_limit = FT_OFFSET( edges, axis->num_edges );
     AF_Edge       edge;
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h b/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h
index bc5aaf12e6e..bd1b39358e0 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter hinting routines for CJK writing system (specification).
  *
- * Copyright (C) 2006-2024 by
+ * Copyright (C) 2006-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afcover.h b/src/java.desktop/share/native/libfreetype/src/autofit/afcover.h
index 7980cf2e979..b93bcd1a2c5 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afcover.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afcover.h
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter coverages (specification only).
  *
- * Copyright (C) 2013-2024 by
+ * Copyright (C) 2013-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.c b/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.c
index ad667d2edc7..8613544f913 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.c
@@ -5,7 +5,7 @@
  *   Auto-fitter dummy routines to be used if no hinting should be
  *   performed (body).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.h b/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.h
index 613c2f88a38..78a79439d95 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.h
@@ -5,7 +5,7 @@
  *   Auto-fitter dummy routines to be used if no hinting should be
  *   performed (specification).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/aferrors.h b/src/java.desktop/share/native/libfreetype/src/autofit/aferrors.h
index ae584ff06db..f3093fc90df 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/aferrors.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/aferrors.h
@@ -4,7 +4,7 @@
  *
  *   Autofitter error codes (specification only).
  *
- * Copyright (C) 2005-2024 by
+ * Copyright (C) 2005-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c b/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c
index b7403fa65e1..e74d8141161 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter routines to compute global hinting values (body).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -22,6 +22,11 @@
 #include "afws-decl.h"
 #include 
 
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
+#  include "afgsub.h"
+#  include "ft-hb-ft.h"
+#endif
+
 
   /**************************************************************************
    *
@@ -184,7 +189,7 @@
           if ( gindex != 0                                                &&
                gindex < globals->glyph_count                              &&
                ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
-            gstyles[gindex] = ss;
+            gstyles[gindex] = ss | AF_HAS_CMAP_ENTRY;
 
           for (;;)
           {
@@ -195,7 +200,7 @@
 
             if ( gindex < globals->glyph_count                              &&
                  ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
-              gstyles[gindex] = ss;
+              gstyles[gindex] = ss | AF_HAS_CMAP_ENTRY;
           }
         }
 
@@ -301,7 +306,7 @@
           if ( !( count % 10 ) )
             FT_TRACE4(( " " ));
 
-          FT_TRACE4(( " %d", idx ));
+          FT_TRACE4(( " %u", idx ));
           count++;
 
           if ( !( count % 10 ) )
@@ -356,8 +361,21 @@
     globals->scale_down_factor         = 0;
 
 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
-    globals->hb_font = hb_ft_font_create_( face, NULL );
-    globals->hb_buf  = hb_buffer_create();
+    if ( ft_hb_enabled ( globals ) )
+    {
+      globals->hb_font = ft_hb_ft_font_create( globals );
+      globals->hb_buf  = hb( buffer_create )();
+
+      af_parse_gsub( globals );
+    }
+    else
+    {
+      globals->hb_font = NULL;
+      globals->hb_buf  = NULL;
+
+      globals->gsub                          = NULL;
+      globals->gsub_lookups_single_alternate = NULL;
+    }
 #endif
 
     error = af_face_globals_compute_style_coverage( globals );
@@ -405,8 +423,14 @@
       }
 
 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
-      hb_font_destroy( globals->hb_font );
-      hb_buffer_destroy( globals->hb_buf );
+      if ( ft_hb_enabled ( globals ) )
+      {
+        hb( font_destroy )( globals->hb_font );
+        hb( buffer_destroy )( globals->hb_buf );
+
+        FT_FREE( globals->gsub );
+        FT_FREE( globals->gsub_lookups_single_alternate );
+      }
 #endif
 
       /* no need to free `globals->glyph_styles'; */
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h b/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h
index ddb54c89b27..dc061159492 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h
@@ -5,7 +5,7 @@
  *   Auto-fitter routines to compute global hinting values
  *   (specification).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -73,15 +73,17 @@ FT_BEGIN_HEADER
   /* default script for OpenType; ignored if HarfBuzz isn't used */
 #define AF_SCRIPT_DEFAULT    AF_SCRIPT_LATN
 
-  /* a bit mask for AF_DIGIT and AF_NONBASE */
-#define AF_STYLE_MASK        0x3FFF
+  /* a bit mask for AF_DIGIT, AF_NONBASE, and AF_HAS_CMAP_ENTRY */
+#define AF_STYLE_MASK        0x1FFF
   /* an uncovered glyph      */
 #define AF_STYLE_UNASSIGNED  AF_STYLE_MASK
 
-  /* if this flag is set, we have an ASCII digit   */
+  /* if this flag is set, we have an ASCII digit */
 #define AF_DIGIT             0x8000U
   /* if this flag is set, we have a non-base character */
 #define AF_NONBASE           0x4000U
+  /* if this flag is set, the glyph has a (direct) cmap entry */
+#define AF_HAS_CMAP_ENTRY    0x2000U
 
   /* `increase-x-height' property */
 #define AF_PROP_INCREASE_X_HEIGHT_MIN  6
@@ -111,6 +113,13 @@ FT_BEGIN_HEADER
 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
     hb_font_t*       hb_font;
     hb_buffer_t*     hb_buf;           /* for feature comparison */
+
+    /* The GSUB table. */
+    FT_Byte*         gsub;
+    /* An array of lookup offsets (of `gsub_lookup_count` elements), */
+    /* with only SingleSubst and AlternateSubst lookups non-NULL.    */
+    FT_UShort        gsub_lookup_count;
+    FT_UInt32*       gsub_lookups_single_alternate;
 #endif
 
     /* per-face auto-hinter properties */
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c b/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c
index 96ffe343aa4..11faa655f62 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter hinting routines (body).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -840,6 +840,10 @@
 
     if ( hints->contours != hints->embedded.contours )
       FT_FREE( hints->contours );
+    if ( hints->contour_y_minima != hints->embedded.contour_y_minima )
+      FT_FREE( hints->contour_y_minima );
+    if ( hints->contour_y_maxima != hints->embedded.contour_y_maxima )
+      FT_FREE( hints->contour_y_maxima );
     hints->max_contours = 0;
     hints->num_contours = 0;
 
@@ -896,19 +900,30 @@
     {
       if ( !hints->contours )
       {
-        hints->contours     = hints->embedded.contours;
+        hints->contours         = hints->embedded.contours;
+        hints->contour_y_minima = hints->embedded.contour_y_minima;
+        hints->contour_y_maxima = hints->embedded.contour_y_maxima;
+
         hints->max_contours = AF_CONTOURS_EMBEDDED;
       }
     }
     else if ( new_max > old_max )
     {
       if ( hints->contours == hints->embedded.contours )
-        hints->contours = NULL;
+      {
+        hints->contours         = NULL;
+        hints->contour_y_minima = NULL;
+        hints->contour_y_maxima = NULL;
+      }
 
       new_max = ( new_max + 3 ) & ~3; /* round up to a multiple of 4 */
 
       if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
         goto Exit;
+      if ( FT_RENEW_ARRAY( hints->contour_y_minima, old_max, new_max ) )
+        goto Exit;
+      if ( FT_RENEW_ARRAY( hints->contour_y_maxima, old_max, new_max ) )
+        goto Exit;
 
       hints->max_contours = new_max;
     }
@@ -1324,7 +1339,7 @@
   af_glyph_hints_align_edge_points( AF_GlyphHints  hints,
                                     AF_Dimension   dim )
   {
-    AF_AxisHints  axis          = & hints->axis[dim];
+    AF_AxisHints  axis          = &hints->axis[dim];
     AF_Segment    segments      = axis->segments;
     AF_Segment    segment_limit = FT_OFFSET( segments, axis->num_segments );
     AF_Segment    seg;
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afhints.h b/src/java.desktop/share/native/libfreetype/src/autofit/afhints.h
index 76fe83006a5..46b3ed3366f 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afhints.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afhints.h
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter hinting routines (specification).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -222,6 +222,9 @@ FT_BEGIN_HEADER
   /* the distance to the next point is very small */
 #define AF_FLAG_NEAR  ( 1U << 5 )
 
+  /* prevent the auto-hinter from adding such a point to a segment */
+#define AF_FLAG_IGNORE  ( 1U << 6 )
+
 
   /* edge hint flags */
 #define AF_EDGE_NORMAL  0
@@ -229,6 +232,7 @@ FT_BEGIN_HEADER
 #define AF_EDGE_SERIF    ( 1U << 1 )
 #define AF_EDGE_DONE     ( 1U << 2 )
 #define AF_EDGE_NEUTRAL  ( 1U << 3 ) /* edge aligns to a neutral blue zone */
+#define AF_EDGE_NO_BLUE  ( 1U << 4 ) /* do not align edge to blue zone     */
 
 
   typedef struct AF_PointRec_*    AF_Point;
@@ -303,6 +307,7 @@ FT_BEGIN_HEADER
 
   } AF_EdgeRec;
 
+
 #define AF_SEGMENTS_EMBEDDED  18   /* number of embedded segments   */
 #define AF_EDGES_EMBEDDED     12   /* number of embedded edges      */
 
@@ -346,9 +351,11 @@ FT_BEGIN_HEADER
     FT_Int           num_points;    /* number of used points      */
     AF_Point         points;        /* points array               */
 
-    FT_Int           max_contours;  /* number of allocated contours */
-    FT_Int           num_contours;  /* number of used contours      */
-    AF_Point*        contours;      /* contours array               */
+    FT_Int           max_contours;     /* number of allocated contours    */
+    FT_Int           num_contours;     /* number of used contours         */
+    AF_Point*        contours;         /* contours array                  */
+    FT_Pos*          contour_y_minima; /* array with y maxima of contours */
+    FT_Pos*          contour_y_maxima; /* array with y minima of contours */
 
     AF_AxisHintsRec  axis[AF_DIMENSION_MAX];
 
@@ -357,11 +364,13 @@ FT_BEGIN_HEADER
                                     /* implementations         */
     AF_StyleMetrics  metrics;
 
-    /* Two arrays to avoid allocation penalty.            */
+    /* Some arrays to avoid allocation penalty.           */
     /* The `embedded' structure must be the last element! */
     struct
     {
       AF_Point       contours[AF_CONTOURS_EMBEDDED];
+      FT_Pos         contour_y_minima[AF_CONTOURS_EMBEDDED];
+      FT_Pos         contour_y_maxima[AF_CONTOURS_EMBEDDED];
       AF_PointRec    points[AF_POINTS_EMBEDDED];
     } embedded;
 
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c b/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c
index c6d23efd86f..a2cd14f8817 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter hinting routines for Indic writing system (body).
  *
- * Copyright (C) 2007-2024 by
+ * Copyright (C) 2007-2025 by
  * Rahul Bhalerao , .
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afindic.h b/src/java.desktop/share/native/libfreetype/src/autofit/afindic.h
index a7f73f25153..a2e825e9f86 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afindic.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afindic.h
@@ -5,7 +5,7 @@
  *   Auto-fitter hinting routines for Indic writing system
  *   (specification).
  *
- * Copyright (C) 2007-2024 by
+ * Copyright (C) 2007-2025 by
  * Rahul Bhalerao , .
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c
index 89287f7ea5a..4a42d919474 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter hinting routines for latin writing system (body).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -22,6 +22,7 @@
 #include "afglobal.h"
 #include "aflatin.h"
 #include "aferrors.h"
+#include "afadjust.h"
 
 
   /**************************************************************************
@@ -81,12 +82,8 @@
 
       /* If HarfBuzz is not available, we need a pointer to a single */
       /* unsigned long value.                                        */
-#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
-      void*     shaper_buf;
-#else
       FT_ULong  shaper_buf_;
       void*     shaper_buf = &shaper_buf_;
-#endif
 
       const char*  p;
 
@@ -97,9 +94,9 @@
 
       p = script_class->standard_charstring;
 
-#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
-      shaper_buf = af_shaper_buf_create( face );
-#endif
+      if ( ft_hb_enabled ( metrics->root.globals ) )
+        shaper_buf = af_shaper_buf_create( metrics->root.globals );
+
       /*
        * We check a list of standard characters to catch features like
        * `c2sc' (small caps from caps) that don't contain lowercase letters
@@ -140,7 +137,7 @@
           break;
       }
 
-      af_shaper_buf_destroy( face, shaper_buf );
+      af_shaper_buf_destroy( metrics->root.globals, shaper_buf );
 
       if ( !glyph_index )
       {
@@ -149,7 +146,7 @@
         goto Exit;
       }
 
-      FT_TRACE5(( "standard character: U+%04lX (glyph index %ld)\n",
+      FT_TRACE5(( "standard character: U+%04lX (glyph index %lu)\n",
                   ch, glyph_index ));
 
       error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
@@ -334,12 +331,8 @@
 
     /* If HarfBuzz is not available, we need a pointer to a single */
     /* unsigned long value.                                        */
-#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
-    void*     shaper_buf;
-#else
     FT_ULong  shaper_buf_;
     void*     shaper_buf = &shaper_buf_;
-#endif
 
 
     /* we walk over the blue character strings as specified in the */
@@ -349,9 +342,8 @@
     FT_TRACE5(( "============================\n" ));
     FT_TRACE5(( "\n" ));
 
-#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
-    shaper_buf = af_shaper_buf_create( face );
-#endif
+    if ( ft_hb_enabled ( metrics->root.globals ) )
+      shaper_buf = af_shaper_buf_create( metrics->root.globals );
 
     for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
     {
@@ -367,7 +359,7 @@
         FT_Bool  have_flag = 0;
 
 
-        FT_TRACE5(( "blue zone %d", axis->blue_count ));
+        FT_TRACE5(( "blue zone %u", axis->blue_count ));
 
         if ( bs->properties )
         {
@@ -407,6 +399,20 @@
             FT_TRACE5(( "long" ));
           }
 
+          if ( AF_LATIN_IS_CAPITAL_BOTTOM_BLUE( bs ) )
+          {
+            if ( have_flag )
+              FT_TRACE5(( ", " ));
+            FT_TRACE5(( "capital bottom" ));
+          }
+
+          if ( AF_LATIN_IS_SMALL_BOTTOM_BLUE( bs ) )
+          {
+            if ( have_flag )
+              FT_TRACE5(( ", " ));
+            FT_TRACE5(( "small bottom" ));
+          }
+
           FT_TRACE5(( ")" ));
         }
 
@@ -454,9 +460,9 @@
         }
 
         if ( AF_LATIN_IS_TOP_BLUE( bs ) )
-          best_y_extremum = FT_INT_MIN;
+          best_y_extremum = FT_LONG_MIN;
         else
-          best_y_extremum = FT_INT_MAX;
+          best_y_extremum = FT_LONG_MAX;
 
         /* iterate over all glyph elements of the character cluster */
         /* and get the data of the `biggest' one                    */
@@ -487,7 +493,7 @@
             if ( num_idx == 1 )
               FT_TRACE5(( "  U+%04lX contains no (usable) outlines\n", ch ));
             else
-              FT_TRACE5(( "  component %d of cluster starting with U+%04lX"
+              FT_TRACE5(( "  component %u of cluster starting with U+%04lX"
                           " contains no (usable) outlines\n", i, ch ));
 #endif
             continue;
@@ -825,7 +831,7 @@
             if ( num_idx == 1 )
               FT_TRACE5(( "  U+%04lX: best_y = %5ld", ch, best_y ));
             else
-              FT_TRACE5(( "  component %d of cluster starting with U+%04lX:"
+              FT_TRACE5(( "  component %u of cluster starting with U+%04lX:"
                           " best_y = %5ld", i, ch, best_y ));
 #endif
 
@@ -879,8 +885,8 @@
 
         } /* end for loop */
 
-        if ( !( best_y_extremum == FT_INT_MIN ||
-                best_y_extremum == FT_INT_MAX ) )
+        if ( !( best_y_extremum == FT_LONG_MIN ||
+                best_y_extremum == FT_LONG_MAX ) )
         {
           if ( best_round )
             rounds[num_rounds++] = best_y_extremum;
@@ -959,6 +965,10 @@
         blue->flags |= AF_LATIN_BLUE_SUB_TOP;
       if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
         blue->flags |= AF_LATIN_BLUE_NEUTRAL;
+      if ( AF_LATIN_IS_CAPITAL_BOTTOM_BLUE( bs ) )
+        blue->flags |= AF_LATIN_BLUE_BOTTOM;
+      if ( AF_LATIN_IS_SMALL_BOTTOM_BLUE( bs ) )
+        blue->flags |= AF_LATIN_BLUE_BOTTOM_SMALL;
 
       /*
        * The following flag is used later to adjust the y and x scales
@@ -973,7 +983,7 @@
 
     } /* end for loop */
 
-    af_shaper_buf_destroy( face, shaper_buf );
+    af_shaper_buf_destroy( metrics->root.globals, shaper_buf );
 
     if ( axis->blue_count )
     {
@@ -1070,23 +1080,20 @@
 
     /* If HarfBuzz is not available, we need a pointer to a single */
     /* unsigned long value.                                        */
-#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
-    void*     shaper_buf;
-#else
     FT_ULong  shaper_buf_;
     void*     shaper_buf = &shaper_buf_;
-#endif
 
     /* in all supported charmaps, digits have character codes 0x30-0x39 */
     const char   digits[] = "0 1 2 3 4 5 6 7 8 9";
     const char*  p;
 
+    FT_UNUSED( face );
+
 
     p = digits;
 
-#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
-    shaper_buf = af_shaper_buf_create( face );
-#endif
+    if ( ft_hb_enabled ( metrics->root.globals ) )
+      shaper_buf = af_shaper_buf_create( metrics->root.globals );
 
     while ( *p )
     {
@@ -1122,7 +1129,7 @@
       }
     }
 
-    af_shaper_buf_destroy( face, shaper_buf );
+    af_shaper_buf_destroy( metrics->root.globals, shaper_buf );
 
     metrics->root.digits_have_same_width = same_width;
   }
@@ -1155,6 +1162,9 @@
       af_latin_metrics_check_digits( metrics, face );
     }
 
+    af_reverse_character_map_new( &metrics->root.reverse_charmap,
+                                  &metrics->root );
+
   Exit:
     face->charmap = oldmap;
     return error;
@@ -1263,7 +1273,7 @@
               max_height = FT_MAX( max_height, -Axis->blues[nn].descender );
             }
 
-            dist  = FT_MulFix( max_height, new_scale - scale );
+            dist = FT_MulFix( max_height, new_scale - scale );
 
             if ( -128 < dist && dist < 128 )
             {
@@ -1466,13 +1476,13 @@
         AF_LatinBlue  blue = &axis->blues[nn];
 
 
-        FT_TRACE5(( "  reference %d: %ld scaled to %.2f%s\n",
+        FT_TRACE5(( "  reference %u: %ld scaled to %.2f%s\n",
                     nn,
                     blue->ref.org,
                     (double)blue->ref.fit / 64,
                     ( blue->flags & AF_LATIN_BLUE_ACTIVE ) ? ""
                                                            : " (inactive)" ));
-        FT_TRACE5(( "  overshoot %d: %ld scaled to %.2f%s\n",
+        FT_TRACE5(( "  overshoot %u: %ld scaled to %.2f%s\n",
                     nn,
                     blue->shoot.org,
                     (double)blue->shoot.fit / 64,
@@ -1484,6 +1494,17 @@
   }
 
 
+  FT_CALLBACK_DEF( void )
+  af_latin_metrics_done( AF_StyleMetrics  metrics_ )
+  {
+    AF_LatinMetrics  metrics = (AF_LatinMetrics)metrics_;
+
+
+    af_reverse_character_map_done( metrics->root.reverse_charmap,
+                                   metrics->root.globals->face->memory );
+  }
+
+
   /* Scale global values in both directions. */
 
   FT_LOCAL_DEF( void )
@@ -1617,7 +1638,8 @@
       FT_Pos     prev_max_on_coord = max_on_coord;
 
 
-      if ( FT_ABS( last->out_dir )  == major_dir &&
+      if ( !( point->flags & AF_FLAG_IGNORE )    &&
+           FT_ABS( last->out_dir )  == major_dir &&
            FT_ABS( point->out_dir ) == major_dir )
       {
         /* we are already on an edge, try to locate its start */
@@ -1676,13 +1698,17 @@
               max_on_coord = v;
           }
 
-          if ( point->out_dir != segment_dir || point == last )
+          if ( point->flags & AF_FLAG_IGNORE ||
+               point->out_dir != segment_dir ||
+               point == last )
           {
             /* check whether the new segment's start point is identical to */
             /* the previous segment's end point; for example, this might   */
             /* happen for spikes                                           */
 
-            if ( !prev_segment || segment->first != prev_segment->last )
+            if ( point->flags & AF_FLAG_IGNORE        ||
+                 !prev_segment                        ||
+                 segment->first != prev_segment->last )
             {
               /* points are different: we are just leaving an edge, thus */
               /* record a new segment                                    */
@@ -1842,7 +1868,8 @@
         /* if we are not on an edge, check whether the major direction */
         /* coincides with the current point's `out' direction, or      */
         /* whether we have a single-point contour                      */
-        if ( !on_edge                                  &&
+        if ( !( point->flags & AF_FLAG_IGNORE )        &&
+             !on_edge                                  &&
              ( FT_ABS( point->out_dir ) == major_dir ||
                point == point->prev                  ) )
         {
@@ -2521,6 +2548,9 @@
       FT_Pos    best_dist;                 /* initial threshold */
 
 
+      if ( edge->flags & AF_EDGE_NO_BLUE )
+        continue;
+
       /* compute the initial threshold as a fraction of the EM size */
       /* (the value 40 is heuristic)                                */
       best_dist = FT_MulFix( metrics->units_per_em / 40, scale );
@@ -2610,7 +2640,7 @@
   }
 
 
-  /* Initalize hinting engine. */
+  /* Initialize hinting engine. */
 
   static FT_Error
   af_latin_hints_init( AF_GlyphHints    hints,
@@ -2737,247 +2767,1439 @@
   }
 
 
-  /* Compute the snapped width of a given stem, ignoring very thin ones. */
-  /* There is a lot of voodoo in this function; changing the hard-coded  */
-  /* parameters influence the whole hinting process.                     */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  afadjust
 
-  static FT_Pos
-  af_latin_compute_stem_width( AF_GlyphHints  hints,
-                               AF_Dimension   dim,
-                               FT_Pos         width,
-                               FT_Pos         base_delta,
-                               FT_UInt        base_flags,
-                               FT_UInt        stem_flags )
+
+  static void
+  af_move_contour_vertically( AF_Point  contour,
+                              FT_Int    movement )
   {
-    AF_LatinMetrics  metrics  = (AF_LatinMetrics)hints->metrics;
-    AF_LatinAxis     axis     = &metrics->axis[dim];
-    FT_Pos           dist     = width;
-    FT_Int           sign     = 0;
-    FT_Int           vertical = ( dim == AF_DIMENSION_VERT );
+    AF_Point  point       = contour;
+    AF_Point  first_point = point;
 
 
-    if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ||
-         axis->extra_light                       )
-      return width;
+    if ( point )
+    {
+      do
+      {
+        point->y += movement;
+        point     = point->next;
 
-    if ( dist < 0 )
+      } while ( point != first_point );
+    }
+  }
+
+
+  /* Move all contours higher than `limit` by `delta`. */
+  static void
+  af_move_contours_up( AF_GlyphHints  hints,
+                       FT_Pos         limit,
+                       FT_Pos         delta )
+  {
+    FT_Int  contour;
+
+
+    for ( contour = 0; contour < hints->num_contours; contour++ )
     {
-      dist = -width;
-      sign = 1;
+      FT_Pos  min_y = hints->contour_y_minima[contour];
+      FT_Pos  max_y = hints->contour_y_maxima[contour];
+
+
+      if ( min_y < max_y &&
+           min_y > limit )
+        af_move_contour_vertically( hints->contours[contour],
+                                    delta );
     }
+  }
 
-    if ( (  vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
-         ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
+
+  static void
+  af_move_contours_down( AF_GlyphHints  hints,
+                         FT_Pos         limit,
+                         FT_Pos         delta )
+  {
+    FT_Int  contour;
+
+
+    for ( contour = 0; contour < hints->num_contours; contour++ )
     {
-      /* smooth hinting process: very lightly quantize the stem width */
+      FT_Pos  min_y = hints->contour_y_minima[contour];
+      FT_Pos  max_y = hints->contour_y_maxima[contour];
 
-      /* leave the widths of serifs alone */
-      if ( ( stem_flags & AF_EDGE_SERIF ) &&
-           vertical                       &&
-           ( dist < 3 * 64 )              )
-        goto Done_Width;
 
-      else if ( base_flags & AF_EDGE_ROUND )
-      {
-        if ( dist < 80 )
-          dist = 64;
-      }
-      else if ( dist < 56 )
-        dist = 56;
+      if ( min_y < max_y &&
+           max_y < limit )
+        af_move_contour_vertically( hints->contours[contour],
+                                    -delta );
+    }
+  }
 
-      if ( axis->width_count > 0 )
-      {
-        FT_Pos  delta;
 
+  /* Compute vertical extrema of all contours and store them in the */
+  /* `contour_y_minima` and `contour_y_maxima` arrays of `hints`.   */
+  static void
+  af_compute_vertical_extrema( AF_GlyphHints  hints )
+  {
+    FT_Int  contour;
 
-        /* compare to standard width */
-        delta = dist - axis->widths[0].cur;
 
-        if ( delta < 0 )
-          delta = -delta;
+    for ( contour = 0; contour < hints->num_contours; contour++ )
+    {
+      FT_Pos  min_y = FT_LONG_MAX;
+      FT_Pos  max_y = FT_LONG_MIN;
 
-        if ( delta < 40 )
-        {
-          dist = axis->widths[0].cur;
-          if ( dist < 48 )
-            dist = 48;
+      AF_Point  first_point = hints->contours[contour];
+      AF_Point  point       = first_point;
 
-          goto Done_Width;
-        }
 
-        if ( dist < 3 * 64 )
-        {
-          delta  = dist & 63;
-          dist  &= -64;
+      if ( !first_point || first_point->next->next == first_point )
+        goto End_loop;
 
-          if ( delta < 10 )
-            dist += delta;
+      do
+      {
+        if ( point->y < min_y )
+          min_y = point->y;
+        if ( point->y > max_y )
+          max_y = point->y;
 
-          else if ( delta < 32 )
-            dist += 10;
+        point = point->next;
 
-          else if ( delta < 54 )
-            dist += 54;
+      } while ( point != first_point );
 
-          else
-            dist += delta;
-        }
-        else
-        {
-          /* A stem's end position depends on two values: the start        */
-          /* position and the stem length.  The former gets usually        */
-          /* rounded to the grid, while the latter gets rounded also if it */
-          /* exceeds a certain length (see below in this function).  This  */
-          /* `double rounding' can lead to a great difference to the       */
-          /* original, unhinted position; this normally doesn't matter for */
-          /* large PPEM values, but for small sizes it can easily make     */
-          /* outlines collide.  For this reason, we adjust the stem length */
-          /* by a small amount depending on the PPEM value in case the     */
-          /* former and latter rounding both point into the same           */
-          /* direction.                                                    */
+    End_loop:
+      hints->contour_y_minima[contour] = min_y;
+      hints->contour_y_maxima[contour] = max_y;
+    }
+  }
 
-          FT_Pos  bdelta = 0;
 
+  static FT_Int
+  af_find_highest_contour( AF_GlyphHints  hints )
+  {
+    FT_Int  highest_contour = 0;
+    FT_Pos  highest_min_y   = FT_LONG_MAX;
+    FT_Pos  highest_max_y   = FT_LONG_MIN;
 
-          if ( ( ( width > 0 ) && ( base_delta > 0 ) ) ||
-               ( ( width < 0 ) && ( base_delta < 0 ) ) )
-          {
-            FT_UInt  ppem = metrics->root.scaler.face->size->metrics.x_ppem;
+    FT_Int  contour;
 
 
-            if ( ppem < 10 )
-              bdelta = base_delta;
-            else if ( ppem < 30 )
-              bdelta = ( base_delta * (FT_Pos)( 30 - ppem ) ) / 20;
+    /* At this point we have one 'lower' (usually the base glyph)   */
+    /* and one 'upper' object (usually the diacritic glyph).  If    */
+    /* there are more contours, they must be enclosed within either */
+    /* 'lower' or 'upper'.  To find this enclosing 'upper' contour  */
+    /* it is thus sufficient to search for the contour with the     */
+    /* highest y maximum value.                                     */
+    for ( contour = 0; contour < hints->num_contours; contour++ )
+    {
+      FT_Pos  current_min_y = hints->contour_y_minima[contour];
+      FT_Pos  current_max_y = hints->contour_y_maxima[contour];
 
-            if ( bdelta < 0 )
-              bdelta = -bdelta;
-          }
 
-          dist = ( dist - bdelta + 32 ) & ~63;
-        }
+      /* If we have two contours with the same maximum value, take */
+      /* the one that has a smaller height.                        */
+      if ( current_max_y > highest_max_y      ||
+           ( current_max_y == highest_max_y &&
+             current_min_y > highest_min_y  ) )
+      {
+        highest_min_y   = current_min_y;
+        highest_max_y   = current_max_y;
+        highest_contour = contour;
       }
     }
-    else
-    {
-      /* strong hinting process: snap the stem width to integer pixels */
 
-      FT_Pos  org_dist = dist;
+    return highest_contour;
+  }
 
 
-      dist = af_latin_snap_width( axis->widths, axis->width_count, dist );
+  static FT_Int
+  af_find_second_highest_contour( AF_GlyphHints  hints )
+  {
+    FT_Int  highest_contour;
+    FT_Pos  highest_min_y;
 
-      if ( vertical )
-      {
-        /* in the case of vertical hinting, always round */
-        /* the stem heights to integer pixels            */
+    FT_Int  second_highest_contour = 0;
+    FT_Pos  second_highest_max_y   = FT_LONG_MIN;
 
-        if ( dist >= 64 )
-          dist = ( dist + 16 ) & ~63;
-        else
-          dist = 64;
-      }
-      else
-      {
-        if ( AF_LATIN_HINTS_DO_MONO( hints ) )
-        {
-          /* monochrome horizontal hinting: snap widths to integer pixels */
-          /* with a different threshold                                   */
+    FT_Int  contour;
 
-          if ( dist < 64 )
-            dist = 64;
-          else
-            dist = ( dist + 32 ) & ~63;
-        }
-        else
-        {
-          /* for horizontal anti-aliased hinting, we adopt a more subtle */
-          /* approach: we strengthen small stems, round stems whose size */
-          /* is between 1 and 2 pixels to an integer, otherwise nothing  */
 
-          if ( dist < 48 )
-            dist = ( dist + 64 ) >> 1;
+    if ( hints->num_contours < 3 )
+      return 0;
 
-          else if ( dist < 128 )
-          {
-            /* We only round to an integer width if the corresponding */
-            /* distortion is less than 1/4 pixel.  Otherwise this     */
-            /* makes everything worse since the diagonals, which are  */
-            /* not hinted, appear a lot bolder or thinner than the    */
-            /* vertical stems.                                        */
+    highest_contour = af_find_highest_contour( hints );
+    highest_min_y   = hints->contour_y_minima[highest_contour];
 
-            FT_Pos  delta;
+    /* Search the contour with the largest vertical maximum that has a */
+    /* vertical minimum lower than the vertical minimum of the topmost */
+    /* contour.                                                        */
+    for ( contour = 0; contour < hints->num_contours; contour++ )
+    {
+      FT_Pos  current_min_y;
+      FT_Pos  current_max_y;
 
 
-            dist = ( dist + 22 ) & ~63;
-            delta = dist - org_dist;
-            if ( delta < 0 )
-              delta = -delta;
+      if ( contour == highest_contour )
+        continue;
 
-            if ( delta >= 16 )
-            {
-              dist = org_dist;
-              if ( dist < 48 )
-                dist = ( dist + 64 ) >> 1;
-            }
-          }
-          else
-            /* round otherwise to prevent color fringes in LCD mode */
-            dist = ( dist + 32 ) & ~63;
-        }
+      current_min_y = hints->contour_y_minima[contour];
+      current_max_y = hints->contour_y_maxima[contour];
+
+      if ( current_max_y > second_highest_max_y &&
+           current_min_y < highest_min_y        )
+      {
+        second_highest_max_y   = current_max_y;
+        second_highest_contour = contour;
       }
     }
 
-  Done_Width:
-    if ( sign )
-      dist = -dist;
-
-    return dist;
+    return second_highest_contour;
   }
 
 
-  /* Align one stem edge relative to the previous stem edge. */
-
-  static void
-  af_latin_align_linked_edge( AF_GlyphHints  hints,
-                              AF_Dimension   dim,
-                              AF_Edge        base_edge,
-                              AF_Edge        stem_edge )
+  static FT_Int
+  af_find_lowest_contour( AF_GlyphHints  hints )
   {
-    FT_Pos  dist, base_delta;
-    FT_Pos  fitted_width;
+    FT_Int  lowest_contour = 0;
+    FT_Pos  lowest_min_y   = FT_LONG_MAX;
+    FT_Pos  lowest_max_y   = FT_LONG_MIN;
 
+    FT_Int  contour;
 
-    dist       = stem_edge->opos - base_edge->opos;
-    base_delta = base_edge->pos - base_edge->opos;
 
-    fitted_width = af_latin_compute_stem_width( hints, dim,
-                                                dist, base_delta,
-                                                base_edge->flags,
-                                                stem_edge->flags );
+    for ( contour = 0; contour < hints->num_contours; contour++ )
+    {
+      FT_Pos  current_min_y = hints->contour_y_minima[contour];
+      FT_Pos  current_max_y = hints->contour_y_maxima[contour];
 
 
-    stem_edge->pos = base_edge->pos + fitted_width;
+      if ( current_min_y < lowest_min_y      ||
+           ( current_min_y == lowest_min_y &&
+             current_max_y < lowest_max_y  ) )
+      {
+        lowest_min_y   = current_min_y;
+        lowest_max_y   = current_max_y;
+        lowest_contour = contour;
+      }
+    }
 
-    FT_TRACE5(( "  LINK: edge %td (opos=%.2f) linked to %.2f,"
-                " dist was %.2f, now %.2f\n",
-                stem_edge - hints->axis[dim].edges,
-                (double)stem_edge->opos / 64, (double)stem_edge->pos / 64,
-                (double)dist / 64, (double)fitted_width / 64 ));
+    return lowest_contour;
   }
 
 
-  /* Shift the coordinates of the `serif' edge by the same amount */
-  /* as the corresponding `base' edge has been moved already.     */
-
-  static void
-  af_latin_align_serif_edge( AF_GlyphHints  hints,
-                             AF_Edge        base,
-                             AF_Edge        serif )
+  static FT_Int
+  af_find_second_lowest_contour( AF_GlyphHints  hints )
   {
-    FT_UNUSED( hints );
+    FT_Int  lowest_contour;
+    FT_Pos  lowest_max_y;
 
-    serif->pos = base->pos + ( serif->opos - base->opos );
+    FT_Int  second_lowest_contour = 0;
+    FT_Pos  second_lowest_min_y   = FT_LONG_MAX;
+
+    FT_Int  contour;
+
+
+    if ( hints->num_contours < 3 )
+      return 0;
+
+    lowest_contour = af_find_lowest_contour( hints );
+    lowest_max_y   = hints->contour_y_maxima[lowest_contour];
+
+    for ( contour = 0; contour < hints->num_contours; contour++ )
+    {
+      FT_Pos  current_min_y;
+      FT_Pos  current_max_y;
+
+
+      if ( contour == lowest_contour )
+        continue;
+
+      current_min_y = hints->contour_y_minima[contour];
+      current_max_y = hints->contour_y_maxima[contour];
+
+      if ( current_min_y < second_lowest_min_y &&
+           current_max_y > lowest_max_y        )
+      {
+        second_lowest_min_y   = current_min_y;
+        second_lowest_contour = contour;
+      }
+    }
+
+    return second_lowest_contour;
+  }
+
+
+  /* While aligning edges to blue zones, make the auto-hinter */
+  /* ignore the ones that are higher than `pos`.              */
+  static void
+  af_prevent_top_blue_alignment( AF_GlyphHints  hints,
+                                 FT_Pos         pos )
+  {
+    AF_AxisHints  axis = &hints->axis[AF_DIMENSION_VERT];
+
+    AF_Edge  edges      = axis->edges;
+    AF_Edge  edge_limit = FT_OFFSET( edges, axis->num_edges );
+    AF_Edge  edge;
+
+
+    for ( edge = edges; edge < edge_limit; edge++ )
+      if ( edge->pos > pos )
+        edge->flags |= AF_EDGE_NO_BLUE;
+  }
+
+
+  static void
+  af_prevent_bottom_blue_alignment( AF_GlyphHints  hints,
+                                    FT_Pos         pos )
+  {
+    AF_AxisHints  axis = &hints->axis[AF_DIMENSION_VERT];
+
+    AF_Edge  edges      = axis->edges;
+    AF_Edge  edge_limit = FT_OFFSET( edges, axis->num_edges );
+    AF_Edge  edge;
+
+
+    for ( edge = edges; edge < edge_limit; edge++ )
+      if ( edge->pos < pos )
+        edge->flags |= AF_EDGE_NO_BLUE;
+  }
+
+
+  static void
+  af_latin_get_base_glyph_blues( AF_GlyphHints  hints,
+                                 FT_Bool        is_capital,
+                                 AF_LatinBlue*  top,
+                                 AF_LatinBlue*  bottom )
+  {
+    AF_LatinMetrics  metrics = (AF_LatinMetrics)hints->metrics;
+    AF_LatinAxis     axis    = &metrics->axis[AF_DIMENSION_VERT];
+
+    FT_UInt  top_flag;
+    FT_UInt  bottom_flag;
+
+    FT_UInt  i;
+
+
+    top_flag  = is_capital ? AF_LATIN_BLUE_TOP
+                           : AF_LATIN_BLUE_ADJUSTMENT;
+    top_flag |= AF_LATIN_BLUE_ACTIVE;
+
+    for ( i = 0; i < axis->blue_count; i++ )
+      if ( ( axis->blues[i].flags & top_flag ) == top_flag )
+        break;
+    if ( i < axis->blue_count )
+      *top = &axis->blues[i];
+
+    bottom_flag  = is_capital ? AF_LATIN_BLUE_BOTTOM
+                              : AF_LATIN_BLUE_BOTTOM_SMALL;
+    bottom_flag |= AF_LATIN_BLUE_ACTIVE;
+
+    for ( i = 0; i < axis->blue_count; i++ )
+      if ( ( axis->blues[i].flags & bottom_flag ) == bottom_flag )
+        break;
+    if ( i < axis->blue_count )
+      *bottom = &axis->blues[i];
+  }
+
+
+  /* Make the auto-hinter ignore top blue zones while aligning edges. */
+  /* This affects everything that is higher than a vertical position  */
+  /* based on the lowercase or uppercase top and bottom blue zones    */
+  /* (depending on `is_capital`).                                     */
+  static void
+  af_latin_ignore_top( AF_GlyphHints  hints,
+                       AF_LatinBlue   top_blue,
+                       AF_LatinBlue   bottom_blue )
+  {
+    FT_Pos  base_glyph_height;
+    FT_Pos  limit;
+
+
+    /* Ignore blue zones that are higher than a heuristic threshold     */
+    /* (value 7 corresponds to approx. 14%, which should be sufficient  */
+    /* to exceed the height of uppercase serifs.  We also add a quarter */
+    /* of a pixel as a safety measure.                                  */
+    base_glyph_height = top_blue->shoot.cur - bottom_blue->shoot.cur;
+    limit             = top_blue->shoot.cur + base_glyph_height / 7 + 16;
+
+    af_prevent_top_blue_alignment( hints, limit );
+  }
+
+
+  static void
+  af_latin_ignore_bottom( AF_GlyphHints  hints,
+                          AF_LatinBlue   top_blue,
+                          AF_LatinBlue   bottom_blue )
+  {
+    FT_Pos  base_glyph_height;
+    FT_Pos  limit;
+
+
+    base_glyph_height = top_blue->shoot.cur - bottom_blue->shoot.cur;
+    limit             = bottom_blue->shoot.cur - base_glyph_height / 7 - 16;
+
+    af_prevent_bottom_blue_alignment( hints, limit );
+  }
+
+
+  static void
+  af_touch_contour( AF_GlyphHints  hints,
+                    FT_Int         contour )
+  {
+    AF_Point  first_point = hints->contours[contour];
+    AF_Point  p           = first_point;
+
+
+    do
+    {
+      p = p->next;
+
+      p->flags |= AF_FLAG_IGNORE;
+      if ( !( p->flags & AF_FLAG_CONTROL ) )
+        p->flags |= AF_FLAG_TOUCH_Y;
+
+    } while ( p != first_point );
+  }
+
+
+  static void
+  af_touch_top_contours( AF_GlyphHints  hints,
+                         FT_Int         limit_contour )
+  {
+    FT_Pos  limit = hints->contour_y_minima[limit_contour];
+
+    FT_Int  contour;
+
+
+    for ( contour = 0; contour < hints->num_contours; contour++ )
+    {
+      FT_Pos  min_y = hints->contour_y_minima[contour];
+      FT_Pos  max_y = hints->contour_y_maxima[contour];
+
+
+      if ( min_y < max_y  &&
+           min_y >= limit )
+        af_touch_contour( hints, contour );
+    }
+  }
+
+
+  static void
+  af_touch_bottom_contours( AF_GlyphHints  hints,
+                            FT_Int         limit_contour )
+  {
+    FT_Pos  limit = hints->contour_y_minima[limit_contour];
+
+    FT_Int  contour;
+
+
+    for ( contour = 0; contour < hints->num_contours; contour++ )
+    {
+      FT_Pos  min_y = hints->contour_y_minima[contour];
+      FT_Pos  max_y = hints->contour_y_maxima[contour];
+
+
+      if ( min_y < max_y  &&
+           max_y <= limit )
+        af_touch_contour( hints, contour );
+    }
+  }
+
+
+  /* Stretch tilde vertically, if necessary, and return the height */
+  /* difference between the original and the stretched outline.    */
+  static FT_Pos
+  af_latin_stretch_top_tilde( AF_GlyphHints  hints,
+                              FT_Int         tilde_contour )
+  {
+    AF_Point  p           = hints->contours[tilde_contour];
+    AF_Point  first_point = p;
+
+    FT_Pos  min_y = hints->contour_y_minima[tilde_contour];
+    FT_Pos  max_y = hints->contour_y_maxima[tilde_contour];
+
+    FT_Pos   min_measurement   = FT_LONG_MAX;
+    FT_Bool  measurement_taken = FALSE;
+
+    FT_Pos  height;
+    FT_Pos  extremum_threshold;
+    FT_Pos  target_height;
+
+
+    if ( min_y == max_y )
+      return 0;
+
+    FT_TRACE4(( "af_latin_stretch_top_tilde: min y: %ld, max y: %ld\n",
+                min_y, max_y ));
+
+    height             = SUB_LONG( max_y, min_y );
+    extremum_threshold = height / 8;    /* Value 8 is heuristic. */
+
+    /* Find points that are local vertical round extrema, and which   */
+    /* do not coincide with the vertical extreme values (i.e., we     */
+    /* search for the 'other' wiggles in the tilde), then measure the */
+    /* distance to the vertical extreme values.  Try to find the one  */
+    /* with the smallest distance.                                    */
+    /*                                                                */
+    /* The algorithm only works for tilde shapes that don't deviate   */
+    /* from the standard shape too much.  In particular, the wiggles  */
+    /* must be round extrema.                                         */
+    do
+    {
+      p = p->next;
+
+      if ( !( p->flags & AF_FLAG_CONTROL )          &&
+           p->prev->y == p->y && p->next->y == p->y &&
+           p->y != min_y && p->y != max_y           &&
+           p->prev->flags & AF_FLAG_CONTROL         &&
+           p->next->flags & AF_FLAG_CONTROL         )
+      {
+        /* This point could be a candidate.  Find the next and previous */
+        /* on-curve points, and make sure they are both either above or */
+        /* below the point, then make the measurement.                  */
+        AF_Point  prev_on = p->prev;
+        AF_Point  next_on = p->next;
+
+        FT_Pos  measurement;
+
+
+        while ( prev_on->flags & AF_FLAG_CONTROL )
+          prev_on = prev_on->prev;
+        while ( next_on->flags & AF_FLAG_CONTROL )
+          next_on = next_on->next;
+
+        if ( next_on->y > p->y && prev_on->y > p->y )
+          measurement = SUB_LONG( p->y, min_y );
+        else if ( next_on->y < p->y && prev_on->y < p->y )
+          measurement = SUB_LONG( max_y, p->y );
+        else
+          continue;
+
+        /* Ignore hits that are too near to a vertical extremum. */
+        if ( measurement < extremum_threshold )
+          continue;
+
+        if ( !measurement_taken || measurement < min_measurement )
+        {
+          measurement_taken = TRUE;
+          min_measurement   = measurement;
+        }
+      }
+
+    } while ( p != first_point );
+
+    if ( !measurement_taken )
+      min_measurement = 0;
+
+    FT_TRACE4(( "af_latin_stretch_top_tilde: min measurement %ld\n",
+                min_measurement ));
+
+    /* To preserve the stretched shape we prevent that the tilde */
+    /* gets auto-hinted; we do this for all contours equal or    */
+    /* above the vertical minimum of `tilde_contour`.            */
+    af_touch_top_contours( hints, tilde_contour );
+
+    /* XXX This is an important element of the algorithm; */
+    /*     we need a description.                         */
+    target_height = min_measurement + 64;
+    if ( height >= target_height )
+      return 0;
+
+    /* Do the scaling. */
+    p = first_point;
+    do
+    {
+      p    = p->next;
+      /* We adjust the height of the diacritic only, which means */
+      /* we are never dealing with (valid) large numbers and can */
+      /* thus avoid `FT_MulFix`.                                 */
+      p->y = ADD_LONG( MUL_LONG( SUB_LONG( p->y,
+                                           min_y ),
+                                 target_height ) / height,
+                       min_y );
+
+    } while ( p != first_point );
+
+    return target_height - height;
+  }
+
+
+  static FT_Pos
+  af_latin_stretch_bottom_tilde( AF_GlyphHints  hints,
+                                 FT_Int         tilde_contour )
+  {
+    AF_Point  p           = hints->contours[tilde_contour];
+    AF_Point  first_point = p;
+
+    FT_Pos  min_y = hints->contour_y_minima[tilde_contour];
+    FT_Pos  max_y = hints->contour_y_maxima[tilde_contour];
+
+    FT_Pos   min_measurement   = FT_LONG_MAX;
+    FT_Bool  measurement_taken = FALSE;
+
+    FT_Pos  height;
+    FT_Pos  extremum_threshold;
+    FT_Pos  target_height;
+
+
+    if ( min_y == max_y )
+      return 0;
+
+    FT_TRACE4(( "af_latin_stretch_bottom_tilde: min y: %ld, max y: %ld\n",
+                min_y, max_y ));
+
+    height             = SUB_LONG( max_y, min_y );
+    extremum_threshold = height / 8;
+
+    do
+    {
+      p = p->next;
+
+      if ( !( p->flags & AF_FLAG_CONTROL )          &&
+           p->prev->y == p->y && p->next->y == p->y &&
+           p->y != min_y && p->y != max_y           &&
+           p->prev->flags & AF_FLAG_CONTROL         &&
+           p->next->flags & AF_FLAG_CONTROL         )
+      {
+        AF_Point  prev_on = p->prev;
+        AF_Point  next_on = p->next;
+
+        FT_Pos  measurement;
+
+
+        while ( prev_on->flags & AF_FLAG_CONTROL )
+          prev_on = prev_on->prev;
+        while ( next_on->flags & AF_FLAG_CONTROL )
+          next_on = next_on->next;
+
+        if ( next_on->y > p->y && prev_on->y > p->y )
+          measurement = SUB_LONG( p->y, min_y );
+        else if ( next_on->y < p->y && prev_on->y < p->y )
+          measurement = SUB_LONG( max_y, p->y );
+        else
+          continue;
+
+        if ( measurement < extremum_threshold )
+          continue;
+
+        if ( !measurement_taken || measurement < min_measurement )
+        {
+          measurement_taken = TRUE;
+          min_measurement   = measurement;
+        }
+      }
+
+    } while ( p != first_point );
+
+    if ( !measurement_taken )
+      min_measurement = 0;
+
+    FT_TRACE4(( "af_latin_stretch_bottom_tilde: min measurement %ld\n",
+                min_measurement ));
+
+    af_touch_bottom_contours( hints, tilde_contour );
+
+    target_height = min_measurement + 64;
+    if ( height >= target_height )
+      return 0;
+
+    p = first_point;
+    do
+    {
+      p    = p->next;
+      p->y = ADD_LONG( MUL_LONG( SUB_LONG( p->y,
+                                           max_y ),
+                                 target_height ) / height,
+                       max_y );
+
+    } while ( p != first_point );
+
+    return target_height - height;
+  }
+
+
+  /*
+    As part of `af_latin_stretch_top_tilde`, normally all points in the
+    tilde are marked as touched, so the existing grid fitting will leave the
+    tilde misaligned with the grid.
+
+    This function moves the tilde contour down to be grid-fitted.  We assume
+    that if moving the tilde down would cause it to touch or overlap another
+    countour, the vertical adjustment step will fix it.
+
+    Because the vertical adjustment step comes after all other grid-fitting
+    steps, the top edge of the contour under the tilde is usually aligned
+    with a horizontal grid line.  The vertical gap enforced by the vertical
+    adjustment is exactly one pixel, so if the top edge of the contour below
+    the tilde is on a grid line, the resulting tilde contour will also be
+    grid-aligned.
+
+    But in cases where the gap is already big enough so that the vertical
+    adjustment does nothing, this function ensures that even without the
+    intervention of the vertical adjustment step, the tilde will be
+    grid-aligned.
+
+    Return the vertical alignment amount.
+  */
+  static FT_Pos
+  af_latin_align_top_tilde( AF_GlyphHints  hints,
+                            FT_Int         tilde_contour )
+  {
+    AF_Point  p           = hints->contours[tilde_contour];
+    AF_Point  first_point = p;
+
+    FT_Pos  min_y = p->y;
+    FT_Pos  max_y = p->y;
+
+    FT_Pos  min_y_rounded;
+    FT_Pos  delta;
+    FT_Pos  height;
+
+
+    /* Find vertical extrema of the (now stretched) tilde contour. */
+    do
+    {
+      p = p->next;
+      if ( p->y < min_y )
+        min_y = p->y;
+      if ( p->y > max_y )
+        max_y = p->y;
+
+    } while ( p != first_point );
+
+    /* Align bottom of the tilde to the grid. */
+    min_y_rounded = FT_PIX_ROUND_LONG( min_y );
+    delta         = SUB_LONG( min_y_rounded, min_y );
+    height        = SUB_LONG( max_y, min_y );
+
+    /* If the tilde is less than 3 pixels tall, snap the center of it */
+    /* to the grid instead of the bottom to improve readability.      */
+    if ( height < 64 * 3 )
+      delta += ( FT_PIX_ROUND( height ) - height ) / 2;
+
+    af_move_contour_vertically( first_point, delta );
+
+    return delta;
+  }
+
+
+  static FT_Pos
+  af_latin_align_bottom_tilde( AF_GlyphHints  hints,
+                               FT_Int         tilde_contour )
+  {
+    AF_Point  p           = hints->contours[tilde_contour];
+    AF_Point  first_point = p;
+
+    FT_Pos  min_y = p->y;
+    FT_Pos  max_y = p->y;
+
+    FT_Pos  max_y_rounded;
+    FT_Pos  delta;
+    FT_Pos  height;
+
+
+    do
+    {
+      p = p->next;
+      if ( p->y < min_y )
+        min_y = p->y;
+      if ( p->y > max_y )
+        max_y = p->y;
+
+    } while ( p != first_point );
+
+    max_y_rounded = FT_PIX_ROUND_LONG( max_y );
+    delta         = SUB_LONG( max_y_rounded, max_y );
+    height        = SUB_LONG( max_y, min_y );
+
+    if ( height < 64 * 3 )
+      delta -= ( FT_PIX_ROUND( height ) - height ) / 2;
+
+    af_move_contour_vertically( first_point, delta );
+
+    return delta;
+  }
+
+
+  /* Return 1 if the given contour overlaps horizontally with the bounding */
+  /* box of all other contours combined.  This is a helper for function    */
+  /* `af_glyph_hints_apply_vertical_separation_adjustments`.               */
+  static FT_Bool
+  af_check_contour_horizontal_overlap( AF_GlyphHints  hints,
+                                       FT_Int         contour_index )
+  {
+    FT_Pos  contour_max_x = FT_LONG_MIN;
+    FT_Pos  contour_min_x = FT_LONG_MAX;
+    FT_Pos  others_max_x  = FT_LONG_MIN;
+    FT_Pos  others_min_x  = FT_LONG_MAX;
+
+    FT_Int  contour;
+
+    FT_Bool  horizontal_overlap;
+
+
+    for ( contour = 0; contour < hints->num_contours; contour++ )
+    {
+      AF_Point  first_point = hints->contours[contour];
+      AF_Point  p           = first_point;
+
+
+      /* Ignore dimensionless contours (i.e., contours with only one or */
+      /* two points).                                                   */
+      if ( first_point->next->next == first_point )
+        continue;
+
+      do
+      {
+        p = p->next;
+
+        if ( contour == contour_index )
+        {
+          if ( p->x < contour_min_x )
+            contour_min_x = p->x;
+          if ( p->x > contour_max_x )
+            contour_max_x = p->x;
+        }
+        else
+        {
+          if ( p->x < others_min_x )
+            others_min_x = p->x;
+          if ( p->x > others_max_x )
+            others_max_x = p->x;
+        }
+      } while ( p != first_point );
+    }
+
+    horizontal_overlap =
+      ( others_min_x <= contour_max_x && contour_max_x <= others_max_x ) ||
+      ( others_min_x <= contour_min_x && contour_min_x <= others_max_x ) ||
+      ( contour_max_x >= others_max_x && contour_min_x <= others_min_x );
+
+    return horizontal_overlap;
+  }
+
+
+  static void
+  af_glyph_hints_apply_vertical_separation_adjustments(
+    AF_GlyphHints  hints,
+    AF_Dimension   dim,
+    FT_UInt        glyph_index,
+    FT_Pos         accent_height_limit,
+    FT_Hash        reverse_charmap )
+  {
+    FT_Bool  adjust_top       = FALSE;
+    FT_Bool  adjust_below_top = FALSE;
+
+    FT_Bool  adjust_bottom       = FALSE;
+    FT_Bool  adjust_above_bottom = FALSE;
+
+    size_t*    val;
+    FT_UInt32  adj_type = AF_ADJUST_NONE;
+
+
+    FT_TRACE4(( "Entering"
+                " af_glyph_hints_apply_vertical_separation_adjustments\n" ));
+
+    if ( dim != AF_DIMENSION_VERT )
+      return;
+
+    val = ft_hash_num_lookup( (FT_Int)glyph_index, reverse_charmap );
+    if ( val )
+    {
+      FT_UInt  codepoint = *val;
+
+
+      adj_type = af_adjustment_database_lookup( codepoint );
+
+      if ( adj_type )
+      {
+        adjust_top       = !!( adj_type & AF_ADJUST_UP );
+        adjust_below_top = !!( adj_type & AF_ADJUST_UP2 );
+
+        adjust_bottom       = !!( adj_type & AF_ADJUST_DOWN );
+        adjust_above_bottom = !!( adj_type & AF_ADJUST_DOWN2 );
+      }
+    }
+
+    if ( ( ( adjust_top || adjust_bottom ) &&
+           hints->num_contours >= 2        )             ||
+         ( ( adjust_below_top || adjust_above_bottom ) &&
+           hints->num_contours >= 3                    ) )
+    {
+      /* Recompute vertical extrema, this time acting on already */
+      /* auto-hinted outlines.                                   */
+      af_compute_vertical_extrema( hints );
+    }
+
+    if ( ( adjust_top && hints->num_contours >= 2 )       ||
+         ( adjust_below_top && hints->num_contours >= 3 ) )
+    {
+      FT_Int  high_contour;
+      FT_Pos  high_min_y;
+      FT_Pos  high_max_y;
+      FT_Pos  high_height;
+
+      FT_Int  tilde_contour;
+      FT_Pos  tilde_min_y;
+      FT_Pos  tilde_max_y;
+      FT_Pos  tilde_height;
+
+      FT_Int   contour;
+      FT_Bool  horizontal_overlap;
+
+      FT_Pos  min_distance         = 64;
+      FT_Pos  adjustment_amount;
+      FT_Pos  calculated_amount;
+      FT_Pos  centering_adjustment = 0;
+      FT_Pos  pos;
+
+      FT_Bool  is_top_tilde       = !!( adj_type & AF_ADJUST_TILDE_TOP );
+      FT_Bool  is_below_top_tilde = !!( adj_type & AF_ADJUST_TILDE_TOP2 );
+
+
+      FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n"
+                  "  Applying vertical adjustment: %s\n",
+                  adjust_top ? "AF_ADJUST_TOP" : "AF_ADJUST_TOP2" ));
+
+      high_contour = adjust_below_top
+                       ? af_find_second_highest_contour( hints )
+                       : af_find_highest_contour( hints );
+
+      /* Check for a horizontal overlap between the high contour and the */
+      /* rest.  If there is no overlap, do not adjust.                   */
+      horizontal_overlap =
+        af_check_contour_horizontal_overlap( hints, high_contour );
+      if ( !horizontal_overlap )
+      {
+        FT_TRACE4(( "    High contour does not horizontally overlap"
+                    " with other contours.\n"
+                    "    Skipping adjustment.\n" ));
+        return;
+      }
+
+      high_min_y  = hints->contour_y_minima[high_contour];
+      high_max_y  = hints->contour_y_maxima[high_contour];
+      high_height = SUB_LONG( high_max_y, high_min_y );
+
+      if ( high_height > accent_height_limit )
+      {
+        FT_TRACE4(( "    High contour height (%.2f) exceeds accent height"
+                    " limit (%.2f).\n"
+                    "    Skipping adjustment.\n",
+                    (double)high_height / 64,
+                    (double)accent_height_limit / 64 ));
+        return;
+      }
+
+      /* If the difference between the vertical minimum of the high   */
+      /* contour and the vertical maximum of another contour is less  */
+      /* than a pixel, shift up the high contour to make the distance */
+      /* one pixel.                                                   */
+      for ( contour = 0; contour < hints->num_contours; contour++ )
+      {
+        FT_Pos  min_y;
+        FT_Pos  max_y;
+        FT_Pos  distance;
+
+
+        if ( contour == high_contour )
+          continue;
+
+        min_y = hints->contour_y_minima[contour];
+        max_y = hints->contour_y_maxima[contour];
+
+        /* We also check that the y minimum of the 'other' contour */
+        /* is below the high contour to avoid potential false hits */
+        /* with contours enclosed in the high one.                 */
+        distance = SUB_LONG( high_min_y, max_y );
+        if ( distance < 64           &&
+             distance < min_distance &&
+             min_y < high_min_y      )
+          min_distance = distance;
+      }
+
+      adjustment_amount = 64 - min_distance;
+
+      if ( is_top_tilde || is_below_top_tilde )
+      {
+        tilde_contour = adjust_top
+                          ? high_contour
+                          : ( is_below_top_tilde
+                                ? high_contour
+                                : af_find_highest_contour( hints ) );
+
+        tilde_min_y  = hints->contour_y_minima[tilde_contour];
+        tilde_max_y  = hints->contour_y_maxima[tilde_contour];
+        tilde_height = SUB_LONG( tilde_max_y, tilde_min_y);
+
+        /* The vertical separation adjustment potentially undoes a */
+        /* tilde center alignment.  If it would grid-align a tilde */
+        /* less than 3 pixels in height, shift additionally to     */
+        /* re-center the tilde.                                    */
+
+        pos = ADD_LONG( high_min_y, adjustment_amount );
+        if ( adjust_below_top && is_top_tilde )
+          pos += high_height;
+
+        if ( pos % 64 == 0 && tilde_height < 3 * 64 )
+        {
+          centering_adjustment = ( FT_PIX_ROUND( tilde_height ) -
+                                   tilde_height ) / 2;
+
+          FT_TRACE4(( "    Additional tilde centering adjustment: %ld\n",
+                      centering_adjustment ));
+        }
+      }
+
+      if ( ( adjust_top && is_top_tilde )             ||
+           ( adjust_below_top && is_below_top_tilde ) )
+        calculated_amount = adjustment_amount + centering_adjustment;
+      else
+        calculated_amount = adjustment_amount;
+
+      /* allow a delta of 2/64px to handle rounding differences */
+      FT_TRACE4(( "    Calculated adjustment amount: %ld%s\n",
+                  calculated_amount,
+                  ( calculated_amount < -2                               ||
+                    ( adjustment_amount > 66 && calculated_amount > 66 ) )
+                      ? " (out of range [-2;66], not adjusting)" : "" ));
+
+      if ( calculated_amount != 0                                 &&
+           calculated_amount >= -2                                &&
+           ( calculated_amount <= 66 || adjustment_amount <= 66 ) )
+      {
+        /* Value 8 is heuristic. */
+        FT_Pos  height_delta = high_height / 8;
+        FT_Pos  min_y_limit  = SUB_LONG( high_min_y, height_delta );
+
+
+        FT_TRACE4(( "    Pushing high contour %ld units up\n",
+                    calculated_amount ));
+
+        /* While we use only a single contour (the 'high' one) for    */
+        /* computing `adjustment_amount`, we apply it to all contours */
+        /* that are (approximately) in the same vertical range or     */
+        /* higher.  This covers, for example, the inner contour of    */
+        /* the Czech ring accent or the second acute accent in the    */
+        /* Hungarian double acute accent.                             */
+        af_move_contours_up( hints, min_y_limit, adjustment_amount );
+
+        if ( adjust_below_top && is_top_tilde )
+        {
+          FT_TRACE4(( "    Pushing top tilde %ld units up\n",
+                      centering_adjustment ));
+
+          af_move_contours_up( hints,
+                               ADD_LONG( min_y_limit, high_height ),
+                               centering_adjustment );
+        }
+      }
+    }
+
+    if ( ( adjust_bottom && hints->num_contours >= 2 )       ||
+         ( adjust_above_bottom && hints->num_contours >= 3 ) )
+    {
+      FT_Int  low_contour;
+      FT_Pos  low_min_y;
+      FT_Pos  low_max_y;
+      FT_Pos  low_height;
+
+      FT_Int  tilde_contour;
+      FT_Pos  tilde_min_y;
+      FT_Pos  tilde_max_y;
+      FT_Pos  tilde_height;
+
+      FT_Int   contour;
+      FT_Bool  horizontal_overlap;
+
+      FT_Pos  min_distance         = 64;
+      FT_Pos  adjustment_amount;
+      FT_Pos  calculated_amount;
+      FT_Pos  centering_adjustment = 0;
+      FT_Pos  pos;
+
+      FT_Bool  is_bottom_tilde =
+                 !!( adj_type & AF_ADJUST_TILDE_BOTTOM );
+      FT_Bool  is_above_bottom_tilde =
+                 !!( adj_type & AF_ADJUST_TILDE_BOTTOM2 );
+
+
+      FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n"
+                  "  Applying vertical adjustment: %s\n",
+                  adjust_bottom ? "AF_ADJUST_DOWN": "AF_ADJUST_DOWN2" ));
+
+      low_contour = adjust_above_bottom
+                      ? af_find_second_lowest_contour( hints )
+                      : af_find_lowest_contour( hints );
+
+      horizontal_overlap =
+        af_check_contour_horizontal_overlap( hints, low_contour );
+      if ( !horizontal_overlap )
+      {
+        FT_TRACE4(( "    Low contour does not horizontally overlap"
+                    " with other contours.\n"
+                    "    Skipping adjustment.\n" ));
+        return;
+      }
+
+      low_min_y  = hints->contour_y_minima[low_contour];
+      low_max_y  = hints->contour_y_maxima[low_contour];
+      low_height = SUB_LONG( low_max_y, low_min_y );
+
+      if ( low_height > accent_height_limit )
+      {
+        FT_TRACE4(( "    Low contour height (%.2f) exceeds accent height"
+                    " limit (%.2f).\n"
+                    "    Skipping adjustment.\n",
+                    (double)low_height / 64,
+                    (double)accent_height_limit / 64 ));
+        return;
+      }
+
+      for ( contour = 0; contour < hints->num_contours; contour++ )
+      {
+        FT_Pos  min_y;
+        FT_Pos  max_y;
+        FT_Pos  distance;
+
+
+        if ( contour == low_contour )
+          continue;
+
+        min_y = hints->contour_y_minima[contour];
+        max_y = hints->contour_y_maxima[contour];
+
+        distance = SUB_LONG( min_y, low_max_y );
+        if ( distance < 64           &&
+             distance < min_distance &&
+             max_y > low_max_y       )
+          min_distance = distance;
+      }
+
+      adjustment_amount = 64 - min_distance;
+
+      if ( is_bottom_tilde || is_above_bottom_tilde )
+      {
+        tilde_contour = adjust_bottom
+                          ? low_contour
+                          : ( is_above_bottom_tilde
+                                ? low_contour
+                                : af_find_lowest_contour( hints ) );
+
+        tilde_min_y  = hints->contour_y_minima[tilde_contour];
+        tilde_max_y  = hints->contour_y_maxima[tilde_contour];
+        tilde_height = SUB_LONG( tilde_max_y, tilde_min_y );
+
+        pos = SUB_LONG( low_max_y, adjustment_amount );
+        if ( adjust_above_bottom && is_bottom_tilde )
+          pos -= low_height;
+
+        if ( pos % 64 == 0 && tilde_height < 3 * 64 )
+        {
+          centering_adjustment = ( FT_PIX_ROUND( tilde_height ) -
+                                   tilde_height ) / 2;
+
+          FT_TRACE4(( "    Additional tilde centering adjustment: %ld\n",
+                      centering_adjustment ));
+        }
+      }
+
+      if ( ( adjust_bottom && is_bottom_tilde )             ||
+           ( adjust_above_bottom && is_above_bottom_tilde ) )
+        calculated_amount = adjustment_amount + centering_adjustment;
+      else
+        calculated_amount = adjustment_amount;
+
+      FT_TRACE4(( "    Calculated adjustment amount: %ld%s\n",
+                  calculated_amount,
+                  ( calculated_amount < -2                               ||
+                    ( adjustment_amount > 66 && calculated_amount > 66 ) )
+                      ? " (out of range [-2;66], not adjusting)" : "" ));
+
+      if ( calculated_amount != 0                                 &&
+           calculated_amount >= -2                                &&
+           ( calculated_amount <= 66 || adjustment_amount <= 66 ) )
+      {
+        FT_Pos  height_delta = low_height / 8;
+        FT_Pos  max_y_limit  = ADD_LONG( low_max_y, height_delta );
+
+
+        FT_TRACE4(( "    Pushing low contour %ld units down\n",
+                    calculated_amount ));
+
+        af_move_contours_down( hints, max_y_limit, adjustment_amount );
+
+        if ( adjust_above_bottom && is_bottom_tilde )
+        {
+          FT_TRACE4(( "    Pushing bottom tilde %ld units down\n",
+                      centering_adjustment ));
+
+          af_move_contours_down( hints,
+                                 SUB_LONG( max_y_limit, low_height ),
+                                 centering_adjustment );
+        }
+      }
+    }
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+    if ( !( ( ( adjust_top || adjust_bottom ) &&
+              hints->num_contours >= 2        )             ||
+            ( ( adjust_below_top || adjust_above_bottom ) &&
+              hints->num_contours >= 3                    ) ) )
+      FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n"
+                  "  No vertical adjustment applied\n" ));
+#endif
+
+    FT_TRACE4(( "Exiting"
+                " af_glyph_hints_apply_vertical_separation_adjustments\n" ));
+  }
+
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  aflatin
+
+
+  /* Compute the snapped width of a given stem, ignoring very thin ones. */
+  /* There is a lot of voodoo in this function; changing the hard-coded  */
+  /* parameters influence the whole hinting process.                     */
+
+  static FT_Pos
+  af_latin_compute_stem_width( AF_GlyphHints  hints,
+                               AF_Dimension   dim,
+                               FT_Pos         width,
+                               FT_Pos         base_delta,
+                               FT_UInt        base_flags,
+                               FT_UInt        stem_flags )
+  {
+    AF_LatinMetrics  metrics  = (AF_LatinMetrics)hints->metrics;
+    AF_LatinAxis     axis     = &metrics->axis[dim];
+    FT_Pos           dist     = width;
+    FT_Int           sign     = 0;
+    FT_Int           vertical = ( dim == AF_DIMENSION_VERT );
+
+
+    if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ||
+         axis->extra_light                       )
+      return width;
+
+    if ( dist < 0 )
+    {
+      dist = -width;
+      sign = 1;
+    }
+
+    if ( (  vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
+         ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
+    {
+      /* smooth hinting process: very lightly quantize the stem width */
+
+      /* leave the widths of serifs alone */
+      if ( ( stem_flags & AF_EDGE_SERIF ) &&
+           vertical                       &&
+           ( dist < 3 * 64 )              )
+        goto Done_Width;
+
+      else if ( base_flags & AF_EDGE_ROUND )
+      {
+        if ( dist < 80 )
+          dist = 64;
+      }
+      else if ( dist < 56 )
+        dist = 56;
+
+      if ( axis->width_count > 0 )
+      {
+        FT_Pos  delta;
+
+
+        /* compare to standard width */
+        delta = dist - axis->widths[0].cur;
+
+        if ( delta < 0 )
+          delta = -delta;
+
+        if ( delta < 40 )
+        {
+          dist = axis->widths[0].cur;
+          if ( dist < 48 )
+            dist = 48;
+
+          goto Done_Width;
+        }
+
+        if ( dist < 3 * 64 )
+        {
+          delta  = dist & 63;
+          dist  &= -64;
+
+          if ( delta < 10 )
+            dist += delta;
+
+          else if ( delta < 32 )
+            dist += 10;
+
+          else if ( delta < 54 )
+            dist += 54;
+
+          else
+            dist += delta;
+        }
+        else
+        {
+          /* A stem's end position depends on two values: the start        */
+          /* position and the stem length.  The former gets usually        */
+          /* rounded to the grid, while the latter gets rounded also if it */
+          /* exceeds a certain length (see below in this function).  This  */
+          /* `double rounding' can lead to a great difference to the       */
+          /* original, unhinted position; this normally doesn't matter for */
+          /* large PPEM values, but for small sizes it can easily make     */
+          /* outlines collide.  For this reason, we adjust the stem length */
+          /* by a small amount depending on the PPEM value in case the     */
+          /* former and latter rounding both point into the same           */
+          /* direction.                                                    */
+
+          FT_Pos  bdelta = 0;
+
+
+          if ( ( ( width > 0 ) && ( base_delta > 0 ) ) ||
+               ( ( width < 0 ) && ( base_delta < 0 ) ) )
+          {
+            FT_UInt  ppem = metrics->root.scaler.face->size->metrics.x_ppem;
+
+
+            if ( ppem < 10 )
+              bdelta = base_delta;
+            else if ( ppem < 30 )
+              bdelta = ( base_delta * (FT_Pos)( 30 - ppem ) ) / 20;
+
+            if ( bdelta < 0 )
+              bdelta = -bdelta;
+          }
+
+          dist = ( dist - bdelta + 32 ) & ~63;
+        }
+      }
+    }
+    else
+    {
+      /* strong hinting process: snap the stem width to integer pixels */
+
+      FT_Pos  org_dist = dist;
+
+
+      dist = af_latin_snap_width( axis->widths, axis->width_count, dist );
+
+      if ( vertical )
+      {
+        /* in the case of vertical hinting, always round */
+        /* the stem heights to integer pixels            */
+
+        if ( dist >= 64 )
+          dist = ( dist + 16 ) & ~63;
+        else
+          dist = 64;
+      }
+      else
+      {
+        if ( AF_LATIN_HINTS_DO_MONO( hints ) )
+        {
+          /* monochrome horizontal hinting: snap widths to integer pixels */
+          /* with a different threshold                                   */
+
+          if ( dist < 64 )
+            dist = 64;
+          else
+            dist = ( dist + 32 ) & ~63;
+        }
+        else
+        {
+          /* for horizontal anti-aliased hinting, we adopt a more subtle */
+          /* approach: we strengthen small stems, round stems whose size */
+          /* is between 1 and 2 pixels to an integer, otherwise nothing  */
+
+          if ( dist < 48 )
+            dist = ( dist + 64 ) >> 1;
+
+          else if ( dist < 128 )
+          {
+            /* We only round to an integer width if the corresponding */
+            /* distortion is less than 1/4 pixel.  Otherwise this     */
+            /* makes everything worse since the diagonals, which are  */
+            /* not hinted, appear a lot bolder or thinner than the    */
+            /* vertical stems.                                        */
+
+            FT_Pos  delta;
+
+
+            dist = ( dist + 22 ) & ~63;
+            delta = dist - org_dist;
+            if ( delta < 0 )
+              delta = -delta;
+
+            if ( delta >= 16 )
+            {
+              dist = org_dist;
+              if ( dist < 48 )
+                dist = ( dist + 64 ) >> 1;
+            }
+          }
+          else
+            /* round otherwise to prevent color fringes in LCD mode */
+            dist = ( dist + 32 ) & ~63;
+        }
+      }
+    }
+
+  Done_Width:
+    if ( sign )
+      dist = -dist;
+
+    return dist;
+  }
+
+
+  /* Align one stem edge relative to the previous stem edge. */
+
+  static void
+  af_latin_align_linked_edge( AF_GlyphHints  hints,
+                              AF_Dimension   dim,
+                              AF_Edge        base_edge,
+                              AF_Edge        stem_edge )
+  {
+    FT_Pos  dist, base_delta;
+    FT_Pos  fitted_width;
+
+
+    dist       = stem_edge->opos - base_edge->opos;
+    base_delta = base_edge->pos - base_edge->opos;
+
+    fitted_width = af_latin_compute_stem_width( hints, dim,
+                                                dist, base_delta,
+                                                base_edge->flags,
+                                                stem_edge->flags );
+
+
+    stem_edge->pos = base_edge->pos + fitted_width;
+
+    FT_TRACE5(( "  LINK: edge %td (opos=%.2f) linked to %.2f,"
+                " dist was %.2f, now %.2f\n",
+                stem_edge - hints->axis[dim].edges,
+                (double)stem_edge->opos / 64, (double)stem_edge->pos / 64,
+                (double)dist / 64, (double)fitted_width / 64 ));
+  }
+
+
+  /* Shift the coordinates of the `serif' edge by the same amount */
+  /* as the corresponding `base' edge has been moved already.     */
+
+  static void
+  af_latin_align_serif_edge( AF_GlyphHints  hints,
+                             AF_Edge        base,
+                             AF_Edge        serif )
+  {
+    FT_UNUSED( hints );
+
+    serif->pos = base->pos + ( serif->opos - base->opos );
   }
 
 
@@ -2998,13 +4220,15 @@
   af_latin_hint_edges( AF_GlyphHints  hints,
                        AF_Dimension   dim )
   {
-    AF_AxisHints  axis       = &hints->axis[dim];
-    AF_Edge       edges      = axis->edges;
-    AF_Edge       edge_limit = FT_OFFSET( edges, axis->num_edges );
-    FT_PtrDist    n_edges;
-    AF_Edge       edge;
-    AF_Edge       anchor     = NULL;
-    FT_Int        has_serifs = 0;
+    AF_AxisHints  axis = &hints->axis[dim];
+
+    AF_Edge     edges      = axis->edges;
+    AF_Edge     edge_limit = FT_OFFSET( edges, axis->num_edges );
+    AF_Edge     edge;
+    FT_PtrDist  n_edges;
+
+    AF_Edge  anchor             = NULL;
+    FT_Bool  has_non_stem_edges = 0;
 
     AF_StyleClass   style_class  = hints->metrics->style_class;
     AF_ScriptClass  script_class = af_script_classes[style_class->script];
@@ -3131,7 +4355,7 @@
       edge2 = edge->link;
       if ( !edge2 )
       {
-        has_serifs++;
+        has_non_stem_edges = TRUE;
         continue;
       }
 
@@ -3408,7 +4632,7 @@
       }
     }
 
-    if ( has_serifs || !anchor )
+    if ( has_non_stem_edges || !anchor )
     {
       /*
        * now hint the remaining edges (serifs and single) in order
@@ -3426,9 +4650,75 @@
 
         if ( edge->serif )
         {
+          AF_Edge  e, top, bottom;
+          FT_Pos   min_pos, max_pos;
+
+
+          /* Check whether we have a real serif -- if there are  */
+          /* other edges with overlapping (or enclosed) segments */
+          /* between the primary and serif edge, we have not.    */
+          /*                                                     */
+          /* Such a situation might happen if an accent is very  */
+          /* near to its base glyph (for example, Vietnamese     */
+          /* uppercase letters with two accents in `arial.ttf`), */
+          /* and the segment detection algorithm classifies the  */
+          /* top of the accent incorrectly as a serif.           */
           delta = edge->serif->opos - edge->opos;
           if ( delta < 0 )
+          {
             delta = -delta;
+
+            top    = edge;
+            bottom = edge->serif;
+          }
+          else
+          {
+            top    = edge->serif;
+            bottom = edge;
+          }
+
+          if ( delta < 64 + 32 )
+          {
+            /* take care of outline orientation while computing extrema */
+            min_pos = FT_MIN( FT_MIN( FT_MIN( top->first->first->v,
+                                              top->first->last->v ),
+                                      FT_MIN( top->last->first->v,
+                                              top->last->last->v ) ),
+                              FT_MIN( FT_MIN( bottom->first->first->v,
+                                              bottom->first->last->v ),
+                                      FT_MIN( bottom->last->first->v,
+                                              bottom->last->last->v ) ) );
+            max_pos = FT_MAX( FT_MAX( FT_MAX( top->first->first->v,
+                                              top->first->last->v ),
+                                      FT_MAX( top->last->first->v,
+                                              top->last->last->v ) ),
+                              FT_MAX( FT_MAX( bottom->first->first->v,
+                                              bottom->first->last->v ),
+                                      FT_MAX( bottom->last->first->v,
+                                              bottom->last->last->v ) ) );
+
+            for ( e = bottom + 1; e < top; e++ )
+            {
+              FT_Pos  e_min = FT_MIN( FT_MIN( e->first->first->v,
+                                              e->first->last->v ),
+                                      FT_MIN( e->last->first->v,
+                                              e->last->last->v ) );
+              FT_Pos  e_max = FT_MAX( FT_MAX( e->first->first->v,
+                                              e->first->last->v ),
+                                      FT_MAX( e->last->first->v,
+                                              e->last->last->v ) );
+
+              if ( !( ( e_min < min_pos && e_max < min_pos ) ||
+                      ( e_min > max_pos && e_max > max_pos ) ) )
+              {
+                delta = 1000;  /* not a real serif */
+                break;
+              }
+            }
+
+            if ( delta == 1000 )
+              continue;
+          }
         }
 
         if ( delta < 64 + 16 )
@@ -3562,6 +4852,8 @@
 
     AF_LatinAxis  axis;
 
+    FT_Pos  accent_height_limit = 0;
+
 
     error = af_glyph_hints_reload( hints, outline );
     if ( error )
@@ -3581,11 +4873,172 @@
 
     if ( AF_HINTS_DO_VERTICAL( hints ) )
     {
+      size_t*  val;
+
+      FT_Int  top_tilde_contour    = 0;
+      FT_Int  bottom_tilde_contour = 0;
+
+      FT_Int  below_top_tilde_contour    = 0;
+      FT_Int  above_bottom_tilde_contour = 0;
+
+      AF_LatinBlue  capital_top_blue    = NULL;
+      AF_LatinBlue  capital_bottom_blue = NULL;
+
+      AF_LatinBlue  small_top_blue    = NULL;
+      AF_LatinBlue  small_bottom_blue = NULL;
+
+      FT_Bool  have_flags = FALSE;
+
+      FT_Bool  is_top_tilde    = FALSE;
+      FT_Bool  is_bottom_tilde = FALSE;
+
+      FT_Bool  is_below_top_tilde    = FALSE;
+      FT_Bool  is_above_bottom_tilde = FALSE;
+
+      FT_Bool  ignore_capital_top    = FALSE;
+      FT_Bool  ignore_capital_bottom = FALSE;
+
+      FT_Bool  ignore_small_top    = FALSE;
+      FT_Bool  ignore_small_bottom = FALSE;
+
+      FT_Bool  do_height_check = TRUE;
+
+      FT_Pos  limit;
+      FT_Pos  y_offset;
+
+
+      val = ft_hash_num_lookup( (FT_Int)glyph_index,
+                                metrics->root.reverse_charmap );
+      if ( val )
+      {
+        FT_UInt    codepoint = *val;
+        FT_UInt32  adj_type  = af_adjustment_database_lookup( codepoint );
+
+
+        if ( adj_type )
+        {
+          have_flags = !!adj_type;
+
+          is_top_tilde    = !!( adj_type & AF_ADJUST_TILDE_TOP );
+          is_bottom_tilde = !!( adj_type & AF_ADJUST_TILDE_BOTTOM );
+
+          is_below_top_tilde    = !!( adj_type & AF_ADJUST_TILDE_TOP2 );
+          is_above_bottom_tilde = !!( adj_type & AF_ADJUST_TILDE_BOTTOM2 );
+
+          ignore_capital_top    = !!( adj_type & AF_IGNORE_CAPITAL_TOP );
+          ignore_capital_bottom = !!( adj_type & AF_IGNORE_CAPITAL_BOTTOM );
+
+          ignore_small_top    = !!( adj_type & AF_IGNORE_SMALL_TOP );
+          ignore_small_bottom = !!( adj_type & AF_IGNORE_SMALL_BOTTOM );
+
+          do_height_check = !( adj_type & AF_ADJUST_NO_HEIGHT_CHECK );
+        }
+      }
+
+      if ( is_top_tilde || is_bottom_tilde             ||
+           is_below_top_tilde || is_above_bottom_tilde )
+        af_compute_vertical_extrema( hints );
+
+      /* Process inner tilde glyphs first. */
+      if ( is_below_top_tilde )
+      {
+        below_top_tilde_contour = af_find_second_highest_contour( hints );
+
+        y_offset = af_latin_stretch_top_tilde(
+                     hints, below_top_tilde_contour );
+        y_offset += af_latin_align_top_tilde(
+                      hints, below_top_tilde_contour );
+
+        limit = hints->contour_y_minima[below_top_tilde_contour];
+        af_move_contours_up( hints, limit, y_offset );
+      }
+      if ( is_above_bottom_tilde )
+      {
+        above_bottom_tilde_contour = af_find_second_lowest_contour( hints );
+
+        y_offset = af_latin_stretch_bottom_tilde(
+                     hints, above_bottom_tilde_contour );
+        y_offset -= af_latin_align_bottom_tilde(
+                      hints, above_bottom_tilde_contour );
+
+        limit = hints->contour_y_maxima[above_bottom_tilde_contour];
+        af_move_contours_down( hints, limit, y_offset );
+      }
+
+      if ( is_top_tilde )
+      {
+        top_tilde_contour = af_find_highest_contour( hints );
+
+        (void)af_latin_stretch_top_tilde( hints, top_tilde_contour );
+        (void)af_latin_align_top_tilde( hints, top_tilde_contour );
+      }
+      if ( is_bottom_tilde )
+      {
+        bottom_tilde_contour = af_find_lowest_contour( hints );
+
+        (void)af_latin_stretch_bottom_tilde( hints, bottom_tilde_contour );
+        (void)af_latin_align_bottom_tilde( hints, bottom_tilde_contour );
+      }
+
       axis  = &metrics->axis[AF_DIMENSION_VERT];
       error = af_latin_hints_detect_features( hints,
                                               axis->width_count,
                                               axis->widths,
                                               AF_DIMENSION_VERT );
+
+      if ( have_flags )
+      {
+        af_latin_get_base_glyph_blues( hints,
+                                       TRUE,
+                                       &capital_top_blue,
+                                       &capital_bottom_blue );
+        af_latin_get_base_glyph_blues( hints,
+                                       FALSE,
+                                       &small_top_blue,
+                                       &small_bottom_blue );
+
+        if ( do_height_check )
+        {
+          /* Set a heuristic limit for the accent height so that    */
+          /* `af_glyph_hints_apply_vertical_separation_adjustments` */
+          /* can correctly ignore the case where an accent is       */
+          /* unexpectedly not the highest (or lowest) contour.      */
+
+          /* Either 2/3 of the lowercase blue zone height... */
+          if ( small_top_blue && small_bottom_blue )
+            accent_height_limit = 2 * ( small_top_blue->shoot.cur -
+                                        small_bottom_blue->shoot.cur ) / 3;
+          /* or 1/2 of the uppercase blue zone height... */
+          else if ( capital_top_blue && capital_bottom_blue )
+            accent_height_limit = ( capital_top_blue->shoot.cur -
+                                    capital_bottom_blue->shoot.cur ) / 2;
+          /* or half of the standard PostScript ascender value (8/10) */
+          /* of the EM value, scaled.                                 */
+          else
+            accent_height_limit = FT_MulFix( metrics->units_per_em * 4 / 10,
+                                             metrics->root.scaler.y_scale );
+        }
+      }
+
+      if ( capital_top_blue && capital_bottom_blue )
+      {
+        if ( ignore_capital_top )
+          af_latin_ignore_top( hints,
+                               capital_top_blue, capital_bottom_blue );
+        if ( ignore_capital_bottom )
+          af_latin_ignore_bottom( hints,
+                                  capital_top_blue, capital_bottom_blue );
+      }
+      if ( small_top_blue && small_bottom_blue )
+      {
+        if ( ignore_small_top )
+          af_latin_ignore_top( hints,
+                               small_top_blue, small_bottom_blue );
+        if ( ignore_small_bottom )
+          af_latin_ignore_bottom( hints,
+                                  small_top_blue, small_bottom_blue );
+      }
+
       if ( error )
         goto Exit;
 
@@ -3604,6 +5057,12 @@
         af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim );
         af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim );
         af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
+        af_glyph_hints_apply_vertical_separation_adjustments(
+          hints,
+          (AF_Dimension)dim,
+          glyph_index,
+          accent_height_limit,
+          metrics->root.reverse_charmap );
       }
     }
 
@@ -3632,7 +5091,7 @@
 
     (AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init,        /* style_metrics_init    */
     (AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale,       /* style_metrics_scale   */
-    (AF_WritingSystem_DoneMetricsFunc) NULL,                         /* style_metrics_done    */
+    (AF_WritingSystem_DoneMetricsFunc) af_latin_metrics_done,        /* style_metrics_done    */
     (AF_WritingSystem_GetStdWidthsFunc)af_latin_get_standard_widths, /* style_metrics_getstdw */
 
     (AF_WritingSystem_InitHintsFunc)   af_latin_hints_init,          /* style_hints_init      */
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h
index 54e50615021..82b4b0d480d 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h
@@ -5,7 +5,7 @@
  *   Auto-fitter hinting routines for latin writing system
  *   (specification).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -61,17 +61,26 @@ FT_BEGIN_HEADER
           ( (b)->properties & AF_BLUE_PROPERTY_LATIN_X_HEIGHT )
 #define AF_LATIN_IS_LONG_BLUE( b ) \
           ( (b)->properties & AF_BLUE_PROPERTY_LATIN_LONG )
+#define AF_LATIN_IS_CAPITAL_BOTTOM_BLUE( b ) \
+          ( (b)->properties & AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM )
+#define AF_LATIN_IS_SMALL_BOTTOM_BLUE( b ) \
+          ( (b)->properties & AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM )
 
 #define AF_LATIN_MAX_WIDTHS  16
 
 
-#define AF_LATIN_BLUE_ACTIVE      ( 1U << 0 ) /* zone height is <= 3/4px   */
-#define AF_LATIN_BLUE_TOP         ( 1U << 1 ) /* we have a top blue zone   */
-#define AF_LATIN_BLUE_SUB_TOP     ( 1U << 2 ) /* we have a subscript top   */
-                                              /* blue zone                 */
-#define AF_LATIN_BLUE_NEUTRAL     ( 1U << 3 ) /* we have neutral blue zone */
-#define AF_LATIN_BLUE_ADJUSTMENT  ( 1U << 4 ) /* used for scale adjustment */
-                                              /* optimization              */
+#define AF_LATIN_BLUE_ACTIVE        ( 1U << 0 ) /* zone height is <= 3/4px */
+#define AF_LATIN_BLUE_TOP           ( 1U << 1 ) /* we have a top blue zone */
+#define AF_LATIN_BLUE_SUB_TOP       ( 1U << 2 ) /* we have a subscript     */
+                                                /* top blue zone           */
+#define AF_LATIN_BLUE_NEUTRAL       ( 1U << 3 ) /* we have a neutral blue  */
+                                                /* zone                    */
+#define AF_LATIN_BLUE_ADJUSTMENT    ( 1U << 4 ) /* used for scale adjustm. */
+                                                /* optimization            */
+#define AF_LATIN_BLUE_BOTTOM        ( 1U << 5 ) /* we have a capital       */
+                                                /* letter bottom blue zone */
+#define AF_LATIN_BLUE_BOTTOM_SMALL  ( 1U << 6 ) /* we have a small letter  */
+                                                /* bottom blue zone        */
 
 
   typedef struct  AF_LatinBlueRec_
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c b/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c
index af1d59a6896..4e2ac1f1ce3 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter glyph loading routines (body).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -524,16 +524,18 @@
 
       bbox.xMin = FT_PIX_FLOOR( bbox.xMin );
       bbox.yMin = FT_PIX_FLOOR( bbox.yMin );
-      bbox.xMax = FT_PIX_CEIL(  bbox.xMax );
-      bbox.yMax = FT_PIX_CEIL(  bbox.yMax );
+      bbox.xMax = FT_PIX_CEIL_LONG( bbox.xMax );
+      bbox.yMax = FT_PIX_CEIL_LONG( bbox.yMax );
 
-      slot->metrics.width        = bbox.xMax - bbox.xMin;
-      slot->metrics.height       = bbox.yMax - bbox.yMin;
+      slot->metrics.width        = SUB_LONG( bbox.xMax, bbox.xMin );
+      slot->metrics.height       = SUB_LONG( bbox.yMax, bbox.yMin );
       slot->metrics.horiBearingX = bbox.xMin;
       slot->metrics.horiBearingY = bbox.yMax;
 
-      slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x );
-      slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y );
+      slot->metrics.vertBearingX = FT_PIX_FLOOR( ADD_LONG( bbox.xMin,
+                                                           vvector.x ) );
+      slot->metrics.vertBearingY = FT_PIX_FLOOR( ADD_LONG( bbox.yMax,
+                                                           vvector.y ) );
 
       /* for mono-width fonts (like Andale, Courier, etc.) we need */
       /* to keep the original rounded advance width; ditto for     */
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afloader.h b/src/java.desktop/share/native/libfreetype/src/autofit/afloader.h
index 99f0e15f92b..a04b4df0b3b 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afloader.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afloader.h
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter glyph loading routines (specification).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c b/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c
index 726f6ca2b78..22d85a889e8 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter module implementation (body).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -146,7 +146,7 @@
 
       if ( !af_style_classes[ss] )
       {
-        FT_TRACE2(( "af_property_set: Invalid value %d for property `%s'\n",
+        FT_TRACE2(( "af_property_set: Invalid value %u for property `%s'\n",
                     *fallback_script, property_name ));
         return FT_THROW( Invalid_Argument );
       }
@@ -412,6 +412,11 @@
     module->darken_params[6]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4;
     module->darken_params[7]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4;
 
+#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ )         && \
+    defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC )
+    ft_hb_funcs_init( module );
+#endif
+
     return FT_Err_Ok;
   }
 
@@ -421,6 +426,11 @@
   {
     FT_UNUSED( ft_module );
 
+#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ )         && \
+    defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC )
+    ft_hb_funcs_done( (AF_Module)ft_module );
+#endif
+
 #ifdef FT_DEBUG_AUTOFIT
     if ( af_debug_hints_rec_->memory )
       af_glyph_hints_done( af_debug_hints_rec_ );
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.h b/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.h
index 91a1abfef1f..c62421ef696 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.h
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter module implementation (specification).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -22,6 +22,7 @@
 #include 
 #include 
 
+#include "ft-hb.h"
 
 FT_BEGIN_HEADER
 
@@ -40,6 +41,11 @@ FT_BEGIN_HEADER
     FT_Bool       no_stem_darkening;
     FT_Int        darken_params[8];
 
+#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ )         && \
+    defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC )
+    ft_hb_funcs_t*  hb_funcs;
+#endif
+
   } AF_ModuleRec, *AF_Module;
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c b/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c
index 007b4328189..fd54948f3a5 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter Unicode script ranges (body).
  *
- * Copyright (C) 2013-2024 by
+ * Copyright (C) 2013-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -73,9 +73,11 @@
   {
     AF_UNIRANGE_REC(  0x0600,  0x06FF ),  /* Arabic                                 */
     AF_UNIRANGE_REC(  0x0750,  0x07FF ),  /* Arabic Supplement                      */
+    AF_UNIRANGE_REC(  0x0870,  0x089F ),  /* Arabic Extended-B                      */
     AF_UNIRANGE_REC(  0x08A0,  0x08FF ),  /* Arabic Extended-A                      */
     AF_UNIRANGE_REC(  0xFB50,  0xFDFF ),  /* Arabic Presentation Forms-A            */
     AF_UNIRANGE_REC(  0xFE70,  0xFEFF ),  /* Arabic Presentation Forms-B            */
+    AF_UNIRANGE_REC( 0x10EC0, 0x10EFF ),  /* Arabic Extended-C                      */
     AF_UNIRANGE_REC( 0x1EE00, 0x1EEFF ),  /* Arabic Mathematical Alphabetic Symbols */
     AF_UNIRANGE_REC(       0,       0 )
   };
@@ -90,8 +92,9 @@
     AF_UNIRANGE_REC(  0x06DF,  0x06E4 ),
     AF_UNIRANGE_REC(  0x06E7,  0x06E8 ),
     AF_UNIRANGE_REC(  0x06EA,  0x06ED ),
-    AF_UNIRANGE_REC(  0x08D4,  0x08E1 ),
-    AF_UNIRANGE_REC(  0x08D3,  0x08FF ),
+    AF_UNIRANGE_REC(  0x0897,  0x089F ),
+    AF_UNIRANGE_REC(  0x08CA,  0x08E1 ),
+    AF_UNIRANGE_REC(  0x08E3,  0x08FF ),
     AF_UNIRANGE_REC(  0xFBB2,  0xFBC1 ),
     AF_UNIRANGE_REC(  0xFE70,  0xFE70 ),
     AF_UNIRANGE_REC(  0xFE72,  0xFE72 ),
@@ -101,6 +104,7 @@
     AF_UNIRANGE_REC(  0xFE7A,  0xFE7A ),
     AF_UNIRANGE_REC(  0xFE7C,  0xFE7C ),
     AF_UNIRANGE_REC(  0xFE7E,  0xFE7E ),
+    AF_UNIRANGE_REC( 0x10EFD, 0x10EFF ),
     AF_UNIRANGE_REC(       0,       0 )
   };
 
@@ -198,8 +202,9 @@
 
   const AF_Script_UniRangeRec  af_cans_uniranges[] =
   {
-    AF_UNIRANGE_REC(  0x1400,  0x167F ), /* Unified Canadian Aboriginal Syllabics          */
-    AF_UNIRANGE_REC(  0x18B0,  0x18FF ), /* Unified Canadian Aboriginal Syllabics Extended */
+    AF_UNIRANGE_REC(  0x1400,  0x167F ), /* Unified Canadian Aboriginal Syllabics            */
+    AF_UNIRANGE_REC(  0x18B0,  0x18FF ), /* Unified Canadian Aboriginal Syllabics Extended   */
+    AF_UNIRANGE_REC( 0x11AB0, 0x11ABF ), /* Unified Canadian Aboriginal Syllabics Extended-A */
     AF_UNIRANGE_REC(       0,       0 )
   };
 
@@ -259,6 +264,9 @@
   };
 
 
+  /* TODO: Split off data for new 'cyrb' (subscript) and 'cyrp'     */
+  /*       (superscript) groups (mainly from the Extended-D block), */
+  /*       in analogy to 'latb' and 'latp'?                         */
   const AF_Script_UniRangeRec  af_cyrl_uniranges[] =
   {
     AF_UNIRANGE_REC(  0x0400,  0x04FF ),  /* Cyrillic            */
@@ -266,6 +274,7 @@
     AF_UNIRANGE_REC(  0x2DE0,  0x2DFF ),  /* Cyrillic Extended-A */
     AF_UNIRANGE_REC(  0xA640,  0xA69F ),  /* Cyrillic Extended-B */
     AF_UNIRANGE_REC(  0x1C80,  0x1C8F ),  /* Cyrillic Extended-C */
+    AF_UNIRANGE_REC( 0x1E030, 0x1E08F ),  /* Cyrillic Extended-D */
     AF_UNIRANGE_REC(       0,       0 )
   };
 
@@ -285,15 +294,16 @@
 
   const AF_Script_UniRangeRec  af_deva_uniranges[] =
   {
-    AF_UNIRANGE_REC(  0x0900,  0x093B ),  /* Devanagari          */
+    AF_UNIRANGE_REC(  0x0900,  0x093B ),  /* Devanagari            */
     /* omitting U+093C nukta */
-    AF_UNIRANGE_REC(  0x093D,  0x0950 ),  /* ... continued       */
+    AF_UNIRANGE_REC(  0x093D,  0x0950 ),  /* ... continued         */
     /* omitting U+0951 udatta, U+0952 anudatta */
-    AF_UNIRANGE_REC(  0x0953,  0x0963 ),  /* ... continued       */
+    AF_UNIRANGE_REC(  0x0953,  0x0963 ),  /* ... continued         */
     /* omitting U+0964 danda, U+0965 double danda */
-    AF_UNIRANGE_REC(  0x0966,  0x097F ),  /* ... continued       */
-    AF_UNIRANGE_REC(  0x20B9,  0x20B9 ),  /* (new) Rupee sign    */
-    AF_UNIRANGE_REC(  0xA8E0,  0xA8FF ),  /* Devanagari Extended */
+    AF_UNIRANGE_REC(  0x0966,  0x097F ),  /* ... continued         */
+    AF_UNIRANGE_REC(  0x20B9,  0x20B9 ),  /* (new) Rupee sign      */
+    AF_UNIRANGE_REC(  0xA8E0,  0xA8FF ),  /* Devanagari Extended   */
+    AF_UNIRANGE_REC( 0x11B00, 0x11B5F ),  /* Devanagari Extended-A */
     AF_UNIRANGE_REC(       0,       0 )
   };
 
@@ -329,6 +339,7 @@
     AF_UNIRANGE_REC(  0x1380,  0x139F ),  /* Ethiopic Supplement */
     AF_UNIRANGE_REC(  0x2D80,  0x2DDF ),  /* Ethiopic Extended   */
     AF_UNIRANGE_REC(  0xAB00,  0xAB2F ),  /* Ethiopic Extended-A */
+    AF_UNIRANGE_REC( 0x1E7E0, 0x1E7FF ),  /* Ethiopic Extended-B */
     AF_UNIRANGE_REC(       0,       0 )
   };
 
@@ -534,7 +545,7 @@
   {
     AF_UNIRANGE_REC(  0x0EB1,  0x0EB1 ),
     AF_UNIRANGE_REC(  0x0EB4,  0x0EBC ),
-    AF_UNIRANGE_REC(  0x0EC8,  0x0ECD ),
+    AF_UNIRANGE_REC(  0x0EC8,  0x0ECE ),
     AF_UNIRANGE_REC(       0,       0 )
   };
 
@@ -567,12 +578,15 @@
     AF_UNIRANGE_REC(  0x2C7E,  0x2C7F ),  /* ... continued                          */
     AF_UNIRANGE_REC(  0x2E00,  0x2E7F ),  /* Supplemental Punctuation               */
     AF_UNIRANGE_REC(  0xA720,  0xA76F ),  /* Latin Extended-D                       */
-    AF_UNIRANGE_REC(  0xA771,  0xA7F7 ),  /* ... continued                          */
+    AF_UNIRANGE_REC(  0xA771,  0xA7F0 ),  /* ... continued                          */
+    AF_UNIRANGE_REC(  0xA7F2,  0xA7F7 ),  /* ... continued                          */
     AF_UNIRANGE_REC(  0xA7FA,  0xA7FF ),  /* ... continued                          */
     AF_UNIRANGE_REC(  0xAB30,  0xAB5B ),  /* Latin Extended-E                       */
-    AF_UNIRANGE_REC(  0xAB60,  0xAB6F ),  /* ... continued                          */
+    AF_UNIRANGE_REC(  0xAB60,  0xAB68 ),  /* ... continued                          */
+    AF_UNIRANGE_REC(  0xAB6A,  0xAB6F ),  /* ... continued                          */
     AF_UNIRANGE_REC(  0xFB00,  0xFB06 ),  /* Alphab. Present. Forms (Latin Ligs)    */
     AF_UNIRANGE_REC( 0x1D400, 0x1D7FF ),  /* Mathematical Alphanumeric Symbols      */
+    AF_UNIRANGE_REC( 0x1DF00, 0x1DFFF ),  /* Latin Extended-G                       */
     AF_UNIRANGE_REC(       0,       0 )
   };
 
@@ -588,7 +602,7 @@
     AF_UNIRANGE_REC(  0x02B9,  0x02DF ),
     AF_UNIRANGE_REC(  0x02E5,  0x02FF ),
     AF_UNIRANGE_REC(  0x0300,  0x036F ),
-    AF_UNIRANGE_REC(  0x1AB0,  0x1ABE ),
+    AF_UNIRANGE_REC(  0x1AB0,  0x1AEB ),
     AF_UNIRANGE_REC(  0x1DC0,  0x1DFF ),
     AF_UNIRANGE_REC(  0x2017,  0x2017 ),
     AF_UNIRANGE_REC(  0x203E,  0x203E ),
@@ -625,8 +639,11 @@
     AF_UNIRANGE_REC(  0x2070,  0x207F ),  /* superscript digits and letters      */
     AF_UNIRANGE_REC(  0x2C7D,  0x2C7D ),  /* modifier letter capital v           */
     AF_UNIRANGE_REC(  0xA770,  0xA770 ),  /* modifier letter us                  */
+    AF_UNIRANGE_REC(  0xA7F1,  0xA7F1 ),  /* modifier letter capital s           */
     AF_UNIRANGE_REC(  0xA7F8,  0xA7F9 ),  /* more modifier letters               */
     AF_UNIRANGE_REC(  0xAB5C,  0xAB5F ),  /* more modifier letters               */
+    AF_UNIRANGE_REC(  0xAB69,  0xAB69 ),  /* modifier letter small turned w      */
+    AF_UNIRANGE_REC( 0x10780, 0x107FB ),  /* Latin Extended-F                    */
     AF_UNIRANGE_REC(       0,       0 )
   };
 
@@ -638,7 +655,8 @@
 
   const AF_Script_UniRangeRec  af_lisu_uniranges[] =
   {
-    AF_UNIRANGE_REC(  0xA4D0,  0xA4FF ),    /* Lisu */
+    AF_UNIRANGE_REC(  0xA4D0,  0xA4FF ),    /* Lisu            */
+    AF_UNIRANGE_REC( 0x11FB0, 0x11FBF ),    /* Lisu Supplement */
     AF_UNIRANGE_REC(       0,       0 )
   };
 
@@ -696,6 +714,7 @@
     AF_UNIRANGE_REC(  0x1000,  0x109F ),    /* Myanmar            */
     AF_UNIRANGE_REC(  0xA9E0,  0xA9FF ),    /* Myanmar Extended-B */
     AF_UNIRANGE_REC(  0xAA60,  0xAA7F ),    /* Myanmar Extended-A */
+    AF_UNIRANGE_REC( 0x116D0, 0x116FF ),    /* Myanmar Extended-C */
     AF_UNIRANGE_REC(       0,       0 )
   };
 
@@ -836,6 +855,7 @@
 
   const AF_Script_UniRangeRec  af_sinh_nonbase_uniranges[] =
   {
+    AF_UNIRANGE_REC(  0x0D81,  0x0D81 ),
     AF_UNIRANGE_REC(  0x0DCA,  0x0DCA ),
     AF_UNIRANGE_REC(  0x0DD2,  0x0DD6 ),
     AF_UNIRANGE_REC(       0,       0 )
@@ -859,7 +879,8 @@
 
   const AF_Script_UniRangeRec  af_taml_uniranges[] =
   {
-    AF_UNIRANGE_REC(  0x0B80,  0x0BFF ),  /* Tamil */
+    AF_UNIRANGE_REC(  0x0B80,  0x0BFF ),  /* Tamil            */
+    AF_UNIRANGE_REC( 0x11FC0, 0x11FFF ),  /* Tamil Supplement */
     AF_UNIRANGE_REC(       0,       0 )
   };
 
@@ -899,6 +920,7 @@
   {
     AF_UNIRANGE_REC(  0x0C00,  0x0C00 ),
     AF_UNIRANGE_REC(  0x0C04,  0x0C04 ),
+    AF_UNIRANGE_REC(  0x0C3C,  0x0C3C ),
     AF_UNIRANGE_REC(  0x0C3E,  0x0C40 ),
     AF_UNIRANGE_REC(  0x0C46,  0x0C56 ),
     AF_UNIRANGE_REC(  0x0C62,  0x0C63 ),
@@ -992,6 +1014,7 @@
     AF_UNIRANGE_REC(  0xA806,  0xA806 ),
     AF_UNIRANGE_REC(  0xA80B,  0xA80B ),
     AF_UNIRANGE_REC(  0xA825,  0xA826 ),
+    AF_UNIRANGE_REC(  0xA82C,  0xA82C ),
     AF_UNIRANGE_REC(       0,       0 )
   };
 
@@ -1048,15 +1071,21 @@
     AF_UNIRANGE_REC(  0xFE10,  0xFE1F ),  /* Vertical forms                          */
     AF_UNIRANGE_REC(  0xFE30,  0xFE4F ),  /* CJK Compatibility Forms                 */
     AF_UNIRANGE_REC(  0xFF00,  0xFFEF ),  /* Halfwidth and Fullwidth Forms           */
+    AF_UNIRANGE_REC( 0x1AFF0, 0x1AFFF ),  /* Kana Extended-B                         */
     AF_UNIRANGE_REC( 0x1B000, 0x1B0FF ),  /* Kana Supplement                         */
     AF_UNIRANGE_REC( 0x1B100, 0x1B12F ),  /* Kana Extended-A                         */
+    AF_UNIRANGE_REC( 0x1B130, 0x1B16F ),  /* Small Kana Extension                    */
     AF_UNIRANGE_REC( 0x1D300, 0x1D35F ),  /* Tai Xuan Hing Symbols                   */
     AF_UNIRANGE_REC( 0x20000, 0x2A6DF ),  /* CJK Unified Ideographs Extension B      */
     AF_UNIRANGE_REC( 0x2A700, 0x2B73F ),  /* CJK Unified Ideographs Extension C      */
     AF_UNIRANGE_REC( 0x2B740, 0x2B81F ),  /* CJK Unified Ideographs Extension D      */
     AF_UNIRANGE_REC( 0x2B820, 0x2CEAF ),  /* CJK Unified Ideographs Extension E      */
     AF_UNIRANGE_REC( 0x2CEB0, 0x2EBEF ),  /* CJK Unified Ideographs Extension F      */
+    AF_UNIRANGE_REC( 0x2EBF0, 0x2EE5D ),  /* CJK Unified Ideographs Extension I      */
     AF_UNIRANGE_REC( 0x2F800, 0x2FA1F ),  /* CJK Compatibility Ideographs Supplement */
+    AF_UNIRANGE_REC( 0x30000, 0x3134A ),  /* CJK Unified Ideographs Extension G      */
+    AF_UNIRANGE_REC( 0x31350, 0x323AF ),  /* CJK Unified Ideographs Extension H      */
+    AF_UNIRANGE_REC( 0x323B0, 0x33479 ),  /* CJK Unified Ideographs Extension J      */
     AF_UNIRANGE_REC(       0,       0 )
   };
 
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afranges.h b/src/java.desktop/share/native/libfreetype/src/autofit/afranges.h
index 813b3ee78ef..fa00eb75046 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afranges.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afranges.h
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter Unicode script ranges (specification).
  *
- * Copyright (C) 2013-2024 by
+ * Copyright (C) 2013-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afscript.h b/src/java.desktop/share/native/libfreetype/src/autofit/afscript.h
index 0a83d771501..5c4cbbcb922 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afscript.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afscript.h
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter scripts (specification only).
  *
- * Copyright (C) 2013-2024 by
+ * Copyright (C) 2013-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c b/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c
index df0f46ada89..f3c0744fd9d 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c
@@ -4,7 +4,7 @@
  *
  *   HarfBuzz interface for accessing OpenType features (body).
  *
- * Copyright (C) 2013-2024 by
+ * Copyright (C) 2013-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -22,8 +22,8 @@
 #include "aftypes.h"
 #include "afshaper.h"
 
-#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
 
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
 
   /**************************************************************************
    *
@@ -89,17 +89,18 @@
 #define SCRIPT( s, S, d, h, H, ss )  h,
 
 
-  static const hb_script_t  scripts[] =
+  FT_LOCAL_ARRAY_DEF( hb_script_t )
+  af_hb_scripts[] =
   {
 #include "afscript.h"
   };
 
 
-  FT_Error
-  af_shaper_get_coverage( AF_FaceGlobals  globals,
-                          AF_StyleClass   style_class,
-                          FT_UShort*      gstyles,
-                          FT_Bool         default_script )
+  static FT_Error
+  af_shaper_get_coverage_hb( AF_FaceGlobals  globals,
+                             AF_StyleClass   style_class,
+                             FT_UShort*      gstyles,
+                             FT_Bool         default_script )
   {
     hb_face_t*  face;
 
@@ -124,10 +125,10 @@
     if ( !globals || !style_class || !gstyles )
       return FT_THROW( Invalid_Argument );
 
-    face = hb_font_get_face( globals->hb_font );
+    face = hb( font_get_face )( globals->hb_font );
 
     coverage_tags = coverages[style_class->coverage];
-    script        = scripts[style_class->script];
+    script        = af_hb_scripts[style_class->script];
 
     /* Convert a HarfBuzz script tag into the corresponding OpenType */
     /* tag or tags -- some Indic scripts like Devanagari have an old */
@@ -137,19 +138,19 @@
       hb_tag_t      tags[3];
 
 
-      hb_ot_tags_from_script_and_language( script,
-                                           HB_LANGUAGE_INVALID,
-                                           &tags_count,
-                                           tags,
-                                           NULL,
-                                           NULL );
+      hb( ot_tags_from_script_and_language )( script,
+                                              HB_LANGUAGE_INVALID,
+                                              &tags_count,
+                                              tags,
+                                              NULL,
+                                              NULL );
       script_tags[0] = tags_count > 0 ? tags[0] : HB_TAG_NONE;
       script_tags[1] = tags_count > 1 ? tags[1] : HB_TAG_NONE;
       script_tags[2] = tags_count > 2 ? tags[2] : HB_TAG_NONE;
     }
 
-    /* If the second tag is HB_OT_TAG_DEFAULT_SCRIPT, change that to     */
-    /* HB_TAG_NONE except for the default script.                        */
+    /* If the second tag is HB_OT_TAG_DEFAULT_SCRIPT, change that to */
+    /* HB_TAG_NONE except for the default script.                    */
     if ( default_script )
     {
       if ( script_tags[0] == HB_TAG_NONE )
@@ -170,15 +171,15 @@
         goto Exit;
     }
 
-    gsub_lookups = hb_set_create();
-    hb_ot_layout_collect_lookups( face,
-                                  HB_OT_TAG_GSUB,
-                                  script_tags,
-                                  NULL,
-                                  coverage_tags,
-                                  gsub_lookups );
+    gsub_lookups = hb( set_create )();
+    hb( ot_layout_collect_lookups )( face,
+                                     HB_OT_TAG_GSUB,
+                                     script_tags,
+                                     NULL,
+                                     coverage_tags,
+                                     gsub_lookups );
 
-    if ( hb_set_is_empty( gsub_lookups ) )
+    if ( hb( set_is_empty )( gsub_lookups ) )
       goto Exit; /* nothing to do */
 
     FT_TRACE4(( "GSUB lookups (style `%s'):\n",
@@ -189,22 +190,22 @@
     count = 0;
 #endif
 
-    gsub_glyphs = hb_set_create();
-    for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups, &idx ); )
+    gsub_glyphs = hb( set_create )();
+    for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gsub_lookups, &idx ); )
     {
 #ifdef FT_DEBUG_LEVEL_TRACE
-      FT_TRACE4(( " %d", idx ));
+      FT_TRACE4(( " %u", idx ));
       count++;
 #endif
 
       /* get output coverage of GSUB feature */
-      hb_ot_layout_lookup_collect_glyphs( face,
-                                          HB_OT_TAG_GSUB,
-                                          idx,
-                                          NULL,
-                                          NULL,
-                                          NULL,
-                                          gsub_glyphs );
+      hb( ot_layout_lookup_collect_glyphs )( face,
+                                             HB_OT_TAG_GSUB,
+                                             idx,
+                                             NULL,
+                                             NULL,
+                                             NULL,
+                                             gsub_glyphs );
     }
 
 #ifdef FT_DEBUG_LEVEL_TRACE
@@ -218,34 +219,34 @@
                 af_style_names[style_class->style] ));
     FT_TRACE4(( " " ));
 
-    gpos_lookups = hb_set_create();
-    hb_ot_layout_collect_lookups( face,
-                                  HB_OT_TAG_GPOS,
-                                  script_tags,
-                                  NULL,
-                                  coverage_tags,
-                                  gpos_lookups );
+    gpos_lookups = hb( set_create )();
+    hb( ot_layout_collect_lookups )( face,
+                                     HB_OT_TAG_GPOS,
+                                     script_tags,
+                                     NULL,
+                                     coverage_tags,
+                                     gpos_lookups );
 
 #ifdef FT_DEBUG_LEVEL_TRACE
     count = 0;
 #endif
 
-    gpos_glyphs = hb_set_create();
-    for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gpos_lookups, &idx ); )
+    gpos_glyphs = hb( set_create )();
+    for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gpos_lookups, &idx ); )
     {
 #ifdef FT_DEBUG_LEVEL_TRACE
-      FT_TRACE4(( " %d", idx ));
+      FT_TRACE4(( " %u", idx ));
       count++;
 #endif
 
       /* get input coverage of GPOS feature */
-      hb_ot_layout_lookup_collect_glyphs( face,
-                                          HB_OT_TAG_GPOS,
-                                          idx,
-                                          NULL,
-                                          gpos_glyphs,
-                                          NULL,
-                                          NULL );
+      hb( ot_layout_lookup_collect_glyphs )( face,
+                                             HB_OT_TAG_GPOS,
+                                             idx,
+                                             NULL,
+                                             gpos_glyphs,
+                                             NULL,
+                                             NULL );
     }
 
 #ifdef FT_DEBUG_LEVEL_TRACE
@@ -281,14 +282,14 @@
 
           GET_UTF8_CHAR( ch, p );
 
-          for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups,
-                                                         &idx ); )
+          for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gsub_lookups,
+                                                            &idx ); )
           {
             hb_codepoint_t  gidx = FT_Get_Char_Index( globals->face, ch );
 
 
-            if ( hb_ot_layout_lookup_would_substitute( face, idx,
-                                                       &gidx, 1, 1 ) )
+            if ( hb( ot_layout_lookup_would_substitute )( face, idx,
+                                                          &gidx, 1, 1 ) )
             {
               found = 1;
               break;
@@ -352,14 +353,14 @@
      *
      */
     if ( style_class->coverage != AF_COVERAGE_DEFAULT )
-      hb_set_subtract( gsub_glyphs, gpos_glyphs );
+      hb( set_subtract )( gsub_glyphs, gpos_glyphs );
 
 #ifdef FT_DEBUG_LEVEL_TRACE
     FT_TRACE4(( "  glyphs without GPOS data (`*' means already assigned)" ));
     count = 0;
 #endif
 
-    for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_glyphs, &idx ); )
+    for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gsub_glyphs, &idx ); )
     {
 #ifdef FT_DEBUG_LEVEL_TRACE
       if ( !( count % 10 ) )
@@ -368,7 +369,7 @@
         FT_TRACE4(( "   " ));
       }
 
-      FT_TRACE4(( " %d", idx ));
+      FT_TRACE4(( " %u", idx ));
       count++;
 #endif
 
@@ -397,10 +398,10 @@
 #endif
 
   Exit:
-    hb_set_destroy( gsub_lookups );
-    hb_set_destroy( gsub_glyphs  );
-    hb_set_destroy( gpos_lookups );
-    hb_set_destroy( gpos_glyphs  );
+    hb( set_destroy )( gsub_lookups );
+    hb( set_destroy )( gsub_glyphs  );
+    hb( set_destroy )( gpos_lookups );
+    hb( set_destroy )( gpos_glyphs  );
 
     return FT_Err_Ok;
   }
@@ -437,31 +438,33 @@
   };
 
 
-  void*
-  af_shaper_buf_create( FT_Face  face )
+  static void*
+  af_shaper_buf_create_hb( AF_FaceGlobals  globals )
   {
-    FT_UNUSED( face );
+    FT_UNUSED( globals );
 
-    return (void*)hb_buffer_create();
+    return (void*)hb( buffer_create )();
   }
 
 
-  void
-  af_shaper_buf_destroy( FT_Face  face,
-                         void*    buf )
+  static void
+  af_shaper_buf_destroy_hb( AF_FaceGlobals  globals,
+                            void*           buf )
   {
-    FT_UNUSED( face );
+    FT_UNUSED( globals );
 
-    hb_buffer_destroy( (hb_buffer_t*)buf );
+    hb( buffer_destroy )( (hb_buffer_t*)buf );
   }
 
 
-  const char*
-  af_shaper_get_cluster( const char*      p,
-                         AF_StyleMetrics  metrics,
-                         void*            buf_,
-                         unsigned int*    count )
+  static const char*
+  af_shaper_get_cluster_hb( const char*      p,
+                            AF_StyleMetrics  metrics,
+                            void*            buf_,
+                            unsigned int*    count )
   {
+    AF_FaceGlobals  globals = metrics->globals;
+
     AF_StyleClass        style_class;
     const hb_feature_t*  feature;
     FT_Int               upem;
@@ -472,6 +475,8 @@
     hb_font_t*      font;
     hb_codepoint_t  dummy;
 
+    FT_UNUSED( globals );
+
 
     upem        = (FT_Int)metrics->globals->face->units_per_EM;
     style_class = metrics->style_class;
@@ -480,7 +485,7 @@
     font = metrics->globals->hb_font;
 
     /* we shape at a size of units per EM; this means font units */
-    hb_font_set_scale( font, upem, upem );
+    hb( font_set_scale )( font, upem, upem );
 
     while ( *p == ' ' )
       p++;
@@ -492,15 +497,15 @@
     len = (int)( q - p );
 
     /* feed character(s) to the HarfBuzz buffer */
-    hb_buffer_clear_contents( buf );
-    hb_buffer_add_utf8( buf, p, len, 0, len );
+    hb( buffer_clear_contents )( buf );
+    hb( buffer_add_utf8 )( buf, p, len, 0, len );
 
     /* we let HarfBuzz guess the script and writing direction */
-    hb_buffer_guess_segment_properties( buf );
+    hb( buffer_guess_segment_properties )( buf );
 
     /* shape buffer, which means conversion from character codes to */
     /* glyph indices, possibly applying a feature                   */
-    hb_shape( font, buf, feature, feature ? 1 : 0 );
+    hb( shape )( font, buf, feature, feature ? 1 : 0 );
 
     if ( feature )
     {
@@ -517,13 +522,13 @@
       /* glyph indices; otherwise the affected glyph or glyphs aren't     */
       /* available at all in the feature                                  */
 
-      hb_buffer_clear_contents( hb_buf );
-      hb_buffer_add_utf8( hb_buf, p, len, 0, len );
-      hb_buffer_guess_segment_properties( hb_buf );
-      hb_shape( font, hb_buf, NULL, 0 );
+      hb( buffer_clear_contents )( hb_buf );
+      hb( buffer_add_utf8 )( hb_buf, p, len, 0, len );
+      hb( buffer_guess_segment_properties )( hb_buf );
+      hb( shape )( font, hb_buf, NULL, 0 );
 
-      ginfo    = hb_buffer_get_glyph_infos( buf, &gcount );
-      hb_ginfo = hb_buffer_get_glyph_infos( hb_buf, &hb_gcount );
+      ginfo    = hb( buffer_get_glyph_infos )( buf, &gcount );
+      hb_ginfo = hb( buffer_get_glyph_infos )( hb_buf, &hb_gcount );
 
       if ( gcount == hb_gcount )
       {
@@ -537,12 +542,12 @@
         if ( i == gcount )
         {
           /* both buffers have identical glyph indices */
-          hb_buffer_clear_contents( buf );
+          hb( buffer_clear_contents )( buf );
         }
       }
     }
 
-    *count = hb_buffer_get_length( buf );
+    *count = hb( buffer_get_length )( buf );
 
 #ifdef FT_DEBUG_LEVEL_TRACE
     if ( feature && *count > 1 )
@@ -554,23 +559,25 @@
   }
 
 
-  FT_ULong
-  af_shaper_get_elem( AF_StyleMetrics  metrics,
-                      void*            buf_,
-                      unsigned int     idx,
-                      FT_Long*         advance,
-                      FT_Long*         y_offset )
+  static FT_ULong
+  af_shaper_get_elem_hb( AF_StyleMetrics  metrics,
+                         void*            buf_,
+                         unsigned int     idx,
+                         FT_Long*         advance,
+                         FT_Long*         y_offset )
   {
+    AF_FaceGlobals  globals = metrics->globals;
+
     hb_buffer_t*          buf = (hb_buffer_t*)buf_;
     hb_glyph_info_t*      ginfo;
     hb_glyph_position_t*  gpos;
     unsigned int          gcount;
 
-    FT_UNUSED( metrics );
+    FT_UNUSED( globals );
 
 
-    ginfo = hb_buffer_get_glyph_infos( buf, &gcount );
-    gpos  = hb_buffer_get_glyph_positions( buf, &gcount );
+    ginfo = hb( buffer_get_glyph_infos )( buf, &gcount );
+    gpos  = hb( buffer_get_glyph_positions )( buf, &gcount );
 
     if ( idx >= gcount )
       return 0;
@@ -584,14 +591,14 @@
   }
 
 
-#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */
+#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */
 
 
-  FT_Error
-  af_shaper_get_coverage( AF_FaceGlobals  globals,
-                          AF_StyleClass   style_class,
-                          FT_UShort*      gstyles,
-                          FT_Bool         default_script )
+  static FT_Error
+  af_shaper_get_coverage_nohb( AF_FaceGlobals  globals,
+                               AF_StyleClass   style_class,
+                               FT_UShort*      gstyles,
+                               FT_Bool         default_script )
   {
     FT_UNUSED( globals );
     FT_UNUSED( style_class );
@@ -602,29 +609,29 @@
   }
 
 
-  void*
-  af_shaper_buf_create( FT_Face  face )
+  static void*
+  af_shaper_buf_create_nohb( AF_FaceGlobals  globals )
   {
-    FT_UNUSED( face );
+    FT_UNUSED( globals );
 
     return NULL;
   }
 
 
-  void
-  af_shaper_buf_destroy( FT_Face  face,
-                         void*    buf )
+  static void
+  af_shaper_buf_destroy_nohb( AF_FaceGlobals  globals,
+                              void*    buf )
   {
-    FT_UNUSED( face );
+    FT_UNUSED( globals );
     FT_UNUSED( buf );
   }
 
 
-  const char*
-  af_shaper_get_cluster( const char*      p,
-                         AF_StyleMetrics  metrics,
-                         void*            buf_,
-                         unsigned int*    count )
+  static const char*
+  af_shaper_get_cluster_nohb( const char*      p,
+                              AF_StyleMetrics  metrics,
+                              void*            buf_,
+                              unsigned int*    count )
   {
     FT_Face    face      = metrics->globals->face;
     FT_ULong   ch, dummy = 0;
@@ -656,12 +663,12 @@
   }
 
 
-  FT_ULong
-  af_shaper_get_elem( AF_StyleMetrics  metrics,
-                      void*            buf_,
-                      unsigned int     idx,
-                      FT_Long*         advance,
-                      FT_Long*         y_offset )
+  static FT_ULong
+  af_shaper_get_elem_nohb( AF_StyleMetrics  metrics,
+                           void*            buf_,
+                           unsigned int     idx,
+                           FT_Long*         advance,
+                           FT_Long*         y_offset )
   {
     FT_Face   face        = metrics->globals->face;
     FT_ULong  glyph_index = *(FT_ULong*)buf_;
@@ -684,7 +691,90 @@
   }
 
 
-#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */
+  /********************************************************************/
+
+  FT_Error
+  af_shaper_get_coverage( AF_FaceGlobals  globals,
+                          AF_StyleClass   style_class,
+                          FT_UShort*      gstyles,
+                          FT_Bool         default_script )
+  {
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
+    if ( ft_hb_enabled( globals ) )
+      return af_shaper_get_coverage_hb( globals,
+                                        style_class,
+                                        gstyles,
+                                        default_script );
+    else
+#endif
+      return af_shaper_get_coverage_nohb( globals,
+                                          style_class,
+                                          gstyles,
+                                          default_script );
+  }
+
+
+  void*
+  af_shaper_buf_create( AF_FaceGlobals  globals )
+  {
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
+    if ( ft_hb_enabled( globals ) )
+      return af_shaper_buf_create_hb( globals );
+    else
+#endif
+      return af_shaper_buf_create_nohb( globals );
+  }
+
+
+  void
+  af_shaper_buf_destroy( AF_FaceGlobals  globals,
+                         void*           buf )
+  {
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
+    if ( ft_hb_enabled( globals ) )
+      af_shaper_buf_destroy_hb( globals, buf );
+    else
+#endif
+      af_shaper_buf_destroy_nohb( globals, buf );
+  }
+
+
+  const char*
+  af_shaper_get_cluster( const char*      p,
+                         AF_StyleMetrics  metrics,
+                         void*            buf_,
+                         unsigned int*    count )
+  {
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
+    if ( ft_hb_enabled( metrics->globals ) )
+      return af_shaper_get_cluster_hb( p, metrics, buf_, count );
+    else
+#endif
+      return af_shaper_get_cluster_nohb( p, metrics, buf_, count );
+  }
+
+
+  FT_ULong
+  af_shaper_get_elem( AF_StyleMetrics  metrics,
+                      void*            buf_,
+                      unsigned int     idx,
+                      FT_Long*         advance,
+                      FT_Long*         y_offset )
+  {
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
+    if ( ft_hb_enabled( metrics->globals ) )
+      return af_shaper_get_elem_hb( metrics,
+                                    buf_,
+                                    idx,
+                                    advance,
+                                    y_offset );
+#endif
+      return af_shaper_get_elem_nohb( metrics,
+                                      buf_,
+                                      idx,
+                                      advance,
+                                      y_offset );
+  }
 
 
 /* END */
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.h b/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.h
index 2eb03bb5d98..757368fc9c0 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.h
@@ -4,7 +4,7 @@
  *
  *   HarfBuzz interface for accessing OpenType features (specification).
  *
- * Copyright (C) 2013-2024 by
+ * Copyright (C) 2013-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -23,17 +23,14 @@
 #include 
 
 
-#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
-
-#include 
-#include 
-#include "ft-hb.h"
+FT_BEGIN_HEADER
 
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
+  FT_LOCAL_ARRAY( hb_script_t )
+  af_hb_scripts[];
 #endif
 
 
-FT_BEGIN_HEADER
-
   FT_Error
   af_shaper_get_coverage( AF_FaceGlobals  globals,
                           AF_StyleClass   style_class,
@@ -42,11 +39,11 @@ FT_BEGIN_HEADER
 
 
   void*
-  af_shaper_buf_create( FT_Face  face );
+  af_shaper_buf_create( AF_FaceGlobals  globals );
 
   void
-  af_shaper_buf_destroy( FT_Face  face,
-                         void*    buf );
+  af_shaper_buf_destroy( AF_FaceGlobals  globals,
+                         void*           buf );
 
   const char*
   af_shaper_get_cluster( const char*      p,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afstyles.h b/src/java.desktop/share/native/libfreetype/src/autofit/afstyles.h
index 7a33f37a856..206232efe25 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afstyles.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afstyles.h
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter styles (specification only).
  *
- * Copyright (C) 2013-2024 by
+ * Copyright (C) 2013-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -50,36 +50,36 @@
                  AF_COVERAGE_ ## C )
 
 #undef  META_STYLE_LATIN
-#define META_STYLE_LATIN( s, S, ds )                     \
-          STYLE_LATIN( s, S, c2cp, C2CP, ds,             \
+#define META_STYLE_LATIN( s, S, ds )                    \
+          STYLE_LATIN( s, S, c2cp, C2CP, ds,            \
                        "petite capitals from capitals", \
-                       PETITE_CAPITALS_FROM_CAPITALS )   \
-          STYLE_LATIN( s, S, c2sc, C2SC, ds,             \
+                       PETITE_CAPITALS_FROM_CAPITALS )  \
+          STYLE_LATIN( s, S, c2sc, C2SC, ds,            \
                        "small capitals from capitals",  \
-                       SMALL_CAPITALS_FROM_CAPITALS )    \
-          STYLE_LATIN( s, S, ordn, ORDN, ds,             \
-                       "ordinals",                       \
-                       ORDINALS )                        \
-          STYLE_LATIN( s, S, pcap, PCAP, ds,             \
-                       "petite capitals",                \
-                       PETITE_CAPITALS )                 \
-          STYLE_LATIN( s, S, sinf, SINF, ds,             \
-                       "scientific inferiors",           \
-                       SCIENTIFIC_INFERIORS )            \
-          STYLE_LATIN( s, S, smcp, SMCP, ds,             \
-                       "small capitals",                 \
-                       SMALL_CAPITALS )                  \
-          STYLE_LATIN( s, S, subs, SUBS, ds,             \
-                       "subscript",                      \
-                       SUBSCRIPT )                       \
-          STYLE_LATIN( s, S, sups, SUPS, ds,             \
-                       "superscript",                    \
-                       SUPERSCRIPT )                     \
-          STYLE_LATIN( s, S, titl, TITL, ds,             \
-                       "titling",                        \
-                       TITLING )                         \
-          STYLE_LATIN( s, S, dflt, DFLT, ds,             \
-                       "default",                        \
+                       SMALL_CAPITALS_FROM_CAPITALS )   \
+          STYLE_LATIN( s, S, ordn, ORDN, ds,            \
+                       "ordinals",                      \
+                       ORDINALS )                       \
+          STYLE_LATIN( s, S, pcap, PCAP, ds,            \
+                       "petite capitals",               \
+                       PETITE_CAPITALS )                \
+          STYLE_LATIN( s, S, sinf, SINF, ds,            \
+                       "scientific inferiors",          \
+                       SCIENTIFIC_INFERIORS )           \
+          STYLE_LATIN( s, S, smcp, SMCP, ds,            \
+                       "small capitals",                \
+                       SMALL_CAPITALS )                 \
+          STYLE_LATIN( s, S, subs, SUBS, ds,            \
+                       "subscript",                     \
+                       SUBSCRIPT )                      \
+          STYLE_LATIN( s, S, sups, SUPS, ds,            \
+                       "superscript",                   \
+                       SUPERSCRIPT )                    \
+          STYLE_LATIN( s, S, titl, TITL, ds,            \
+                       "titling",                       \
+                       TITLING )                        \
+          STYLE_LATIN( s, S, dflt, DFLT, ds,            \
+                       "default",                       \
                        DEFAULT )
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/aftypes.h b/src/java.desktop/share/native/libfreetype/src/autofit/aftypes.h
index 27e4185e9f8..959640a12ec 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/aftypes.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/aftypes.h
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter types (specification only).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -35,6 +35,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -406,6 +407,7 @@ extern void*  af_debug_hints_;
 
   typedef struct AF_FaceGlobalsRec_*  AF_FaceGlobals;
 
+
   /* This is the main structure that combines everything.  Autofit modules */
   /* specific to writing systems derive their structures from it, for      */
   /* example `AF_LatinMetrics'.                                            */
@@ -418,6 +420,8 @@ extern void*  af_debug_hints_;
 
     AF_FaceGlobals  globals;    /* to access properties */
 
+    FT_Hash  reverse_charmap;
+
   } AF_StyleMetricsRec;
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afws-decl.h b/src/java.desktop/share/native/libfreetype/src/autofit/afws-decl.h
index b78745af74e..12fa7a27a2b 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afws-decl.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afws-decl.h
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter writing system declarations (specification only).
  *
- * Copyright (C) 2013-2024 by
+ * Copyright (C) 2013-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afws-iter.h b/src/java.desktop/share/native/libfreetype/src/autofit/afws-iter.h
index c86d609a352..1752697b375 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afws-iter.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afws-iter.h
@@ -4,7 +4,7 @@
  *
  *   Auto-fitter writing systems iterator (specification only).
  *
- * Copyright (C) 2013-2024 by
+ * Copyright (C) 2013-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/ft-hb.c b/src/java.desktop/share/native/libfreetype/src/autofit/ft-hb.c
new file mode 100644
index 00000000000..3c145d04640
--- /dev/null
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/ft-hb.c
@@ -0,0 +1,197 @@
+/****************************************************************************
+ *
+ * ft-hb.c
+ *
+ *   FreeType-HarfBuzz bridge (body).
+ *
+ * Copyright (C) 2025 by
+ * Behdad Esfahbod.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT.  By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+
+#if !defined( _WIN32 ) && !defined( _GNU_SOURCE )
+#  define _GNU_SOURCE  1  /* for RTLD_DEFAULT */
+#endif
+
+#include 
+#include 
+
+#include "afglobal.h"
+
+#include "ft-hb.h"
+
+
+#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ )         && \
+    defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC )
+
+#ifndef FT_LIBHARFBUZZ
+#  ifdef _WIN32
+#    define FT_LIBHARFBUZZ "libharfbuzz-0.dll"
+#  else
+#    ifdef __APPLE__
+#      define FT_LIBHARFBUZZ "libharfbuzz.0.dylib"
+#    else
+#      define FT_LIBHARFBUZZ "libharfbuzz.so.0"
+#    endif
+#  endif
+#endif
+
+#ifdef _WIN32
+
+#  include 
+
+#else /* !_WIN32 */
+
+#  include 
+
+  /* The GCC pragma suppresses the warning "ISO C forbids     */
+  /* assignment between function pointer and 'void *'", which */
+  /* inevitably gets emitted with `-Wpedantic`; see the man   */
+  /* page of function `dlsym` for more information.           */
+#  if defined( __GNUC__ )
+#    pragma GCC diagnostic push
+#    ifndef __cplusplus
+#      pragma GCC diagnostic ignored "-Wpedantic"
+#    endif
+#  endif
+
+#endif /* !_WIN32 */
+
+
+  FT_LOCAL_DEF( void )
+  ft_hb_funcs_init( struct AF_ModuleRec_  *af_module )
+  {
+    FT_Memory  memory = af_module->root.memory;
+    FT_Error   error;
+
+    ft_hb_funcs_t                *funcs           = NULL;
+    ft_hb_version_atleast_func_t  version_atleast = NULL;
+
+#ifdef _WIN32
+    HANDLE  lib;
+#  define DLSYM( lib, name ) \
+            (ft_ ## name ## _func_t)GetProcAddress( lib, #name )
+#else
+    void  *lib;
+#  define DLSYM( lib, name ) \
+            (ft_ ## name ## _func_t)dlsym( lib, #name )
+#endif
+
+
+    af_module->hb_funcs = NULL;
+
+    if ( FT_NEW( funcs ) )
+      return;
+    FT_ZERO( funcs );
+
+#ifdef _WIN32
+
+    lib = LoadLibraryA( FT_LIBHARFBUZZ );
+    if ( !lib )
+      goto Fail;
+    version_atleast = DLSYM( lib, hb_version_atleast );
+
+#else /* !_WIN32 */
+
+#  ifdef RTLD_DEFAULT
+#    define FT_RTLD_FLAGS RTLD_LAZY | RTLD_GLOBAL
+    lib             = RTLD_DEFAULT;
+    version_atleast = DLSYM( lib, hb_version_atleast );
+#  else
+#    define FT_RTLD_FLAGS RTLD_LAZY
+#  endif
+
+    if ( !version_atleast )
+    {
+      /* Load the HarfBuzz library.
+       *
+       * We never close the library, since we opened it with RTLD_GLOBAL.
+       * This is important for the case where we are using HarfBuzz as a
+       * shared library, and we want to use the symbols from the library in
+       * other shared libraries or clients.  HarfBuzz holds onto global
+       * variables, and closing the library will cause them to be
+       * invalidated.
+       */
+      lib = dlopen( FT_LIBHARFBUZZ, FT_RTLD_FLAGS );
+      if ( !lib )
+        goto Fail;
+      version_atleast = DLSYM( lib, hb_version_atleast );
+    }
+
+#endif /* !_WIN32 */
+
+    if ( !version_atleast )
+      goto Fail;
+
+    /* Load all symbols we use. */
+#define HB_EXTERN( ret, name, args )  \
+  {                                   \
+    funcs->name = DLSYM( lib, name ); \
+    if ( !funcs->name )               \
+      goto Fail;                      \
+  }
+#include "ft-hb-decls.h"
+#undef HB_EXTERN
+
+#undef DLSYM
+
+    af_module->hb_funcs = funcs;
+    return;
+
+  Fail:
+    if ( funcs )
+      FT_FREE( funcs );
+  }
+
+
+  FT_LOCAL_DEF( void )
+  ft_hb_funcs_done( struct AF_ModuleRec_  *af_module )
+  {
+    FT_Memory  memory = af_module->root.memory;
+
+
+    if ( af_module->hb_funcs )
+    {
+      FT_FREE( af_module->hb_funcs );
+      af_module->hb_funcs = NULL;
+    }
+  }
+
+
+  FT_LOCAL_DEF( FT_Bool )
+  ft_hb_enabled( struct AF_FaceGlobalsRec_  *globals )
+  {
+    return globals->module->hb_funcs != NULL;
+  }
+
+#ifndef _WIN32
+#  if defined( __GNUC__ )
+#    pragma GCC diagnostic pop
+#  endif
+#endif
+
+#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */
+
+  FT_LOCAL_DEF( FT_Bool )
+  ft_hb_enabled( struct AF_FaceGlobalsRec_  *globals )
+  {
+    FT_UNUSED( globals );
+
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
+    return TRUE;
+#else
+    return FALSE;
+#endif
+  }
+
+#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */
+
+
+/* END */
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/ft-hb.h b/src/java.desktop/share/native/libfreetype/src/autofit/ft-hb.h
new file mode 100644
index 00000000000..95914deb8d3
--- /dev/null
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/ft-hb.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+ *
+ * ft-hb.h
+ *
+ *   FreeType-HarfBuzz bridge (specification).
+ *
+ * Copyright (C) 2025 by
+ * Behdad Esfahbod.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT.  By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+
+#ifndef FT_HB_H
+#define FT_HB_H
+
+#include 
+#include 
+
+
+FT_BEGIN_HEADER
+
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
+
+#  include "ft-hb-types.h"
+
+#  ifdef FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC
+
+#    define HB_EXTERN( ret, name, args ) \
+              typedef ret (*ft_ ## name ## _func_t) args;
+#    include "ft-hb-decls.h"
+#    undef HB_EXTERN
+
+  typedef struct ft_hb_funcs_t
+  {
+#    define HB_EXTERN( ret, name, args ) \
+              ft_ ## name ## _func_t  name;
+#    include "ft-hb-decls.h"
+#    undef HB_EXTERN
+  } ft_hb_funcs_t;
+
+  struct  AF_ModuleRec_;
+
+  FT_LOCAL( void )
+  ft_hb_funcs_init( struct AF_ModuleRec_  *af_module );
+
+  FT_LOCAL( void )
+  ft_hb_funcs_done( struct AF_ModuleRec_  *af_module );
+
+#    define hb( x )  globals->module->hb_funcs->hb_ ## x
+
+#  else /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */
+
+#    define HB_EXTERN( ret, name, args ) \
+              ret name args;
+#    include "ft-hb-decls.h"
+#    undef HB_EXTERN
+
+#    define hb( x )  hb_ ## x
+
+#  endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */
+
+#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */
+
+
+  struct AF_FaceGlobalsRec_;
+
+  FT_LOCAL( FT_Bool )
+  ft_hb_enabled( struct AF_FaceGlobalsRec_  *globals );
+
+
+FT_END_HEADER
+
+#endif /* FT_HB_H */
+
+
+/* END */
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftadvanc.c b/src/java.desktop/share/native/libfreetype/src/base/ftadvanc.c
index 717f7d08b35..7b965c62d58 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftadvanc.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftadvanc.c
@@ -4,7 +4,7 @@
  *
  *   Quick computation of advance widths (body).
  *
- * Copyright (C) 2008-2024 by
+ * Copyright (C) 2008-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -20,6 +20,7 @@
 
 #include 
 #include 
+#include 
 
 
   static FT_Error
@@ -47,11 +48,43 @@
     /* (see `FT_Load_Glyph' implementation in src/base/ftobjs.c)        */
 
     for ( nn = 0; nn < count; nn++ )
-      advances[nn] = FT_MulDiv( advances[nn], scale, 64 );
+      advances[nn] = FT_MulFix( 1024 * advances[nn], scale );
 
     return FT_Err_Ok;
   }
 
+  /* loading (and hinting) to calculate the advances is slow  */
+  /* unless TrueType hdmx table is provided as an accelerator */
+  static FT_Error
+  ft_load_advances( FT_Face   face,
+                    FT_UInt   gindex,
+                    FT_UInt   count,
+                    FT_Int32  flags,
+                    FT_Fixed  *padvances )
+  {
+    FT_UInt   nn;
+    FT_Error  error   = FT_Err_Ok;
+    FT_Pos    factor  = flags & FT_LOAD_NO_SCALE ? 1 : 1024;
+    FT_Pos*   advance = flags & FT_LOAD_VERTICAL_LAYOUT
+                          ? &face->glyph->advance.y
+                          : &face->glyph->advance.x;
+
+
+    flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY;
+
+    for ( nn = 0; nn < count; nn++ )
+    {
+      error = FT_Load_Glyph( face, gindex + nn, flags );
+      if ( error )
+        break;
+
+      /* scale from 26.6 to 16.16, unless NO_SCALE was requested */
+      padvances[nn] = *advance * factor;
+    }
+
+    return error;
+  }
+
 
    /* at the moment, we can perform fast advance retrieval only in */
    /* the following cases:                                         */
@@ -102,7 +135,10 @@
         return error;
     }
 
-    return FT_Get_Advances( face, gindex, 1, flags, padvance );
+    if ( flags & FT_ADVANCE_FLAG_FAST_ONLY )
+      return FT_THROW( Unimplemented_Feature );
+
+    return ft_load_advances( face, gindex, 1, flags, padvance );
   }
 
 
@@ -115,12 +151,9 @@
                    FT_Int32   flags,
                    FT_Fixed  *padvances )
   {
-    FT_Error  error = FT_Err_Ok;
-
     FT_Face_GetAdvancesFunc  func;
 
-    FT_UInt  num, end, nn;
-    FT_Int   factor;
+    FT_UInt  num, end;
 
 
     if ( !face )
@@ -140,6 +173,9 @@
     func = face->driver->clazz->get_advances;
     if ( func && LOAD_ADVANCE_FAST_CHECK( face, flags ) )
     {
+      FT_Error  error;
+
+
       error = func( face, start, count, flags, padvances );
       if ( !error )
         return ft_face_scale_advances_( face, padvances, count, flags );
@@ -148,26 +184,10 @@
         return error;
     }
 
-    error = FT_Err_Ok;
-
     if ( flags & FT_ADVANCE_FLAG_FAST_ONLY )
       return FT_THROW( Unimplemented_Feature );
 
-    flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY;
-    factor = ( flags & FT_LOAD_NO_SCALE ) ? 1 : 1024;
-    for ( nn = 0; nn < count; nn++ )
-    {
-      error = FT_Load_Glyph( face, start + nn, flags );
-      if ( error )
-        break;
-
-      /* scale from 26.6 to 16.16, unless NO_SCALE was requested */
-      padvances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT )
-                      ? face->glyph->advance.y * factor
-                      : face->glyph->advance.x * factor;
-    }
-
-    return error;
+    return ft_load_advances( face, start, count, flags, padvances );
   }
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftbase.h b/src/java.desktop/share/native/libfreetype/src/base/ftbase.h
index 1d98b26dd51..66f091165fe 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftbase.h
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftbase.h
@@ -4,7 +4,7 @@
  *
  *   Private functions used in the `base' module (specification).
  *
- * Copyright (C) 2008-2024 by
+ * Copyright (C) 2008-2025 by
  * David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -34,7 +34,7 @@ FT_BEGIN_HEADER
 #ifdef FT_CONFIG_OPTION_MAC_FONTS
 
   /* MacOS resource fork cannot exceed 16MB at least for Carbon code; */
-  /* see https://support.microsoft.com/en-us/kb/130437                */
+  /* see https://jeffpar.github.io/kbarchive/kb/130/Q130437/          */
 #define FT_MAC_RFORK_MAX_LEN  0x00FFFFFFUL
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c b/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c
index d6aa5d56df8..feccdee5dd7 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c
@@ -4,7 +4,7 @@
  *
  *   FreeType bbox computation (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c b/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c
index 4be145679fd..364f881e435 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c
@@ -4,7 +4,7 @@
  *
  *   FreeType utility functions for bitmaps (body).
  *
- * Copyright (C) 2004-2024 by
+ * Copyright (C) 2004-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -876,13 +876,13 @@
 
 #ifdef FT_DEBUG_LEVEL_TRACE
     FT_TRACE5(( "FT_Bitmap_Blend:\n" ));
-    FT_TRACE5(( "  source bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n",
+    FT_TRACE5(( "  source bitmap: (%ld, %ld) -- (%ld, %ld); %u x %u\n",
       source_llx / 64, source_lly / 64,
       source_urx / 64, source_ury / 64,
       source_->width, source_->rows ));
 
     if ( target->width && target->rows )
-      FT_TRACE5(( "  target bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n",
+      FT_TRACE5(( "  target bitmap: (%ld, %ld) -- (%ld, %ld); %u x %u\n",
         target_llx / 64, target_lly / 64,
         target_urx / 64, target_ury / 64,
         target->width, target->rows ));
@@ -890,7 +890,7 @@
       FT_TRACE5(( "  target bitmap: empty\n" ));
 
     if ( final_width && final_rows )
-      FT_TRACE5(( "  final bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n",
+      FT_TRACE5(( "  final bitmap: (%ld, %ld) -- (%ld, %ld); %u x %u\n",
         final_llx / 64, final_lly / 64,
         final_urx / 64, final_ury / 64,
         final_width, final_rows ));
@@ -922,14 +922,7 @@
       target->pitch      = (int)final_width * 4;
       target->num_grays  = 256;
 
-      if ( FT_LONG_MAX / target->pitch < (int)target->rows )
-      {
-        FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n",
-                     final_width, final_rows ));
-        return FT_THROW( Invalid_Argument );
-      }
-
-      if ( FT_ALLOC( target->buffer, target->pitch * (int)target->rows ) )
+      if ( FT_ALLOC_MULT( target->buffer, target->rows, target->pitch ) )
         return error;
 
       free_target_bitmap_on_error = 1;
@@ -950,16 +943,9 @@
 
       new_pitch = (int)final_width * 4;
 
-      if ( FT_LONG_MAX / new_pitch < (int)final_rows )
-      {
-        FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n",
-                     final_width, final_rows ));
-        return FT_THROW( Invalid_Argument );
-      }
-
       /* TODO: provide an in-buffer solution for large bitmaps */
       /*       to avoid allocation of a new buffer             */
-      if ( FT_ALLOC( buffer, new_pitch * (int)final_rows ) )
+      if ( FT_ALLOC_MULT( buffer, final_rows, new_pitch ) )
         goto Error;
 
       /* copy data to new buffer */
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c b/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c
index 92de09ed877..7d6e12e2543 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c
@@ -4,7 +4,7 @@
  *
  *   Arithmetic computations (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -38,24 +38,11 @@
 #include 
 #include 
 
-
-#ifdef FT_MULFIX_ASSEMBLER
-#undef FT_MulFix
+  /* cancel inlining macro from internal/ftcalc.h */
+#ifdef FT_MulFix
+#  undef FT_MulFix
 #endif
 
-/* we need to emulate a 64-bit data type if a real one isn't available */
-
-#ifndef FT_INT64
-
-  typedef struct  FT_Int64_
-  {
-    FT_UInt32  lo;
-    FT_UInt32  hi;
-
-  } FT_Int64;
-
-#endif /* !FT_INT64 */
-
 
   /**************************************************************************
    *
@@ -88,7 +75,7 @@
   FT_EXPORT_DEF( FT_Fixed )
   FT_RoundFix( FT_Fixed  a )
   {
-    return ( ADD_LONG( a, 0x8000L - ( a < 0 ) ) ) & ~0xFFFFL;
+    return ADD_LONG( a, 0x8000L - ( a < 0 ) ) & ~0xFFFFL;
   }
 
 
@@ -97,7 +84,7 @@
   FT_EXPORT_DEF( FT_Fixed )
   FT_CeilFix( FT_Fixed  a )
   {
-    return ( ADD_LONG( a, 0xFFFFL ) ) & ~0xFFFFL;
+    return ADD_LONG( a, 0xFFFFL ) & ~0xFFFFL;
   }
 
 
@@ -225,18 +212,18 @@
   FT_MulFix( FT_Long  a_,
              FT_Long  b_ )
   {
-#ifdef FT_MULFIX_ASSEMBLER
+#ifdef FT_CONFIG_OPTION_INLINE_MULFIX
 
-    return FT_MULFIX_ASSEMBLER( (FT_Int32)a_, (FT_Int32)b_ );
+    return FT_MulFix_64( a_, b_ );
 
 #else
 
-    FT_Int64  ab = (FT_Int64)a_ * (FT_Int64)b_;
+    FT_Int64  ab = MUL_INT64( a_, b_ );
 
     /* this requires arithmetic right shift of signed numbers */
-    return (FT_Long)( ( ab + 0x8000L - ( ab < 0 ) ) >> 16 );
+    return (FT_Long)( ( ab + 0x8000L + ( ab >> 63 ) ) >> 16 );
 
-#endif /* FT_MULFIX_ASSEMBLER */
+#endif /* FT_CONFIG_OPTION_INLINE_MULFIX */
   }
 
 
@@ -975,43 +962,36 @@
 
 #else
 
-    FT_Int  result;
+    FT_Int64  z1, z2;
+    FT_Int    result;
 
 
-    if ( ADD_LONG( FT_ABS( in_x ), FT_ABS( out_y ) ) <= 131071L &&
-         ADD_LONG( FT_ABS( in_y ), FT_ABS( out_x ) ) <= 131071L )
+    if ( (FT_ULong)FT_ABS( in_x ) + (FT_ULong)FT_ABS( out_y ) <= 92681UL )
     {
-      FT_Long  z1 = MUL_LONG( in_x, out_y );
-      FT_Long  z2 = MUL_LONG( in_y, out_x );
-
-
-      if ( z1 > z2 )
-        result = +1;
-      else if ( z1 < z2 )
-        result = -1;
-      else
-        result = 0;
+      z1.lo = (FT_UInt32)in_x * (FT_UInt32)out_y;
+      z1.hi = (FT_UInt32)( (FT_Int32)z1.lo >> 31 );  /* sign-expansion */
     }
-    else /* products might overflow 32 bits */
-    {
-      FT_Int64  z1, z2;
-
-
-      /* XXX: this function does not allow 64-bit arguments */
+    else
       ft_multo64( (FT_UInt32)in_x, (FT_UInt32)out_y, &z1 );
-      ft_multo64( (FT_UInt32)in_y, (FT_UInt32)out_x, &z2 );
 
-      if ( z1.hi > z2.hi )
-        result = +1;
-      else if ( z1.hi < z2.hi )
-        result = -1;
-      else if ( z1.lo > z2.lo )
-        result = +1;
-      else if ( z1.lo < z2.lo )
-        result = -1;
-      else
-        result = 0;
+    if ( (FT_ULong)FT_ABS( in_y ) + (FT_ULong)FT_ABS( out_x ) <= 92681UL )
+    {
+      z2.lo = (FT_UInt32)in_y * (FT_UInt32)out_x;
+      z2.hi = (FT_UInt32)( (FT_Int32)z2.lo >> 31 );  /* sign-expansion */
     }
+    else
+      ft_multo64( (FT_UInt32)in_y, (FT_UInt32)out_x, &z2 );
+
+    if      ( (FT_Int32)z1.hi > (FT_Int32)z2.hi )
+      result = +1;
+    else if ( (FT_Int32)z1.hi < (FT_Int32)z2.hi )
+      result = -1;
+    else if ( z1.lo > z2.lo )
+      result = +1;
+    else if ( z1.lo < z2.lo )
+      result = -1;
+    else
+      result =  0;
 
     /* XXX: only the sign of return value, +1/0/-1 must be used */
     return result;
@@ -1065,62 +1045,4 @@
   }
 
 
-  FT_BASE_DEF( FT_Int32 )
-  FT_MulAddFix( FT_Fixed*  s,
-                FT_Int32*  f,
-                FT_UInt    count )
-  {
-    FT_UInt   i;
-    FT_Int64  temp;
-
-
-#ifdef FT_INT64
-    temp = 0;
-
-    for ( i = 0; i < count; ++i )
-      temp += (FT_Int64)s[i] * f[i];
-
-    return (FT_Int32)( ( temp + 0x8000 ) >> 16 );
-#else
-    temp.hi = 0;
-    temp.lo = 0;
-
-    for ( i = 0; i < count; ++i )
-    {
-      FT_Int64  multResult;
-
-      FT_Int     sign  = 1;
-      FT_UInt32  carry = 0;
-
-      FT_UInt32  scalar;
-      FT_UInt32  factor;
-
-
-      FT_MOVE_SIGN( FT_UInt32, s[i], scalar, sign );
-      FT_MOVE_SIGN( FT_UInt32, f[i], factor, sign );
-
-      ft_multo64( scalar, factor, &multResult );
-
-      if ( sign < 0 )
-      {
-        /* Emulated `FT_Int64` negation. */
-        carry = ( multResult.lo == 0 );
-
-        multResult.lo = ~multResult.lo + 1;
-        multResult.hi = ~multResult.hi + carry;
-      }
-
-      FT_Add64( &temp, &multResult, &temp );
-    }
-
-    /* Shift and round value. */
-    return (FT_Int32)( ( ( temp.hi << 16 ) | ( temp.lo >> 16 ) )
-                                     + ( 1 & ( temp.lo >> 15 ) ) );
-
-
-#endif /* !FT_INT64 */
-
-  }
-
-
 /* END */
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftcid.c b/src/java.desktop/share/native/libfreetype/src/base/ftcid.c
index 4f2deb19a05..35cd0fcd2be 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftcid.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftcid.c
@@ -4,7 +4,7 @@
  *
  *   FreeType API for accessing CID font information.
  *
- * Copyright (C) 2007-2024 by
+ * Copyright (C) 2007-2025 by
  * Derek Clegg and Michael Toftdal.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftcolor.c b/src/java.desktop/share/native/libfreetype/src/base/ftcolor.c
index c6bf2a3cd1a..90b02b7d2de 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftcolor.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftcolor.c
@@ -4,7 +4,7 @@
  *
  *   FreeType's glyph color management (body).
  *
- * Copyright (C) 2018-2024 by
+ * Copyright (C) 2018-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -56,9 +56,7 @@
                      FT_Color*  *apalette )
   {
     FT_Error  error;
-
-    TT_Face       ttface;
-    SFNT_Service  sfnt;
+    TT_Face   ttface = (TT_Face)face;
 
 
     if ( !face )
@@ -72,14 +70,17 @@
       return FT_Err_Ok;
     }
 
-    ttface = (TT_Face)face;
-    sfnt   = (SFNT_Service)ttface->sfnt;
+    if ( palette_index != ttface->palette_index )
+    {
+      SFNT_Service  sfnt = (SFNT_Service)ttface->sfnt;
 
-    error = sfnt->set_palette( ttface, palette_index );
-    if ( error )
-      return error;
 
-    ttface->palette_index = palette_index;
+      error = sfnt->set_palette( ttface, palette_index );
+      if ( error )
+        return error;
+
+      ttface->palette_index = palette_index;
+    }
 
     if ( apalette )
       *apalette = ttface->palette;
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c b/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c
index 902a5dc8bbc..7f54e759b16 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c
@@ -4,7 +4,7 @@
  *
  *   Memory debugger (body).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -139,7 +139,6 @@
   } FT_MemTableRec;
 
 
-#define FT_MEM_SIZE_MIN  7
 #define FT_MEM_SIZE_MAX  13845163
 
 #define FT_FILENAME( x )  ( (x) ? (x) : "unknown file" )
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftdebug.c b/src/java.desktop/share/native/libfreetype/src/base/ftdebug.c
index 11307eaace4..c615f29e521 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftdebug.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftdebug.c
@@ -4,7 +4,7 @@
  *
  *   Debugging and logging component (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -64,7 +64,7 @@
    *    with the actual log message if set to true.
    *
    * 5. The flag `ft_timestamp_flag` prints time along with the actual log
-   *    message if set to ture.
+   *    message if set to true.
    *
    * 6. `ft_have_newline_char` is used to differentiate between a log
    *    message with and without a trailing newline character.
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftfntfmt.c b/src/java.desktop/share/native/libfreetype/src/base/ftfntfmt.c
index 77b4089e7e2..7f4f14ffdb0 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftfntfmt.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftfntfmt.c
@@ -4,7 +4,7 @@
  *
  *   FreeType utility file for font formats (body).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftfstype.c b/src/java.desktop/share/native/libfreetype/src/base/ftfstype.c
index 1565c3b7e25..3a95752ffaa 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftfstype.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftfstype.c
@@ -4,7 +4,7 @@
  *
  *   FreeType utility file to access FSType data (body).
  *
- * Copyright (C) 2008-2024 by
+ * Copyright (C) 2008-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftgasp.c b/src/java.desktop/share/native/libfreetype/src/base/ftgasp.c
index c63d30e978c..2202240b57e 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftgasp.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftgasp.c
@@ -4,7 +4,7 @@
  *
  *   Access of TrueType's `gasp' table (body).
  *
- * Copyright (C) 2007-2024 by
+ * Copyright (C) 2007-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftgloadr.c b/src/java.desktop/share/native/libfreetype/src/base/ftgloadr.c
index 484d98f1722..47781bc4d5c 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftgloadr.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftgloadr.c
@@ -4,7 +4,7 @@
  *
  *   The FreeType glyph loader (body).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftglyph.c b/src/java.desktop/share/native/libfreetype/src/base/ftglyph.c
index 1b5849f99af..6138cfeec2c 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftglyph.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftglyph.c
@@ -4,7 +4,7 @@
  *
  *   FreeType convenience functions to handle glyphs (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -62,7 +62,7 @@
                         FT_GlyphSlot  slot )
   {
     FT_BitmapGlyph  glyph   = (FT_BitmapGlyph)bitmap_glyph;
-    FT_Error        error   = FT_Err_Ok;
+    FT_Error        error;
     FT_Library      library = FT_GLYPH( glyph )->library;
 
 
@@ -75,17 +75,8 @@
     glyph->left = slot->bitmap_left;
     glyph->top  = slot->bitmap_top;
 
-    /* do lazy copying whenever possible */
-    if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
-    {
-      glyph->bitmap          = slot->bitmap;
-      slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
-    }
-    else
-    {
-      FT_Bitmap_Init( &glyph->bitmap );
-      error = FT_Bitmap_Copy( library, &slot->bitmap, &glyph->bitmap );
-    }
+    FT_Bitmap_Init( &glyph->bitmap );
+    error = FT_Bitmap_Copy( library, &slot->bitmap, &glyph->bitmap );
 
   Exit:
     return error;
diff --git a/src/java.desktop/share/native/libfreetype/src/base/fthash.c b/src/java.desktop/share/native/libfreetype/src/base/fthash.c
index 313bbbb4b27..ab248ace8bd 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/fthash.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/fthash.c
@@ -41,6 +41,7 @@
 
 #include 
 #include 
+#include 
 
 
 #define INITIAL_HT_SIZE  241
@@ -233,7 +234,8 @@
   hash_insert( FT_Hashkey  key,
                size_t      data,
                FT_Hash     hash,
-               FT_Memory   memory )
+               FT_Memory   memory,
+               FT_Bool     overwrite )
   {
     FT_Hashnode   nn;
     FT_Hashnode*  bp    = hash_bucket( key, hash );
@@ -259,7 +261,7 @@
 
       hash->used++;
     }
-    else
+    else if ( overwrite )
       nn->data = data;
 
   Exit:
@@ -278,7 +280,7 @@
 
     hk.str = key;
 
-    return hash_insert( hk, data, hash, memory );
+    return hash_insert( hk, data, hash, memory, TRUE );
   }
 
 
@@ -293,7 +295,37 @@
 
     hk.num = num;
 
-    return hash_insert( hk, data, hash, memory );
+    return hash_insert( hk, data, hash, memory, TRUE );
+  }
+
+
+  FT_Error
+  ft_hash_str_insert_no_overwrite( const char*  key,
+                                   size_t       data,
+                                   FT_Hash      hash,
+                                   FT_Memory    memory )
+  {
+    FT_Hashkey  hk;
+
+
+    hk.str = key;
+
+    return hash_insert( hk, data, hash, memory, FALSE );
+  }
+
+
+  FT_Error
+  ft_hash_num_insert_no_overwrite( FT_Int     num,
+                                   size_t     data,
+                                   FT_Hash    hash,
+                                   FT_Memory  memory )
+  {
+    FT_Hashkey  hk;
+
+
+    hk.num = num;
+
+    return hash_insert( hk, data, hash, memory, FALSE );
   }
 
 
@@ -335,4 +367,68 @@
   }
 
 
+  FT_Bool
+  ft_hash_num_iterator( FT_UInt  *idx,
+                        FT_Int   *key,
+                        size_t   *value,
+                        FT_Hash   hash )
+  {
+    FT_Hashnode  nn = NULL;
+
+
+    while ( 1 )
+    {
+      if ( *idx >= hash->size )
+        return 0;
+
+      nn = hash->table[*idx];
+      if ( nn )
+        break;
+
+      (*idx)++;
+    }
+
+    if ( key )
+      *key = nn->key.num;
+    if ( value )
+      *value = nn->data;
+
+    (*idx)++;
+
+    return 1;
+  }
+
+
+  FT_Bool
+  ft_hash_str_iterator( FT_UInt      *idx,
+                        const char*  *key,
+                        size_t       *value,
+                        FT_Hash       hash )
+  {
+    FT_Hashnode  nn = NULL;
+
+
+    while ( 1 )
+    {
+      if ( *idx >= hash->size )
+        return 0;
+
+      nn = hash->table[*idx];
+      if ( nn )
+        break;
+
+      (*idx)++;
+    }
+
+    if ( key )
+      *key = nn->key.str;
+    if ( value )
+      *value = nn->data;
+
+    (*idx)++;
+
+    return 1;
+  }
+
+
 /* END */
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftinit.c b/src/java.desktop/share/native/libfreetype/src/base/ftinit.c
index 9a6c00e13ef..37d7f87bcb9 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftinit.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftinit.c
@@ -4,7 +4,7 @@
  *
  *   FreeType initialization layer (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftlcdfil.c b/src/java.desktop/share/native/libfreetype/src/base/ftlcdfil.c
index 1e69d4da70f..51c6fd48a1b 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftlcdfil.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftlcdfil.c
@@ -4,7 +4,7 @@
  *
  *   FreeType API for color filtering of subpixel bitmap glyphs (body).
  *
- * Copyright (C) 2006-2024 by
+ * Copyright (C) 2006-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -25,264 +25,27 @@
 
 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
 
-/* define USE_LEGACY to implement the legacy filter */
-#define  USE_LEGACY
-
-#define FT_SHIFTCLAMP( x )  ( x >>= 8, (FT_Byte)( x > 255 ? 255 : x ) )
-
-
-  /* add padding according to filter weights */
+  /* add padding sufficient for a 5-tap filter, */
+  /* which is 2/3 of a pixel                    */
   FT_BASE_DEF( void )
   ft_lcd_padding( FT_BBox*        cbox,
                   FT_GlyphSlot    slot,
                   FT_Render_Mode  mode )
   {
-    FT_Byte*                 lcd_weights;
-    FT_Bitmap_LcdFilterFunc  lcd_filter_func;
-
-
-    /* Per-face LCD filtering takes priority if set up. */
-    if ( slot->face && slot->face->internal->lcd_filter_func )
-    {
-      lcd_weights     = slot->face->internal->lcd_weights;
-      lcd_filter_func = slot->face->internal->lcd_filter_func;
-    }
-    else
-    {
-      lcd_weights     = slot->library->lcd_weights;
-      lcd_filter_func = slot->library->lcd_filter_func;
-    }
-
-    if ( lcd_filter_func == ft_lcd_filter_fir )
-    {
-      if ( mode == FT_RENDER_MODE_LCD )
-      {
-        cbox->xMin -= lcd_weights[0] ? 43 :
-                      lcd_weights[1] ? 22 : 0;
-        cbox->xMax += lcd_weights[4] ? 43 :
-                      lcd_weights[3] ? 22 : 0;
-      }
-      else if ( mode == FT_RENDER_MODE_LCD_V )
-      {
-        cbox->yMin -= lcd_weights[0] ? 43 :
-                      lcd_weights[1] ? 22 : 0;
-        cbox->yMax += lcd_weights[4] ? 43 :
-                      lcd_weights[3] ? 22 : 0;
-      }
-    }
-  }
-
-
-  /* FIR filter used by the default and light filters */
-  FT_BASE_DEF( void )
-  ft_lcd_filter_fir( FT_Bitmap*           bitmap,
-                     FT_LcdFiveTapFilter  weights )
-  {
-    FT_UInt   width  = (FT_UInt)bitmap->width;
-    FT_UInt   height = (FT_UInt)bitmap->rows;
-    FT_Int    pitch  = bitmap->pitch;
-    FT_Byte*  origin = bitmap->buffer;
-    FT_Byte   mode   = bitmap->pixel_mode;
-
-
-    /* take care of bitmap flow */
-    if ( pitch > 0 && height > 0 )
-      origin += pitch * (FT_Int)( height - 1 );
-
-    /* horizontal in-place FIR filter */
-    if ( mode == FT_PIXEL_MODE_LCD && width >= 2 )
-    {
-      FT_Byte*  line = origin;
-
-
-      /* `fir' must be at least 32 bit wide, since the sum of */
-      /* the values in `weights' can exceed 0xFF              */
-
-      for ( ; height > 0; height--, line -= pitch )
-      {
-        FT_UInt  fir[5];
-        FT_UInt  val, xx;
-
-
-        val    = line[0];
-        fir[2] = weights[2] * val;
-        fir[3] = weights[3] * val;
-        fir[4] = weights[4] * val;
-
-        val    = line[1];
-        fir[1] = fir[2] + weights[1] * val;
-        fir[2] = fir[3] + weights[2] * val;
-        fir[3] = fir[4] + weights[3] * val;
-        fir[4] =          weights[4] * val;
-
-        for ( xx = 2; xx < width; xx++ )
-        {
-          val    = line[xx];
-          fir[0] = fir[1] + weights[0] * val;
-          fir[1] = fir[2] + weights[1] * val;
-          fir[2] = fir[3] + weights[2] * val;
-          fir[3] = fir[4] + weights[3] * val;
-          fir[4] =          weights[4] * val;
-
-          line[xx - 2] = FT_SHIFTCLAMP( fir[0] );
-        }
-
-        line[xx - 2] = FT_SHIFTCLAMP( fir[1] );
-        line[xx - 1] = FT_SHIFTCLAMP( fir[2] );
-      }
-    }
-
-    /* vertical in-place FIR filter */
-    else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 2 )
-    {
-      FT_Byte*  column = origin;
-
-
-      for ( ; width > 0; width--, column++ )
-      {
-        FT_Byte*  col = column;
-        FT_UInt   fir[5];
-        FT_UInt   val, yy;
-
-
-        val    = col[0];
-        fir[2] = weights[2] * val;
-        fir[3] = weights[3] * val;
-        fir[4] = weights[4] * val;
-        col   -= pitch;
-
-        val    = col[0];
-        fir[1] = fir[2] + weights[1] * val;
-        fir[2] = fir[3] + weights[2] * val;
-        fir[3] = fir[4] + weights[3] * val;
-        fir[4] =          weights[4] * val;
-        col   -= pitch;
-
-        for ( yy = 2; yy < height; yy++, col -= pitch )
-        {
-          val    = col[0];
-          fir[0] = fir[1] + weights[0] * val;
-          fir[1] = fir[2] + weights[1] * val;
-          fir[2] = fir[3] + weights[2] * val;
-          fir[3] = fir[4] + weights[3] * val;
-          fir[4] =          weights[4] * val;
-
-          col[pitch * 2]  = FT_SHIFTCLAMP( fir[0] );
-        }
-
-        col[pitch * 2]  = FT_SHIFTCLAMP( fir[1] );
-        col[pitch]      = FT_SHIFTCLAMP( fir[2] );
-      }
-    }
-  }
-
+    FT_UNUSED( slot );
 
-#ifdef USE_LEGACY
-
-  /* intra-pixel filter used by the legacy filter */
-  static void
-  _ft_lcd_filter_legacy( FT_Bitmap*      bitmap,
-                         FT_Byte*        weights )
-  {
-    FT_UInt   width  = (FT_UInt)bitmap->width;
-    FT_UInt   height = (FT_UInt)bitmap->rows;
-    FT_Int    pitch  = bitmap->pitch;
-    FT_Byte*  origin = bitmap->buffer;
-    FT_Byte   mode   = bitmap->pixel_mode;
-
-    static const unsigned int  filters[3][3] =
-    {
-      { 65538 * 9/13, 65538 * 1/6, 65538 * 1/13 },
-      { 65538 * 3/13, 65538 * 4/6, 65538 * 3/13 },
-      { 65538 * 1/13, 65538 * 1/6, 65538 * 9/13 }
-    };
-
-    FT_UNUSED( weights );
-
-
-    /* take care of bitmap flow */
-    if ( pitch > 0 && height > 0 )
-      origin += pitch * (FT_Int)( height - 1 );
-
-    /* horizontal in-place intra-pixel filter */
-    if ( mode == FT_PIXEL_MODE_LCD && width >= 3 )
+    if ( mode == FT_RENDER_MODE_LCD )
     {
-      FT_Byte*  line = origin;
-
-
-      for ( ; height > 0; height--, line -= pitch )
-      {
-        FT_UInt  xx;
-
-
-        for ( xx = 0; xx < width; xx += 3 )
-        {
-          FT_UInt  r, g, b;
-          FT_UInt  p;
-
-
-          p  = line[xx];
-          r  = filters[0][0] * p;
-          g  = filters[0][1] * p;
-          b  = filters[0][2] * p;
-
-          p  = line[xx + 1];
-          r += filters[1][0] * p;
-          g += filters[1][1] * p;
-          b += filters[1][2] * p;
-
-          p  = line[xx + 2];
-          r += filters[2][0] * p;
-          g += filters[2][1] * p;
-          b += filters[2][2] * p;
-
-          line[xx]     = (FT_Byte)( r / 65536 );
-          line[xx + 1] = (FT_Byte)( g / 65536 );
-          line[xx + 2] = (FT_Byte)( b / 65536 );
-        }
-      }
+      cbox->xMin -= 43;
+      cbox->xMax += 43;
     }
-    else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 3 )
+    else if ( mode == FT_RENDER_MODE_LCD_V )
     {
-      FT_Byte*  column = origin;
-
-
-      for ( ; width > 0; width--, column++ )
-      {
-        FT_Byte*  col = column - 2 * pitch;
-
-
-        for ( ; height > 0; height -= 3, col -= 3 * pitch )
-        {
-          FT_UInt  r, g, b;
-          FT_UInt  p;
-
-
-          p  = col[0];
-          r  = filters[0][0] * p;
-          g  = filters[0][1] * p;
-          b  = filters[0][2] * p;
-
-          p  = col[pitch];
-          r += filters[1][0] * p;
-          g += filters[1][1] * p;
-          b += filters[1][2] * p;
-
-          p  = col[pitch * 2];
-          r += filters[2][0] * p;
-          g += filters[2][1] * p;
-          b += filters[2][2] * p;
-
-          col[0]         = (FT_Byte)( r / 65536 );
-          col[pitch]     = (FT_Byte)( g / 65536 );
-          col[pitch * 2] = (FT_Byte)( b / 65536 );
-        }
-      }
+      cbox->yMin -= 43;
+      cbox->yMax += 43;
     }
   }
 
-#endif /* USE_LEGACY */
-
 
   /* documentation in ftlcdfil.h */
 
@@ -297,7 +60,6 @@
       return FT_THROW( Invalid_Argument );
 
     ft_memcpy( library->lcd_weights, weights, FT_LCD_FILTER_FIVE_TAPS );
-    library->lcd_filter_func = ft_lcd_filter_fir;
 
     return FT_Err_Ok;
   }
@@ -321,32 +83,23 @@
     switch ( filter )
     {
     case FT_LCD_FILTER_NONE:
-      library->lcd_filter_func = NULL;
+      ft_memset( library->lcd_weights,
+                 0,
+                 FT_LCD_FILTER_FIVE_TAPS );
       break;
 
     case FT_LCD_FILTER_DEFAULT:
       ft_memcpy( library->lcd_weights,
                  default_weights,
                  FT_LCD_FILTER_FIVE_TAPS );
-      library->lcd_filter_func = ft_lcd_filter_fir;
       break;
 
     case FT_LCD_FILTER_LIGHT:
       ft_memcpy( library->lcd_weights,
                  light_weights,
                  FT_LCD_FILTER_FIVE_TAPS );
-      library->lcd_filter_func = ft_lcd_filter_fir;
       break;
 
-#ifdef USE_LEGACY
-
-    case FT_LCD_FILTER_LEGACY:
-    case FT_LCD_FILTER_LEGACY1:
-      library->lcd_filter_func = _ft_lcd_filter_legacy;
-      break;
-
-#endif
-
     default:
       return FT_THROW( Invalid_Argument );
     }
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftmac.c b/src/java.desktop/share/native/libfreetype/src/base/ftmac.c
index e8e35627b50..37d97be1838 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftmac.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftmac.c
@@ -8,7 +8,7 @@
  * This file is for Mac OS X only; see builds/mac/ftoldmac.c for
  * classic platforms built by MPW.
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftmm.c b/src/java.desktop/share/native/libfreetype/src/base/ftmm.c
index cc4ca22fba3..9e67001406c 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftmm.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftmm.c
@@ -4,7 +4,7 @@
  *
  *   Multiple Master font support (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -292,6 +292,9 @@
     if ( num_coords && !coords )
       return FT_THROW( Invalid_Argument );
 
+    if ( !num_coords && !FT_IS_VARIATION( face ) )
+      return FT_Err_Ok;  /* nothing to be done */
+
     error = ft_face_get_mm_service( face, &service_mm );
     if ( !error )
     {
@@ -299,15 +302,21 @@
       if ( service_mm->set_var_design )
         error = service_mm->set_var_design( face, num_coords, coords );
 
-      if ( !error || error == -1 )
+      if ( !error || error == -1 || error == -2 )
       {
         FT_Bool  is_variation_old = FT_IS_VARIATION( face );
 
 
-        if ( num_coords )
-          face->face_flags |= FT_FACE_FLAG_VARIATION;
-        else
-          face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+        if ( error != -1 )
+        {
+          if ( error == -2 ) /* -2 means is_variable. */
+          {
+            face->face_flags |= FT_FACE_FLAG_VARIATION;
+            error             = FT_Err_Ok;
+          }
+          else
+            face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+        }
 
         if ( service_mm->construct_ps_name )
         {
@@ -474,15 +483,21 @@
       if ( service_mm->set_mm_blend )
         error = service_mm->set_mm_blend( face, num_coords, coords );
 
-      if ( !error || error == -1 )
+      if ( !error || error == -1 || error == -2 )
       {
         FT_Bool  is_variation_old = FT_IS_VARIATION( face );
 
 
-        if ( num_coords )
-          face->face_flags |= FT_FACE_FLAG_VARIATION;
-        else
-          face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+        if ( error != -1 )
+        {
+          if ( error == -2 ) /* -2 means is_variable. */
+          {
+            face->face_flags |= FT_FACE_FLAG_VARIATION;
+            error             = FT_Err_Ok;
+          }
+          else
+            face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+        }
 
         if ( service_mm->construct_ps_name )
         {
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c b/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c
index 9b97820c379..323dd5efac2 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c
@@ -4,7 +4,7 @@
  *
  *   The FreeType private base classes (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -524,12 +524,28 @@
     bitmap->rows       = (unsigned int)height;
     bitmap->pitch      = pitch;
 
-    if ( pbox.xMin < -0x8000 || pbox.xMax > 0x7FFF ||
-         pbox.yMin < -0x8000 || pbox.yMax > 0x7FFF )
+    /* Flag the bounding box size unsuitable for rendering. */
+    /* FT_Renderer modules should check the return value.   */
+    /* The limit is based on the ppem value when available. */
     {
-      FT_TRACE3(( "ft_glyphslot_preset_bitmap: [%ld %ld %ld %ld]\n",
-                  pbox.xMin, pbox.yMin, pbox.xMax, pbox.yMax ));
-      return 1;
+      FT_Face  face = slot->face;
+      FT_Pos   xlim = 0x8000;
+      FT_Pos   ylim = 0x8000;
+
+
+      if ( face )
+      {
+        xlim = FT_MIN( xlim, 10 * face->size->metrics.x_ppem );
+        ylim = FT_MIN( ylim, 10 * face->size->metrics.y_ppem );
+      }
+
+      if ( pbox.xMin < -xlim || pbox.xMax >= xlim ||
+           pbox.yMin < -ylim || pbox.yMax >= ylim )
+      {
+        FT_TRACE3(( "ft_glyphslot_preset_bitmap: [%ld %ld %ld %ld]\n",
+                    pbox.xMin, pbox.yMin, pbox.xMax, pbox.yMax ));
+        return 1;
+      }
     }
 
     return 0;
@@ -549,8 +565,7 @@
 
 
   FT_BASE_DEF( FT_Error )
-  ft_glyphslot_alloc_bitmap( FT_GlyphSlot  slot,
-                             FT_ULong      size )
+  ft_glyphslot_alloc_bitmap( FT_GlyphSlot  slot )
   {
     FT_Memory  memory = FT_FACE_MEMORY( slot->face );
     FT_Error   error;
@@ -561,7 +576,10 @@
     else
       slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
 
-    FT_MEM_ALLOC( slot->bitmap.buffer, size );
+    /* dimensions must be preset */
+    FT_MEM_ALLOC_MULT( slot->bitmap.buffer,
+                       slot->bitmap.rows,
+                       slot->bitmap.pitch );
     return error;
   }
 
@@ -905,7 +923,6 @@
     FT_Library    library;
     FT_Bool       autohint = FALSE;
     FT_Module     hinter;
-    TT_Face       ttface = (TT_Face)face;
 
 
     if ( !face || !face->size || !face->glyph )
@@ -983,6 +1000,7 @@
       {
         FT_Render_Mode  mode = FT_LOAD_TARGET_MODE( load_flags );
         FT_Bool         is_light_type1;
+        TT_Face         ttface = (TT_Face)face;
 
 
         /* only the new Adobe engine (for both CFF and Type 1) is `light'; */
@@ -994,8 +1012,7 @@
         /* the check for `num_locations' assures that we actually    */
         /* test for instructions in a TTF and not in a CFF-based OTF */
         /*                                                           */
-        /* since `maxSizeOfInstructions' might be unreliable, we     */
-        /* check the size of the `fpgm' and `prep' tables, too --    */
+        /* we check the size of the `fpgm' and `prep' tables, too -- */
         /* the assumption is that there don't exist real TTFs where  */
         /* both `fpgm' and `prep' tables are missing                 */
         if ( ( mode == FT_RENDER_MODE_LIGHT           &&
@@ -1003,9 +1020,8 @@
                  !is_light_type1                    ) )         ||
              ( FT_IS_SFNT( face )                             &&
                ttface->num_locations                          &&
-               ttface->max_profile.maxSizeOfInstructions == 0 &&
                ttface->font_program_size == 0                 &&
-               ttface->cvt_program_size == 0                  ) )
+               ttface->cvt_program_size <= 7                  ) )
           autohint = TRUE;
       }
     }
@@ -1172,9 +1188,9 @@
     }
 
 #ifdef FT_DEBUG_LEVEL_TRACE
-    FT_TRACE5(( "FT_Load_Glyph: index %d, flags 0x%x\n",
+    FT_TRACE5(( "FT_Load_Glyph: index %u, flags 0x%x\n",
                 glyph_index, load_flags ));
-    FT_TRACE5(( "  bitmap %dx%d %s, %s (mode %d)\n",
+    FT_TRACE5(( "  bitmap %ux%u %s, %s (mode %d)\n",
                 slot->bitmap.width,
                 slot->bitmap.rows,
                 slot->outline.points ?
@@ -1253,14 +1269,14 @@
     FT_Driver  driver = (FT_Driver)driver_;
 
 
-    /* finalize client-specific data */
-    if ( size->generic.finalizer )
-      size->generic.finalizer( size );
-
     /* finalize format-specific stuff */
     if ( driver->clazz->done_size )
       driver->clazz->done_size( size );
 
+    /* finalize client-specific data */
+    if ( size->generic.finalizer )
+      size->generic.finalizer( size );
+
     FT_FREE( size->internal );
     FT_FREE( size );
   }
@@ -1322,10 +1338,6 @@
                       driver );
     face->size = NULL;
 
-    /* now discard client data */
-    if ( face->generic.finalizer )
-      face->generic.finalizer( face );
-
     /* discard charmaps */
     destroy_charmaps( face, memory );
 
@@ -1340,6 +1352,10 @@
 
     face->stream = NULL;
 
+    /* now discard client data */
+    if ( face->generic.finalizer )
+      face->generic.finalizer( face );
+
     /* get rid of it */
     if ( face->internal )
     {
@@ -1359,21 +1375,9 @@
   }
 
 
-  /**************************************************************************
-   *
-   * @Function:
-   *   find_unicode_charmap
-   *
-   * @Description:
-   *   This function finds a Unicode charmap, if there is one.
-   *   And if there is more than one, it tries to favour the more
-   *   extensive one, i.e., one that supports UCS-4 against those which
-   *   are limited to the BMP (said UCS-2 encoding.)
-   *
-   *   This function is called from open_face() (just below), and also
-   *   from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ).
-   */
-  static FT_Error
+  /* documentation is in ftobjs.h */
+
+  FT_BASE_DEF( FT_Error )
   find_unicode_charmap( FT_Face  face )
   {
     FT_CharMap*  first;
@@ -1427,7 +1431,10 @@
         if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT &&
                cur[0]->encoding_id == TT_MS_ID_UCS_4        )     ||
              ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
-               cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32    ) )
+               cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32    ) ||
+             ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
+               cur[0]->encoding_id == TT_APPLE_ID_FULL_UNICODE  &&
+               FT_Get_CMap_Format( cur[0] ) == 13               ) )
         {
           face->charmap = cur[0];
           return FT_Err_Ok;
@@ -2125,7 +2132,7 @@
       if ( pfb_pos > pfb_len || pfb_pos + rlen > pfb_len )
         goto Exit2;
 
-      FT_TRACE3(( "    Load POST fragment #%d (%ld byte) to buffer"
+      FT_TRACE3(( "    Load POST fragment #%d (%lu byte) to buffer"
                   " %p + 0x%08lx\n",
                   i, rlen, (void*)pfb_data, pfb_pos ));
 
@@ -2398,7 +2405,7 @@
       is_darwin_vfs = ft_raccess_rule_by_darwin_vfs( library, i );
       if ( is_darwin_vfs && vfs_rfork_has_no_font )
       {
-        FT_TRACE3(( "Skip rule %d: darwin vfs resource fork"
+        FT_TRACE3(( "Skip rule %u: darwin vfs resource fork"
                     " is already checked and"
                     " no font is found\n",
                     i ));
@@ -2407,7 +2414,7 @@
 
       if ( errors[i] )
       {
-        FT_TRACE3(( "Error 0x%x has occurred in rule %d\n",
+        FT_TRACE3(( "Error 0x%x has occurred in rule %u\n",
                     errors[i], i ));
         continue;
       }
@@ -2415,7 +2422,7 @@
       args2.flags    = FT_OPEN_PATHNAME;
       args2.pathname = file_names[i] ? file_names[i] : args->pathname;
 
-      FT_TRACE3(( "Try rule %d: %s (offset=%ld) ...",
+      FT_TRACE3(( "Try rule %u: %s (offset=%ld) ...",
                   i, args2.pathname, offsets[i] ));
 
       error = FT_Stream_New( library, &args2, &stream2 );
@@ -2812,11 +2819,6 @@
       internal->refcount = 1;
 
       internal->no_stem_darkening = -1;
-
-#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
-      /* Per-face filtering can only be set up by FT_Face_Properties */
-      internal->lcd_filter_func = NULL;
-#endif
     }
 
     if ( aface )
@@ -4046,18 +4048,8 @@
       }
       else if ( properties->tag == FT_PARAM_TAG_LCD_FILTER_WEIGHTS )
       {
-#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
-        if ( properties->data )
-        {
-          ft_memcpy( face->internal->lcd_weights,
-                     properties->data,
-                     FT_LCD_FILTER_FIVE_TAPS );
-          face->internal->lcd_filter_func = ft_lcd_filter_fir;
-        }
-#else
         error = FT_THROW( Unimplemented_Feature );
         goto Exit;
-#endif
       }
       else if ( properties->tag == FT_PARAM_TAG_RANDOM_SEED )
       {
@@ -5044,9 +5036,9 @@
   static void
   Destroy_Module( FT_Module  module )
   {
-    FT_Memory         memory  = module->memory;
-    FT_Module_Class*  clazz   = module->clazz;
-    FT_Library        library = module->library;
+    const FT_Module_Class*  clazz   = module->clazz;
+    FT_Library              library = module->library;
+    FT_Memory               memory  = module->memory;
 
 
     if ( library && library->auto_hinter == module )
@@ -5125,9 +5117,9 @@
       goto Exit;
 
     /* base initialization */
+    module->clazz   = clazz;
     module->library = library;
     module->memory  = memory;
-    module->clazz   = (FT_Module_Class*)clazz;
 
     /* check whether the module is a renderer - this must be performed */
     /* before the normal module initialization                         */
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c b/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c
index ef699b3c7cd..8a15b03eb83 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c
@@ -4,7 +4,7 @@
  *
  *   FreeType outline management (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftpatent.c b/src/java.desktop/share/native/libfreetype/src/base/ftpatent.c
index 2055757e023..664bc34deea 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftpatent.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftpatent.c
@@ -5,7 +5,7 @@
  *   FreeType API for checking patented TrueType bytecode instructions
  *   (body).  Obsolete, retained for backward compatibility.
  *
- * Copyright (C) 2007-2024 by
+ * Copyright (C) 2007-2025 by
  * David Turner.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftpsprop.c b/src/java.desktop/share/native/libfreetype/src/base/ftpsprop.c
index 37a6cee6cc9..0631cd63f62 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftpsprop.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftpsprop.c
@@ -5,7 +5,7 @@
  *   Get and set properties of PostScript drivers (body).
  *   See `ftdriver.h' for available properties.
  *
- * Copyright (C) 2017-2024 by
+ * Copyright (C) 2017-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftrfork.c b/src/java.desktop/share/native/libfreetype/src/base/ftrfork.c
index dc9b043d8bb..1e241f4f95b 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftrfork.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftrfork.c
@@ -4,7 +4,7 @@
  *
  *   Embedded resource forks accessor (body).
  *
- * Copyright (C) 2004-2024 by
+ * Copyright (C) 2004-2025 by
  * Masatake YAMATO and Redhat K.K.
  *
  * FT_Raccess_Get_HeaderInfo() and raccess_guess_darwin_hfsplus() are
@@ -269,14 +269,8 @@
            * According to Inside Macintosh: More Macintosh Toolbox,
            * "Resource IDs" (1-46), there are some reserved IDs.
            * However, FreeType2 is not a font synthesizer, no need
-           * to check the acceptable resource ID.
+           * to check the acceptable resource ID or its attributes.
            */
-          if ( temp < 0 )
-          {
-            error = FT_THROW( Invalid_Table );
-            goto Exit;
-          }
-
           ref[j].offset = temp & 0xFFFFFFL;
 
           FT_TRACE3(( "             [%d]:"
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftsnames.c b/src/java.desktop/share/native/libfreetype/src/base/ftsnames.c
index f7231fd61cc..34a67a148fc 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftsnames.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftsnames.c
@@ -7,7 +7,7 @@
  *
  *   This is _not_ used to retrieve glyph names!
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftstream.c b/src/java.desktop/share/native/libfreetype/src/base/ftstream.c
index 66722246128..c04a0506def 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftstream.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftstream.c
@@ -4,7 +4,7 @@
  *
  *   I/O stream support (body).
  *
- * Copyright (C) 2000-2024 by
+ * Copyright (C) 2000-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -242,7 +242,7 @@
     FT_ULong  read_bytes;
 
 
-    FT_TRACE7(( "FT_Stream_EnterFrame: %ld bytes\n", count ));
+    FT_TRACE7(( "FT_Stream_EnterFrame: %lu bytes\n", count ));
 
     /* check for nested frame access */
     FT_ASSERT( stream && stream->cursor == 0 );
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c b/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c
index 64f46ce43e7..591f18eaa83 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c
@@ -4,7 +4,7 @@
  *
  *   FreeType path stroker (body).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -1070,7 +1070,7 @@
         if ( theta == FT_ANGLE_PI2 )
           theta = -rotate;
 
-        phi    = stroker->angle_in + theta + rotate;
+        phi = stroker->angle_in + theta + rotate;
 
         FT_Vector_From_Polar( &sigma, stroker->miter_limit, theta );
 
@@ -1371,7 +1371,7 @@
     arc[1] = *control;
     arc[2] = stroker->center;
 
-    while ( arc >= bez_stack )
+    do
     {
       FT_Angle  angle_in, angle_out;
 
@@ -1524,10 +1524,12 @@
         }
       }
 
-      arc -= 2;
-
       stroker->angle_in = angle_out;
-    }
+
+      if ( arc == bez_stack )
+        break;
+      arc -= 2;
+    } while ( 1 );
 
     stroker->center      = *to;
     stroker->line_length = 0;
@@ -1577,7 +1579,7 @@
     arc[2] = *control1;
     arc[3] = stroker->center;
 
-    while ( arc >= bez_stack )
+    do
     {
       FT_Angle  angle_in, angle_mid, angle_out;
 
@@ -1741,10 +1743,12 @@
         }
       }
 
-      arc -= 3;
-
       stroker->angle_in = angle_out;
-    }
+
+      if ( arc == bez_stack )
+        break;
+      arc -= 3;
+    } while ( 1 );
 
     stroker->center      = *to;
     stroker->line_length = 0;
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c b/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c
index ec05bce33a9..08bc1742202 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c
@@ -4,7 +4,7 @@
  *
  *   FreeType synthesizing code for emboldening and slanting (body).
  *
- * Copyright (C) 2000-2024 by
+ * Copyright (C) 2000-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -141,7 +141,7 @@
       /*
        * XXX: overflow check for 16-bit system, for compatibility
        *      with FT_GlyphSlot_Embolden() since FreeType 2.1.10.
-       *      unfortunately, this function return no informations
+       *      unfortunately, this function returns no information
        *      about the cause of error.
        */
       if ( ( ystr >> 6 ) > FT_INT_MAX || ( ystr >> 6 ) < FT_INT_MIN )
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c b/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c
index eee3642334f..186119d5581 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c
@@ -4,7 +4,7 @@
  *
  *   ANSI-specific FreeType low-level system interface (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -280,7 +280,7 @@
     stream->close = ft_ansi_stream_close;
 
     FT_TRACE1(( "FT_Stream_Open:" ));
-    FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n",
+    FT_TRACE1(( " opened `%s' (%lu bytes) successfully\n",
                 filepathname, stream->size ));
 
     return FT_Err_Ok;
diff --git a/src/java.desktop/share/native/libfreetype/src/base/fttrigon.c b/src/java.desktop/share/native/libfreetype/src/base/fttrigon.c
index 4b1aced1cba..29eff639c51 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/fttrigon.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/fttrigon.c
@@ -4,7 +4,7 @@
  *
  *   FreeType trigonometric functions (body).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/base/fttype1.c b/src/java.desktop/share/native/libfreetype/src/base/fttype1.c
index cedf7c40505..77978df674d 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/fttype1.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/fttype1.c
@@ -4,7 +4,7 @@
  *
  *   FreeType utility file for PS names support (body).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftutil.c b/src/java.desktop/share/native/libfreetype/src/base/ftutil.c
index b13512f8704..f83c4394893 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftutil.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftutil.c
@@ -4,7 +4,7 @@
  *
  *   FreeType utility file for memory and list management (body).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -424,11 +424,10 @@
     while ( cur )
     {
       FT_ListNode  next = cur->next;
-      void*        data = cur->data;
 
 
       if ( destroy )
-        destroy( memory, data, user );
+        destroy( memory, cur->data, user );
 
       FT_FREE( cur );
       cur = next;
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c b/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c
index ea5f8ed2885..cb69abdb90f 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c
@@ -4,7 +4,7 @@
  *
  *   CFF character mapping table (cmap) support (body).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.h b/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.h
index 1dd8700cd8b..60e16d94875 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.h
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.h
@@ -4,7 +4,7 @@
  *
  *   CFF character mapping table (cmap) support (specification).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c b/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c
index f6ebdb3810a..44ff44aecbd 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c
@@ -4,7 +4,7 @@
  *
  *   OpenType font driver implementation (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -121,7 +121,20 @@
     kerning->y = 0;
 
     if ( sfnt )
-      kerning->x = sfnt->get_kerning( cffface, left_glyph, right_glyph );
+    {
+      /* Use 'kern' table if available since that can be faster; otherwise */
+      /* use GPOS kerning pairs if available.                              */
+      if ( cffface->kern_avail_bits )
+        kerning->x = sfnt->get_kerning( cffface,
+                                        left_glyph,
+                                        right_glyph );
+#ifdef TT_CONFIG_OPTION_GPOS_KERNING
+      else if ( cffface->num_gpos_lookups_kerning )
+        kerning->x = sfnt->get_gpos_kerning( cffface,
+                                             left_glyph,
+                                             right_glyph );
+#endif
+    }
 
     return FT_Err_Ok;
   }
@@ -168,25 +181,7 @@
     CFF_Size       cffsize = (CFF_Size)size;
 
 
-    if ( !cffslot )
-      return FT_THROW( Invalid_Slot_Handle );
-
-    FT_TRACE1(( "cff_glyph_load: glyph index %d\n", glyph_index ));
-
-    /* check whether we want a scaled outline or bitmap */
-    if ( !cffsize )
-      load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
-
-    /* reset the size object if necessary */
-    if ( load_flags & FT_LOAD_NO_SCALE )
-      size = NULL;
-
-    if ( size )
-    {
-      /* these two objects must have the same parent */
-      if ( size->face != slot->face )
-        return FT_THROW( Invalid_Face_Handle );
-    }
+    FT_TRACE1(( "cff_glyph_load: glyph index %u\n", glyph_index ));
 
     /* now load the glyph outline if necessary */
     error = cff_slot_load( cffslot, cffsize, glyph_index, load_flags );
@@ -205,105 +200,70 @@
                     FT_Int32   flags,
                     FT_Fixed*  advances )
   {
-    FT_UInt       nn;
-    FT_Error      error = FT_Err_Ok;
-    FT_GlyphSlot  slot  = face->glyph;
+    CFF_Face  cffface = (CFF_Face)face;
+    FT_Bool   horz;
+    FT_UInt   nn;
 
 
-    if ( FT_IS_SFNT( face ) )
+    if ( !FT_IS_SFNT( face ) )
+      return FT_THROW( Unimplemented_Feature );
+
+    horz = !( flags & FT_LOAD_VERTICAL_LAYOUT );
+
+    if ( horz )
     {
       /* OpenType 1.7 mandates that the data from `hmtx' table be used; */
       /* it is no longer necessary that those values are identical to   */
       /* the values in the `CFF' table                                  */
+      if ( !cffface->horizontal.number_Of_HMetrics )
+        return FT_THROW( Unimplemented_Feature );
 
-      CFF_Face  cffface = (CFF_Face)face;
-      FT_Short  dummy;
-
-
-      if ( flags & FT_LOAD_VERTICAL_LAYOUT )
-      {
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-        /* no fast retrieval for blended MM fonts without VVAR table */
-        if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
-             !( cffface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) )
-          return FT_THROW( Unimplemented_Feature );
+      /* no fast retrieval for blended MM fonts without HVAR table */
+      if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
+           !( cffface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) )
+        return FT_THROW( Unimplemented_Feature );
 #endif
+    }
+    else  /* vertical */
+    {
+      /* check whether we have data from the `vmtx' table at all; */
+      /* otherwise we extract the info from the CFF glyphstrings  */
+      /* (instead of synthesizing a global value using the `OS/2' */
+      /* table)                                                   */
+      if ( !cffface->vertical_info )
+        return FT_THROW( Unimplemented_Feature );
 
-        /* check whether we have data from the `vmtx' table at all; */
-        /* otherwise we extract the info from the CFF glyphstrings  */
-        /* (instead of synthesizing a global value using the `OS/2' */
-        /* table)                                                   */
-        if ( !cffface->vertical_info )
-          goto Missing_Table;
-
-        for ( nn = 0; nn < count; nn++ )
-        {
-          FT_UShort  ah;
-
-
-          ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface,
-                                                        1,
-                                                        start + nn,
-                                                        &dummy,
-                                                        &ah );
-
-          FT_TRACE5(( "  idx %d: advance height %d font unit%s\n",
-                      start + nn,
-                      ah,
-                      ah == 1 ? "" : "s" ));
-          advances[nn] = ah;
-        }
-      }
-      else
-      {
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-        /* no fast retrieval for blended MM fonts without HVAR table */
-        if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
-             !( cffface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) )
-          return FT_THROW( Unimplemented_Feature );
+      /* no fast retrieval for blended MM fonts without VVAR table */
+      if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
+           !( cffface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) )
+        return FT_THROW( Unimplemented_Feature );
 #endif
-
-        /* check whether we have data from the `hmtx' table at all */
-        if ( !cffface->horizontal.number_Of_HMetrics )
-          goto Missing_Table;
-
-        for ( nn = 0; nn < count; nn++ )
-        {
-          FT_UShort  aw;
-
-
-          ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface,
-                                                        0,
-                                                        start + nn,
-                                                        &dummy,
-                                                        &aw );
-
-          FT_TRACE5(( "  idx %d: advance width %d font unit%s\n",
-                      start + nn,
-                      aw,
-                      aw == 1 ? "" : "s" ));
-          advances[nn] = aw;
-        }
-      }
-
-      return error;
     }
 
-  Missing_Table:
-    flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY;
-
+    /* proceed to fast advances */
     for ( nn = 0; nn < count; nn++ )
     {
-      error = cff_glyph_load( slot, face->size, start + nn, flags );
-      if ( error )
-        break;
-
-      advances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT )
-                     ? slot->linearVertAdvance
-                     : slot->linearHoriAdvance;
+      FT_UShort  aw;
+      FT_Short   dummy;
+
+
+      ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface,
+                                                    !horz,
+                                                    start + nn,
+                                                    &dummy,
+                                                    &aw );
+
+      FT_TRACE5(( "  idx %u: advance %s %d font unit%s\n",
+                  start + nn,
+                  horz ? "width" : "height",
+                  aw,
+                  aw == 1 ? "" : "s" ));
+      advances[nn] = aw;
     }
 
-    return error;
+    return FT_Err_Ok;
   }
 
 
@@ -496,8 +456,8 @@
                                                          dict->weight );
       font_info->italic_angle        = dict->italic_angle;
       font_info->is_fixed_pitch      = dict->is_fixed_pitch;
-      font_info->underline_position  = (FT_Short)dict->underline_position;
-      font_info->underline_thickness = (FT_UShort)dict->underline_thickness;
+      font_info->underline_position  = dict->underline_position;
+      font_info->underline_thickness = dict->underline_thickness;
 
       cff->font_info = font_info;
     }
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.h b/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.h
index fd5bc37ecd4..52a1e727a6a 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.h
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.h
@@ -4,7 +4,7 @@
  *
  *   High-level OpenType driver interface (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cfferrs.h b/src/java.desktop/share/native/libfreetype/src/cff/cfferrs.h
index 128adc3b716..7491886c7be 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cfferrs.h
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cfferrs.h
@@ -4,7 +4,7 @@
  *
  *   CFF error codes (specification only).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c b/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c
index cbb071abdfe..e8bab3c1e33 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c
@@ -4,7 +4,7 @@
  *
  *   OpenType Glyph Loader (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -238,24 +238,12 @@
     else if ( glyph_index >= cff->num_glyphs )
       return FT_THROW( Invalid_Argument );
 
-    if ( load_flags & FT_LOAD_NO_RECURSE )
-      load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
-
-    glyph->x_scale = 0x10000L;
-    glyph->y_scale = 0x10000L;
-    if ( size )
-    {
-      glyph->x_scale = size->root.metrics.x_scale;
-      glyph->y_scale = size->root.metrics.y_scale;
-    }
-
 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
 
     /* try to load embedded bitmap if any              */
     /*                                                 */
     /* XXX: The convention should be emphasized in     */
     /*      the documents because it can be confusing. */
-    if ( size )
     {
       CFF_Face      cff_face = (CFF_Face)size->root.face;
       SFNT_Service  sfnt     = (SFNT_Service)cff_face->sfnt;
@@ -284,9 +272,6 @@
           FT_Short   dummy;
 
 
-          glyph->root.outline.n_points   = 0;
-          glyph->root.outline.n_contours = 0;
-
           glyph->root.metrics.width  = (FT_Pos)metrics.width  * 64;
           glyph->root.metrics.height = (FT_Pos)metrics.height * 64;
 
@@ -423,6 +408,25 @@
 
 #endif /* FT_CONFIG_OPTION_SVG */
 
+    /* top-level code ensures that FT_LOAD_NO_HINTING is set */
+    /* if FT_LOAD_NO_SCALE is active                         */
+    hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
+    scaled  = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE   ) == 0 );
+
+    glyph->hint        = hinting;
+    glyph->scaled      = scaled;
+
+    if ( scaled )
+    {
+      glyph->x_scale = size->root.metrics.x_scale;
+      glyph->y_scale = size->root.metrics.y_scale;
+    }
+    else
+    {
+      glyph->x_scale = 0x10000L;
+      glyph->y_scale = 0x10000L;
+    }
+
     /* if we have a CID subfont, use its matrix (which has already */
     /* been multiplied with the root matrix)                       */
 
@@ -457,18 +461,6 @@
       font_offset = cff->top_font.font_dict.font_offset;
     }
 
-    glyph->root.outline.n_points   = 0;
-    glyph->root.outline.n_contours = 0;
-
-    /* top-level code ensures that FT_LOAD_NO_HINTING is set */
-    /* if FT_LOAD_NO_SCALE is active                         */
-    hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
-    scaled  = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE   ) == 0 );
-
-    glyph->hint        = hinting;
-    glyph->scaled      = scaled;
-    glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;  /* by default */
-
     {
 #ifdef CFF_CONFIG_OPTION_OLD_ENGINE
       PS_Driver  driver = (PS_Driver)FT_FACE_DRIVER( face );
@@ -602,10 +594,8 @@
     {
       /* Now, set the metrics -- this is rather simple, as   */
       /* the left side bearing is the xMin, and the top side */
-      /* bearing the yMax.                                   */
-
-      /* For composite glyphs, return only left side bearing and */
-      /* advance width.                                          */
+      /* bearing the yMax. For composite glyphs, return only */
+      /* left side bearing and advance width.                */
       if ( load_flags & FT_LOAD_NO_RECURSE )
       {
         FT_Slot_Internal  internal = glyph->root.internal;
@@ -624,6 +614,12 @@
         FT_Bool            has_vertical_info;
 
 
+        glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
+
+        glyph->root.outline.flags = FT_OUTLINE_REVERSE_FILL;
+        if ( size && size->root.metrics.y_ppem < 24 )
+          glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION;
+
         if ( face->horizontal.number_Of_HMetrics )
         {
           FT_Short   horiBearingX = 0;
@@ -677,14 +673,6 @@
 
         glyph->root.linearVertAdvance = metrics->vertAdvance;
 
-        glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
-
-        glyph->root.outline.flags = 0;
-        if ( size && size->root.metrics.y_ppem < 24 )
-          glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION;
-
-        glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL;
-
         /* apply the font matrix, if any */
         if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L ||
              font_matrix.xy != 0        || font_matrix.yx != 0        )
@@ -707,7 +695,7 @@
           metrics->vertAdvance += font_offset.y;
         }
 
-        if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling )
+        if ( scaled || force_scaling )
         {
           /* scale the outline and the metrics */
           FT_Int       n;
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffgload.h b/src/java.desktop/share/native/libfreetype/src/cff/cffgload.h
index 346d4b11c31..662bb7cff53 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffgload.h
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffgload.h
@@ -4,7 +4,7 @@
  *
  *   OpenType Glyph Loader (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffload.c b/src/java.desktop/share/native/libfreetype/src/cff/cffload.c
index 979fd45f6ca..39d662eb434 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffload.c
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffload.c
@@ -4,7 +4,7 @@
  *
  *   OpenType and CFF data/program tables loader (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -442,7 +442,7 @@
       if ( cur_offset != 0 )
       {
         FT_TRACE0(( "cff_index_get_pointers:"
-                    " invalid first offset value %ld set to zero\n",
+                    " invalid first offset value %lu set to zero\n",
                     cur_offset ));
         cur_offset = 0;
       }
@@ -559,8 +559,8 @@
            idx->data_offset > stream->size - off2 + 1 )
       {
         FT_ERROR(( "cff_index_access_element:"
-                   " offset to next entry (%ld)"
-                   " exceeds the end of stream (%ld)\n",
+                   " offset to next entry (%lu)"
+                   " exceeds the end of stream (%lu)\n",
                    off2, stream->size - idx->data_offset + 1 ));
         off2 = stream->size - idx->data_offset + 1;
       }
@@ -982,7 +982,7 @@
             if ( glyph_sid > 0xFFFFL - nleft )
             {
               FT_ERROR(( "cff_charset_load: invalid SID range trimmed"
-                         " nleft=%d -> %ld\n", nleft, 0xFFFFL - glyph_sid ));
+                         " nleft=%u -> %ld\n", nleft, 0xFFFFL - glyph_sid ));
               nleft = ( FT_UInt )( 0xFFFFL - glyph_sid );
             }
 
@@ -1315,7 +1315,7 @@
 
     if ( numOperands > count )
     {
-      FT_TRACE4(( " cff_blend_doBlend: Stack underflow %d argument%s\n",
+      FT_TRACE4(( " cff_blend_doBlend: Stack underflow %u argument%s\n",
                   count,
                   count == 1 ? "" : "s" ));
 
@@ -1466,7 +1466,7 @@
       if ( master == 0 )
       {
         blend->BV[master] = FT_FIXED_ONE;
-        FT_TRACE4(( "   build blend vector len %d\n", len ));
+        FT_TRACE4(( "   build blend vector len %u\n", len ));
         FT_TRACE4(( "   [ %f ", blend->BV[master] / 65536.0 ));
         continue;
       }
@@ -2014,8 +2014,8 @@
     /* set defaults */
     FT_ZERO( top );
 
-    top->underline_position  = -( 100L << 16 );
-    top->underline_thickness = 50L << 16;
+    top->underline_position  = -100;
+    top->underline_thickness = 50;
     top->charstring_type     = 2;
     top->font_matrix.xx      = 0x10000L;
     top->font_matrix.yy      = 0x10000L;
@@ -2341,7 +2341,7 @@
       if ( face_index > 0 && subfont_index >= font->name_index.count )
       {
         FT_ERROR(( "cff_font_load:"
-                   " invalid subfont index for pure CFF font (%d)\n",
+                   " invalid subfont index for pure CFF font (%u)\n",
                    subfont_index ));
         error = FT_THROW( Invalid_Argument );
         goto Exit;
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffload.h b/src/java.desktop/share/native/libfreetype/src/cff/cffload.h
index 02209245421..fdc132c8f3f 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffload.h
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffload.h
@@ -4,7 +4,7 @@
  *
  *   OpenType & CFF data/program tables loader (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c b/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c
index 7c6713739a1..9e00943a95d 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c
@@ -4,7 +4,7 @@
  *
  *   OpenType objects manager (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -537,8 +537,8 @@
 
       sfnt_format = 1;
 
-      /* now, the font can be either an OpenType/CFF font, or an SVG CEF */
-      /* font; in the latter case it doesn't have a `head' table         */
+      /* the font may be OpenType/CFF, SVG CEF, or sfnt/CFF; a `head' table */
+      /* implies OpenType/CFF, otherwise just look for an optional cmap     */
       error = face->goto_table( face, TTAG_head, stream, 0 );
       if ( !error )
       {
@@ -554,7 +554,9 @@
       {
         /* load the `cmap' table explicitly */
         error = sfnt->load_cmap( face, stream );
-        if ( error )
+
+        /* this may fail because CID-keyed fonts don't have a cmap */
+        if ( FT_ERR_NEQ( error, Table_Missing ) && FT_ERR_NEQ( error, Ok ) )
           goto Exit;
       }
 
@@ -651,7 +653,7 @@
         {
           s = cff_index_get_sid_string( cff, idx );
           if ( s )
-            FT_TRACE4(( "  %5d %s\n", idx, s ));
+            FT_TRACE4(( "  %5u %s\n", idx, s ));
         }
 
         /* In Multiple Master CFFs, two SIDs hold the Normalize Design  */
@@ -666,7 +668,7 @@
           FT_PtrDist  l;
 
 
-          FT_TRACE4(( "  %5d ", idx + 390 ));
+          FT_TRACE4(( "  %5u ", idx + 390 ));
           for ( l = 0; l < s1len; l++ )
             FT_TRACE4(( "%c", s1[l] ));
           FT_TRACE4(( "\n" ));
@@ -681,7 +683,7 @@
           FT_PtrDist  l;
 
 
-          FT_TRACE4(( "  %5d ", cff->num_strings + 390 ));
+          FT_TRACE4(( "  %5u ", cff->num_strings + 390 ));
           for ( l = 0; l < s1len; l++ )
             FT_TRACE4(( "%c", s1[l] ));
           FT_TRACE4(( "\n" ));
@@ -844,10 +846,8 @@
           cffface->height = (FT_Short)( cffface->ascender -
                                         cffface->descender );
 
-        cffface->underline_position  =
-          (FT_Short)( dict->underline_position >> 16 );
-        cffface->underline_thickness =
-          (FT_Short)( dict->underline_thickness >> 16 );
+        cffface->underline_position  = (FT_Short)dict->underline_position;
+        cffface->underline_thickness = (FT_Short)dict->underline_thickness;
 
         /* retrieve font family & style name */
         if ( dict->family_name )
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.h b/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.h
index 91ad83b1cd0..982dcd64dd0 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.h
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.h
@@ -4,7 +4,7 @@
  *
  *   OpenType objects manager (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c b/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c
index 92a69c3b516..864b2490b3b 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c
@@ -4,7 +4,7 @@
  *
  *   CFF token stream parser (body)
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -892,7 +892,7 @@
                    dict->cid_supplement ));
       error = FT_Err_Ok;
 
-      FT_TRACE4(( " %d %d %ld\n",
+      FT_TRACE4(( " %u %u %ld\n",
                   dict->cid_registry,
                   dict->cid_ordering,
                   dict->cid_supplement ));
@@ -929,7 +929,7 @@
 
     priv->vsindex = (FT_UInt)cff_parse_num( parser, data++ );
 
-    FT_TRACE4(( " %d\n", priv->vsindex ));
+    FT_TRACE4(( " %u\n", priv->vsindex ));
 
     error = FT_Err_Ok;
 
@@ -979,7 +979,7 @@
       goto Exit;
     }
 
-    FT_TRACE4(( "   %d value%s blended\n",
+    FT_TRACE4(( "   %u value%s blended\n",
                 numBlends,
                 numBlends == 1 ? "" : "s" ));
 
@@ -1014,7 +1014,7 @@
     if ( dict->maxstack < CFF2_DEFAULT_STACK )
       dict->maxstack = CFF2_DEFAULT_STACK;
 
-    FT_TRACE4(( " %d\n", dict->maxstack ));
+    FT_TRACE4(( " %u\n", dict->maxstack ));
 
   Exit:
     return error;
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h b/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h
index ca6b18af6aa..47cceb1a4a0 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h
@@ -4,7 +4,7 @@
  *
  *   CFF token stream parser (specification)
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cfftoken.h b/src/java.desktop/share/native/libfreetype/src/cff/cfftoken.h
index da45faa7f4e..a7ee1cb3fe7 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cfftoken.h
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cfftoken.h
@@ -4,7 +4,7 @@
  *
  *   CFF token definitions (specification only).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -30,8 +30,8 @@
   CFF_FIELD_STRING  ( 4,     weight,              "Weight" )
   CFF_FIELD_BOOL    ( 0x101, is_fixed_pitch,      "isFixedPitch" )
   CFF_FIELD_FIXED   ( 0x102, italic_angle,        "ItalicAngle" )
-  CFF_FIELD_FIXED   ( 0x103, underline_position,  "UnderlinePosition" )
-  CFF_FIELD_FIXED   ( 0x104, underline_thickness, "UnderlineThickness" )
+  CFF_FIELD_NUM     ( 0x103, underline_position,  "UnderlinePosition" )
+  CFF_FIELD_NUM     ( 0x104, underline_thickness, "UnderlineThickness" )
   CFF_FIELD_NUM     ( 0x105, paint_type,          "PaintType" )
   CFF_FIELD_NUM     ( 0x106, charstring_type,     "CharstringType" )
   CFF_FIELD_CALLBACK( 0x107, font_matrix,         "FontMatrix" )
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/ciderrs.h b/src/java.desktop/share/native/libfreetype/src/cid/ciderrs.h
index c439a8c4a0b..1591979d370 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/ciderrs.h
+++ b/src/java.desktop/share/native/libfreetype/src/cid/ciderrs.h
@@ -4,7 +4,7 @@
  *
  *   CID error codes (specification only).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c b/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c
index 7b571322d45..249ede5757d 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c
@@ -4,7 +4,7 @@
  *
  *   CID-keyed Type1 Glyph Loader (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -103,20 +103,20 @@
       if ( ( cid->fd_bytes == 1 && fd_select == 0xFFU   ) ||
            ( cid->fd_bytes == 2 && fd_select == 0xFFFFU ) )
       {
-        FT_TRACE1(( "cid_load_glyph: fail for glyph index %d:\n",
+        FT_TRACE1(( "cid_load_glyph: fail for glyph index %u:\n",
                     glyph_index ));
-        FT_TRACE1(( "                FD number %ld is the maximum\n",
+        FT_TRACE1(( "                FD number %lu is the maximum\n",
                     fd_select ));
-        FT_TRACE1(( "                integer fitting into %d byte%s\n",
+        FT_TRACE1(( "                integer fitting into %u byte%s\n",
                     cid->fd_bytes, cid->fd_bytes == 1 ? "" : "s" ));
       }
       else
       {
-        FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n",
+        FT_TRACE0(( "cid_load_glyph: fail for glyph index %u:\n",
                     glyph_index ));
-        FT_TRACE0(( "                FD number %ld is larger\n",
+        FT_TRACE0(( "                FD number %lu is larger\n",
                     fd_select ));
-        FT_TRACE0(( "                than number of dictionaries (%d)\n",
+        FT_TRACE0(( "                than number of dictionaries (%u)\n",
                     cid->num_dicts ));
       }
 
@@ -125,7 +125,7 @@
     }
     else if ( off2 > stream->size )
     {
-      FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n",
+      FT_TRACE0(( "cid_load_glyph: fail for glyph index %u:\n",
                   glyph_index ));
       FT_TRACE0(( "               end of the glyph data\n" ));
       FT_TRACE0(( "               is beyond the data stream\n" ));
@@ -135,7 +135,7 @@
     }
     else if ( off1 > off2 )
     {
-      FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n",
+      FT_TRACE0(( "cid_load_glyph: fail for glyph index %u:\n",
                   glyph_index ));
       FT_TRACE0(( "                the end position of glyph data\n" ));
       FT_TRACE0(( "                is set before the start position\n" ));
@@ -252,8 +252,8 @@
       cs_offset = decoder->lenIV >= 0 ? (FT_UInt)decoder->lenIV : 0;
       if ( cs_offset > glyph_length )
       {
-        FT_TRACE0(( "cid_load_glyph: fail for glyph_index=%d, "
-                    "offset to the charstring is beyond glyph length\n",
+        FT_TRACE0(( "cid_load_glyph: fail for glyph_index=%u,"
+                    " offset to the charstring is beyond glyph length\n",
                     glyph_index ));
         error = FT_THROW( Invalid_Offset );
         goto Exit;
@@ -452,16 +452,12 @@
     glyph->x_scale = cidsize->metrics.x_scale;
     glyph->y_scale = cidsize->metrics.y_scale;
 
-    cidglyph->outline.n_points   = 0;
-    cidglyph->outline.n_contours = 0;
-
     hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE   ) == 0 &&
                        ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
     scaled  = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE   ) == 0 );
 
     glyph->hint      = hinting;
     glyph->scaled    = scaled;
-    cidglyph->format = FT_GLYPH_FORMAT_OUTLINE;
 
     error = psaux->t1_decoder_funcs->init( &decoder,
                                            cidglyph->face,
@@ -501,12 +497,8 @@
 
     /* now set the metrics -- this is rather simple, as    */
     /* the left side bearing is the xMin, and the top side */
-    /* bearing the yMax                                    */
-    cidglyph->outline.flags &= FT_OUTLINE_OWNER;
-    cidglyph->outline.flags |= FT_OUTLINE_REVERSE_FILL;
-
-    /* for composite glyphs, return only left side bearing and */
-    /* advance width                                           */
+    /* bearing the yMax; for composite glyphs, return only */
+    /* left side bearing and advance width                 */
     if ( load_flags & FT_LOAD_NO_RECURSE )
     {
       FT_Slot_Internal  internal = cidglyph->internal;
@@ -527,6 +519,13 @@
       FT_Glyph_Metrics*  metrics = &cidglyph->metrics;
 
 
+      cidglyph->format = FT_GLYPH_FORMAT_OUTLINE;
+
+      cidglyph->outline.flags &= FT_OUTLINE_OWNER;
+      cidglyph->outline.flags |= FT_OUTLINE_REVERSE_FILL;
+      if ( cidsize->metrics.y_ppem < 24 )
+        cidglyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
+
       /* copy the _unscaled_ advance width */
       metrics->horiAdvance =
         FIXED_TO_INT( decoder.builder.advance.x );
@@ -539,11 +538,6 @@
                                       face->cid.font_bbox.yMin ) >> 16;
       cidglyph->linearVertAdvance = metrics->vertAdvance;
 
-      cidglyph->format            = FT_GLYPH_FORMAT_OUTLINE;
-
-      if ( cidsize->metrics.y_ppem < 24 )
-        cidglyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
-
       /* apply the font matrix, if any */
       if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L ||
            font_matrix.xy != 0        || font_matrix.yx != 0        )
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h b/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h
index 9fdc9db5892..cef96073ded 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h
@@ -4,7 +4,7 @@
  *
  *   OpenType Glyph Loader (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidload.c b/src/java.desktop/share/native/libfreetype/src/cid/cidload.c
index 722f5a34ddf..bb1bf13e221 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidload.c
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidload.c
@@ -4,7 +4,7 @@
  *
  *   CID-keyed Type1 font loader (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidload.h b/src/java.desktop/share/native/libfreetype/src/cid/cidload.h
index 7f030b32df7..659dd0e378c 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidload.h
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidload.h
@@ -4,7 +4,7 @@
  *
  *   CID-keyed Type1 font loader (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c b/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c
index 8d337c41128..634bbf2f135 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c
@@ -4,7 +4,7 @@
  *
  *   CID objects manager (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.h b/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.h
index d371cbe9954..800268efa2f 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.h
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.h
@@ -4,7 +4,7 @@
  *
  *   CID objects manager (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c b/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c
index 73a3ade893b..4d1ba335960 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c
@@ -4,7 +4,7 @@
  *
  *   CID-keyed Type1 parser (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidparse.h b/src/java.desktop/share/native/libfreetype/src/cid/cidparse.h
index 0f5baddcb92..6ae2e542394 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidparse.h
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidparse.h
@@ -4,7 +4,7 @@
  *
  *   CID-keyed Type1 parser (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c b/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c
index 4be8a5c00d5..a3a587c57bf 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c
@@ -4,7 +4,7 @@
  *
  *   CID driver interface (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidriver.h b/src/java.desktop/share/native/libfreetype/src/cid/cidriver.h
index 7ddce431c5b..55d0b8a0d9b 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidriver.h
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidriver.h
@@ -4,7 +4,7 @@
  *
  *   High-level CID driver interface (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidtoken.h b/src/java.desktop/share/native/libfreetype/src/cid/cidtoken.h
index 160897d1447..d40ebfab86d 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidtoken.h
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidtoken.h
@@ -4,7 +4,7 @@
  *
  *   CID token definitions (specification only).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -47,7 +47,7 @@
   T1_FIELD_STRING( "FullName",           full_name,           0 )
   T1_FIELD_STRING( "FamilyName",         family_name,         0 )
   T1_FIELD_STRING( "Weight",             weight,              0 )
-  T1_FIELD_NUM   ( "ItalicAngle",        italic_angle,        0 )
+  T1_FIELD_FIXED ( "ItalicAngle",        italic_angle,        0 )
   T1_FIELD_BOOL  ( "isFixedPitch",       is_fixed_pitch,      0 )
   T1_FIELD_NUM   ( "UnderlinePosition",  underline_position,  0 )
   T1_FIELD_NUM   ( "UnderlineThickness", underline_thickness, 0 )
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c b/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c
index e2f6a8e5adb..b813efde4eb 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c
@@ -4,7 +4,7 @@
  *
  *   AFM parser (body).
  *
- * Copyright (C) 2006-2024 by
+ * Copyright (C) 2006-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.h b/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.h
index b7766372821..add8597717d 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.h
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.h
@@ -4,7 +4,7 @@
  *
  *   AFM parser (specification).
  *
- * Copyright (C) 2006-2024 by
+ * Copyright (C) 2006-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c b/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c
index 9556e11a586..17bdd23c7d4 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c
@@ -4,7 +4,7 @@
  *
  *   PostScript CFF (Type 2) decoding routines (body).
  *
- * Copyright (C) 2017-2024 by
+ * Copyright (C) 2017-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -2141,7 +2141,7 @@
                                       decoder->locals_bias );
 
 
-            FT_TRACE4(( " callsubr (idx %d, entering level %td)\n",
+            FT_TRACE4(( " callsubr (idx %u, entering level %td)\n",
                         idx,
                         zone - decoder->zones + 1 ));
 
@@ -2185,7 +2185,7 @@
                                       decoder->globals_bias );
 
 
-            FT_TRACE4(( " callgsubr (idx %d, entering level %td)\n",
+            FT_TRACE4(( " callgsubr (idx %u, entering level %td)\n",
                         idx,
                         zone - decoder->zones + 1 ));
 
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.h b/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.h
index 038f7235c3d..e72ec043baa 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.h
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.h
@@ -4,7 +4,7 @@
  *
  *   PostScript CFF (Type 2) decoding routines (specification).
  *
- * Copyright (C) 2017-2024 by
+ * Copyright (C) 2017-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psauxerr.h b/src/java.desktop/share/native/libfreetype/src/psaux/psauxerr.h
index 18428c40d5a..0d7fe2b6121 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/psauxerr.h
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/psauxerr.h
@@ -4,7 +4,7 @@
  *
  *   PS auxiliary module error codes (specification only).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.c b/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.c
index 6826f9d8d3e..942804190c5 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.c
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.c
@@ -4,7 +4,7 @@
  *
  *   FreeType auxiliary PostScript module implementation (body).
  *
- * Copyright (C) 2000-2024 by
+ * Copyright (C) 2000-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.h b/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.h
index 82d7e348af8..4a5ebc1b607 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.h
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.h
@@ -4,7 +4,7 @@
  *
  *   FreeType auxiliary PostScript module implementation (specification).
  *
- * Copyright (C) 2000-2024 by
+ * Copyright (C) 2000-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -46,9 +46,6 @@ FT_BEGIN_HEADER
   const CFF_Decoder_FuncsRec  cff_decoder_funcs;
 
 
-  FT_EXPORT_VAR( const FT_Module_Class )  psaux_driver_class;
-
-
   FT_DECLARE_MODULE( psaux_module_class )
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psconv.c b/src/java.desktop/share/native/libfreetype/src/psaux/psconv.c
index 56c0ecd1d7f..4567d3f3c06 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/psconv.c
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/psconv.c
@@ -4,7 +4,7 @@
  *
  *   Some convenience conversions (body).
  *
- * Copyright (C) 2006-2024 by
+ * Copyright (C) 2006-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psconv.h b/src/java.desktop/share/native/libfreetype/src/psaux/psconv.h
index 91fcd15a1c9..63735af411f 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/psconv.h
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/psconv.h
@@ -4,7 +4,7 @@
  *
  *   Some convenience conversions (specification).
  *
- * Copyright (C) 2006-2024 by
+ * Copyright (C) 2006-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c b/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c
index 7572e225e37..7e3475e6f58 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c
@@ -618,7 +618,7 @@
     /*       Our copy of it does not change that requirement.         */
     cf2_arrstack_setCount( &subrStack, CF2_MAX_SUBR + 1 );
 
-    charstring  = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack );
+    charstring = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack );
 
     /* catch errors so far */
     if ( *error )
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.c b/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.c
index eca465f009e..8159fd6ef15 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.c
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.c
@@ -4,7 +4,7 @@
  *
  *   Auxiliary functions for PostScript fonts (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -460,6 +460,9 @@
       case '%':
         skip_comment( &cur, limit );
         break;
+
+      default:
+        break;
       }
     }
 
@@ -1145,7 +1148,7 @@
             FT_ERROR(( "ps_parser_load_field:"
                        " expected a name or string\n" ));
             FT_ERROR(( "                     "
-                       " but found token of type %d instead\n",
+                       " but found token of type %u instead\n",
                        token.type ));
             error = FT_THROW( Invalid_File_Format );
             goto Exit;
@@ -1225,7 +1228,7 @@
             if ( result < 0 || (FT_UInt)result < max_objects )
             {
               FT_ERROR(( "ps_parser_load_field:"
-                         " expected %d integer%s in the %s subarray\n",
+                         " expected %u integer%s in the %s subarray\n",
                          max_objects, max_objects > 1 ? "s" : "",
                          i == 0 ? "first"
                                 : ( i == 1 ? "second"
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.h b/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.h
index 345fc8a7335..277aa1247c5 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.h
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.h
@@ -4,7 +4,7 @@
  *
  *   Auxiliary functions for PostScript fonts (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c b/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c
index 5681c3bd0fd..66493b68123 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c
@@ -4,7 +4,7 @@
  *
  *   Type 1 character map support (body).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.h b/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.h
index 445e6a2784f..114bfbb0410 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.h
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.h
@@ -4,7 +4,7 @@
  *
  *   Type 1 character map support (specification).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c b/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c
index c74baa8038f..c3fb343d4c9 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c
@@ -4,7 +4,7 @@
  *
  *   PostScript Type 1 decoding routines (body).
  *
- * Copyright (C) 2000-2024 by
+ * Copyright (C) 2000-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -1633,7 +1633,7 @@
 
         default:
           FT_ERROR(( "t1_decoder_parse_charstrings:"
-                     " unhandled opcode %d\n", op ));
+                     " unhandled opcode %u\n", op ));
           goto Syntax_Error;
         }
 
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.h b/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.h
index 16203b8f734..7b913f55dff 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.h
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.h
@@ -4,7 +4,7 @@
  *
  *   PostScript Type 1 decoding routines (specification).
  *
- * Copyright (C) 2000-2024 by
+ * Copyright (C) 2000-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c b/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c
index 967767b3485..e053dba17b2 100644
--- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c
+++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c
@@ -4,7 +4,7 @@
  *
  *   PostScript hinting algorithm (body).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used
@@ -35,10 +35,6 @@
 #endif
 
 
-#define  COMPUTE_INFLEXS  /* compute inflection points to optimize `S' */
-                          /* and similar glyphs                        */
-
-
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -100,7 +96,7 @@
 
     if ( idx >= table->max_hints )
     {
-      FT_TRACE0(( "psh_hint_table_record: invalid hint index %d\n", idx ));
+      FT_TRACE0(( "psh_hint_table_record: invalid hint index %u\n", idx ));
       return;
     }
 
@@ -920,117 +916,6 @@
 #define  psh_corner_orientation  ft_corner_orientation
 
 
-#ifdef COMPUTE_INFLEXS
-
-  /* compute all inflex points in a given glyph */
-  static void
-  psh_glyph_compute_inflections( PSH_Glyph  glyph )
-  {
-    FT_UInt  n;
-
-
-    for ( n = 0; n < glyph->num_contours; n++ )
-    {
-      PSH_Point  first, start, end, before, after;
-      FT_Pos     in_x, in_y, out_x, out_y;
-      FT_Int     orient_prev, orient_cur;
-      FT_Int     finished = 0;
-
-
-      /* we need at least 4 points to create an inflection point */
-      if ( glyph->contours[n].count < 4 )
-        continue;
-
-      /* compute first segment in contour */
-      first = glyph->contours[n].start;
-
-      start = end = first;
-      do
-      {
-        end = end->next;
-        if ( end == first )
-          goto Skip;
-
-        in_x = end->org_u - start->org_u;
-        in_y = end->org_v - start->org_v;
-
-      } while ( in_x == 0 && in_y == 0 );
-
-      /* extend the segment start whenever possible */
-      before = start;
-      do
-      {
-        do
-        {
-          start  = before;
-          before = before->prev;
-          if ( before == first )
-            goto Skip;
-
-          out_x = start->org_u - before->org_u;
-          out_y = start->org_v - before->org_v;
-
-        } while ( out_x == 0 && out_y == 0 );
-
-        orient_prev = psh_corner_orientation( in_x, in_y, out_x, out_y );
-
-      } while ( orient_prev == 0 );
-
-      first = start;
-      in_x  = out_x;
-      in_y  = out_y;
-
-      /* now, process all segments in the contour */
-      do
-      {
-        /* first, extend current segment's end whenever possible */
-        after = end;
-        do
-        {
-          do
-          {
-            end   = after;
-            after = after->next;
-            if ( after == first )
-              finished = 1;
-
-            out_x = after->org_u - end->org_u;
-            out_y = after->org_v - end->org_v;
-
-          } while ( out_x == 0 && out_y == 0 );
-
-          orient_cur = psh_corner_orientation( in_x, in_y, out_x, out_y );
-
-        } while ( orient_cur == 0 );
-
-        if ( ( orient_cur ^ orient_prev ) < 0 )
-        {
-          do
-          {
-            psh_point_set_inflex( start );
-            start = start->next;
-          }
-          while ( start != end );
-
-          psh_point_set_inflex( start );
-        }
-
-        start       = end;
-        end         = after;
-        orient_prev = orient_cur;
-        in_x        = out_x;
-        in_y        = out_y;
-
-      } while ( !finished );
-
-    Skip:
-      ;
-    }
-  }
-
-#endif /* COMPUTE_INFLEXS */
-
-
   static void
   psh_glyph_done( PSH_Glyph  glyph )
   {
@@ -1258,11 +1143,6 @@
     glyph->outline = outline;
     glyph->globals = globals;
 
-#ifdef COMPUTE_INFLEXS
-    psh_glyph_load_points( glyph, 0 );
-    psh_glyph_compute_inflections( glyph );
-#endif /* COMPUTE_INFLEXS */
-
     /* now deal with hints tables */
     error = psh_hint_table_init( &glyph->hint_tables [0],
                                  &ps_hints->dimension[0].hints,
@@ -1285,122 +1165,47 @@
   }
 
 
-  /* compute all extrema in a glyph for a given dimension */
+  /* compute all extreme and inflection points */
+  /* in a glyph for a given dimension          */
   static void
   psh_glyph_compute_extrema( PSH_Glyph  glyph )
   {
     FT_UInt  n;
 
 
-    /* first of all, compute all local extrema */
     for ( n = 0; n < glyph->num_contours; n++ )
     {
-      PSH_Point  first = glyph->contours[n].start;
-      PSH_Point  point, before, after;
+      PSH_Point  first, point, before, after;
 
 
-      if ( glyph->contours[n].count == 0 )
+      /* we need at least 3 points to create an extremum */
+      if ( glyph->contours[n].count < 3 )
         continue;
 
-      point  = first;
-      before = point;
+      first = glyph->contours[n].start;
+      point = first->prev;
+      after = first;
 
       do
       {
-        before = before->prev;
-        if ( before == first )
-          goto Skip;
-
-      } while ( before->org_u == point->org_u );
-
-      first = point = before->next;
-
-      for (;;)
-      {
-        after = point;
-        do
-        {
-          after = after->next;
-          if ( after == first )
-            goto Next;
-
-        } while ( after->org_u == point->org_u );
-
-        if ( before->org_u < point->org_u )
-        {
-          if ( after->org_u < point->org_u )
-          {
-            /* local maximum */
-            goto Extremum;
-          }
-        }
-        else /* before->org_u > point->org_u */
-        {
-          if ( after->org_u > point->org_u )
-          {
-            /* local minimum */
-          Extremum:
-            do
-            {
-              psh_point_set_extremum( point );
-              point = point->next;
-
-            } while ( point != after );
-          }
-        }
-
-        before = after->prev;
+        before = point;
         point  = after;
+        after  = point->next;
 
-      } /* for  */
-
-    Next:
-      ;
-    }
-
-    /* for each extremum, determine its direction along the */
-    /* orthogonal axis                                      */
-    for ( n = 0; n < glyph->num_points; n++ )
-    {
-      PSH_Point  point, before, after;
-
-
-      point  = &glyph->points[n];
-      before = point;
-      after  = point;
-
-      if ( psh_point_is_extremum( point ) )
-      {
-        do
-        {
-          before = before->prev;
-          if ( before == point )
-            goto Skip;
-
-        } while ( before->org_v == point->org_v );
-
-        do
-        {
-          after = after->next;
-          if ( after == point )
-            goto Skip;
+        if ( ( before->org_u < point->org_u && point->org_u < after->org_u ) ||
+             ( before->org_u > point->org_u && point->org_u > after->org_u ) )
+          continue;
 
-        } while ( after->org_v == point->org_v );
-      }
+        /* otherwise this is either extremum or inflection point */
+        psh_point_set_extremum( point );
 
-      if ( before->org_v < point->org_v &&
-           after->org_v  > point->org_v )
-      {
-        psh_point_set_positive( point );
-      }
-      else if ( before->org_v > point->org_v &&
-                after->org_v  < point->org_v )
-      {
-        psh_point_set_negative( point );
-      }
+        /* also note its direction */
+        if ( before->org_v < after->org_v )
+          psh_point_set_positive( point );
+        else if ( before->org_v > after->org_v )
+          psh_point_set_negative( point );
 
-    Skip:
-      ;
+      } while ( after != first );
     }
   }
 
@@ -1836,8 +1641,7 @@
              point->dir_in != point->dir_out )
           continue;
 
-        if ( !psh_point_is_extremum( point ) &&
-             !psh_point_is_inflex( point )   )
+        if ( !psh_point_is_extremum( point ) )
           continue;
 
         point->flags &= ~PSH_POINT_SMOOTH;
diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.h b/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.h
index fb362f061b6..f4aa8540559 100644
--- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.h
+++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.h
@@ -4,7 +4,7 @@
  *
  *   PostScript hinting algorithm (specification).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.c b/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.c
index 435f45838ff..a772b66f309 100644
--- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.c
+++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.c
@@ -5,7 +5,7 @@
  *   PostScript hinter global hinting management (body).
  *   Inspired by the new auto-hinter module.
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used
@@ -376,36 +376,24 @@
     /* not.  We simply need to compare the vertical scale     */
     /* parameter to the raw bluescale value.  Here is why:    */
     /*                                                        */
-    /*   We need to suppress overshoots for all pointsizes.   */
-    /*   At 300dpi that satisfies:                            */
+    /* The specs explain how the bluescale is calculated      */
+    /* from the desired maximum rounded pointsize at 300 dpi  */
+    /* and assuming upem of 1000.                             */
     /*                                                        */
-    /*      pointsize < 240*bluescale + 0.49                  */
+    /*    bluescale = ( pointsize - 0.49 ) / 240              */
     /*                                                        */
-    /*   This corresponds to:                                 */
+    /* For unrounded pointsize in general terms               */
     /*                                                        */
-    /*      pixelsize < 1000*bluescale + 49/24                */
+    /*    bluescale = ( pointsize * dpi / 72 ) / upem         */
     /*                                                        */
-    /*      scale*EM_Size < 1000*bluescale + 49/24            */
+    /* which is                                               */
     /*                                                        */
-    /*   However, for normal Type 1 fonts, EM_Size is 1000!   */
-    /*   We thus only check:                                  */
+    /*    bluescale = pixelsize / upem                        */
     /*                                                        */
-    /*      scale < bluescale + 49/24000                      */
+    /* Therefore, the bluescale value can be used directly    */
+    /* as a scale limit, now that it is in comparable units   */
     /*                                                        */
-    /*   which we shorten to                                  */
-    /*                                                        */
-    /*      "scale < bluescale"                               */
-    /*                                                        */
-    /* Note that `blue_scale' is stored 1000 times its real   */
-    /* value, and that `scale' converts from font units to    */
-    /* fractional pixels.                                     */
-    /*                                                        */
-
-    /* 1000 / 64 = 125 / 8 */
-    if ( scale >= 0x20C49BAL )
-      blues->no_overshoots = FT_BOOL( scale < blues->blue_scale * 8 / 125 );
-    else
-      blues->no_overshoots = FT_BOOL( scale * 125 < blues->blue_scale * 8 );
+    blues->no_overshoots = FT_BOOL( scale < blues->blue_scale );
 
     /*                                                        */
     /*  The blue threshold is the font units distance under   */
@@ -420,8 +408,8 @@
       FT_Int  threshold = blues->blue_shift;
 
 
-      while ( threshold > 0 && FT_MulFix( threshold, scale ) > 32 )
-        threshold--;
+      if ( threshold > 0 && FT_MulFix( threshold, scale ) > 32 )
+        threshold = 32 * 0x10000L / scale;
 
       blues->blue_threshold = threshold;
     }
@@ -708,7 +696,6 @@
 
       /* limit the BlueScale value to `1 / max_of_blue_zone_heights' */
       {
-        FT_Fixed  max_scale;
         FT_Short  max_height = 1;
 
 
@@ -725,11 +712,12 @@
                                           priv->family_other_blues,
                                           max_height );
 
-        /* BlueScale is scaled 1000 times */
-        max_scale = FT_DivFix( 1000, max_height );
-        globals->blues.blue_scale = priv->blue_scale < max_scale
-                                      ? priv->blue_scale
-                                      : max_scale;
+        /* restrict BlueScale value that is amplified 1000-fold and */
+        /* rescale it to be comparable to the metrics scale         */
+        if ( FT_MulFix( max_height, priv->blue_scale ) < 1000 )
+          globals->blues.blue_scale = priv->blue_scale * 8 / 125;
+        else
+          globals->blues.blue_scale = 64 * 0x10000L / max_height;
       }
 
       globals->blues.blue_shift = priv->blue_shift;
diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.h b/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.h
index c5a5c913168..555e99facb2 100644
--- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.h
+++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.h
@@ -4,7 +4,7 @@
  *
  *   PostScript hinter global hinting management.
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c b/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c
index 9965d5b16bf..c9f4a94fe98 100644
--- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c
+++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c
@@ -4,7 +4,7 @@
  *
  *   FreeType PostScript hinter module implementation (body).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.h b/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.h
index 62ac0a60fdc..de9c398e9fb 100644
--- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.h
+++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.h
@@ -4,7 +4,7 @@
  *
  *   PostScript hinter module interface (specification).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshnterr.h b/src/java.desktop/share/native/libfreetype/src/pshinter/pshnterr.h
index e9641340e53..7076664ddde 100644
--- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshnterr.h
+++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshnterr.h
@@ -4,7 +4,7 @@
  *
  *   PS Hinter error codes (specification only).
  *
- * Copyright (C) 2003-2024 by
+ * Copyright (C) 2003-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c b/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c
index 0b2b549fc29..13754313fbb 100644
--- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c
+++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c
@@ -4,7 +4,7 @@
  *
  *   FreeType PostScript hints recorder (body).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -467,7 +467,7 @@
       table->num_masks--;
     }
     else
-      FT_TRACE0(( "ps_mask_table_merge: ignoring invalid indices (%d,%d)\n",
+      FT_TRACE0(( "ps_mask_table_merge: ignoring invalid indices (%u,%u)\n",
                   index1, index2 ));
 
   Exit:
@@ -817,7 +817,7 @@
     /* limit "dimension" to 0..1 */
     if ( dimension > 1 )
     {
-      FT_TRACE0(( "ps_hints_stem: invalid dimension (%d) used\n",
+      FT_TRACE0(( "ps_hints_stem: invalid dimension (%u) used\n",
                   dimension ));
       dimension = ( dimension != 0 );
     }
@@ -870,7 +870,7 @@
       /* limit "dimension" to 0..1 */
       if ( dimension > 1 )
       {
-        FT_TRACE0(( "ps_hints_t1stem3: invalid dimension (%d) used\n",
+        FT_TRACE0(( "ps_hints_t1stem3: invalid dimension (%u) used\n",
                     dimension ));
         dimension = ( dimension != 0 );
       }
@@ -976,7 +976,7 @@
       if ( bit_count !=  count1 + count2 )
       {
         FT_TRACE0(( "ps_hints_t2mask:"
-                    " called with invalid bitcount %d (instead of %d)\n",
+                    " called with invalid bitcount %u (instead of %u)\n",
                    bit_count, count1 + count2 ));
 
         /* simply ignore the operator */
@@ -1022,7 +1022,7 @@
       if ( bit_count !=  count1 + count2 )
       {
         FT_TRACE0(( "ps_hints_t2counter:"
-                    " called with invalid bitcount %d (instead of %d)\n",
+                    " called with invalid bitcount %u (instead of %u)\n",
                    bit_count, count1 + count2 ));
 
         /* simply ignore the operator */
diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.h b/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.h
index 7e375af7ba8..a79069f98d2 100644
--- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.h
+++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.h
@@ -4,7 +4,7 @@
  *
  *   Postscript (Type1/Type2) hints recorder (specification).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c b/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c
index 35d054d1cfb..c5d71edad88 100644
--- a/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c
+++ b/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c
@@ -4,7 +4,7 @@
  *
  *   psnames module implementation (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.h b/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.h
index 770458316b1..482fd0a36d1 100644
--- a/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.h
+++ b/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.h
@@ -4,7 +4,7 @@
  *
  *   High-level psnames module interface (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/psnames/psnamerr.h b/src/java.desktop/share/native/libfreetype/src/psnames/psnamerr.h
index e123eb65e39..17987f9cd4f 100644
--- a/src/java.desktop/share/native/libfreetype/src/psnames/psnamerr.h
+++ b/src/java.desktop/share/native/libfreetype/src/psnames/psnamerr.h
@@ -4,7 +4,7 @@
  *
  *   PS names module error codes (specification only).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/psnames/pstables.h b/src/java.desktop/share/native/libfreetype/src/psnames/pstables.h
index 2a941b04609..65ce6c0b47f 100644
--- a/src/java.desktop/share/native/libfreetype/src/psnames/pstables.h
+++ b/src/java.desktop/share/native/libfreetype/src/psnames/pstables.h
@@ -4,7 +4,7 @@
  *
  *   PostScript glyph names.
  *
- * Copyright (C) 2005-2024 by
+ * Copyright (C) 2005-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftmisc.h b/src/java.desktop/share/native/libfreetype/src/raster/ftmisc.h
index 943f2aa0a50..9d97223e94e 100644
--- a/src/java.desktop/share/native/libfreetype/src/raster/ftmisc.h
+++ b/src/java.desktop/share/native/libfreetype/src/raster/ftmisc.h
@@ -5,7 +5,7 @@
  *   Miscellaneous macros for stand-alone rasterizer (specification
  *   only).
  *
- * Copyright (C) 2005-2024 by
+ * Copyright (C) 2005-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used
diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c b/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c
index e4b7b937d5a..807d444e7aa 100644
--- a/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c
+++ b/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c
@@ -4,7 +4,7 @@
  *
  *   The FreeType glyph rasterizer (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -251,7 +251,11 @@
   /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */
   /* for clipping computations.  It simply uses the FT_MulDiv() function   */
   /* defined in `ftcalc.h'.                                                */
-#define SMulDiv_No_Round  FT_MulDiv_No_Round
+#ifdef FT_INT64
+#define SMulDiv( a, b, c )  (Long)( (FT_Int64)(a) * (b) / (c) )
+#else
+#define SMulDiv  FT_MulDiv_No_Round
+#endif
 
   /* The rasterizer is a very general purpose component; please leave */
   /* the following redefinitions there (you never know your target    */
@@ -653,7 +657,7 @@
       ras.cProfile->height = 0;
     }
 
-    ras.cProfile->flags  = ras.dropOutControl;
+    ras.cProfile->flags = ras.dropOutControl;
 
     switch ( aState )
     {
@@ -967,14 +971,14 @@
       goto Fin;
     }
 
-    Ix     = SMulDiv_No_Round( e - y1, Dx, Dy );
+    Ix     = SMulDiv( e - y1, Dx, Dy );
     x1    += Ix;
     *top++ = x1;
 
     if ( --size )
     {
       Ax = Dx * ( e - y1 )    - Dy * Ix;  /* remainder */
-      Ix = FMulDiv( ras.precision, Dx, Dy );
+      Ix = SMulDiv( ras.precision, Dx, Dy );
       Rx = Dx * ras.precision - Dy * Ix;  /* remainder */
       Dx = 1;
 
@@ -1090,8 +1094,8 @@
     PLong  top;
 
 
-    y1  = arc[degree].y;
-    y2  = arc[0].y;
+    y1 = arc[degree].y;
+    y2 = arc[0].y;
 
     if ( y2 < miny || y1 > maxy )
       return SUCCESS;
diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftraster.h b/src/java.desktop/share/native/libfreetype/src/raster/ftraster.h
index ad9cb1b9fe0..64499bf955b 100644
--- a/src/java.desktop/share/native/libfreetype/src/raster/ftraster.h
+++ b/src/java.desktop/share/native/libfreetype/src/raster/ftraster.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType glyph rasterizer (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used
diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c b/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c
index fd9f174f2e1..3fa008704e5 100644
--- a/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c
+++ b/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c
@@ -4,7 +4,7 @@
  *
  *   The FreeType glyph rasterizer interface (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.h b/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.h
index cf3e73c0a24..d838a942b04 100644
--- a/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.h
+++ b/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.h
@@ -4,7 +4,7 @@
  *
  *   The FreeType glyph rasterizer interface (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/raster/rasterrs.h b/src/java.desktop/share/native/libfreetype/src/raster/rasterrs.h
index 326d42e0438..39d82a8051a 100644
--- a/src/java.desktop/share/native/libfreetype/src/raster/rasterrs.h
+++ b/src/java.desktop/share/native/libfreetype/src/raster/rasterrs.h
@@ -4,7 +4,7 @@
  *
  *   monochrome renderer error codes (specification only).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c b/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c
index 76181568af9..24fb3455598 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c
@@ -4,7 +4,7 @@
  *
  *   PNG Bitmap glyph support.
  *
- * Copyright (C) 2013-2024 by
+ * Copyright (C) 2013-2025 by
  * Google, Inc.
  * Written by Stuart Gill and Behdad Esfahbod.
  *
@@ -420,10 +420,7 @@
     if ( populate_map_and_metrics )
     {
       /* this doesn't overflow: 0x7FFF * 0x7FFF * 4 < 2^32 */
-      FT_ULong  size = map->rows * (FT_ULong)map->pitch;
-
-
-      error = ft_glyphslot_alloc_bitmap( slot, size );
+      error = ft_glyphslot_alloc_bitmap( slot );
       if ( error )
         goto DestroyExit;
     }
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.h b/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.h
index 6e7a5c08e71..c59199e60df 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.h
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.h
@@ -4,7 +4,7 @@
  *
  *   PNG Bitmap glyph support.
  *
- * Copyright (C) 2013-2024 by
+ * Copyright (C) 2013-2025 by
  * Google, Inc.
  * Written by Stuart Gill and Behdad Esfahbod.
  *
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c
index 81072207b49..32291e23e36 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c
@@ -4,7 +4,7 @@
  *
  *   High-level SFNT driver interface (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -895,7 +895,7 @@
         FT_TRACE0(( "sfnt_get_var_ps_name:"
                     " Shortening variation PS name prefix\n" ));
         FT_TRACE0(( "                     "
-                    " to %d characters\n", len ));
+                    " to %u characters\n", len ));
       }
 
       face->var_postscript_prefix     = result;
@@ -1142,12 +1142,7 @@
     FT_Error         error;
 
 
-    /* XXX: I don't know whether this is correct, since
-     *      tt_face_find_bdf_prop only returns something correct if we have
-     *      previously selected a size that is listed in the BDF table.
-     *      Should we change the BDF table format to include single offsets
-     *      for `CHARSET_REGISTRY' and `CHARSET_ENCODING'?
-     */
+    /* We expect that a bitmap strike has been selected. */
     error = tt_face_find_bdf_prop( face, "CHARSET_REGISTRY", ®istry );
     if ( !error )
     {
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.h b/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.h
index 6f71489fdc1..be4e33166c1 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.h
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.h
@@ -4,7 +4,7 @@
  *
  *   High-level SFNT driver interface (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sferrors.h b/src/java.desktop/share/native/libfreetype/src/sfnt/sferrors.h
index d3ca1d9aa8b..2da4ac776b0 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/sferrors.h
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sferrors.h
@@ -4,7 +4,7 @@
  *
  *   SFNT error codes (specification only).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c
index 6ee4e5e939b..6af35787e85 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c
@@ -4,7 +4,7 @@
  *
  *   SFNT object management (base).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -579,6 +579,9 @@
     if ( face_instance_index < 0 && face_index > 0 )
       face_index--;
 
+    /* Note that `face_index` is also used to enumerate elements */
+    /* of containers like a Mac Resource; this means we must     */
+    /* check whether we actually have a TTC.                     */
     if ( face_index >= face->ttc_header.count )
     {
       if ( face_instance_index >= 0 )
@@ -1127,9 +1130,9 @@
         flags |= FT_FACE_FLAG_VERTICAL;
 
       /* kerning available ? */
-      if ( TT_FACE_HAS_KERNING( face )
+      if ( face->kern_avail_bits
 #ifdef TT_CONFIG_OPTION_GPOS_KERNING
-           || face->gpos_kerning_available
+           || face->num_gpos_lookups_kerning
 #endif
          )
         flags |= FT_FACE_FLAG_KERNING;
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.h b/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.h
index 90847d95732..8c38b727950 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.h
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.h
@@ -4,7 +4,7 @@
  *
  *   SFNT object management (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c
index 14514bf9574..015c7b78b4d 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c
@@ -4,7 +4,7 @@
  *
  *   WOFF format management (base).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.h b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.h
index a04735ffe28..df7ace5c209 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.h
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.h
@@ -4,7 +4,7 @@
  *
  *   WOFFF format management (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c
index 589b3e0c6b7..41c233597b8 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c
@@ -4,7 +4,7 @@
  *
  *   WOFF2 format management (base).
  *
- * Copyright (C) 2019-2024 by
+ * Copyright (C) 2019-2025 by
  * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -902,7 +902,7 @@
       substreams[i].offset = pos + offset;
       substreams[i].size   = substream_size;
 
-      FT_TRACE5(( "  Substream %d: offset = %lu; size = %lu;\n",
+      FT_TRACE5(( "  Substream %u: offset = %lu; size = %lu;\n",
                   i, substreams[i].offset, substreams[i].size ));
       offset += substream_size;
     }
@@ -1043,7 +1043,6 @@
         FT_ULong   total_n_points = 0;
         FT_UShort  n_points_contour;
         FT_UInt    j;
-        FT_ULong   flag_size;
         FT_ULong   triplet_size;
         FT_ULong   triplet_bytes_used;
         FT_Bool    have_overlap  = FALSE;
@@ -1088,8 +1087,8 @@
         }
         substreams[N_POINTS_STREAM].offset = FT_STREAM_POS();
 
-        flag_size = total_n_points;
-        if ( flag_size > substreams[FLAG_STREAM].size )
+        points_size += total_n_points;
+        if ( points_size > substreams[FLAG_STREAM].size )
           goto Fail;
 
         flags_buf   = stream->base + substreams[FLAG_STREAM].offset;
@@ -1106,8 +1105,7 @@
         triplet_bytes_used = 0;
 
         /* Create array to store point information. */
-        points_size = total_n_points;
-        if ( FT_QNEW_ARRAY( points, points_size ) )
+        if ( FT_QNEW_ARRAY( points, total_n_points ) )
           goto Fail;
 
         if ( triplet_decode( flags_buf,
@@ -1118,7 +1116,7 @@
                              &triplet_bytes_used ) )
           goto Fail;
 
-        substreams[FLAG_STREAM].offset  += flag_size;
+        substreams[FLAG_STREAM].offset  += total_n_points;
         substreams[GLYPH_STREAM].offset += triplet_bytes_used;
 
         if ( FT_STREAM_SEEK( substreams[GLYPH_STREAM].offset ) ||
@@ -1592,7 +1590,7 @@
       WOFF2_TableRec  table = *( indices[nn] );
 
 
-      FT_TRACE3(( "Seeking to %ld with table size %ld.\n",
+      FT_TRACE3(( "Seeking to %lu with table size %lu.\n",
                   table.src_offset, table.src_length ));
       FT_TRACE3(( "Table tag: %c%c%c%c.\n",
                   (FT_Char)( table.Tag >> 24 ),
@@ -1943,7 +1941,7 @@
       src_offset       += table->TransformLength;
       table->dst_offset = 0;
 
-      FT_TRACE2(( "  %c%c%c%c  %08d  %08d   %08ld    %08ld    %08ld\n",
+      FT_TRACE2(( "  %c%c%c%c  %08d  %08d   %08lu    %08lu    %08lu\n",
                   (FT_Char)( table->Tag >> 24 ),
                   (FT_Char)( table->Tag >> 16 ),
                   (FT_Char)( table->Tag >> 8  ),
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.h b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.h
index f41140648dc..588761d0c8e 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.h
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.h
@@ -4,7 +4,7 @@
  *
  *   WOFFF2 format management (specification).
  *
- * Copyright (C) 2019-2024 by
+ * Copyright (C) 2019-2025 by
  * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c
index 28f4d1173c0..91b02344224 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c
@@ -4,7 +4,7 @@
  *
  *   TrueType character mapping table (cmap) support (body).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -179,7 +179,7 @@
 
 
     cmap_info->format   = 0;
-    cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
+    cmap_info->language = TT_PEEK_USHORT( p );
 
     return FT_Err_Ok;
   }
@@ -596,7 +596,7 @@
 
 
     cmap_info->format   = 2;
-    cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
+    cmap_info->language = TT_PEEK_USHORT( p );
 
     return FT_Err_Ok;
   }
@@ -1539,7 +1539,7 @@
 
 
     cmap_info->format   = 4;
-    cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
+    cmap_info->language = TT_PEEK_USHORT( p );
 
     return FT_Err_Ok;
   }
@@ -1712,7 +1712,7 @@
 
 
     cmap_info->format   = 6;
-    cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
+    cmap_info->language = TT_PEEK_USHORT( p );
 
     return FT_Err_Ok;
   }
@@ -2009,7 +2009,7 @@
 
 
     cmap_info->format   = 8;
-    cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p );
+    cmap_info->language = TT_PEEK_ULONG( p );
 
     return FT_Err_Ok;
   }
@@ -2184,7 +2184,7 @@
 
 
     cmap_info->format   = 10;
-    cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p );
+    cmap_info->language = TT_PEEK_ULONG( p );
 
     return FT_Err_Ok;
   }
@@ -2528,7 +2528,7 @@
 
 
     cmap_info->format   = 12;
-    cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p );
+    cmap_info->language = TT_PEEK_ULONG( p );
 
     return FT_Err_Ok;
   }
@@ -2844,7 +2844,7 @@
 
 
     cmap_info->format   = 13;
-    cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p );
+    cmap_info->language = TT_PEEK_ULONG( p );
 
     return FT_Err_Ok;
   }
@@ -3792,7 +3792,7 @@
       return FT_THROW( Invalid_Table );
 
     /* Version 1.8.3 of the OpenType specification contains the following */
-    /* (https://docs.microsoft.com/en-us/typography/opentype/spec/cmap):  */
+    /* (https://learn.microsoft.com/typography/opentype/spec/cmap):       */
     /*                                                                    */
     /*   The 'cmap' table version number remains at 0x0000 for fonts that */
     /*   make use of the newer subtable formats.                          */
@@ -3803,7 +3803,7 @@
     p += 2;
 
     num_cmaps = TT_NEXT_USHORT( p );
-    FT_TRACE4(( "tt_face_build_cmaps: %d cmaps\n", num_cmaps ));
+    FT_TRACE4(( "tt_face_build_cmaps: %u cmaps\n", num_cmaps ));
 
     limit = table + face->cmap_size;
     for ( ; num_cmaps > 0 && p + 8 <= limit; num_cmaps-- )
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h
index e2c5e72bf02..645e9e37e0c 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h
@@ -4,7 +4,7 @@
  *
  *   TrueType character mapping table (cmap) support (specification).
  *
- * Copyright (C) 2002-2024 by
+ * Copyright (C) 2002-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h
index 370898363f3..65807bb7378 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h
@@ -4,7 +4,7 @@
  *
  *   TT CMAP classes definitions (specification only).
  *
- * Copyright (C) 2009-2024 by
+ * Copyright (C) 2009-2025 by
  * Oran Agra and Mickey Gabel.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c
index b37658dde9e..7929b7aaf4c 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c
@@ -4,7 +4,7 @@
  *
  *   TrueType and OpenType colored glyph layer support (body).
  *
- * Copyright (C) 2018-2024 by
+ * Copyright (C) 2018-2025 by
  * David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg.
  *
  * Originally written by Shao Yu Zhang .
@@ -51,7 +51,7 @@
 #define COLOR_STOP_SIZE                   6U
 #define VAR_IDX_BASE_SIZE                 4U
 #define LAYER_SIZE                        4U
-/* https://docs.microsoft.com/en-us/typography/opentype/spec/colr#colr-header */
+/* https://learn.microsoft.com/typography/opentype/spec/colr#colr-header */
 /* 3 * uint16 + 2 * Offset32 */
 #define COLRV0_HEADER_SIZE               14U
 /* COLRV0_HEADER_SIZE + 5 * Offset32 */
@@ -1749,7 +1749,6 @@
     FT_UInt  x, y;
     FT_Byte  b, g, r, alpha;
 
-    FT_ULong  size;
     FT_Byte*  src;
     FT_Byte*  dst;
 
@@ -1767,13 +1766,9 @@
       dstSlot->bitmap.pitch      = (int)dstSlot->bitmap.width * 4;
       dstSlot->bitmap.num_grays  = 256;
 
-      size = dstSlot->bitmap.rows * (unsigned int)dstSlot->bitmap.pitch;
-
-      error = ft_glyphslot_alloc_bitmap( dstSlot, size );
+      error = ft_glyphslot_alloc_bitmap( dstSlot );
       if ( error )
         return error;
-
-      FT_MEM_ZERO( dstSlot->bitmap.buffer, size );
     }
     else
     {
@@ -1805,8 +1800,7 @@
         FT_Byte*  q;
 
 
-        size  = rows * pitch;
-        if ( FT_ALLOC( buf, size ) )
+        if ( FT_ALLOC_MULT( buf, rows, pitch ) )
           return error;
 
         p = dstSlot->bitmap.buffer;
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.h
index 30031464c73..3913acc74d5 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.h
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.h
@@ -4,7 +4,7 @@
  *
  *   TrueType and OpenType colored glyph layer support (specification).
  *
- * Copyright (C) 2018-2024 by
+ * Copyright (C) 2018-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * Originally written by Shao Yu Zhang .
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c
index 997eb869ffc..6d1208f6af2 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c
@@ -4,7 +4,7 @@
  *
  *   TrueType and OpenType color palette support (body).
  *
- * Copyright (C) 2018-2024 by
+ * Copyright (C) 2018-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * Originally written by Shao Yu Zhang .
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.h
index bb301ae88b6..a0b4c9d927f 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.h
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.h
@@ -4,7 +4,7 @@
  *
  *   TrueType and OpenType color palette support (specification).
  *
- * Copyright (C) 2018-2024 by
+ * Copyright (C) 2018-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * Originally written by Shao Yu Zhang .
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.c
index f0411366af4..76618b0d3bb 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.c
@@ -2,10 +2,9 @@
  *
  * ttkern.c
  *
- *   Load the basic TrueType kerning table.  This doesn't handle
- *   kerning data within the GPOS table at the moment.
+ *   Routines to parse and access the 'kern' table for kerning (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.h
index a54e51df12d..e0075dce61d 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.h
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.h
@@ -2,10 +2,10 @@
  *
  * ttkern.h
  *
- *   Load the basic TrueType kerning table.  This doesn't handle
- *   kerning data within the GPOS table at the moment.
+ *   Routines to parse and access the 'kern' table for kerning
+ *   (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -40,8 +40,6 @@ FT_BEGIN_HEADER
                        FT_UInt     left_glyph,
                        FT_UInt     right_glyph );
 
-#define TT_FACE_HAS_KERNING( face )  ( (face)->kern_avail_bits != 0 )
-
 
 FT_END_HEADER
 
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c
index c3a5fae2cb9..0c257ce4d31 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c
@@ -5,7 +5,7 @@
  *   Load the basic TrueType tables, i.e., tables that can be either in
  *   TTF or OTF fonts (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -535,7 +535,8 @@
    *     The tag of table to load.  Use the value 0 if you want
    *     to access the whole font file, else set this parameter
    *     to a valid TrueType table tag that you can forge with
-   *     the MAKE_TT_TAG macro.
+   *     the MAKE_TT_TAG macro.  Use value 1 to access the table
+   *     directory.
    *
    *   offset ::
    *     The starting offset in the table (or the file if
@@ -577,7 +578,29 @@
     FT_ULong   size;
 
 
-    if ( tag != 0 )
+    if ( tag == 0 )
+    {
+      /* The whole font file. */
+      size = face->root.stream->size;
+    }
+    else if ( tag == 1 )
+    {
+      /* The currently selected font's table directory.            */
+      /*                                                           */
+      /* Note that `face_index` is also used to enumerate elements */
+      /* of containers like a Mac Resource; this means we must     */
+      /* check whether we actually have a TTC (with multiple table */
+      /* directories).                                             */
+      FT_Long  idx = face->root.face_index & 0xFFFF;
+
+
+      if ( idx >= face->ttc_header.count )
+        idx = 0;
+
+      offset += face->ttc_header.offsets[idx];
+      size    = 4 + 8 + 16 * face->num_tables;
+    }
+    else
     {
       /* look for tag in font directory */
       table = tt_face_lookup_table( face, tag );
@@ -590,9 +613,6 @@
       offset += table->Offset;
       size    = table->Length;
     }
-    else
-      /* tag == 0 -- the user wants to access the font file directly */
-      size = face->root.stream->size;
 
     if ( length && *length == 0 )
     {
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.h
index 2b1d62d9bd9..e3666c901b1 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.h
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.h
@@ -5,7 +5,7 @@
  *   Load the basic TrueType tables, i.e., tables that can be either in
  *   TTF or OTF fonts (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c
index 27884118563..541d8447470 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c
@@ -4,7 +4,7 @@
  *
  *   Load the metrics tables common to TTF and OTF fonts (body).
  *
- * Copyright (C) 2006-2024 by
+ * Copyright (C) 2006-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -306,7 +306,7 @@
     }
 
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-    if ( var && face->blend )
+    if ( var && FT_IS_VARIATION( &face->root ) )
     {
       FT_Face  f = FT_FACE( face );
       FT_Int   a = (FT_Int)*aadvance;
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.h
index 34b3c0e18f2..1ee84507f15 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.h
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.h
@@ -4,7 +4,7 @@
  *
  *   Load the metrics tables common to TTF and OTF fonts (specification).
  *
- * Copyright (C) 2006-2024 by
+ * Copyright (C) 2006-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c
index 5698a62c8d1..4246b6c8eff 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c
@@ -5,7 +5,7 @@
  *   PostScript name table processing for TrueType and OpenType fonts
  *   (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.h
index 150db6c3981..a11b6696854 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.h
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.h
@@ -5,7 +5,7 @@
  *   PostScript name table processing for TrueType and OpenType fonts
  *   (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c
index cb3a8abf182..34e45619817 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c
@@ -4,7 +4,7 @@
  *
  *   TrueType and OpenType embedded bitmap support (body).
  *
- * Copyright (C) 2005-2024 by
+ * Copyright (C) 2005-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * Copyright 2013 by Google, Inc.
@@ -342,7 +342,7 @@
             FT_TRACE2(( "tt_face_load_strike_metrics:"
                         " sanitizing invalid ascender and descender\n" ));
             FT_TRACE2(( "                            "
-                        " values for strike %ld (%dppem, %dppem)\n",
+                        " values for strike %lu (%dppem, %dppem)\n",
                         strike_index,
                         metrics->x_ppem, metrics->y_ppem ));
 
@@ -547,7 +547,6 @@
     FT_Error    error = FT_Err_Ok;
     FT_UInt     width, height;
     FT_Bitmap*  map = decoder->bitmap;
-    FT_ULong    size;
 
 
     if ( !decoder->metrics_loaded )
@@ -599,17 +598,11 @@
       goto Exit;
     }
 
-    size = map->rows * (FT_ULong)map->pitch;
-
-    /* check that there is no empty image */
-    if ( size == 0 )
-      goto Exit;     /* exit successfully! */
-
     if ( metrics_only )
       goto Exit;     /* only metrics are requested */
 
-    error = ft_glyphslot_alloc_bitmap( decoder->face->root.glyph, size );
-    if ( error )
+    error = ft_glyphslot_alloc_bitmap( decoder->face->root.glyph );
+    if ( error || !map->buffer )
       goto Exit;
 
     decoder->bitmap_allocated = 1;
@@ -993,7 +986,7 @@
       goto Fail;
     }
 
-    FT_TRACE3(( "tt_sbit_decoder_load_compound: loading %d component%s\n",
+    FT_TRACE3(( "tt_sbit_decoder_load_compound: loading %u component%s\n",
                 num_components,
                 num_components == 1 ? "" : "s" ));
 
@@ -1419,7 +1412,7 @@
     image_start = image_offset + image_start;
 
     FT_TRACE3(( "tt_sbit_decoder_load_image:"
-                " found sbit (format %d) for glyph index %d\n",
+                " found sbit (format %u) for glyph index %u\n",
                 image_format, glyph_index ));
 
     return tt_sbit_decoder_load_bitmap( decoder,
@@ -1438,13 +1431,13 @@
     if ( recurse_count )
     {
       FT_TRACE4(( "tt_sbit_decoder_load_image:"
-                  " missing subglyph sbit with glyph index %d\n",
+                  " missing subglyph sbit with glyph index %u\n",
                   glyph_index ));
       return FT_THROW( Invalid_Composite );
     }
 
     FT_TRACE4(( "tt_sbit_decoder_load_image:"
-                " no sbit found for glyph index %d\n", glyph_index ));
+                " no sbit found for glyph index %u\n", glyph_index ));
     return FT_THROW( Missing_Bitmap );
   }
 
@@ -1462,12 +1455,13 @@
     FT_Int    originOffsetX, originOffsetY;
     FT_Tag    graphicType;
     FT_Int    recurse_depth = 0;
+    FT_Bool   flipped       = FALSE;
 
     FT_Error  error;
     FT_Byte*  p;
 
-    FT_UNUSED( map );
 #ifndef FT_CONFIG_OPTION_USE_PNG
+    FT_UNUSED( map );
     FT_UNUSED( metrics_only );
 #endif
 
@@ -1517,12 +1511,16 @@
 
     switch ( graphicType )
     {
+    case FT_MAKE_TAG( 'f', 'l', 'i', 'p' ):
+      flipped = !flipped;
+      FALL_THROUGH;
+
     case FT_MAKE_TAG( 'd', 'u', 'p', 'e' ):
-      if ( recurse_depth < 4 )
+      if ( recurse_depth++ < 4 )
       {
         glyph_index = FT_GET_USHORT();
         FT_FRAME_EXIT();
-        recurse_depth++;
+
         goto retry;
       }
       error = FT_THROW( Invalid_File_Format );
@@ -1540,6 +1538,38 @@
                              glyph_end - glyph_start - 8,
                              TRUE,
                              metrics_only );
+      if ( flipped && !metrics_only && !error )
+      {
+        FT_UInt32*  curr_pos = (FT_UInt32*)map->buffer;
+
+        /* `Load_SBit_Png` always returns a pixmap with 32 bits per pixel */
+        /* and no extra pitch bytes.                                      */
+        FT_UInt  width = map->width;
+        FT_UInt  y;
+
+
+        for ( y = 0; y < map->rows; y++ )
+        {
+          FT_UInt32*  left  = curr_pos;
+          FT_UInt32*  right = curr_pos + width - 1;
+
+
+          while ( left < right )
+          {
+            FT_UInt32  value;
+
+
+            value  = *right;
+            *right = *left;
+            *left  = value;
+
+            left++;
+            right--;
+          }
+
+          curr_pos += width;
+        }
+      }
 #else
       error = FT_THROW( Unimplemented_Feature );
 #endif
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.h
index 96f80a58424..7427149d68f 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.h
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.h
@@ -4,7 +4,7 @@
  *
  *   TrueType and OpenType embedded bitmap support (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c b/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c
index 532ccfa1737..0f9e3889aab 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c
@@ -4,7 +4,7 @@
  *
  *   WOFF2 Font table tags (base).
  *
- * Copyright (C) 2019-2024 by
+ * Copyright (C) 2019-2025 by
  * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.h b/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.h
index d03b4b41bc9..e223022962e 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.h
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.h
@@ -4,7 +4,7 @@
  *
  *   WOFF2 Font table tags (specification).
  *
- * Copyright (C) 2019-2024 by
+ * Copyright (C) 2019-2025 by
  * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c b/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c
index b7c0632a6fa..3c387aea0ac 100644
--- a/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c
+++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c
@@ -4,7 +4,7 @@
  *
  *   A new `perfect' anti-aliasing renderer (body).
  *
- * Copyright (C) 2000-2024 by
+ * Copyright (C) 2000-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -157,10 +157,6 @@
 
 #define ft_memset   memset
 
-#define ft_setjmp   setjmp
-#define ft_longjmp  longjmp
-#define ft_jmp_buf  jmp_buf
-
 typedef ptrdiff_t  FT_PtrDist;
 
 
@@ -170,8 +166,8 @@ typedef ptrdiff_t  FT_PtrDist;
 #define Smooth_Err_Invalid_Argument     -3
 #define Smooth_Err_Raster_Overflow      -4
 
-#define FT_BEGIN_HEADER
-#define FT_END_HEADER
+#define FT_BEGIN_HEADER  /* nothing */
+#define FT_END_HEADER    /* nothing */
 
 #include "ftimage.h"
 #include "ftgrays.h"
@@ -495,6 +491,7 @@ typedef ptrdiff_t  FT_PtrDist;
     TCoord  min_ey, max_ey;
     TCoord  count_ey;        /* same as (max_ey - min_ey) */
 
+    int         error;       /* pool overflow exception                  */
     PCell       cell;        /* current cell                             */
     PCell       cell_free;   /* call allocation next free slot           */
     PCell       cell_null;   /* last cell, used as dumpster and limit    */
@@ -510,8 +507,6 @@ typedef ptrdiff_t  FT_PtrDist;
     FT_Raster_Span_Func  render_span;
     void*                render_span_data;
 
-    ft_jmp_buf  jump_buffer;
-
   } gray_TWorker, *gray_PWorker;
 
 #if defined( _MSC_VER )
@@ -613,9 +608,14 @@ typedef ptrdiff_t  FT_PtrDist;
       }
 
       /* insert new cell */
-      cell = ras.cell_free++;
-      if ( cell >= ras.cell_null )
-        ft_longjmp( ras.jump_buffer, 1 );
+      cell = ras.cell_free;
+      if ( cell == ras.cell_null )
+      {
+        ras.error = FT_THROW( Raster_Overflow );
+        goto Found;
+      }
+
+      ras.cell_free = cell + 1;
 
       cell->x     = ex;
       cell->area  = 0;
@@ -1353,7 +1353,8 @@ typedef ptrdiff_t  FT_PtrDist;
 
     ras.x = x;
     ras.y = y;
-    return 0;
+
+    return ras.error;
   }
 
 
@@ -1365,7 +1366,8 @@ typedef ptrdiff_t  FT_PtrDist;
 
 
     gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) );
-    return 0;
+
+    return ras.error;
   }
 
 
@@ -1378,7 +1380,8 @@ typedef ptrdiff_t  FT_PtrDist;
 
 
     gray_render_conic( RAS_VAR_ control, to );
-    return 0;
+
+    return ras.error;
   }
 
 
@@ -1392,7 +1395,8 @@ typedef ptrdiff_t  FT_PtrDist;
 
 
     gray_render_cubic( RAS_VAR_ control1, control2, to );
-    return 0;
+
+    return ras.error;
   }
 
 
@@ -1700,30 +1704,22 @@ typedef ptrdiff_t  FT_PtrDist;
   gray_convert_glyph_inner( RAS_ARG_
                             int  continued )
   {
-    volatile int  error;
+    int  error;
 
 
-    if ( ft_setjmp( ras.jump_buffer ) == 0 )
-    {
-      if ( continued )
-        FT_Trace_Disable();
-      error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras );
-      if ( continued )
-        FT_Trace_Enable();
-
-      FT_TRACE7(( "band [%d..%d]: %td cell%s remaining\n",
-                  ras.min_ey,
-                  ras.max_ey,
-                  ras.cell_null - ras.cell_free,
-                  ras.cell_null - ras.cell_free == 1 ? "" : "s" ));
-    }
-    else
-    {
-      error = FT_THROW( Raster_Overflow );
+    if ( continued )
+      FT_Trace_Disable();
+    error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras );
+    if ( continued )
+      FT_Trace_Enable();
 
-      FT_TRACE7(( "band [%d..%d]: to be bisected\n",
-                  ras.min_ey, ras.max_ey ));
-    }
+    FT_TRACE7(( error == Smooth_Err_Raster_Overflow
+                  ? "band [%d..%d]: to be bisected\n"
+                  : "band [%d..%d]: %td cell%s remaining\n",
+                ras.min_ey,
+                ras.max_ey,
+                ras.cell_null - ras.cell_free,
+                ras.cell_null - ras.cell_free == 1 ? "" : "s" ));
 
     return error;
   }
@@ -1808,7 +1804,7 @@ typedef ptrdiff_t  FT_PtrDist;
           FT_FILL_RULE( coverage, cover, fill );
 
           span[n].coverage = (unsigned char)coverage;
-          span[n].x        = (short)x;
+          span[n].x        = (unsigned short)x;
           span[n].len      = (unsigned short)( cell->x - x );
 
           if ( ++n == FT_MAX_GRAY_SPANS )
@@ -1827,7 +1823,7 @@ typedef ptrdiff_t  FT_PtrDist;
           FT_FILL_RULE( coverage, area, fill );
 
           span[n].coverage = (unsigned char)coverage;
-          span[n].x        = (short)cell->x;
+          span[n].x        = (unsigned short)cell->x;
           span[n].len      = 1;
 
           if ( ++n == FT_MAX_GRAY_SPANS )
@@ -1873,6 +1869,7 @@ typedef ptrdiff_t  FT_PtrDist;
     TCoord*  band;
 
     int  continued = 0;
+    int  error     = Smooth_Err_Ok;
 
 
     /* Initialize the null cell at the end of the poll. */
@@ -1907,7 +1904,6 @@ typedef ptrdiff_t  FT_PtrDist;
       do
       {
         TCoord  i;
-        int     error;
 
 
         ras.min_ex = band[1];
@@ -1922,6 +1918,7 @@ typedef ptrdiff_t  FT_PtrDist;
 
         ras.cell_free = buffer + n;
         ras.cell      = ras.cell_null;
+        ras.error     = Smooth_Err_Ok;
 
         error     = gray_convert_glyph_inner( RAS_VAR_ continued );
         continued = 1;
@@ -1936,7 +1933,7 @@ typedef ptrdiff_t  FT_PtrDist;
           continue;
         }
         else if ( error != Smooth_Err_Raster_Overflow )
-          return error;
+          goto Exit;
 
         /* render pool overflow; we will reduce the render band by half */
         i = ( band[0] - band[1] ) >> 1;
@@ -1945,7 +1942,8 @@ typedef ptrdiff_t  FT_PtrDist;
         if ( i == 0 )
         {
           FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" ));
-          return FT_THROW( Raster_Overflow );
+          error = FT_THROW( Raster_Overflow );
+          goto Exit;
         }
 
         band++;
@@ -1954,7 +1952,11 @@ typedef ptrdiff_t  FT_PtrDist;
       } while ( band >= bands );
     }
 
-    return Smooth_Err_Ok;
+  Exit:
+    ras.cell   = ras.cell_free = ras.cell_null = NULL;
+    ras.ycells = NULL;
+
+    return error;
   }
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.h b/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.h
index 940fbe8c79b..e463e5b3eb8 100644
--- a/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.h
+++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.h
@@ -4,7 +4,7 @@
  *
  *   FreeType smooth renderer declaration
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -19,11 +19,6 @@
 #ifndef FTGRAYS_H_
 #define FTGRAYS_H_
 
-#ifdef __cplusplus
-  extern "C" {
-#endif
-
-
 #ifdef STANDALONE_
 #include "ftimage.h"
 #else
@@ -31,6 +26,7 @@
 #include 
 #endif
 
+FT_BEGIN_HEADER
 
   /**************************************************************************
    *
@@ -46,10 +42,7 @@
 
   FT_EXPORT_VAR( const FT_Raster_Funcs )  ft_grays_raster;
 
-
-#ifdef __cplusplus
-  }
-#endif
+FT_END_HEADER
 
 #endif /* FTGRAYS_H_ */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmerrs.h b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmerrs.h
index 6d41fb8e0fd..8d5068549fa 100644
--- a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmerrs.h
+++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmerrs.h
@@ -4,7 +4,7 @@
  *
  *   smooth renderer error codes (specification only).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c
index f0acc1ea4a6..5a7a852a619 100644
--- a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c
+++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c
@@ -4,7 +4,7 @@
  *
  *   Anti-aliasing renderer interface (body).
  *
- * Copyright (C) 2000-2024 by
+ * Copyright (C) 2000-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -80,6 +80,7 @@
   {
     unsigned char*  origin;  /* pixmap origin at the bottom-left */
     int             pitch;   /* pitch to go down one row */
+    unsigned char   wght[5]; /* filtering weights */
 
   } TOrigin;
 
@@ -274,6 +275,32 @@
   }
 
 
+  /* This function applies a horizontal filter in direct rendering mode */
+  static void
+  ft_smooth_lcd_spans( int             y,
+                       int             count,
+                       const FT_Span*  spans,
+                       void*           target_ )   /* TOrigin* */
+  {
+    TOrigin*  target = (TOrigin*)target_;
+
+    unsigned char*  dst_line = target->origin - y * target->pitch - 2;
+    unsigned char*  dst;
+    unsigned short  w;
+
+
+    for ( ; count--; spans++ )
+      for ( dst = dst_line + spans->x, w = spans->len; w--; dst++ )
+      {
+        dst[0] += ( spans->coverage * target->wght[0] + 85 ) >> 8;
+        dst[1] += ( spans->coverage * target->wght[1] + 85 ) >> 8;
+        dst[2] += ( spans->coverage * target->wght[2] + 85 ) >> 8;
+        dst[3] += ( spans->coverage * target->wght[3] + 85 ) >> 8;
+        dst[4] += ( spans->coverage * target->wght[4] + 85 ) >> 8;
+      }
+  }
+
+
   static FT_Error
   ft_smooth_raster_lcd( FT_Renderer  render,
                         FT_Outline*  outline,
@@ -285,11 +312,47 @@
     FT_Vector*  vec;
 
     FT_Raster_Params  params;
+    TOrigin           target;
 
 
-    params.target = bitmap;
-    params.source = outline;
-    params.flags  = FT_RASTER_FLAG_AA;
+    if ( render->root.library->lcd_weights[2] )
+    {
+      /* Reject outlines that are too wide for 16-bit FT_Span.       */
+      /* Other limits are applied upstream with the same error code. */
+      if ( bitmap->width > 0x7FFF )
+        return FT_THROW( Raster_Overflow );
+
+      /* Set up direct rendering for instant filtering. */
+      params.source     = outline;
+      params.flags      = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
+      params.gray_spans = ft_smooth_lcd_spans;
+      params.user       = ⌖
+
+      params.clip_box.xMin = 0;
+      params.clip_box.yMin = 0;
+      params.clip_box.xMax = bitmap->width;
+      params.clip_box.yMax = bitmap->rows;
+
+      if ( bitmap->pitch < 0 )
+        target.origin = bitmap->buffer;
+      else
+        target.origin = bitmap->buffer
+                        + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch;
+
+      target.pitch = bitmap->pitch;
+
+      target.wght[0] = render->root.library->lcd_weights[0];
+      target.wght[1] = render->root.library->lcd_weights[1];
+      target.wght[2] = render->root.library->lcd_weights[2];
+      target.wght[3] = render->root.library->lcd_weights[3];
+      target.wght[4] = render->root.library->lcd_weights[4];
+    }
+    else
+    {
+      params.target = bitmap;
+      params.source = outline;
+      params.flags  = FT_RASTER_FLAG_AA;
+    }
 
     /* implode outline */
     for ( vec = points; vec < points_end; vec++ )
@@ -306,6 +369,32 @@
   }
 
 
+  /* This function applies a vertical filter in direct rendering mode */
+  static void
+  ft_smooth_lcdv_spans( int             y,
+                        int             count,
+                        const FT_Span*  spans,
+                        void*           target_ )   /* TOrigin* */
+  {
+    TOrigin*  target = (TOrigin*)target_;
+
+    int             pitch    = target->pitch;
+    unsigned char*  dst_line = target->origin - ( y + 2 ) * pitch;
+    unsigned char*  dst;
+    unsigned short  w;
+
+
+    for ( ; count--; spans++ )
+      for ( dst = dst_line + spans->x, w = spans->len; w--; dst++ )
+      {
+        dst[        0] += ( spans->coverage * target->wght[0] + 85 ) >> 8;
+        dst[    pitch] += ( spans->coverage * target->wght[1] + 85 ) >> 8;
+        dst[2 * pitch] += ( spans->coverage * target->wght[2] + 85 ) >> 8;
+        dst[3 * pitch] += ( spans->coverage * target->wght[3] + 85 ) >> 8;
+        dst[4 * pitch] += ( spans->coverage * target->wght[4] + 85 ) >> 8;
+      }
+  }
+
   static FT_Error
   ft_smooth_raster_lcdv( FT_Renderer  render,
                          FT_Outline*  outline,
@@ -317,11 +406,42 @@
     FT_Vector*  vec;
 
     FT_Raster_Params  params;
+    TOrigin           target;
 
 
-    params.target = bitmap;
-    params.source = outline;
-    params.flags  = FT_RASTER_FLAG_AA;
+    if ( render->root.library->lcd_weights[2] )
+    {
+      /* Set up direct rendering for instant filtering. */
+      params.source     = outline;
+      params.flags      = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
+      params.gray_spans = ft_smooth_lcdv_spans;
+      params.user       = ⌖
+
+      params.clip_box.xMin = 0;
+      params.clip_box.yMin = 0;
+      params.clip_box.xMax = bitmap->width;
+      params.clip_box.yMax = bitmap->rows;
+
+      if ( bitmap->pitch < 0 )
+        target.origin = bitmap->buffer;
+      else
+        target.origin = bitmap->buffer
+                        + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch;
+
+      target.pitch = bitmap->pitch;
+
+      target.wght[0] = render->root.library->lcd_weights[0];
+      target.wght[1] = render->root.library->lcd_weights[1];
+      target.wght[2] = render->root.library->lcd_weights[2];
+      target.wght[3] = render->root.library->lcd_weights[3];
+      target.wght[4] = render->root.library->lcd_weights[4];
+    }
+    else
+    {
+      params.target = bitmap;
+      params.source = outline;
+      params.flags  = FT_RASTER_FLAG_AA;
+    }
 
     /* implode outline */
     for ( vec = points; vec < points_end; vec++ )
@@ -494,12 +614,6 @@
     else
       y_shift += 64 * (FT_Int)bitmap->rows;
 
-    if ( origin )
-    {
-      x_shift += origin->x;
-      y_shift += origin->y;
-    }
-
     /* translate outline to render it into the bitmap */
     if ( x_shift || y_shift )
       FT_Outline_Translate( outline, x_shift, y_shift );
@@ -527,33 +641,6 @@
         error = ft_smooth_raster_lcd ( render, outline, bitmap );
       else if ( mode == FT_RENDER_MODE_LCD_V )
         error = ft_smooth_raster_lcdv( render, outline, bitmap );
-
-#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
-
-      /* finally apply filtering */
-      {
-        FT_Byte*                 lcd_weights;
-        FT_Bitmap_LcdFilterFunc  lcd_filter_func;
-
-
-        /* Per-face LCD filtering takes priority if set up. */
-        if ( slot->face && slot->face->internal->lcd_filter_func )
-        {
-          lcd_weights     = slot->face->internal->lcd_weights;
-          lcd_filter_func = slot->face->internal->lcd_filter_func;
-        }
-        else
-        {
-          lcd_weights     = slot->library->lcd_weights;
-          lcd_filter_func = slot->library->lcd_filter_func;
-        }
-
-        if ( lcd_filter_func )
-          lcd_filter_func( bitmap, lcd_weights );
-      }
-
-#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
-
     }
 
   Exit:
diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.h b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.h
index d7b61a9e60e..f76708ae701 100644
--- a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.h
+++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.h
@@ -4,7 +4,7 @@
  *
  *   Anti-aliasing renderer interface (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c
index 4ab68eb9a12..6369d83d6d5 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c
@@ -4,7 +4,7 @@
  *
  *   TrueType font driver implementation (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -220,12 +220,12 @@
     {
       /* Use 'kern' table if available since that can be faster; otherwise */
       /* use GPOS kerning pairs if available.                              */
-      if ( ttface->kern_avail_bits != 0 )
+      if ( ttface->kern_avail_bits )
         kerning->x = sfnt->get_kerning( ttface,
                                         left_glyph,
                                         right_glyph );
 #ifdef TT_CONFIG_OPTION_GPOS_KERNING
-      else if ( ttface->gpos_kerning_available )
+      else if ( ttface->num_gpos_lookups_kerning )
         kerning->x = sfnt->get_gpos_kerning( ttface,
                                              left_glyph,
                                              right_glyph );
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.h
index 3e1cf234fcf..943eaae3482 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.h
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.h
@@ -4,7 +4,7 @@
  *
  *   High-level TrueType driver interface (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/tterrors.h b/src/java.desktop/share/native/libfreetype/src/truetype/tterrors.h
index 7ad937bd04d..631dbf5a80f 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/tterrors.h
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/tterrors.h
@@ -4,7 +4,7 @@
  *
  *   TrueType error codes (specification only).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c
index b656ccf04e3..4dd68ab1019 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c
@@ -4,7 +4,7 @@
  *
  *   TrueType Glyph Loader (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -660,7 +660,7 @@
     } while ( subglyph->flags & MORE_COMPONENTS );
 
     gloader->current.num_subglyphs = num_subglyphs;
-    FT_TRACE5(( "  %d component%s\n",
+    FT_TRACE5(( "  %u component%s\n",
                 num_subglyphs,
                 num_subglyphs > 1 ? "s" : "" ));
 
@@ -674,7 +674,7 @@
       for ( i = 0; i < num_subglyphs; i++ )
       {
         if ( num_subglyphs > 1 )
-          FT_TRACE7(( "    subglyph %d:\n", i ));
+          FT_TRACE7(( "    subglyph %u:\n", i ));
 
         FT_TRACE7(( "      glyph index: %d\n", subglyph->index ));
 
@@ -777,15 +777,11 @@
   TT_Hint_Glyph( TT_Loader  loader,
                  FT_Bool    is_composite )
   {
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-    TT_Face    face   = loader->face;
-    TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
-#endif
-
     TT_GlyphZone  zone = &loader->zone;
 
 #ifdef TT_USE_BYTECODE_INTERPRETER
     TT_ExecContext  exec  = loader->exec;
+    TT_Size         size  = loader->size;
     FT_Long         n_ins = exec->glyphSize;
 #else
     FT_UNUSED( is_composite );
@@ -797,9 +793,6 @@
     if ( n_ins > 0 )
       FT_ARRAY_COPY( zone->org, zone->cur, zone->n_points );
 
-    /* Reset graphics state. */
-    exec->GS = loader->size->GS;
-
     /* XXX: UNDOCUMENTED! Hinting instructions of a composite glyph */
     /*      completely refer to the (already) hinted subglyphs.     */
     if ( is_composite )
@@ -811,8 +804,8 @@
     }
     else
     {
-      exec->metrics.x_scale = loader->size->metrics->x_scale;
-      exec->metrics.y_scale = loader->size->metrics->y_scale;
+      exec->metrics.x_scale = size->metrics->x_scale;
+      exec->metrics.y_scale = size->metrics->y_scale;
     }
 #endif
 
@@ -838,7 +831,7 @@
       exec->is_composite = is_composite;
       exec->pts          = *zone;
 
-      error = TT_Run_Context( exec );
+      error = TT_Run_Context( exec, size );
       if ( error && exec->pedantic_hinting )
         return error;
 
@@ -854,8 +847,7 @@
     /* to change bearings or advance widths.                               */
 
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-    if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 &&
-         exec->backward_compatibility )
+    if ( exec->backward_compatibility )
       return FT_Err_Ok;
 #endif
 
@@ -1152,30 +1144,15 @@
         x = FT_MulFix( x, x_scale );
         y = FT_MulFix( y, y_scale );
 
-        if ( subglyph->flags & ROUND_XY_TO_GRID )
+        if ( subglyph->flags & ROUND_XY_TO_GRID &&
+             IS_HINTED( loader->load_flags )    )
         {
-          TT_Face    face   = loader->face;
-          TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
-
+#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
+          if ( !loader->exec->backward_compatibility )
+#endif
+            x = FT_PIX_ROUND( x );
 
-          if ( IS_HINTED( loader->load_flags ) )
-          {
-            /*
-             * We round the horizontal offset only if there is hinting along
-             * the x axis; this corresponds to integer advance width values.
-             *
-             * Theoretically, a glyph's bytecode can toggle ClearType's
-             * `backward compatibility' mode, which would allow modification
-             * of the advance width.  In reality, however, applications
-             * neither allow nor expect modified advance widths if subpixel
-             * rendering is active.
-             *
-             */
-            if ( driver->interpreter_version == TT_INTERPRETER_VERSION_35 )
-              x = FT_PIX_ROUND( x );
-
-            y = FT_PIX_ROUND( y );
-          }
+          y = FT_PIX_ROUND( y );
         }
       }
     }
@@ -1204,8 +1181,6 @@
   {
     FT_Error     error;
     FT_Outline*  outline = &loader->gloader->base.outline;
-    FT_Stream    stream = loader->stream;
-    FT_UShort    n_ins;
     FT_UInt      i;
 
 
@@ -1224,8 +1199,10 @@
 #ifdef TT_USE_BYTECODE_INTERPRETER
 
     {
-      TT_ExecContext  exec = loader->exec;
+      TT_ExecContext  exec   = loader->exec;
       FT_Memory       memory = exec->memory;
+      FT_Stream       stream = loader->stream;
+      FT_UShort       n_ins;
 
 
       if ( exec->glyphSize )
@@ -1378,8 +1355,9 @@
 
       if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 &&
            loader->exec                                             &&
-           loader->exec->subpixel_hinting_lean                      &&
-           loader->exec->grayscale_cleartype                        )
+           loader->exec->mode != FT_RENDER_MODE_MONO                &&
+           loader->exec->mode != FT_RENDER_MODE_LCD                 &&
+           loader->exec->mode != FT_RENDER_MODE_LCD_V               )
       {
         loader->pp3.x = loader->advance / 2;
         loader->pp4.x = loader->advance / 2;
@@ -1444,13 +1422,13 @@
 
 #ifdef FT_DEBUG_LEVEL_TRACE
     if ( recurse_count )
-      FT_TRACE5(( "  nesting level: %d\n", recurse_count ));
+      FT_TRACE5(( "  nesting level: %u\n", recurse_count ));
 #endif
 
     /* some fonts have an incorrect value of `maxComponentDepth' */
     if ( recurse_count > face->max_profile.maxComponentDepth )
     {
-      FT_TRACE1(( "load_truetype_glyph: maxComponentDepth set to %d\n",
+      FT_TRACE1(( "load_truetype_glyph: maxComponentDepth set to %u\n",
                   recurse_count ));
       face->max_profile.maxComponentDepth = (FT_UShort)recurse_count;
     }
@@ -1566,18 +1544,18 @@
     if ( header_only )
       goto Exit;
 
-    if ( loader->byte_len == 0 || loader->n_contours == 0 )
-    {
 #ifdef FT_CONFIG_OPTION_INCREMENTAL
-      tt_get_metrics_incremental( loader, glyph_index );
+    tt_get_metrics_incremental( loader, glyph_index );
 #endif
-      tt_loader_set_pp( loader );
+    tt_loader_set_pp( loader );
 
+    /* shortcut for empty glyphs */
+    if ( loader->byte_len == 0 || loader->n_contours == 0 )
+    {
 
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
 
-      if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ||
-           FT_IS_VARIATION( FT_FACE( face ) )      )
+      if ( !IS_DEFAULT_INSTANCE( FT_FACE( face ) ) )
       {
         /* a small outline structure with four elements for */
         /* communication with `TT_Vary_Apply_Glyph_Deltas'  */
@@ -1627,11 +1605,6 @@
       goto Exit;
     }
 
-#ifdef FT_CONFIG_OPTION_INCREMENTAL
-    tt_get_metrics_incremental( loader, glyph_index );
-#endif
-    tt_loader_set_pp( loader );
-
 
     /***********************************************************************/
     /***********************************************************************/
@@ -1735,8 +1708,7 @@
 
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
 
-      if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ||
-           FT_IS_VARIATION( FT_FACE( face ) )      )
+      if ( !IS_DEFAULT_INSTANCE( FT_FACE( face ) ) )
       {
         FT_UShort    i, limit;
         FT_SubGlyph  subglyph;
@@ -1953,6 +1925,9 @@
 
 #ifdef FT_CONFIG_OPTION_INCREMENTAL
 
+    /* restore the original stream */
+    loader->stream = face->root.stream;
+
     if ( glyph_data_loaded )
       face->root.internal->incremental_interface->funcs->free_glyph_data(
         face->root.internal->incremental_interface->object,
@@ -2112,7 +2087,6 @@
   {
     TT_Face             face   = (TT_Face)glyph->face;
     SFNT_Service        sfnt   = (SFNT_Service)face->sfnt;
-    FT_Stream           stream = face->root.stream;
     FT_Error            error;
     TT_SBit_MetricsRec  sbit_metrics;
 
@@ -2121,14 +2095,11 @@
                                    size->strike_index,
                                    glyph_index,
                                    (FT_UInt)load_flags,
-                                   stream,
+                                   face->root.stream,
                                    &glyph->bitmap,
                                    &sbit_metrics );
     if ( !error )
     {
-      glyph->outline.n_points   = 0;
-      glyph->outline.n_contours = 0;
-
       glyph->metrics.width  = (FT_Pos)sbit_metrics.width  * 64;
       glyph->metrics.height = (FT_Pos)sbit_metrics.height * 64;
 
@@ -2153,6 +2124,50 @@
         glyph->bitmap_top  = sbit_metrics.horiBearingY;
       }
     }
+    /* a missing glyph in a bitmap-only font is assumed whitespace */
+    /* that needs to be constructed using metrics data from `hmtx' */
+    /* and, optionally, `vmtx' tables                              */
+    else if ( FT_ERR_EQ( error, Missing_Bitmap ) &&
+              !FT_IS_SCALABLE( glyph->face )     &&
+              face->horz_metrics_size            )
+    {
+      FT_Fixed  x_scale = size->root.metrics.x_scale;
+      FT_Fixed  y_scale = size->root.metrics.y_scale;
+
+      FT_Short  left_bearing = 0;
+      FT_Short  top_bearing  = 0;
+
+      FT_UShort  advance_width  = 0;
+      FT_UShort  advance_height = 0;
+
+
+      TT_Get_HMetrics( face, glyph_index,
+                       &left_bearing,
+                       &advance_width );
+      TT_Get_VMetrics( face, glyph_index,
+                       0,
+                       &top_bearing,
+                       &advance_height );
+
+      glyph->metrics.width  = 0;
+      glyph->metrics.height = 0;
+
+      glyph->metrics.horiBearingX = FT_MulFix( left_bearing, x_scale );
+      glyph->metrics.horiBearingY = 0;
+      glyph->metrics.horiAdvance  = FT_MulFix( advance_width, x_scale );
+
+      glyph->metrics.vertBearingX = 0;
+      glyph->metrics.vertBearingY = FT_MulFix( top_bearing, y_scale );
+      glyph->metrics.vertAdvance  = FT_MulFix( advance_height, y_scale );
+
+      glyph->format            = FT_GLYPH_FORMAT_BITMAP;
+      glyph->bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
+
+      glyph->bitmap_left = 0;
+      glyph->bitmap_top  = 0;
+
+      error = FT_Err_Ok;
+    }
 
     return error;
   }
@@ -2168,15 +2183,6 @@
                   FT_Bool       glyf_table_only )
   {
     TT_Face    face   = (TT_Face)glyph->face;
-    FT_Stream  stream = face->root.stream;
-
-#ifdef TT_USE_BYTECODE_INTERPRETER
-    FT_Error   error;
-    FT_Bool    pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC );
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-    TT_Driver  driver   = (TT_Driver)FT_FACE_DRIVER( glyph->face );
-#endif
-#endif
 
 
     FT_ZERO( loader );
@@ -2186,122 +2192,80 @@
     /* load execution context */
     if ( IS_HINTED( load_flags ) && !glyf_table_only )
     {
+      FT_Error        error;
       TT_ExecContext  exec;
-      FT_Bool         grayscale = TRUE;
+      FT_Render_Mode  mode      = FT_LOAD_TARGET_MODE( load_flags );
+      FT_Bool         grayscale = FT_BOOL( mode != FT_RENDER_MODE_MONO );
+      FT_Bool         reexecute = FALSE;
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-      FT_Bool         subpixel_hinting_lean;
-      FT_Bool         grayscale_cleartype;
+      TT_Driver       driver    = (TT_Driver)FT_FACE_DRIVER( glyph->face );
 #endif
 
-      FT_Bool  reexecute = FALSE;
-
 
-      if ( size->bytecode_ready < 0 || size->cvt_ready < 0 )
+      if ( size->bytecode_ready > 0 )
+        return size->bytecode_ready;
+      if ( size->bytecode_ready < 0 )
       {
-        error = tt_size_ready_bytecode( size, pedantic );
+        FT_Bool  pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC );
+
+
+        error = tt_size_init_bytecode( size, pedantic );
         if ( error )
           return error;
       }
-      else if ( size->bytecode_ready )
-        return size->bytecode_ready;
-      else if ( size->cvt_ready )
-        return size->cvt_ready;
 
-      /* query new execution context */
       exec = size->context;
-      if ( !exec )
-        return FT_THROW( Could_Not_Find_Context );
-
-      grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
-                             FT_RENDER_MODE_MONO             );
 
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
+      /* reset backward compatibility; note that */
+      /* the CVT program always runs without it  */
+      exec->backward_compatibility = 0;
+
       if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 )
       {
-        subpixel_hinting_lean =
-          FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
-                   FT_RENDER_MODE_MONO               );
-        grayscale_cleartype =
-          FT_BOOL( subpixel_hinting_lean         &&
-                   !( ( load_flags         &
-                        FT_LOAD_TARGET_LCD )   ||
-                      ( load_flags           &
-                        FT_LOAD_TARGET_LCD_V ) ) );
-        exec->vertical_lcd_lean =
-          FT_BOOL( subpixel_hinting_lean    &&
-                   ( load_flags           &
-                     FT_LOAD_TARGET_LCD_V ) );
-        grayscale = FT_BOOL( grayscale && !subpixel_hinting_lean );
-      }
-      else
-      {
-        subpixel_hinting_lean   = FALSE;
-        grayscale_cleartype     = FALSE;
-        exec->vertical_lcd_lean = FALSE;
-      }
-#endif
-
-      error = TT_Load_Context( exec, face, size );
-      if ( error )
-        return error;
+        grayscale = FALSE;
 
-      {
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-        if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 )
+        /* any mode change requires a re-execution of the CVT program */
+        if ( mode != exec->mode )
         {
-          /* a change from mono to subpixel rendering (and vice versa) */
-          /* requires a re-execution of the CVT program                */
-          if ( subpixel_hinting_lean != exec->subpixel_hinting_lean )
-          {
-            FT_TRACE4(( "tt_loader_init: subpixel hinting change,"
-                        " re-executing `prep' table\n" ));
-
-            exec->subpixel_hinting_lean = subpixel_hinting_lean;
-            reexecute                   = TRUE;
-          }
-
-          /* a change from colored to grayscale subpixel rendering (and */
-          /* vice versa) requires a re-execution of the CVT program     */
-          if ( grayscale_cleartype != exec->grayscale_cleartype )
-          {
-            FT_TRACE4(( "tt_loader_init: grayscale subpixel hinting change,"
-                        " re-executing `prep' table\n" ));
+          FT_TRACE4(( "tt_loader_init: render mode change,"
+                      " re-executing `prep' table\n" ));
 
-            exec->grayscale_cleartype = grayscale_cleartype;
-            reexecute                 = TRUE;
-          }
+          exec->mode = mode;
+          reexecute  = TRUE;
         }
+      }
 #endif
 
-        /* a change from mono to grayscale rendering (and vice versa) */
-        /* requires a re-execution of the CVT program                 */
-        if ( grayscale != exec->grayscale )
-        {
-          FT_TRACE4(( "tt_loader_init: grayscale hinting change,"
-                      " re-executing `prep' table\n" ));
+      /* a change from mono to grayscale rendering (and vice versa) */
+      /* requires a re-execution of the CVT program                 */
+      if ( grayscale != exec->grayscale )
+      {
+        FT_TRACE4(( "tt_loader_init: grayscale hinting change,"
+                    " re-executing `prep' table\n" ));
 
-          exec->grayscale = grayscale;
-          reexecute       = TRUE;
-        }
+        exec->grayscale = grayscale;
+        reexecute       = TRUE;
       }
 
-      if ( reexecute )
+      if ( size->cvt_ready > 0 )
+        return size->cvt_ready;
+      if ( size->cvt_ready < 0 || reexecute )
       {
-        error = tt_size_run_prep( size, pedantic );
-        if ( error )
-          return error;
-        error = TT_Load_Context( exec, face, size );
+        error = tt_size_run_prep( size );
         if ( error )
           return error;
       }
 
+      TT_Load_Context( exec, face, size );
+
       /* check whether the cvt program has disabled hinting */
-      if ( exec->GS.instruct_control & 1 )
+      if ( size->GS.instruct_control & 1 )
         load_flags |= FT_LOAD_NO_HINTING;
 
-      /* load default graphics state -- if needed */
-      if ( exec->GS.instruct_control & 2 )
-        exec->GS = tt_default_graphics_state;
+      /* check whether GS modifications should be reverted */
+      if ( size->GS.instruct_control & 2 )
+        size->GS = tt_default_graphics_state;
 
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
       /*
@@ -2318,28 +2282,24 @@
        *
        */
       if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 &&
-           subpixel_hinting_lean                                    &&
+           mode != FT_RENDER_MODE_MONO                              &&
            !FT_IS_TRICKY( glyph->face )                             )
-        exec->backward_compatibility = !( exec->GS.instruct_control & 4 );
-      else
-        exec->backward_compatibility = FALSE;
+        exec->backward_compatibility = ( size->GS.instruct_control & 4 ) ^ 4;
+
 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */
 
-      exec->pedantic_hinting = FT_BOOL( load_flags & FT_LOAD_PEDANTIC );
       loader->exec = exec;
-      loader->instructions = exec->glyphIns;
 
       /* Use the hdmx table if any unless FT_LOAD_COMPUTE_METRICS */
       /* is set or backward compatibility mode of the v38 or v40  */
       /* interpreters is active.  See `ttinterp.h' for details on */
       /* backward compatibility mode.                             */
-      if ( IS_HINTED( loader->load_flags )                                &&
-           !( loader->load_flags & FT_LOAD_COMPUTE_METRICS )              &&
+      if ( IS_HINTED( load_flags )                   &&
+           !( load_flags & FT_LOAD_COMPUTE_METRICS ) &&
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-           !( driver->interpreter_version == TT_INTERPRETER_VERSION_40  &&
-              exec->backward_compatibility                              ) &&
+           !exec->backward_compatibility             &&
 #endif
-           !face->postscript.isFixedPitch                                 )
+           !face->postscript.isFixedPitch            )
       {
         loader->widthp = size->widthp;
       }
@@ -2364,7 +2324,7 @@
     loader->face   = face;
     loader->size   = size;
     loader->glyph  = (FT_GlyphSlot)glyph;
-    loader->stream = stream;
+    loader->stream = face->root.stream;
 
     loader->composites.head = NULL;
     loader->composites.tail = NULL;
@@ -2426,84 +2386,26 @@
     TT_LoaderRec  loader;
 
 
-    FT_TRACE1(( "TT_Load_Glyph: glyph index %d\n", glyph_index ));
+    FT_TRACE1(( "TT_Load_Glyph: glyph index %u\n", glyph_index ));
 
 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
 
     /* try to load embedded bitmap (if any) */
-    if ( size->strike_index != 0xFFFFFFFFUL      &&
-         ( load_flags & FT_LOAD_NO_BITMAP ) == 0 &&
-         IS_DEFAULT_INSTANCE( glyph->face )      )
+    if ( size->strike_index != 0xFFFFFFFFUL  &&
+         !( load_flags & FT_LOAD_NO_BITMAP &&
+            FT_IS_SCALABLE( glyph->face )  ) &&
+         IS_DEFAULT_INSTANCE( glyph->face )  )
     {
-      FT_Fixed  x_scale = size->root.metrics.x_scale;
-      FT_Fixed  y_scale = size->root.metrics.y_scale;
-
-
       error = load_sbit_image( size, glyph, glyph_index, load_flags );
-      if ( FT_ERR_EQ( error, Missing_Bitmap ) )
-      {
-        /* the bitmap strike is incomplete and misses the requested glyph; */
-        /* if we have a bitmap-only font, return an empty glyph            */
-        if ( !FT_IS_SCALABLE( glyph->face ) )
-        {
-          FT_Short  left_bearing = 0;
-          FT_Short  top_bearing  = 0;
-
-          FT_UShort  advance_width  = 0;
-          FT_UShort  advance_height = 0;
-
-
-          /* to return an empty glyph, however, we need metrics data   */
-          /* from the `hmtx' (or `vmtx') table; the assumption is that */
-          /* empty glyphs are missing intentionally, representing      */
-          /* whitespace - not having at least horizontal metrics is    */
-          /* thus considered an error                                  */
-          if ( !face->horz_metrics_size )
-            return error;
-
-          /* we now construct an empty bitmap glyph */
-          TT_Get_HMetrics( face, glyph_index,
-                           &left_bearing,
-                           &advance_width );
-          TT_Get_VMetrics( face, glyph_index,
-                           0,
-                           &top_bearing,
-                           &advance_height );
-
-          glyph->outline.n_points   = 0;
-          glyph->outline.n_contours = 0;
-
-          glyph->metrics.width  = 0;
-          glyph->metrics.height = 0;
-
-          glyph->metrics.horiBearingX = FT_MulFix( left_bearing, x_scale );
-          glyph->metrics.horiBearingY = 0;
-          glyph->metrics.horiAdvance  = FT_MulFix( advance_width, x_scale );
-
-          glyph->metrics.vertBearingX = 0;
-          glyph->metrics.vertBearingY = FT_MulFix( top_bearing, y_scale );
-          glyph->metrics.vertAdvance  = FT_MulFix( advance_height, y_scale );
-
-          glyph->format            = FT_GLYPH_FORMAT_BITMAP;
-          glyph->bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
-
-          glyph->bitmap_left = 0;
-          glyph->bitmap_top  = 0;
-
-          return FT_Err_Ok;
-        }
-      }
-      else if ( error )
-      {
-        /* return error if font is not scalable */
-        if ( !FT_IS_SCALABLE( glyph->face ) )
-          return error;
-      }
-      else
+      if ( !error )
       {
         if ( FT_IS_SCALABLE( glyph->face ) ||
              FT_HAS_SBIX( glyph->face )    )
         {
+          FT_Fixed  x_scale = size->root.metrics.x_scale;
+          FT_Fixed  y_scale = size->root.metrics.y_scale;
+
+
           /* for the bbox we need the header only */
           (void)tt_loader_init( &loader, size, glyph, load_flags, TRUE );
           (void)load_truetype_glyph( &loader, glyph_index, 0, TRUE );
@@ -2550,8 +2452,10 @@
                                                     y_scale );
         }
 
-        return FT_Err_Ok;
+        goto Exit;
       }
+      else if ( !FT_IS_SCALABLE( glyph->face ) )
+        goto Exit;
     }
 
     if ( load_flags & FT_LOAD_SBITS_ONLY )
@@ -2563,7 +2467,7 @@
 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
 
     /* if FT_LOAD_NO_SCALE is not set, `ttmetrics' must be valid */
-    if ( !( load_flags & FT_LOAD_NO_SCALE ) && !size->ttmetrics.valid )
+    if ( !( load_flags & FT_LOAD_NO_SCALE ) && !size->ttmetrics.ppem )
     {
       error = FT_THROW( Invalid_Size_Handle );
       goto Exit;
@@ -2614,7 +2518,7 @@
         glyph->metrics.horiAdvance = FT_MulFix( advanceX, x_scale );
         glyph->metrics.vertAdvance = FT_MulFix( advanceY, y_scale );
 
-        return error;
+        goto Exit;
       }
 
       FT_TRACE3(( "Failed to load SVG glyph\n" ));
@@ -2642,10 +2546,6 @@
       goto Done;
     }
 
-    glyph->format        = FT_GLYPH_FORMAT_OUTLINE;
-    glyph->num_subglyphs = 0;
-    glyph->outline.flags = 0;
-
     /* main loading loop */
     error = load_truetype_glyph( &loader, glyph_index, 0, FALSE );
     if ( !error )
@@ -2657,9 +2557,18 @@
       }
       else
       {
+        glyph->format         = FT_GLYPH_FORMAT_OUTLINE;
+
         glyph->outline        = loader.gloader->base.outline;
         glyph->outline.flags &= ~FT_OUTLINE_SINGLE_PASS;
 
+        /* Set the `high precision' bit flag.  This is _critical_ to   */
+        /* get correct output for monochrome TrueType glyphs at all    */
+        /* sizes using the bytecode interpreter.                       */
+        if ( !( load_flags & FT_LOAD_NO_SCALE ) &&
+             size->metrics->y_ppem < 24         )
+          glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
+
         /* Translate array so that (0,0) is the glyph's origin.  Note  */
         /* that this behaviour is independent on the value of bit 1 of */
         /* the `flags' field in the `head' table -- at least major     */
@@ -2708,14 +2617,6 @@
       error = compute_glyph_metrics( &loader, glyph_index );
     }
 
-    /* Set the `high precision' bit flag.                           */
-    /* This is _critical_ to get correct output for monochrome      */
-    /* TrueType glyphs at all sizes using the bytecode interpreter. */
-    /*                                                              */
-    if ( !( load_flags & FT_LOAD_NO_SCALE ) &&
-         size->metrics->y_ppem < 24         )
-      glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
-
     FT_TRACE1(( "  subglyphs = %u, contours = %hu, points = %hu,"
                 " flags = 0x%.3x\n",
                 loader.gloader->base.num_subglyphs,
@@ -2727,11 +2628,8 @@
     tt_loader_done( &loader );
 
   Exit:
-#ifdef FT_DEBUG_LEVEL_TRACE
-    if ( error )
-      FT_TRACE1(( "  failed (error code 0x%x)\n",
-                  error ));
-#endif
+    FT_TRACE1(( error ? "  failed (error code 0x%x)\n" : "",
+                error ));
 
     return error;
   }
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.h
index 22ea967f301..39d6ae3664c 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.h
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.h
@@ -4,7 +4,7 @@
  *
  *   TrueType Glyph Loader (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c
index 4f0083c96b7..f8842795f14 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c
@@ -4,7 +4,7 @@
  *
  *   TrueType GX Font Variation loader
  *
- * Copyright (C) 2004-2024 by
+ * Copyright (C) 2004-2025 by
  * David Turner, Robert Wilhelm, Werner Lemberg, and George Williams.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -489,8 +489,9 @@
     FT_UShort  axis_count;
     FT_UInt    region_count;
 
-    FT_UInt  i, j;
-    FT_Bool  long_words;
+    FT_UInt   i, j;
+    FT_Byte*  bytes;
+    FT_Bool   long_words;
 
     GX_Blend   blend           = ttface->blend;
     FT_ULong*  dataOffsetArray = NULL;
@@ -526,11 +527,15 @@
     if ( FT_QNEW_ARRAY( dataOffsetArray, data_count ) )
       goto Exit;
 
+    if ( FT_FRAME_ENTER( data_count * 4 ) )
+      goto Exit;
+
+    bytes = stream->cursor;
+
     for ( i = 0; i < data_count; i++ )
-    {
-      if ( FT_READ_ULONG( dataOffsetArray[i] ) )
-        goto Exit;
-    }
+      dataOffsetArray[i] = FT_NEXT_ULONG( bytes );
+
+    FT_FRAME_EXIT();
 
     /* parse array of region records (region list) */
     if ( FT_STREAM_SEEK( offset + region_offset ) )
@@ -564,13 +569,26 @@
       goto Exit;
     itemStore->regionCount = region_count;
 
-    for ( i = 0; i < itemStore->regionCount; i++ )
+    if ( FT_FRAME_ENTER( (FT_Long)region_count * axis_count * 6 ) )
+    {
+      FT_TRACE2(( "tt_var_load_item_variation_store:"
+                  " not enough data for variation regions\n" ));
+      error = FT_THROW( Invalid_Table );
+      goto Exit;
+    }
+
+    bytes = stream->cursor;
+
+    for ( i = 0; i < region_count; i++ )
     {
       GX_AxisCoords  axisCoords;
 
 
       if ( FT_NEW_ARRAY( itemStore->varRegionList[i].axisList, axis_count ) )
+      {
+        FT_FRAME_EXIT();
         goto Exit;
+      }
 
       axisCoords = itemStore->varRegionList[i].axisList;
 
@@ -579,10 +597,9 @@
         FT_Int  start, peak, end;
 
 
-        if ( FT_READ_SHORT( start ) ||
-             FT_READ_SHORT( peak )  ||
-             FT_READ_SHORT( end )   )
-          goto Exit;
+        start = FT_NEXT_SHORT( bytes );
+        peak  = FT_NEXT_SHORT( bytes );
+        end   = FT_NEXT_SHORT( bytes );
 
         /* immediately tag invalid ranges with special peak = 0 */
         if ( ( start < 0 && end > 0 ) || start > peak || peak > end )
@@ -594,6 +611,8 @@
       }
     }
 
+    FT_FRAME_EXIT();
+
     /* end of region list parse */
 
     /* use dataOffsetArray now to parse varData items */
@@ -625,7 +644,7 @@
       /* check some data consistency */
       if ( word_delta_count > region_idx_count )
       {
-        FT_TRACE2(( "bad short count %d or region count %d\n",
+        FT_TRACE2(( "bad short count %d or region count %u\n",
                     word_delta_count,
                     region_idx_count ));
         error = FT_THROW( Invalid_Table );
@@ -634,7 +653,7 @@
 
       if ( region_idx_count > itemStore->regionCount )
       {
-        FT_TRACE2(( "inconsistent regionCount %d in varData[%d]\n",
+        FT_TRACE2(( "inconsistent regionCount %u in varData[%u]\n",
                     region_idx_count,
                     i ));
         error = FT_THROW( Invalid_Table );
@@ -648,29 +667,39 @@
       varData->wordDeltaCount = word_delta_count;
       varData->longWords      = long_words;
 
+      if ( FT_FRAME_ENTER( region_idx_count * 2 ) )
+      {
+        FT_TRACE2(( "tt_var_load_item_variation_store:"
+                    " not enough data for region indices\n" ));
+        error = FT_THROW( Invalid_Table );
+        goto Exit;
+      }
+
+      bytes = stream->cursor;
+
       for ( j = 0; j < varData->regionIdxCount; j++ )
       {
-        if ( FT_READ_USHORT( varData->regionIndices[j] ) )
-          goto Exit;
+        varData->regionIndices[j] = FT_NEXT_USHORT( bytes );
 
         if ( varData->regionIndices[j] >= itemStore->regionCount )
         {
-          FT_TRACE2(( "bad region index %d\n",
+          FT_TRACE2(( "bad region index %u\n",
                       varData->regionIndices[j] ));
+          FT_FRAME_EXIT();
           error = FT_THROW( Invalid_Table );
           goto Exit;
         }
       }
 
+      FT_FRAME_EXIT();
+
       per_region_size = word_delta_count + region_idx_count;
       if ( long_words )
         per_region_size *= 2;
 
-      if ( FT_NEW_ARRAY( varData->deltaSet, per_region_size * item_count ) )
+      if ( FT_QALLOC_MULT( varData->deltaSet, item_count, per_region_size ) )
         goto Exit;
-      if ( FT_Stream_Read( stream,
-                           varData->deltaSet,
-                           per_region_size * item_count ) )
+      if ( FT_STREAM_READ( varData->deltaSet, item_count * per_region_size ) )
       {
         FT_TRACE2(( "deltaSet read failed." ));
         error = FT_THROW( Invalid_Table );
@@ -706,6 +735,7 @@
     FT_UInt   innerIndexMask;
     FT_ULong  i;
     FT_UInt   j;
+    FT_Byte*  bytes;
 
 
     if ( FT_STREAM_SEEK( offset )    ||
@@ -757,6 +787,16 @@
     if ( FT_NEW_ARRAY( map->outerIndex, map->mapCount ) )
       goto Exit;
 
+    if ( FT_FRAME_ENTER( map->mapCount * entrySize ) )
+    {
+      FT_TRACE2(( "tt_var_load_delta_set_index_mapping:"
+                  " invalid number of delta-set index mappings\n" ));
+      error = FT_THROW( Invalid_Table );
+      goto Exit;
+    }
+
+    bytes = stream->cursor;
+
     for ( i = 0; i < map->mapCount; i++ )
     {
       FT_UInt  mapData = 0;
@@ -769,9 +809,7 @@
         FT_Byte  data;
 
 
-        if ( FT_READ_BYTE( data ) )
-          goto Exit;
-
+        data    = FT_NEXT_BYTE( bytes );
         mapData = ( mapData << 8 ) | data;
       }
 
@@ -789,7 +827,7 @@
 
       if ( outerIndex >= itemStore->dataCount )
       {
-        FT_TRACE2(( "outerIndex[%ld] == %d out of range\n",
+        FT_TRACE2(( "outerIndex[%lu] == %u out of range\n",
                     i,
                     outerIndex ));
         error = FT_THROW( Invalid_Table );
@@ -802,7 +840,7 @@
 
       if ( innerIndex >= itemStore->varData[outerIndex].itemCount )
       {
-        FT_TRACE2(( "innerIndex[%ld] == %d out of range\n",
+        FT_TRACE2(( "innerIndex[%lu] == %u out of range\n",
                     i,
                     innerIndex ));
         error = FT_THROW( Invalid_Table );
@@ -812,6 +850,8 @@
       map->innerIndex[i] = innerIndex;
     }
 
+    FT_FRAME_EXIT();
+
   Exit:
     return error;
   }
@@ -965,28 +1005,181 @@
   }
 
 
+  static FT_Fixed
+  tt_calculate_scalar( GX_AxisCoords  axis,
+                       FT_UInt        axisCount,
+                       FT_Fixed*      normalizedcoords )
+  {
+    FT_Fixed  scalar = 0x10000L;
+    FT_UInt   j;
+
+
+    /* Inner loop steps through axes in this region. */
+    for ( j = 0; j < axisCount; j++, axis++ )
+    {
+      FT_Fixed  ncv = normalizedcoords[j];
+
+
+      /* Compute the scalar contribution of this axis, */
+      /* with peak of 0 used for invalid axes.         */
+      if ( axis->peakCoord == ncv ||
+           axis->peakCoord == 0   )
+        continue;
+
+      /* Ignore this region if coordinates are out of range. */
+      else if ( ncv <= axis->startCoord ||
+                ncv >= axis->endCoord   )
+      {
+        scalar = 0;
+        break;
+      }
+
+      /* Cumulative product of all the axis scalars. */
+      else if ( ncv < axis->peakCoord )
+        scalar = FT_MulDiv( scalar,
+                            ncv - axis->startCoord,
+                            axis->peakCoord - axis->startCoord );
+      else   /* ncv > axis->peakCoord */
+        scalar = FT_MulDiv( scalar,
+                            axis->endCoord - ncv,
+                            axis->endCoord - axis->peakCoord );
+
+    } /* per-axis loop */
+
+    return scalar;
+  }
+
+
+  static FT_Int64
+  ft_mul_add_delta_scalar( FT_Int64  returnValue,
+                           FT_Int32  delta,
+                           FT_Int32  scalar )
+  {
+
+#ifdef FT_INT64
+
+    return returnValue + (FT_Int64)delta * scalar;
+
+#else /* !FT_INT64 */
+
+    if ( (FT_UInt32)( delta + 0x8000 ) <= 0x20000 )
+    {
+      /* Fast path: multiplication result fits into 32 bits. */
+
+      FT_Int32  lo = delta * scalar;
+
+
+      returnValue.lo += (FT_UInt32)lo;
+
+      if ( returnValue.lo < (FT_UInt32)lo )
+        returnValue.hi += ( lo < 0 ) ? 0 : 1;
+
+      if ( lo < 0 )
+        returnValue.hi -= 1;
+
+      return returnValue;
+    }
+    else
+    {
+      /* Slow path: full 32x32 -> 64-bit signed multiplication. */
+
+      FT_Int64 product;
+
+      /* Get absolute values. */
+      FT_UInt32  a = ( delta < 0 ) ? -delta : delta;
+      FT_UInt32  b = ( scalar < 0 ) ? -scalar : scalar;
+
+      /* Prepare unsigned multiplication. */
+      FT_UInt32  a_lo = a & 0xFFFF;
+      FT_UInt32  a_hi = a >> 16;
+
+      FT_UInt32  b_lo = b & 0xFFFF;
+      FT_UInt32  b_hi = b >> 16;
+
+      /* Partial products. */
+      FT_UInt32  p0 = a_lo * b_lo;
+      FT_UInt32  p1 = a_lo * b_hi;
+      FT_UInt32  p2 = a_hi * b_lo;
+      FT_UInt32  p3 = a_hi * b_hi;
+
+      /* Combine: result = p3 << 32 + (p1 + p2) << 16 + p0 */
+      FT_UInt32  mid       = p1 + p2;
+      FT_UInt32  mid_carry = ( mid < p1 );
+
+      FT_UInt32  carry;
+
+
+      product.lo = ( mid << 16 ) + ( p0 & 0xFFFF );
+      carry      = ( product.lo < ( p0 & 0xFFFF ) ) ? 1 : 0;
+      product.hi = p3 + ( mid >> 16 ) + mid_carry + carry;
+
+      /* If result should be negative, negate. */
+      if ( ( delta < 0 ) ^ ( scalar < 0 ) )
+      {
+        product.lo = ~product.lo + 1;
+        product.hi = ~product.hi + ( product.lo == 0 ? 1 : 0 );
+      }
+
+      /* Add to `returnValue`. */
+      returnValue.lo += product.lo;
+      if ( returnValue.lo < product.lo )
+        returnValue.hi++;
+      returnValue.hi += product.hi;
+
+      return returnValue;
+    }
+
+#endif /* !FT_INT64 */
+
+  }
+
+
+  static FT_ItemVarDelta
+  ft_round_and_shift16( FT_Int64  returnValue )
+  {
+
+#ifdef FT_INT64
+
+    return (FT_ItemVarDelta)( returnValue + 0x8000L ) >> 16;
+
+#else /* !FT_INT64 */
+
+    FT_UInt hi = returnValue.hi;
+    FT_UInt lo = returnValue.lo;
+
+    FT_UInt delta;
+
+
+    /* Add 0x8000 to round. */
+    lo += 0x8000;
+    if ( lo < 0x8000 )  /* overflow occurred */
+      hi += 1;
+
+    /* Shift right by 16 bits. */
+    delta = ( hi << 16 ) | ( lo >> 16 );
+
+    return (FT_ItemVarDelta)delta;
+
+#endif /* !FT_INT64 */
+
+  }
+
+
   FT_LOCAL_DEF( FT_ItemVarDelta )
   tt_var_get_item_delta( FT_Face          face,        /* TT_Face */
                          GX_ItemVarStore  itemStore,
                          FT_UInt          outerIndex,
                          FT_UInt          innerIndex )
   {
-    TT_Face    ttface = (TT_Face)face;
-    FT_Stream  stream = FT_FACE_STREAM( face );
-    FT_Memory  memory = stream->memory;
-    FT_Error   error  = FT_Err_Ok;
-
-    GX_ItemVarData    varData;
-    FT_ItemVarDelta*  deltaSet = NULL;
-    FT_ItemVarDelta   deltaSetStack[16];
+    TT_Face  ttface = (TT_Face)face;
 
-    FT_Fixed*  scalars = NULL;
-    FT_Fixed   scalarsStack[16];
+    GX_ItemVarData  varData;
 
-    FT_UInt          master, j;
-    FT_ItemVarDelta  returnValue = 0;
-    FT_UInt          per_region_size;
-    FT_Byte*         bytes;
+    FT_UInt   master;
+    FT_Int64  returnValue = FT_INT64_ZERO;
+    FT_UInt   shift_base  = 1;
+    FT_UInt   per_region_size;
+    FT_Byte*  bytes;
 
 
     if ( !ttface->blend || !ttface->blend->normalizedcoords )
@@ -1011,113 +1204,63 @@
     if ( varData->regionIdxCount == 0 )
       return 0; /* Avoid "applying zero offset to null pointer". */
 
-    if ( varData->regionIdxCount < 16 )
-    {
-      deltaSet = deltaSetStack;
-      scalars  = scalarsStack;
-    }
-    else
-    {
-      if ( FT_QNEW_ARRAY( deltaSet, varData->regionIdxCount ) )
-        goto Exit;
-      if ( FT_QNEW_ARRAY( scalars, varData->regionIdxCount ) )
-        goto Exit;
-    }
-
     /* Parse delta set.                                            */
     /*                                                             */
     /* Deltas are (word_delta_count + region_idx_count) bytes each */
     /* if `longWords` isn't set, and twice as much otherwise.      */
     per_region_size = varData->wordDeltaCount + varData->regionIdxCount;
     if ( varData->longWords )
+    {
+      shift_base       = 2;
       per_region_size *= 2;
+    }
 
     bytes = varData->deltaSet + per_region_size * innerIndex;
 
-    if ( varData->longWords )
-    {
-      for ( master = 0; master < varData->wordDeltaCount; master++ )
-        deltaSet[master] = FT_NEXT_LONG( bytes );
-      for ( ; master < varData->regionIdxCount; master++ )
-        deltaSet[master] = FT_NEXT_SHORT( bytes );
-    }
-    else
-    {
-      for ( master = 0; master < varData->wordDeltaCount; master++ )
-        deltaSet[master] = FT_NEXT_SHORT( bytes );
-      for ( ; master < varData->regionIdxCount; master++ )
-        deltaSet[master] = FT_NEXT_CHAR( bytes );
-    }
-
     /* outer loop steps through master designs to be blended */
     for ( master = 0; master < varData->regionIdxCount; master++ )
     {
-      FT_Fixed  scalar      = 0x10000L;
-      FT_UInt   regionIndex = varData->regionIndices[master];
+      FT_UInt  regionIndex = varData->regionIndices[master];
 
       GX_AxisCoords  axis = itemStore->varRegionList[regionIndex].axisList;
 
+      FT_Fixed  scalar = tt_calculate_scalar(
+                           axis,
+                           itemStore->axisCount,
+                           ttface->blend->normalizedcoords );
 
-      /* inner loop steps through axes in this region */
-      for ( j = 0; j < itemStore->axisCount; j++, axis++ )
-      {
-        FT_Fixed  ncv = ttface->blend->normalizedcoords[j];
 
+      if ( scalar )
+      {
+        FT_Int  delta;
 
-        /* compute the scalar contribution of this axis */
-        /* with peak of 0 used for invalid axes         */
-        if ( axis->peakCoord == ncv ||
-             axis->peakCoord == 0   )
-          continue;
 
-        /* ignore this region if coords are out of range */
-        else if ( ncv <= axis->startCoord ||
-                  ncv >= axis->endCoord   )
+        if ( varData->longWords )
         {
-          scalar = 0;
-          break;
+          if ( master < varData->wordDeltaCount )
+            delta = FT_NEXT_LONG( bytes );
+          else
+            delta = FT_NEXT_SHORT( bytes );
+        }
+        else
+        {
+          if ( master < varData->wordDeltaCount )
+            delta = FT_NEXT_SHORT( bytes );
+          else
+            delta = FT_NEXT_CHAR( bytes );
         }
 
-        /* cumulative product of all the axis scalars */
-        else if ( ncv < axis->peakCoord )
-          scalar = FT_MulDiv( scalar,
-                              ncv - axis->startCoord,
-                              axis->peakCoord - axis->startCoord );
-        else   /* ncv > axis->peakCoord */
-          scalar = FT_MulDiv( scalar,
-                              axis->endCoord - ncv,
-                              axis->endCoord - axis->peakCoord );
-
-      } /* per-axis loop */
-
-      scalars[master] = scalar;
+        returnValue = ft_mul_add_delta_scalar( returnValue, delta, scalar );
+      }
+      else
+      {
+        /* Branch-free, yay. */
+        bytes += shift_base << ( master < varData->wordDeltaCount );
+      }
 
     } /* per-region loop */
 
-
-    /* Compute the scaled delta for this region.
-     *
-     * From: https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#item-variation-store-header-and-item-variation-data-subtables:
-     *
-     *   `Fixed` is a 32-bit (16.16) type and, in the general case, requires
-     *   32-bit deltas.  As described above, the `DeltaSet` record can
-     *   accommodate deltas that are, logically, either 16-bit or 32-bit.
-     *   When scaled deltas are applied to `Fixed` values, the `Fixed` value
-     *   is treated like a 32-bit integer.
-     *
-     * `FT_MulAddFix` internally uses 64-bit precision; it thus can handle
-     * deltas ranging from small 8-bit to large 32-bit values that are
-     * applied to 16.16 `FT_Fixed` / OpenType `Fixed` values.
-     */
-    returnValue = FT_MulAddFix( scalars, deltaSet, varData->regionIdxCount );
-
-  Exit:
-    if ( scalars != scalarsStack )
-      FT_FREE( scalars );
-    if ( deltaSet != deltaSetStack )
-      FT_FREE( deltaSet );
-
-    return returnValue;
+    return ft_round_and_shift16( returnValue );
   }
 
 
@@ -1643,6 +1786,7 @@
     GX_Blend      blend  = face->blend;
     FT_Error      error;
     FT_UInt       i, j;
+    FT_Byte*      bytes;
     FT_ULong      table_len;
     FT_ULong      gvar_start;
     FT_ULong      offsetToData;
@@ -1734,6 +1878,8 @@
     if ( FT_FRAME_ENTER( offsets_len ) )
       goto Exit;
 
+    bytes = stream->cursor;
+
     /* offsets (one more offset than glyphs, to mark size of last) */
     if ( FT_QNEW_ARRAY( blend->glyphoffsets, gvar_head.glyphCount + 1 ) )
       goto Fail2;
@@ -1744,16 +1890,24 @@
       FT_ULong  max_offset = 0;
 
 
+      if ( stream->limit - stream->cursor < gvar_head.glyphCount * 4 )
+      {
+        FT_TRACE2(( "ft_var_load_gvar:"
+                    " glyph variation data offset not enough\n" ));
+        error = FT_THROW( Invalid_Table );
+        goto Fail;
+      }
+
       for ( i = 0; i <= gvar_head.glyphCount; i++ )
       {
-        blend->glyphoffsets[i] = offsetToData + FT_GET_ULONG();
+        blend->glyphoffsets[i] = offsetToData + FT_NEXT_ULONG( bytes );
 
         if ( max_offset <= blend->glyphoffsets[i] )
           max_offset = blend->glyphoffsets[i];
         else
         {
           FT_TRACE2(( "ft_var_load_gvar:"
-                      " glyph variation data offset %d not monotonic\n",
+                      " glyph variation data offset %u not monotonic\n",
                       i ));
           blend->glyphoffsets[i] = max_offset;
         }
@@ -1762,7 +1916,7 @@
         if ( limit < blend->glyphoffsets[i] )
         {
           FT_TRACE2(( "ft_var_load_gvar:"
-                      " glyph variation data offset %d out of range\n",
+                      " glyph variation data offset %u out of range\n",
                       i ));
           blend->glyphoffsets[i] = limit;
         }
@@ -1774,16 +1928,24 @@
       FT_ULong  max_offset = 0;
 
 
+      if ( stream->limit - stream->cursor < gvar_head.glyphCount * 2 )
+      {
+        FT_TRACE2(( "ft_var_load_gvar:"
+                    " glyph variation data offset not enough\n" ));
+        error = FT_THROW( Invalid_Table );
+        goto Fail;
+      }
+
       for ( i = 0; i <= gvar_head.glyphCount; i++ )
       {
-        blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2;
+        blend->glyphoffsets[i] = offsetToData + FT_NEXT_USHORT( bytes ) * 2;
 
         if ( max_offset <= blend->glyphoffsets[i] )
           max_offset = blend->glyphoffsets[i];
         else
         {
           FT_TRACE2(( "ft_var_load_gvar:"
-                      " glyph variation data offset %d not monotonic\n",
+                      " glyph variation data offset %u not monotonic\n",
                       i ));
           blend->glyphoffsets[i] = max_offset;
         }
@@ -1792,7 +1954,7 @@
         if ( limit < blend->glyphoffsets[i] )
         {
           FT_TRACE2(( "ft_var_load_gvar:"
-                      " glyph variation data offset %d out of range\n",
+                      " glyph variation data offset %u out of range\n",
                       i ));
           blend->glyphoffsets[i] = limit;
         }
@@ -1814,6 +1976,8 @@
         goto Fail;
       }
 
+      bytes = stream->cursor;
+
       if ( FT_QNEW_ARRAY( blend->tuplecoords,
                           gvar_head.axisCount * gvar_head.globalCoordCount ) )
         goto Fail2;
@@ -1824,13 +1988,17 @@
         for ( j = 0; j < (FT_UInt)gvar_head.axisCount; j++ )
         {
           blend->tuplecoords[i * gvar_head.axisCount + j] =
-            FT_fdot14ToFixed( FT_GET_SHORT() );
+            FT_fdot14ToFixed( FT_NEXT_SHORT( bytes ) );
           FT_TRACE5(( "%.5f ",
             (double)blend->tuplecoords[i * gvar_head.axisCount + j] / 65536 ));
         }
         FT_TRACE5(( "]\n" ));
       }
 
+      if ( FT_NEW_ARRAY( blend->tuplescalars,
+                         gvar_head.globalCoordCount ) )
+        goto Fail2;
+
       blend->tuplecount = gvar_head.globalCoordCount;
 
       FT_TRACE5(( "\n" ));
@@ -1896,15 +2064,25 @@
 
     for ( i = 0; i < blend->num_axis; i++ )
     {
-      FT_Fixed  ncv = blend->normalizedcoords[i];
+      FT_Fixed  ncv;
 
 
-      FT_TRACE6(( "    axis %d coordinate %.5f:\n", i, (double)ncv / 65536 ));
+      if ( tuple_coords[i] == 0 )
+      {
+        FT_TRACE6(( "      tuple coordinate is zero, ignore\n" ));
+        continue;
+      }
 
-      /* It's not clear why (for intermediate tuples) we don't need     */
-      /* to check against start/end -- the documentation says we don't. */
-      /* Similarly, it's unclear why we don't need to scale along the   */
-      /* axis.                                                          */
+      ncv = blend->normalizedcoords[i];
+
+      FT_TRACE6(( "    axis %u coordinate %.5f:\n", i, (double)ncv / 65536 ));
+
+      if ( ncv == 0 )
+      {
+        FT_TRACE6(( "      axis coordinate is zero, stop\n" ));
+        apply = 0;
+        break;
+      }
 
       if ( tuple_coords[i] == ncv )
       {
@@ -1914,12 +2092,6 @@
         continue;
       }
 
-      if ( tuple_coords[i] == 0 )
-      {
-        FT_TRACE6(( "      tuple coordinate is zero, ignore\n" ));
-        continue;
-      }
-
       if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) )
       {
         /* not an intermediate tuple */
@@ -2001,7 +2173,7 @@
     if ( num_coords > mmvar->num_axis )
     {
       FT_TRACE2(( "ft_var_to_normalized:"
-                  " only using first %d of %d coordinates\n",
+                  " only using first %u of %u coordinates\n",
                   mmvar->num_axis, num_coords ));
       num_coords = mmvar->num_axis;
     }
@@ -2016,7 +2188,7 @@
       FT_Fixed  coord = coords[i];
 
 
-      FT_TRACE5(( "    %d: %.5f\n", i, (double)coord / 65536 ));
+      FT_TRACE5(( "    %u: %.5f\n", i, (double)coord / 65536 ));
       if ( coord > a->maximum || coord < a->minimum )
       {
         FT_TRACE1(( "ft_var_to_normalized: design coordinate %.5f\n",
@@ -2156,7 +2328,7 @@
     if ( num_coords > blend->num_axis )
     {
       FT_TRACE2(( "ft_var_to_design:"
-                  " only using first %d of %d coordinates\n",
+                  " only using first %u of %u coordinates\n",
                   blend->num_axis, num_coords ));
       nc = blend->num_axis;
     }
@@ -2516,7 +2688,7 @@
                       "    minimum     default     maximum   flags\n" ));
                    /* "  XXXX.XXXXX  XXXX.XXXXX  XXXX.XXXXX  0xXXXX" */
 
-        FT_TRACE5(( "  %3d  `%s'"
+        FT_TRACE5(( "  %3u  `%s'"
                     "  %10.5f  %10.5f  %10.5f  0x%04X%s\n",
                     i,
                     a->name,
@@ -2608,7 +2780,7 @@
 
           (void)FT_STREAM_SEEK( pos );
 
-          FT_TRACE5(( "  named instance %d (%s%s%s, %s%s%s)\n",
+          FT_TRACE5(( "  named instance %u (%s%s%s, %s%s%s)\n",
                       i,
                       strname ? "name: `" : "",
                       strname ? strname : "unnamed",
@@ -2636,7 +2808,7 @@
         FT_UInt  strid = ~0U;
 
 
-        /* The default instance is missing in array the    */
+        /* The default instance is missing in the array    */
         /* of named instances; try to synthesize an entry. */
         /* If this fails, `default_named_instance` remains */
         /* at value zero, which doesn't do any harm.       */
@@ -2766,10 +2938,18 @@
     } manageCvt;
 
 
-    face->doblend = FALSE;
-
     if ( !face->blend )
     {
+      face->doblend = FALSE;
+      for ( i = 0; i < num_coords; i++ )
+        if ( coords[i] )
+        {
+          face->doblend = TRUE;
+          break;
+        }
+      if ( !face->doblend )
+        goto Exit;
+
       if ( FT_SET_ERROR( TT_Get_MM_Var( FT_FACE( face ), NULL ) ) )
         goto Exit;
     }
@@ -2780,7 +2960,7 @@
     if ( num_coords > mmvar->num_axis )
     {
       FT_TRACE2(( "TT_Set_MM_Blend:"
-                  " only using first %d of %d coordinates\n",
+                  " only using first %u of %u coordinates\n",
                   mmvar->num_axis, num_coords ));
       num_coords = mmvar->num_axis;
     }
@@ -2882,11 +3062,7 @@
 
       /* return value -1 indicates `no change' */
       if ( !have_diff )
-      {
-        face->doblend = TRUE;
-
         return -1;
-      }
 
       for ( ; i < mmvar->num_axis; i++ )
       {
@@ -2915,7 +3091,15 @@
                         blend->normalizedcoords,
                         blend->coords );
 
-    face->doblend = TRUE;
+    face->doblend = FALSE;
+    for ( i = 0; i < blend->num_axis; i++ )
+    {
+      if ( blend->normalizedcoords[i] )
+      {
+        face->doblend = TRUE;
+        break;
+      }
+    }
 
     if ( face->cvt )
     {
@@ -2941,6 +3125,9 @@
       }
     }
 
+    for ( i = 0 ; i < blend->tuplecount ; i++ )
+      blend->tuplescalars[i] = (FT_Fixed)-0x20000L;
+
   Exit:
     return error;
   }
@@ -2980,7 +3167,24 @@
                    FT_UInt    num_coords,
                    FT_Fixed*  coords )
   {
-    return tt_set_mm_blend( (TT_Face)face, num_coords, coords, 1 );
+    FT_Error  error;
+
+
+    error = tt_set_mm_blend( (TT_Face)face, num_coords, coords, 1 );
+    if ( error == FT_Err_Ok )
+    {
+      FT_UInt  i;
+
+
+      for ( i = 0; i < num_coords; i++ )
+        if ( coords[i] )
+        {
+          error = -2; /* -2 means is_variable. */
+          break;
+        }
+    }
+
+    return error;
   }
 
 
@@ -3043,7 +3247,7 @@
     if ( num_coords > blend->num_axis )
     {
       FT_TRACE2(( "TT_Get_MM_Blend:"
-                  " only using first %d of %d coordinates\n",
+                  " only using first %u of %u coordinates\n",
                   blend->num_axis, num_coords ));
       nc = blend->num_axis;
     }
@@ -3125,7 +3329,7 @@
     if ( num_coords > mmvar->num_axis )
     {
       FT_TRACE2(( "TT_Set_Var_Design:"
-                  " only using first %d of %d coordinates\n",
+                  " only using first %u of %u coordinates\n",
                   mmvar->num_axis, num_coords ));
       num_coords = mmvar->num_axis;
     }
@@ -3201,6 +3405,15 @@
     if ( error )
       goto Exit;
 
+    for ( i = 0; i < num_coords; i++ )
+    {
+      if ( normalized[i] )
+      {
+        error = -2; /* -2 means is_variable. */
+        break;
+      }
+    }
+
   Exit:
     FT_FREE( normalized );
     return error;
@@ -3237,10 +3450,12 @@
                      FT_UInt    num_coords,
                      FT_Fixed*  coords )
   {
-    TT_Face   ttface = (TT_Face)face;
-    FT_Error  error  = FT_Err_Ok;
-    GX_Blend  blend;
-    FT_UInt   i, nc;
+    TT_Face       ttface = (TT_Face)face;
+    FT_Error      error  = FT_Err_Ok;
+    GX_Blend      blend;
+    FT_MM_Var*    mmvar;
+    FT_Var_Axis*  a;
+    FT_UInt       i, nc;
 
 
     if ( !ttface->blend )
@@ -3263,24 +3478,26 @@
     if ( num_coords > blend->num_axis )
     {
       FT_TRACE2(( "TT_Get_Var_Design:"
-                  " only using first %d of %d coordinates\n",
+                  " only using first %u of %u coordinates\n",
                   blend->num_axis, num_coords ));
       nc = blend->num_axis;
     }
 
+    mmvar = blend->mmvar;
+    a     = mmvar->axis;
     if ( ttface->doblend )
     {
-      for ( i = 0; i < nc; i++ )
+      for ( i = 0; i < nc; i++, a++ )
         coords[i] = blend->coords[i];
     }
     else
     {
-      for ( i = 0; i < nc; i++ )
-        coords[i] = 0;
+      for ( i = 0; i < nc; i++, a++ )
+        coords[i] = a->def;
     }
 
-    for ( ; i < num_coords; i++ )
-      coords[i] = 0;
+    for ( ; i < num_coords; i++, a++ )
+      coords[i] = a->def;
 
     return FT_Err_Ok;
   }
@@ -3373,6 +3590,9 @@
       error = TT_Set_Var_Design( face, 0, NULL );
     }
 
+    if ( error == -1 || error == -2 )
+      error = FT_Err_Ok;
+
   Exit:
     return error;
   }
@@ -3591,7 +3811,7 @@
       FT_Stream_SeekSet( stream, here );
     }
 
-    FT_TRACE5(( "cvar: there %s %d tuple%s:\n",
+    FT_TRACE5(( "cvar: there %s %u tuple%s:\n",
                 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are",
                 tupleCount & GX_TC_TUPLE_COUNT_MASK,
                 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" ));
@@ -3610,7 +3830,7 @@
       FT_Fixed  apply;
 
 
-      FT_TRACE6(( "  tuple %d:\n", i ));
+      FT_TRACE6(( "  tuple %u:\n", i ));
 
       tupleDataSize = FT_GET_USHORT();
       tupleIndex    = FT_GET_USHORT();
@@ -3676,7 +3896,7 @@
       if ( !points || !deltas )
         ; /* failure, ignore it */
 
-      else if ( localpoints == ALL_POINTS )
+      else if ( points == ALL_POINTS )
       {
 #ifdef FT_DEBUG_LEVEL_TRACE
         int  count = 0;
@@ -3697,7 +3917,7 @@
 #ifdef FT_DEBUG_LEVEL_TRACE
           if ( old_cvt_delta != cvt_deltas[j] )
           {
-            FT_TRACE7(( "      %d: %f -> %f\n",
+            FT_TRACE7(( "      %u: %f -> %f\n",
                         j,
                         (double)( FT_fdot6ToFixed( face->cvt[j] ) +
                                     old_cvt_delta ) / 65536,
@@ -4027,7 +4247,7 @@
                               FT_Outline*  outline,
                               FT_Vector*   unrounded )
   {
-    FT_Error   error;
+    FT_Error   error       = FT_Err_Ok;
     TT_Face    face        = loader->face;
     FT_Stream  stream      = face->root.stream;
     FT_Memory  memory      = stream->memory;
@@ -4047,6 +4267,15 @@
     FT_ULong  here;
     FT_UInt   i, j;
 
+    FT_UInt   peak_coords_size;
+    FT_UInt   point_deltas_x_size;
+    FT_UInt   points_org_size;
+    FT_UInt   points_out_size;
+    FT_UInt   has_delta_size;
+    FT_UInt   pool_size;
+    FT_Byte*  pool = NULL;
+    FT_Byte*  p;
+
     FT_Fixed*  peak_coords = NULL;
     FT_Fixed*  tuple_coords;
     FT_Fixed*  im_start_coords;
@@ -4067,21 +4296,24 @@
     FT_Fixed*  point_deltas_y = NULL;
 
 
-    if ( !face->doblend || !blend )
-      return FT_THROW( Invalid_Argument );
-
     for ( i = 0; i < n_points; i++ )
     {
       unrounded[i].x = INT_TO_F26DOT6( outline->points[i].x );
       unrounded[i].y = INT_TO_F26DOT6( outline->points[i].y );
     }
 
+    if ( !face->doblend  )
+      goto Exit;
+
+    if ( !blend )
+      return FT_THROW( Invalid_Argument );
+
     if ( glyph_index >= blend->gv_glyphcnt      ||
          blend->glyphoffsets[glyph_index] ==
            blend->glyphoffsets[glyph_index + 1] )
     {
       FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
-                  " no variation data for glyph %d\n", glyph_index ));
+                  " no variation data for glyph %u\n", glyph_index ));
       return FT_Err_Ok;
     }
 
@@ -4125,18 +4357,41 @@
       FT_Stream_SeekSet( stream, here );
     }
 
-    FT_TRACE5(( "gvar: there %s %d tuple%s:\n",
+    FT_TRACE5(( "gvar: there %s %u tuple%s:\n",
                 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are",
                 tupleCount & GX_TC_TUPLE_COUNT_MASK,
                 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" ));
 
-    if ( FT_QNEW_ARRAY( peak_coords, 3 * blend->num_axis ) ||
-         FT_NEW_ARRAY( point_deltas_x, 2 * n_points )      ||
-         FT_QNEW_ARRAY( points_org, n_points )             ||
-         FT_QNEW_ARRAY( points_out, n_points )             ||
-         FT_QNEW_ARRAY( has_delta, n_points )              )
+    peak_coords_size    = ALIGN_SIZE( 3 * blend->num_axis *
+                                      sizeof ( *peak_coords ) );
+    point_deltas_x_size = ALIGN_SIZE( 2 * n_points *
+                                      sizeof ( *point_deltas_x ) );
+    points_org_size     = ALIGN_SIZE( n_points * sizeof ( *points_org ) );
+    points_out_size     = ALIGN_SIZE( n_points * sizeof ( *points_out ) );
+    has_delta_size      = ALIGN_SIZE( n_points * sizeof ( *has_delta ) );
+
+    pool_size = peak_coords_size    +
+                point_deltas_x_size +
+                points_org_size     +
+                points_out_size     +
+                has_delta_size;
+
+    if ( FT_ALLOC( pool, pool_size ) )
       goto Exit;
 
+    p               = pool;
+    peak_coords     = (FT_Fixed*)p;
+    p              += peak_coords_size;
+    point_deltas_x  = (FT_Fixed*)p;
+    p              += point_deltas_x_size;
+    points_org      = (FT_Vector*)p;
+    p              += points_org_size;
+    points_out      = (FT_Vector*)p;
+    p              += points_out_size;
+    has_delta       = (FT_Bool*)p;
+
+    FT_ARRAY_ZERO( point_deltas_x, 2 * n_points );
+
     im_start_coords = peak_coords + blend->num_axis;
     im_end_coords   = im_start_coords + blend->num_axis;
     point_deltas_y  = point_deltas_x + n_points;
@@ -4147,27 +4402,70 @@
       points_org[j].y = FT_intToFixed( outline->points[j].y );
     }
 
-    for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ )
+    p = stream->cursor;
+
+    tupleCount &= GX_TC_TUPLE_COUNT_MASK;
+    for ( i = 0; i < tupleCount; i++ )
     {
-      FT_UInt   tupleDataSize;
-      FT_UInt   tupleIndex;
-      FT_Fixed  apply;
+      FT_UInt    tupleDataSize;
+      FT_UInt    tupleIndex;
+      FT_Fixed   apply;
+      FT_Fixed*  tupleScalars;
 
 
-      FT_TRACE6(( "  tuple %d:\n", i ));
+      FT_TRACE6(( "  tuple %u:\n", i ));
 
-      tupleDataSize = FT_GET_USHORT();
-      tupleIndex    = FT_GET_USHORT();
+      tupleScalars = blend->tuplescalars;
+
+      /* Enter frame for four bytes. */
+      if ( 4 > stream->limit - p )
+      {
+        FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
+                    " invalid glyph variation array header\n" ));
+        error = FT_THROW( Invalid_Table );
+        goto Exit;
+      }
+
+      tupleDataSize = FT_NEXT_USHORT( p );
+      tupleIndex    = FT_NEXT_USHORT( p );
+
+      if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
+        tupleScalars = NULL;
 
       if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
       {
+        if ( 2 * blend->num_axis > (FT_UInt)( stream->limit - p ) )
+        {
+          FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
+                      " invalid glyph variation array header\n" ));
+          error = FT_THROW( Invalid_Table );
+          goto Exit;
+        }
+
         for ( j = 0; j < blend->num_axis; j++ )
-          peak_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() );
+          peak_coords[j] = FT_fdot14ToFixed( FT_NEXT_SHORT( p ) );
+
         tuple_coords = peak_coords;
+        tupleScalars = NULL;
       }
       else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) < blend->tuplecount )
+      {
+        FT_Fixed  scalar =
+                    tupleScalars
+                      ? tupleScalars[tupleIndex & GX_TI_TUPLE_INDEX_MASK]
+                      : (FT_Fixed)-0x20000;
+
+
+        if ( scalar != (FT_Fixed)-0x20000 )
+        {
+          apply = scalar;
+          goto apply_found;
+        }
+
         tuple_coords = blend->tuplecoords +
-            ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis;
+                         ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) *
+                         blend->num_axis;
+      }
       else
       {
         FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
@@ -4179,10 +4477,18 @@
 
       if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
       {
+        if ( 4 * blend->num_axis > (FT_UInt)( stream->limit - p ) )
+        {
+          FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
+                      " invalid glyph variation array header\n" ));
+          error = FT_THROW( Invalid_Table );
+          goto Exit;
+        }
+
         for ( j = 0; j < blend->num_axis; j++ )
-          im_start_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() );
+          im_start_coords[j] = FT_fdot14ToFixed( FT_NEXT_SHORT( p ) );
         for ( j = 0; j < blend->num_axis; j++ )
-          im_end_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() );
+          im_end_coords[j] = FT_fdot14ToFixed( FT_NEXT_SHORT( p ) );
       }
 
       apply = ft_var_apply_tuple( blend,
@@ -4191,6 +4497,11 @@
                                   im_start_coords,
                                   im_end_coords );
 
+      if ( tupleScalars )
+        tupleScalars[tupleIndex & GX_TI_TUPLE_INDEX_MASK] = apply;
+
+    apply_found:
+
       if ( apply == 0 )              /* tuple isn't active for our blend */
       {
         offsetToData += tupleDataSize;
@@ -4247,7 +4558,7 @@
 #ifdef FT_DEBUG_LEVEL_TRACE
           if ( point_delta_x || point_delta_y )
           {
-            FT_TRACE7(( "      %d: (%f, %f) -> (%f, %f)\n",
+            FT_TRACE7(( "      %u: (%f, %f) -> (%f, %f)\n",
                         j,
                         (double)( FT_intToFixed( outline->points[j].x ) +
                                     old_point_delta_x ) / 65536,
@@ -4321,7 +4632,7 @@
 #ifdef FT_DEBUG_LEVEL_TRACE
           if ( point_delta_x || point_delta_y )
           {
-            FT_TRACE7(( "      %d: (%f, %f) -> (%f, %f)\n",
+            FT_TRACE7(( "      %u: (%f, %f) -> (%f, %f)\n",
                         j,
                         (double)( FT_intToFixed( outline->points[j].x ) +
                                     old_point_delta_x ) / 65536,
@@ -4402,11 +4713,7 @@
   Exit:
     if ( sharedpoints != ALL_POINTS )
       FT_FREE( sharedpoints );
-    FT_FREE( points_org );
-    FT_FREE( points_out );
-    FT_FREE( has_delta );
-    FT_FREE( peak_coords );
-    FT_FREE( point_deltas_x );
+    FT_FREE( pool );
 
   FExit:
     FT_FRAME_EXIT();
@@ -4577,6 +4884,7 @@
         FT_FREE( blend->mvar_table );
       }
 
+      FT_FREE( blend->tuplescalars );
       FT_FREE( blend->tuplecoords );
       FT_FREE( blend->glyphoffsets );
       FT_FREE( blend );
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h
index 9326011e3a2..568c8027bbf 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h
@@ -4,7 +4,7 @@
  *
  *   TrueType GX Font Variation loader (specification)
  *
- * Copyright (C) 2004-2024 by
+ * Copyright (C) 2004-2025 by
  * David Turner, Robert Wilhelm, Werner Lemberg and George Williams.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -255,6 +255,10 @@ FT_BEGIN_HEADER
    *     A two-dimensional array that holds the shared tuple coordinates
    *     in the `gvar' table.
    *
+   *   tuplescalars ::
+   *     A one-dimensional array that holds the shared tuple
+   *     scalars in the `gvar' table for current face coordinates.
+   *
    *   gv_glyphcnt ::
    *     The number of glyphs handled in the `gvar' table.
    *
@@ -293,6 +297,7 @@ FT_BEGIN_HEADER
 
     FT_UInt         tuplecount;
     FT_Fixed*       tuplecoords;      /* tuplecoords[tuplecount][num_axis] */
+    FT_Fixed*       tuplescalars;     /* tuplescalars[tuplecount]          */
 
     FT_UInt         gv_glyphcnt;
     FT_ULong*       glyphoffsets;         /* glyphoffsets[gv_glyphcnt + 1] */
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c
index 951891dbf51..f46cc77fe5f 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c
@@ -4,7 +4,7 @@
  *
  *   TrueType bytecode interpreter (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -27,6 +27,8 @@
 #include 
 #include 
 
+#ifdef TT_USE_BYTECODE_INTERPRETER
+
 #include "ttinterp.h"
 #include "tterrors.h"
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
@@ -34,9 +36,6 @@
 #endif
 
 
-#ifdef TT_USE_BYTECODE_INTERPRETER
-
-
   /**************************************************************************
    *
    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
@@ -89,58 +88,37 @@
 #define FAILURE  1
 
 
-  /**************************************************************************
-   *
-   *                       CODERANGE FUNCTIONS
-   *
-   */
+  /* The default value for `scan_control' is documented as FALSE in the */
+  /* TrueType specification.  This is confusing since it implies a      */
+  /* Boolean value.  However, this is not the case, thus both the       */
+  /* default values of our `scan_type' and `scan_control' fields (which */
+  /* the documentation's `scan_control' variable is split into) are     */
+  /* zero.                                                              */
+  /*                                                                    */
+  /* The rounding compensation should logically belong here but poorly  */
+  /* described in the OpenType specs.  It was probably important in the */
+  /* days of dot matrix printers.  The values are referenced by color   */
+  /* as Gray, Black, and White in order. The Apple specification says   */
+  /* that the Gray compensation is always zero.  The fourth value is    */
+  /* not described at all, but Greg says that it is the same as Gray.   */
+  /* FreeType sets all compensation values to zero.                     */
+
+  const TT_GraphicsState  tt_default_graphics_state =
+  {
+    0, 0, 0,  1, 1, 1,
+    { 0x4000, 0 }, { 0x4000, 0 }, { 0x4000, 0 },
+    1, 1, { 0, 0, 0, 0 },
+
+    64, 68, 0, 0, 9, 3,
+    TRUE, 0, FALSE, 0
+  };
 
 
   /**************************************************************************
    *
-   * @Function:
-   *   TT_Goto_CodeRange
-   *
-   * @Description:
-   *   Switches to a new code range (updates the code related elements in
-   *   `exec', and `IP').
-   *
-   * @Input:
-   *   range ::
-   *     The new execution code range.
-   *
-   *   IP ::
-   *     The new IP in the new code range.
+   *                       CODERANGE FUNCTIONS
    *
-   * @InOut:
-   *   exec ::
-   *     The target execution context.
    */
-  FT_LOCAL_DEF( void )
-  TT_Goto_CodeRange( TT_ExecContext  exec,
-                     FT_Int          range,
-                     FT_Long         IP )
-  {
-    TT_CodeRange*  coderange;
-
-
-    FT_ASSERT( range >= 1 && range <= 3 );
-
-    coderange = &exec->codeRangeTable[range - 1];
-
-    FT_ASSERT( coderange->base );
-
-    /* NOTE: Because the last instruction of a program may be a CALL */
-    /*       which will return to the first byte *after* the code    */
-    /*       range, we test for IP <= Size instead of IP < Size.     */
-    /*                                                               */
-    FT_ASSERT( IP <= coderange->size );
-
-    exec->code     = coderange->base;
-    exec->codeSize = coderange->size;
-    exec->IP       = IP;
-    exec->curRange = range;
-  }
 
 
   /**************************************************************************
@@ -168,13 +146,19 @@
   FT_LOCAL_DEF( void )
   TT_Set_CodeRange( TT_ExecContext  exec,
                     FT_Int          range,
-                    void*           base,
+                    FT_Byte*        base,
                     FT_Long         length )
   {
     FT_ASSERT( range >= 1 && range <= 3 );
 
-    exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
+    exec->codeRangeTable[range - 1].base = base;
     exec->codeRangeTable[range - 1].size = length;
+
+    exec->code     = base;
+    exec->codeSize = length;
+    exec->IP       = 0;
+    exec->curRange = range;
+    exec->iniRange = range;
   }
 
 
@@ -224,9 +208,6 @@
    *   exec ::
    *     A handle to the target execution context.
    *
-   *   memory ::
-   *     A handle to the parent memory object.
-   *
    * @Note:
    *   Only the glyph loader and debugger should call this function.
    */
@@ -240,10 +221,6 @@
     exec->maxPoints   = 0;
     exec->maxContours = 0;
 
-    /* free stack */
-    FT_FREE( exec->stack );
-    exec->stackSize = 0;
-
     /* free glyf cvt working area */
     FT_FREE( exec->glyfCvt );
     exec->glyfCvtSize = 0;
@@ -295,79 +272,31 @@
    *
    *   Note that not all members of `TT_ExecContext` get initialized.
    */
-  FT_LOCAL_DEF( FT_Error )
+  FT_LOCAL_DEF( void )
   TT_Load_Context( TT_ExecContext  exec,
                    TT_Face         face,
                    TT_Size         size )
   {
-    FT_Int          i;
-    TT_MaxProfile*  maxp;
-    FT_Error        error;
-    FT_Memory       memory = exec->memory;
+    FT_Memory  memory = exec->memory;
 
 
     exec->face = face;
-    maxp       = &face->max_profile;
     exec->size = size;
 
-    if ( size )
-    {
-      exec->numFDefs   = size->num_function_defs;
-      exec->maxFDefs   = size->max_function_defs;
-      exec->numIDefs   = size->num_instruction_defs;
-      exec->maxIDefs   = size->max_instruction_defs;
-      exec->FDefs      = size->function_defs;
-      exec->IDefs      = size->instruction_defs;
-      exec->pointSize  = size->point_size;
-      exec->tt_metrics = size->ttmetrics;
-      exec->metrics    = *size->metrics;
-
-      exec->maxFunc    = size->max_func;
-      exec->maxIns     = size->max_ins;
-
-      for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
-        exec->codeRangeTable[i] = size->codeRangeTable[i];
-
-      /* set graphics state */
-      exec->GS = size->GS;
-
-      exec->cvtSize = size->cvt_size;
-      exec->cvt     = size->cvt;
-
-      exec->storeSize = size->storage_size;
-      exec->storage   = size->storage;
-
-      exec->twilight  = size->twilight;
-
-      /* In case of multi-threading it can happen that the old size object */
-      /* no longer exists, thus we must clear all glyph zone references.   */
-      FT_ZERO( &exec->zp0 );
-      exec->zp1 = exec->zp0;
-      exec->zp2 = exec->zp0;
-    }
-
-    /* XXX: We reserve a little more elements on the stack to deal safely */
-    /*      with broken fonts like arialbs, courbs, timesbs, etc.         */
-    if ( FT_QRENEW_ARRAY( exec->stack,
-                          exec->stackSize,
-                          maxp->maxStackElements + 32 ) )
-      return error;
-    exec->stackSize = maxp->maxStackElements + 32;
+    /* CVT and storage are not persistent in FreeType */
+    /* reset them after they might have been modified */
+    exec->storage = exec->stack   + exec->stackSize;
+    exec->cvt     = exec->storage + exec->storeSize;
 
     /* free previous glyph code range */
     FT_FREE( exec->glyphIns );
     exec->glyphSize = 0;
 
-    exec->pts.n_points   = 0;
-    exec->pts.n_contours = 0;
-
-    exec->zp1 = exec->pts;
-    exec->zp2 = exec->pts;
-    exec->zp0 = exec->pts;
-
-    exec->instruction_trap = FALSE;
+    exec->pointSize  = size->point_size;
+    exec->tt_metrics = size->ttmetrics;
+    exec->metrics    = *size->metrics;
 
-    return FT_Err_Ok;
+    exec->twilight   = size->twilight;
   }
 
 
@@ -394,89 +323,22 @@
   TT_Save_Context( TT_ExecContext  exec,
                    TT_Size         size )
   {
-    FT_Int  i;
-
-
-    /* XXX: Will probably disappear soon with all the code range */
-    /*      management, which is now rather obsolete.            */
-    /*                                                           */
-    size->num_function_defs    = exec->numFDefs;
-    size->num_instruction_defs = exec->numIDefs;
-
-    size->max_func = exec->maxFunc;
-    size->max_ins  = exec->maxIns;
-
-    for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
-      size->codeRangeTable[i] = exec->codeRangeTable[i];
-  }
-
-
-  /**************************************************************************
-   *
-   * @Function:
-   *   TT_Run_Context
-   *
-   * @Description:
-   *   Executes one or more instructions in the execution context.
-   *
-   * @Input:
-   *   exec ::
-   *     A handle to the target execution context.
-   *
-   * @Return:
-   *   TrueType error code.  0 means success.
-   */
-  FT_LOCAL_DEF( FT_Error )
-  TT_Run_Context( TT_ExecContext  exec )
-  {
-    TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 );
-
-    exec->zp0 = exec->pts;
-    exec->zp1 = exec->pts;
-    exec->zp2 = exec->pts;
-
-    exec->GS.gep0 = 1;
-    exec->GS.gep1 = 1;
-    exec->GS.gep2 = 1;
-
-    exec->GS.projVector.x = 0x4000;
-    exec->GS.projVector.y = 0x0000;
-
-    exec->GS.freeVector = exec->GS.projVector;
-    exec->GS.dualVector = exec->GS.projVector;
-
-    exec->GS.round_state = 1;
-    exec->GS.loop        = 1;
-
-    /* some glyphs leave something on the stack. so we clean it */
-    /* before a new execution.                                  */
-    exec->top     = 0;
-    exec->callTop = 0;
+    /* UNDOCUMENTED!                                            */
+    /* Only these GS values can be modified by the CVT program. */
 
-    return exec->face->interpreter( exec );
+    size->GS.minimum_distance    = exec->GS.minimum_distance;
+    size->GS.control_value_cutin = exec->GS.control_value_cutin;
+    size->GS.single_width_cutin  = exec->GS.single_width_cutin;
+    size->GS.single_width_value  = exec->GS.single_width_value;
+    size->GS.delta_base          = exec->GS.delta_base;
+    size->GS.delta_shift         = exec->GS.delta_shift;
+    size->GS.auto_flip           = exec->GS.auto_flip;
+    size->GS.instruct_control    = exec->GS.instruct_control;
+    size->GS.scan_control        = exec->GS.scan_control;
+    size->GS.scan_type           = exec->GS.scan_type;
   }
 
 
-  /* The default value for `scan_control' is documented as FALSE in the */
-  /* TrueType specification.  This is confusing since it implies a      */
-  /* Boolean value.  However, this is not the case, thus both the       */
-  /* default values of our `scan_type' and `scan_control' fields (which */
-  /* the documentation's `scan_control' variable is split into) are     */
-  /* zero.                                                              */
-
-  const TT_GraphicsState  tt_default_graphics_state =
-  {
-    0, 0, 0,
-    { 0x4000, 0 },
-    { 0x4000, 0 },
-    { 0x4000, 0 },
-
-    1, 64, 1,
-    TRUE, 68, 0, 0, 9, 3,
-    0, FALSE, 0, 1, 1, 1
-  };
-
-
   /* documentation is in ttinterp.h */
 
   FT_EXPORT_DEF( TT_ExecContext )
@@ -485,7 +347,8 @@
     FT_Memory  memory;
     FT_Error   error;
 
-    TT_ExecContext  exec = NULL;
+    TT_ExecContext     exec = NULL;
+    FT_DebugHook_Func  interp;
 
 
     if ( !driver )
@@ -497,6 +360,15 @@
     if ( FT_NEW( exec ) )
       goto Fail;
 
+    /* set `exec->interpreter' according to the debug hook present, */
+    /* which is used by 'ttdebug'.                                  */
+    interp = driver->root.root.library->debug_hooks[FT_DEBUG_HOOK_TRUETYPE];
+
+    if ( interp )
+      exec->interpreter = (TT_Interpreter)interp;
+    else
+      exec->interpreter = (TT_Interpreter)TT_RunIns;
+
     /* create callStack here, other allocations delayed */
     exec->memory   = memory;
     exec->callSize = 32;
@@ -1160,20 +1032,35 @@
 #undef PACK
 
 
-#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER
+#ifdef FT_INT64
+
+#define TT_MulFix14( a, b )  TT_MulFix14_64( a, b )
+
+  static inline FT_F26Dot6
+  TT_MulFix14_64( FT_F26Dot6  a,
+                  FT_F2Dot14  b )
+  {
+    FT_Int64  ab = MUL_INT64( a, b );
+
+
+    ab = ADD_INT64( ab, 0x2000 + ( ab >> 63 ) );  /* rounding phase */
+
+    return (FT_F26Dot6)( ab >> 14 );
+  }
+
+#elif !defined( FT_CONFIG_OPTION_NO_ASSEMBLER )
 
 #if defined( __arm__ )                                 && \
     ( defined( __thumb2__ ) || !defined( __thumb__ ) )
 
 #define TT_MulFix14  TT_MulFix14_arm
 
-  static FT_Int32
+  static __inline FT_Int32
   TT_MulFix14_arm( FT_Int32  a,
-                   FT_Int    b )
+                   FT_Int32  b )
   {
     FT_Int32  t, t2;
 
-
 #if defined( __CC_ARM ) || defined( __ARMCC__ )
 
     __asm
@@ -1199,8 +1086,8 @@
 #endif
       "adds   %1, %1, %0\n\t"           /* %1 += %0 */
       "adc    %2, %2, #0\n\t"           /* %2 += carry */
-      "mov    %0, %1, lsr #14\n\t"      /* %0  = %1 >> 16 */
-      "orr    %0, %0, %2, lsl #18\n\t"  /* %0 |= %2 << 16 */
+      "mov    %0, %1, lsr #14\n\t"      /* %0  = %1 >> 14 */
+      "orr    %0, %0, %2, lsl #18\n\t"  /* %0 |= %2 << 18 */
       : "=r"(a), "=&r"(t2), "=&r"(t)
       : "r"(a), "r"(b)
       : "cc" );
@@ -1210,49 +1097,60 @@
     return a;
   }
 
-#endif /* __arm__ && ( __thumb2__ || !__thumb__ ) */
-
-#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */
-
-
-#if defined( __GNUC__ )                              && \
-    ( defined( __i386__ ) || defined( __x86_64__ ) )
+#elif defined( __i386__ ) || defined( _M_IX86 )
 
-#define TT_MulFix14  TT_MulFix14_long_long
+#define TT_MulFix14  TT_MulFix14_i386
 
-  /* Temporarily disable the warning that C90 doesn't support `long long'. */
-#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406
-#pragma GCC diagnostic push
-#endif
-#pragma GCC diagnostic ignored "-Wlong-long"
+  /* documentation is in freetype.h */
 
-  /* This is declared `noinline' because inlining the function results */
-  /* in slower code.  The `pure' attribute indicates that the result   */
-  /* only depends on the parameters.                                   */
-  static __attribute__(( noinline ))
-         __attribute__(( pure )) FT_Int32
-  TT_MulFix14_long_long( FT_Int32  a,
-                         FT_Int    b )
+  static __inline FT_Int32
+  TT_MulFixi14_i386( FT_Int32  a,
+                     FT_Int32  b )
   {
+    FT_Int32  result;
 
-    long long  ret = (long long)a * b;
+#if defined( __GNUC__ )
 
-    /* The following line assumes that right shifting of signed values */
-    /* will actually preserve the sign bit.  The exact behaviour is    */
-    /* undefined, but this is true on x86 and x86_64.                  */
-    long long  tmp = ret >> 63;
+    __asm__ __volatile__ (
+      "imul  %%edx\n"
+      "movl  %%edx, %%ecx\n"
+      "sarl  $31, %%ecx\n"
+      "addl  $0x2000, %%ecx\n"
+      "addl  %%ecx, %%eax\n"
+      "adcl  $0, %%edx\n"
+      "shrl  $14, %%eax\n"
+      "shll  $18, %%edx\n"
+      "addl  %%edx, %%eax\n"
+      : "=a"(result), "=d"(b)
+      : "a"(a), "d"(b)
+      : "%ecx", "cc" );
+
+#elif defined( _MSC_VER)
 
+    __asm
+    {
+      mov eax, a
+      mov edx, b
+      imul edx
+      mov ecx, edx
+      sar ecx, 31
+      add ecx, 2000h
+      add eax, ecx
+      adc edx, 0
+      shr eax, 14
+      shl edx, 18
+      add eax, edx
+      mov result, eax
+    }
 
-    ret += 0x2000 + tmp;
+#endif
 
-    return (FT_Int32)( ret >> 14 );
+    return result;
   }
 
-#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406
-#pragma GCC diagnostic pop
-#endif
+#endif /* __i386__ || _M_IX86 */
 
-#endif /* __GNUC__ && ( __i386__ || __x86_64__ ) */
+#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */
 
 
 #ifndef TT_MulFix14
@@ -1262,92 +1160,59 @@
   /* for platforms where sizeof(int) == 2.                   */
   static FT_Int32
   TT_MulFix14( FT_Int32  a,
-               FT_Int    b )
+               FT_Int16  b )
   {
-    FT_Int32   sign;
-    FT_UInt32  ah, al, mid, lo, hi;
-
-
-    sign = a ^ b;
+    FT_Int32   m, hi;
+    FT_UInt32  l, lo;
 
-    if ( a < 0 )
-      a = -a;
-    if ( b < 0 )
-      b = -b;
 
-    ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU );
-    al = (FT_UInt32)( a & 0xFFFFU );
+    /* compute a*b as 64-bit (hi_lo) value */
+    l = (FT_UInt32)( ( a & 0xFFFFU ) * b );
+    m = ( a >> 16 ) * b;
 
-    lo    = al * b;
-    mid   = ah * b;
-    hi    = mid >> 16;
-    mid   = ( mid << 16 ) + ( 1 << 13 ); /* rounding */
-    lo   += mid;
-    if ( lo < mid )
-      hi += 1;
+    lo = l + ( (FT_UInt32)m << 16 );
+    hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l );
 
-    mid = ( lo >> 14 ) | ( hi << 18 );
+    /* divide the result by 2^14 with rounding */
+    l   = lo + 0x2000U + (FT_UInt32)( hi >> 31 );  /* rounding phase */
+    hi += ( l < lo );
 
-    return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid;
+    return (FT_F26Dot6)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) );
   }
 
 #endif  /* !TT_MulFix14 */
 
 
-#if defined( __GNUC__ )        && \
-    ( defined( __i386__ )   ||    \
-      defined( __x86_64__ ) ||    \
-      defined( __arm__ )    )
-
-#define TT_DotFix14  TT_DotFix14_long_long
-
-#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406
-#pragma GCC diagnostic push
-#endif
-#pragma GCC diagnostic ignored "-Wlong-long"
+#ifdef FT_INT64
 
-  static __attribute__(( pure )) FT_Int32
-  TT_DotFix14_long_long( FT_Int32  ax,
-                         FT_Int32  ay,
-                         FT_Int    bx,
-                         FT_Int    by )
+  /* compute (ax*bx+ay*by)/2^14 with maximum accuracy and rounding */
+  static inline FT_F26Dot6
+  TT_DotFix14( FT_F26Dot6  ax,
+               FT_F26Dot6  ay,
+               FT_F2Dot14  bx,
+               FT_F2Dot14  by )
   {
-    /* Temporarily disable the warning that C90 doesn't support */
-    /* `long long'.                                             */
-
-    long long  temp1 = (long long)ax * bx;
-    long long  temp2 = (long long)ay * by;
-
+    FT_Int64  c = ADD_INT64( MUL_INT64( ax, bx ), MUL_INT64( ay, by ) );
 
-    temp1 += temp2;
-    temp2  = temp1 >> 63;
-    temp1 += 0x2000 + temp2;
 
-    return (FT_Int32)( temp1 >> 14 );
+    c = ADD_INT64( c, 0x2000 + ( c >> 63 ) );  /* rounding phase */
 
+    return (FT_F26Dot6)( c >> 14 );
   }
 
-#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406
-#pragma GCC diagnostic pop
-#endif
-
-#endif /* __GNUC__ && (__arm__ || __i386__ || __x86_64__) */
-
-
-#ifndef TT_DotFix14
+#else
 
-  /* compute (ax*bx+ay*by)/2^14 with maximum accuracy and rounding */
-  static FT_Int32
-  TT_DotFix14( FT_Int32  ax,
-               FT_Int32  ay,
-               FT_Int    bx,
-               FT_Int    by )
+  static inline FT_F26Dot6
+  TT_DotFix14( FT_F26Dot6  ax,
+               FT_F26Dot6  ay,
+               FT_F2Dot14  bx,
+               FT_F2Dot14  by )
   {
-    FT_Int32   m, s, hi1, hi2, hi;
+    FT_Int32   m, hi1, hi2, hi;
     FT_UInt32  l, lo1, lo2, lo;
 
 
-    /* compute ax*bx as 64-bit value */
+    /* compute ax*bx as 64-bit (hi_lo) value */
     l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );
     m = ( ax >> 16 ) * bx;
 
@@ -1366,18 +1231,13 @@
     hi = hi1 + hi2 + ( lo < lo1 );
 
     /* divide the result by 2^14 with rounding */
-    s   = hi >> 31;
-    l   = lo + (FT_UInt32)s;
-    hi += s + ( l < lo );
-    lo  = l;
-
-    l   = lo + 0x2000U;
+    l   = lo + 0x2000U + (FT_UInt32)( hi >> 31 );  /* rounding phase */
     hi += ( l < lo );
 
-    return (FT_Int32)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) );
+    return (FT_F26Dot6)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) );
   }
 
-#endif /* TT_DotFix14 */
+#endif /* !FT_INT64 */
 
 
   /**************************************************************************
@@ -1531,31 +1391,6 @@
   }
 
 
-  /**************************************************************************
-   *
-   * @Function:
-   *   GetShortIns
-   *
-   * @Description:
-   *   Returns a short integer taken from the instruction stream at
-   *   address IP.
-   *
-   * @Return:
-   *   Short read at code[IP].
-   *
-   * @Note:
-   *   This one could become a macro.
-   */
-  static FT_Short
-  GetShortIns( TT_ExecContext  exc )
-  {
-    /* Reading a byte stream so there is no endianness (DaveP) */
-    exc->IP += 2;
-    return (FT_Short)( ( exc->code[exc->IP - 2] << 8 ) +
-                         exc->code[exc->IP - 1]      );
-  }
-
-
   /**************************************************************************
    *
    * @Function:
@@ -1609,6 +1444,7 @@
     exc->code     = range->base;
     exc->codeSize = range->size;
     exc->IP       = aIP;
+    exc->length   = 0;
     exc->curRange = aRange;
 
     return SUCCESS;
@@ -1671,48 +1507,33 @@
                FT_UShort       point,
                FT_F26Dot6      distance )
   {
-    FT_F26Dot6  v;
+    FT_Fixed  v;
 
 
-    v = exc->GS.freeVector.x;
-
+    v = exc->moveVector.x;
     if ( v != 0 )
     {
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
       /* Exception to the post-IUP curfew: Allow the x component of */
       /* diagonal moves, but only post-IUP.  DejaVu tries to adjust */
       /* diagonal stems like on `Z' and `z' post-IUP.               */
-      if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility )
-        zone->cur[point].x = ADD_LONG( zone->cur[point].x,
-                                       FT_MulDiv( distance,
-                                                  v,
-                                                  exc->F_dot_P ) );
-      else
+      if ( !exc->backward_compatibility )
 #endif
-
-      if ( NO_SUBPIXEL_HINTING )
         zone->cur[point].x = ADD_LONG( zone->cur[point].x,
-                                       FT_MulDiv( distance,
-                                                  v,
-                                                  exc->F_dot_P ) );
+                                       FT_MulFix( distance, v ) );
 
       zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
     }
 
-    v = exc->GS.freeVector.y;
-
+    v = exc->moveVector.y;
     if ( v != 0 )
     {
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-      if ( !( SUBPIXEL_HINTING_MINIMAL    &&
-              exc->backward_compatibility &&
-              exc->iupx_called            &&
-              exc->iupy_called            ) )
+      /* See `ttinterp.h' for details on backward compatibility mode. */
+      if ( exc->backward_compatibility != 0x7 )
 #endif
         zone->cur[point].y = ADD_LONG( zone->cur[point].y,
-                                       FT_MulDiv( distance,
-                                                  v,
-                                                  exc->F_dot_P ) );
+                                       FT_MulFix( distance, v ) );
 
       zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
     }
@@ -1745,24 +1566,20 @@
                     FT_UShort       point,
                     FT_F26Dot6      distance )
   {
-    FT_F26Dot6  v;
+    FT_Fixed  v;
 
 
-    v = exc->GS.freeVector.x;
+    v = exc->moveVector.x;
 
     if ( v != 0 )
       zone->org[point].x = ADD_LONG( zone->org[point].x,
-                                     FT_MulDiv( distance,
-                                                v,
-                                                exc->F_dot_P ) );
+                                     FT_MulFix( distance, v ) );
 
-    v = exc->GS.freeVector.y;
+    v = exc->moveVector.y;
 
     if ( v != 0 )
       zone->org[point].y = ADD_LONG( zone->org[point].y,
-                                     FT_MulDiv( distance,
-                                                v,
-                                                exc->F_dot_P ) );
+                                     FT_MulFix( distance, v ) );
   }
 
 
@@ -1784,12 +1601,8 @@
                  FT_F26Dot6      distance )
   {
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-    if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility )
-      zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
-    else
+    if ( !exc->backward_compatibility )
 #endif
-
-    if ( NO_SUBPIXEL_HINTING )
       zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
 
     zone->tags[point]  |= FT_CURVE_TAG_TOUCH_X;
@@ -1805,9 +1618,8 @@
     FT_UNUSED( exc );
 
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-    if ( !( SUBPIXEL_HINTING_MINIMAL             &&
-            exc->backward_compatibility          &&
-            exc->iupx_called && exc->iupy_called ) )
+    /* See `ttinterp.h' for details on backward compatibility mode. */
+    if ( exc->backward_compatibility != 0x7 )
 #endif
       zone->cur[point].y = ADD_LONG( zone->cur[point].y, distance );
 
@@ -1860,8 +1672,8 @@
    *   distance ::
    *     The distance (not) to round.
    *
-   *   color ::
-   *     The engine compensation color.
+   *   compensation ::
+   *     The engine compensation.
    *
    * @Return:
    *   The compensated distance.
@@ -1869,10 +1681,10 @@
   static FT_F26Dot6
   Round_None( TT_ExecContext  exc,
               FT_F26Dot6      distance,
-              FT_Int          color )
+              FT_F26Dot6      compensation )
   {
-    FT_F26Dot6  compensation = exc->tt_metrics.compensations[color];
     FT_F26Dot6  val;
+    FT_UNUSED( exc );
 
 
     if ( distance >= 0 )
@@ -1903,8 +1715,8 @@
    *   distance ::
    *     The distance to round.
    *
-   *   color ::
-   *     The engine compensation color.
+   *   compensation ::
+   *     The engine compensation.
    *
    * @Return:
    *   Rounded distance.
@@ -1912,10 +1724,10 @@
   static FT_F26Dot6
   Round_To_Grid( TT_ExecContext  exc,
                  FT_F26Dot6      distance,
-                 FT_Int          color )
+                 FT_F26Dot6      compensation )
   {
-    FT_F26Dot6  compensation = exc->tt_metrics.compensations[color];
     FT_F26Dot6  val;
+    FT_UNUSED( exc );
 
 
     if ( distance >= 0 )
@@ -1948,8 +1760,8 @@
    *   distance ::
    *     The distance to round.
    *
-   *   color ::
-   *     The engine compensation color.
+   *   compensation ::
+   *     The engine compensation.
    *
    * @Return:
    *   Rounded distance.
@@ -1957,10 +1769,10 @@
   static FT_F26Dot6
   Round_To_Half_Grid( TT_ExecContext  exc,
                       FT_F26Dot6      distance,
-                      FT_Int          color )
+                      FT_F26Dot6      compensation )
   {
-    FT_F26Dot6  compensation = exc->tt_metrics.compensations[color];
     FT_F26Dot6  val;
+    FT_UNUSED( exc );
 
 
     if ( distance >= 0 )
@@ -1995,8 +1807,8 @@
    *   distance ::
    *     The distance to round.
    *
-   *   color ::
-   *     The engine compensation color.
+   *   compensation ::
+   *     The engine compensation.
    *
    * @Return:
    *   Rounded distance.
@@ -2004,10 +1816,10 @@
   static FT_F26Dot6
   Round_Down_To_Grid( TT_ExecContext  exc,
                       FT_F26Dot6      distance,
-                      FT_Int          color )
+                      FT_F26Dot6      compensation )
   {
-    FT_F26Dot6  compensation = exc->tt_metrics.compensations[color];
     FT_F26Dot6  val;
+    FT_UNUSED( exc );
 
 
     if ( distance >= 0 )
@@ -2039,8 +1851,8 @@
    *   distance ::
    *     The distance to round.
    *
-   *   color ::
-   *     The engine compensation color.
+   *   compensation ::
+   *     The engine compensation.
    *
    * @Return:
    *   Rounded distance.
@@ -2048,10 +1860,10 @@
   static FT_F26Dot6
   Round_Up_To_Grid( TT_ExecContext  exc,
                     FT_F26Dot6      distance,
-                    FT_Int          color )
+                    FT_F26Dot6      compensation )
   {
-    FT_F26Dot6  compensation = exc->tt_metrics.compensations[color];
     FT_F26Dot6  val;
+    FT_UNUSED( exc );
 
 
     if ( distance >= 0 )
@@ -2084,8 +1896,8 @@
    *   distance ::
    *     The distance to round.
    *
-   *   color ::
-   *     The engine compensation color.
+   *   compensation ::
+   *     The engine compensation.
    *
    * @Return:
    *   Rounded distance.
@@ -2093,10 +1905,10 @@
   static FT_F26Dot6
   Round_To_Double_Grid( TT_ExecContext  exc,
                         FT_F26Dot6      distance,
-                        FT_Int          color )
+                        FT_F26Dot6      compensation )
   {
-    FT_F26Dot6  compensation = exc->tt_metrics.compensations[color];
     FT_F26Dot6  val;
+    FT_UNUSED( exc );
 
 
     if ( distance >= 0 )
@@ -2129,8 +1941,8 @@
    *   distance ::
    *     The distance to round.
    *
-   *   color ::
-   *     The engine compensation color.
+   *   compensation ::
+   *     The engine compensation.
    *
    * @Return:
    *   Rounded distance.
@@ -2144,9 +1956,8 @@
   static FT_F26Dot6
   Round_Super( TT_ExecContext  exc,
                FT_F26Dot6      distance,
-               FT_Int          color )
+               FT_F26Dot6      compensation )
   {
-    FT_F26Dot6  compensation = exc->tt_metrics.compensations[color];
     FT_F26Dot6  val;
 
 
@@ -2185,8 +1996,8 @@
    *   distance ::
    *     The distance to round.
    *
-   *   color ::
-   *     The engine compensation color.
+   *   compensation ::
+   *     The engine compensation.
    *
    * @Return:
    *   Rounded distance.
@@ -2198,9 +2009,8 @@
   static FT_F26Dot6
   Round_Super_45( TT_ExecContext  exc,
                   FT_F26Dot6      distance,
-                  FT_Int          color )
+                  FT_F26Dot6      compensation )
   {
-    FT_F26Dot6  compensation = exc->tt_metrics.compensations[color];
     FT_F26Dot6  val;
 
 
@@ -2227,59 +2037,6 @@
   }
 
 
-  /**************************************************************************
-   *
-   * @Function:
-   *   Compute_Round
-   *
-   * @Description:
-   *   Sets the rounding mode.
-   *
-   * @Input:
-   *   round_mode ::
-   *     The rounding mode to be used.
-   */
-  static void
-  Compute_Round( TT_ExecContext  exc,
-                 FT_Byte         round_mode )
-  {
-    switch ( round_mode )
-    {
-    case TT_Round_Off:
-      exc->func_round = (TT_Round_Func)Round_None;
-      break;
-
-    case TT_Round_To_Grid:
-      exc->func_round = (TT_Round_Func)Round_To_Grid;
-      break;
-
-    case TT_Round_Up_To_Grid:
-      exc->func_round = (TT_Round_Func)Round_Up_To_Grid;
-      break;
-
-    case TT_Round_Down_To_Grid:
-      exc->func_round = (TT_Round_Func)Round_Down_To_Grid;
-      break;
-
-    case TT_Round_To_Half_Grid:
-      exc->func_round = (TT_Round_Func)Round_To_Half_Grid;
-      break;
-
-    case TT_Round_To_Double_Grid:
-      exc->func_round = (TT_Round_Func)Round_To_Double_Grid;
-      break;
-
-    case TT_Round_Super:
-      exc->func_round = (TT_Round_Func)Round_Super;
-      break;
-
-    case TT_Round_Super_45:
-      exc->func_round = (TT_Round_Func)Round_Super_45;
-      break;
-    }
-  }
-
-
   /**************************************************************************
    *
    * @Function:
@@ -2481,14 +2238,45 @@
   static void
   Compute_Funcs( TT_ExecContext  exc )
   {
-    if ( exc->GS.freeVector.x == 0x4000 )
-      exc->F_dot_P = exc->GS.projVector.x;
-    else if ( exc->GS.freeVector.y == 0x4000 )
-      exc->F_dot_P = exc->GS.projVector.y;
+    FT_Long  F_dot_P =
+             ( (FT_Long)exc->GS.projVector.x * exc->GS.freeVector.x +
+               (FT_Long)exc->GS.projVector.y * exc->GS.freeVector.y +
+               0x2000L ) >> 14;
+
+
+    if ( F_dot_P >= 0x3FFEL )
+    {
+      /* commonly collinear */
+      exc->moveVector.x = exc->GS.freeVector.x * 4;
+      exc->moveVector.y = exc->GS.freeVector.y * 4;
+    }
+    else if ( -0x400L < F_dot_P && F_dot_P < 0x400L )
+    {
+      /* prohibitively orthogonal */
+      exc->moveVector.x = 0;
+      exc->moveVector.y = 0;
+    }
+    else
+    {
+      exc->moveVector.x = exc->GS.freeVector.x * 0x10000L / F_dot_P;
+      exc->moveVector.y = exc->GS.freeVector.y * 0x10000L / F_dot_P;
+    }
+
+    if ( F_dot_P >= 0x3FFEL && exc->GS.freeVector.x == 0x4000 )
+    {
+      exc->func_move      = (TT_Move_Func)Direct_Move_X;
+      exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
+    }
+    else if ( F_dot_P >= 0x3FFEL && exc->GS.freeVector.y == 0x4000 )
+    {
+      exc->func_move      = (TT_Move_Func)Direct_Move_Y;
+      exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
+    }
     else
-      exc->F_dot_P =
-        ( (FT_Long)exc->GS.projVector.x * exc->GS.freeVector.x +
-          (FT_Long)exc->GS.projVector.y * exc->GS.freeVector.y ) >> 14;
+    {
+      exc->func_move      = (TT_Move_Func)Direct_Move;
+      exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig;
+    }
 
     if ( exc->GS.projVector.x == 0x4000 )
       exc->func_project = (TT_Project_Func)Project_x;
@@ -2504,29 +2292,6 @@
     else
       exc->func_dualproj = (TT_Project_Func)Dual_Project;
 
-    exc->func_move      = (TT_Move_Func)Direct_Move;
-    exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig;
-
-    if ( exc->F_dot_P == 0x4000L )
-    {
-      if ( exc->GS.freeVector.x == 0x4000 )
-      {
-        exc->func_move      = (TT_Move_Func)Direct_Move_X;
-        exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
-      }
-      else if ( exc->GS.freeVector.y == 0x4000 )
-      {
-        exc->func_move      = (TT_Move_Func)Direct_Move_Y;
-        exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
-      }
-    }
-
-    /* at small sizes, F_dot_P can become too small, resulting   */
-    /* in overflows and `spikes' in a number of glyphs like `w'. */
-
-    if ( FT_ABS( exc->F_dot_P ) < 0x400L )
-      exc->F_dot_P = 0x4000L;
-
     /* Disable cached aspect ratio */
     exc->tt_metrics.ratio = 0;
   }
@@ -2799,7 +2564,7 @@
   Ins_ODD( TT_ExecContext  exc,
            FT_Long*        args )
   {
-    args[0] = ( ( exc->func_round( exc, args[0], 3 ) & 127 ) == 64 );
+    args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 64 ) == 64 );
   }
 
 
@@ -2813,7 +2578,7 @@
   Ins_EVEN( TT_ExecContext  exc,
             FT_Long*        args )
   {
-    args[0] = ( ( exc->func_round( exc, args[0], 3 ) & 127 ) == 0 );
+    args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 64 ) == 0 );
   }
 
 
@@ -3020,7 +2785,7 @@
         FT_MEM_QRENEW_ARRAY( exc->glyfStorage,
                              exc->glyfStoreSize,
                              exc->storeSize );
-        exc->error  = error;
+        exc->error = error;
         if ( error )
           return;
 
@@ -3143,7 +2908,8 @@
   Ins_ROUND( TT_ExecContext  exc,
              FT_Long*        args )
   {
-    args[0] = exc->func_round( exc, args[0], exc->opcode & 3 );
+    args[0] = exc->func_round( exc, args[0],
+                               exc->GS.compensation[exc->opcode & 3] );
   }
 
 
@@ -3157,7 +2923,8 @@
   Ins_NROUND( TT_ExecContext  exc,
               FT_Long*        args )
   {
-    args[0] = Round_None( exc, args[0], exc->opcode & 3 );
+    args[0] = Round_None( exc, args[0],
+                          exc->GS.compensation[exc->opcode & 3] );
   }
 
 
@@ -3211,13 +2978,11 @@
     }
     else
     {
-      K = exc->stack[exc->args - L];
+      K = args[-L];
 
-      FT_ARRAY_MOVE( &exc->stack[exc->args - L    ],
-                     &exc->stack[exc->args - L + 1],
-                     ( L - 1 ) );
+      FT_ARRAY_MOVE( args - L, args - L + 1, L - 1 );
 
-      exc->stack[exc->args - 1] = K;
+      args[-1] = K;
     }
   }
 
@@ -3244,7 +3009,7 @@
       args[0] = 0;
     }
     else
-      args[0] = exc->stack[exc->args - L];
+      args[0] = args[-L];
   }
 
 
@@ -3314,8 +3079,7 @@
         exc->length = 2 - exc->length * exc->code[exc->IP + 1];
       }
 
-      if ( exc->IP + exc->length <= exc->codeSize )
-        return SUCCESS;
+      return SUCCESS;
     }
 
   Fail_Overflow:
@@ -3363,6 +3127,9 @@
         nIfs--;
         Out = FT_BOOL( nIfs == 0 );
         break;
+
+      default:
+        break;
       }
     } while ( Out == 0 );
   }
@@ -3396,6 +3163,9 @@
       case 0x59:    /* EIF */
         nIfs--;
         break;
+
+      default:
+        break;
       }
     } while ( nIfs != 0 );
   }
@@ -3439,7 +3209,7 @@
       return;
     }
 
-    exc->step_ins = FALSE;
+    exc->length = 0;
 
     if ( args[0] < 0 )
     {
@@ -3540,10 +3310,10 @@
       return;
     }
 
-    rec->range          = exc->curRange;
-    rec->opc            = (FT_UInt16)n;
-    rec->start          = exc->IP + 1;
-    rec->active         = TRUE;
+    rec->range  = exc->curRange;
+    rec->opc    = (FT_UInt16)n;
+    rec->start  = exc->IP + 1;
+    rec->active = TRUE;
 
     if ( n > exc->maxFunc )
       exc->maxFunc = (FT_UInt16)n;
@@ -3555,14 +3325,17 @@
     {
       switch ( exc->opcode )
       {
-      case 0x89:    /* IDEF */
-      case 0x2C:    /* FDEF */
+      case 0x89:   /* IDEF */
+      case 0x2C:   /* FDEF */
         exc->error = FT_THROW( Nested_DEFS );
         return;
 
       case 0x2D:   /* ENDF */
         rec->end = exc->IP;
         return;
+
+      default:
+        break;
       }
     }
   }
@@ -3592,12 +3365,11 @@
 
     pRec->Cur_Count--;
 
-    exc->step_ins = FALSE;
-
     if ( pRec->Cur_Count > 0 )
     {
       exc->callTop++;
-      exc->IP = pRec->Def->start;
+      exc->IP     = pRec->Def->start;
+      exc->length = 0;
     }
     else
       /* Loop through the current function */
@@ -3685,8 +3457,6 @@
 
     Ins_Goto_CodeRange( exc, def->range, def->start );
 
-    exc->step_ins = FALSE;
-
     return;
 
   Fail:
@@ -3764,8 +3534,6 @@
 
       Ins_Goto_CodeRange( exc, def->range, def->start );
 
-      exc->step_ins = FALSE;
-
       exc->loopcall_counter += (FT_ULong)args[0];
       if ( exc->loopcall_counter > exc->loopcall_counter_max )
         exc->error = FT_THROW( Execution_Too_Long );
@@ -3845,9 +3613,13 @@
       case 0x2C:   /* FDEF */
         exc->error = FT_THROW( Nested_DEFS );
         return;
+
       case 0x2D:   /* ENDF */
         def->end = exc->IP;
         return;
+
+      default:
+        break;
       }
     }
   }
@@ -3870,10 +3642,23 @@
   Ins_NPUSHB( TT_ExecContext  exc,
               FT_Long*        args )
   {
-    FT_UShort  L, K;
+    FT_Long  IP = exc->IP;
+    FT_Int   L, K;
+
 
+    if ( ++IP >= exc->codeSize )
+    {
+      exc->error = FT_THROW( Code_Overflow );
+      return;
+    }
 
-    L = (FT_UShort)exc->code[exc->IP + 1];
+    L = exc->code[IP];
+
+    if ( IP + L >= exc->codeSize )
+    {
+      exc->error = FT_THROW( Code_Overflow );
+      return;
+    }
 
     if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
     {
@@ -3881,10 +3666,11 @@
       return;
     }
 
-    for ( K = 1; K <= L; K++ )
-      args[K - 1] = exc->code[exc->IP + K + 1];
+    for ( K = 0; K < L; K++ )
+      args[K] = exc->code[++IP];
 
     exc->new_top += L;
+    exc->IP       = IP;
   }
 
 
@@ -3898,10 +3684,23 @@
   Ins_NPUSHW( TT_ExecContext  exc,
               FT_Long*        args )
   {
-    FT_UShort  L, K;
+    FT_Long  IP = exc->IP;
+    FT_Int   L, K;
 
 
-    L = (FT_UShort)exc->code[exc->IP + 1];
+    if ( ++IP >= exc->codeSize )
+    {
+      exc->error = FT_THROW( Code_Overflow );
+      return;
+    }
+
+    L = exc->code[IP];
+
+    if ( IP + 2 * L >= exc->codeSize )
+    {
+      exc->error = FT_THROW( Code_Overflow );
+      return;
+    }
 
     if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
     {
@@ -3909,13 +3708,12 @@
       return;
     }
 
-    exc->IP += 2;
+    /* note casting for sign-extension */
+    for ( K = 0; K < L; K++, IP += 2 )
+      args[K] = (FT_Short)( exc->code[IP + 1] << 8 ) | exc->code[IP + 2];
 
-    for ( K = 0; K < L; K++ )
-      args[K] = GetShortIns( exc );
-
-    exc->step_ins = FALSE;
     exc->new_top += L;
+    exc->IP       = IP;
   }
 
 
@@ -3929,10 +3727,17 @@
   Ins_PUSHB( TT_ExecContext  exc,
              FT_Long*        args )
   {
-    FT_UShort  L, K;
+    FT_Long  IP = exc->IP;
+    FT_Int   L, K;
 
 
-    L = (FT_UShort)( exc->opcode - 0xB0 + 1 );
+    L = exc->opcode - 0xB0 + 1;
+
+    if ( IP + L >= exc->codeSize )
+    {
+      exc->error = FT_THROW( Code_Overflow );
+      return;
+    }
 
     if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
     {
@@ -3940,8 +3745,10 @@
       return;
     }
 
-    for ( K = 1; K <= L; K++ )
-      args[K - 1] = exc->code[exc->IP + K];
+    for ( K = 0; K < L; K++ )
+      args[K] = exc->code[++IP];
+
+    exc->IP = IP;
   }
 
 
@@ -3955,10 +3762,17 @@
   Ins_PUSHW( TT_ExecContext  exc,
              FT_Long*        args )
   {
-    FT_UShort  L, K;
+    FT_Long  IP = exc->IP;
+    FT_Int   L, K;
+
 
+    L = exc->opcode - 0xB8 + 1;
 
-    L = (FT_UShort)( exc->opcode - 0xB8 + 1 );
+    if ( IP + 2 * L >= exc->codeSize )
+    {
+      exc->error = FT_THROW( Code_Overflow );
+      return;
+    }
 
     if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
     {
@@ -3966,12 +3780,11 @@
       return;
     }
 
-    exc->IP++;
+    /* note casting for sign-extension */
+    for ( K = 0; K < L; K++, IP += 2 )
+      args[K] = (FT_Short)( exc->code[IP + 1] << 8 ) | exc->code[IP + 2];
 
-    for ( K = 0; K < L; K++ )
-      args[K] = GetShortIns( exc );
-
-    exc->step_ins = FALSE;
+    exc->IP = IP;
   }
 
 
@@ -4142,15 +3955,12 @@
   Ins_SPVFS( TT_ExecContext  exc,
              FT_Long*        args )
   {
-    FT_Short  S;
     FT_Long   X, Y;
 
 
     /* Only use low 16bits, then sign extend */
-    S = (FT_Short)args[1];
-    Y = (FT_Long)S;
-    S = (FT_Short)args[0];
-    X = (FT_Long)S;
+    Y = (FT_Short)args[1];
+    X = (FT_Short)args[0];
 
     Normalize( X, Y, &exc->GS.projVector );
 
@@ -4169,15 +3979,12 @@
   Ins_SFVFS( TT_ExecContext  exc,
              FT_Long*        args )
   {
-    FT_Short  S;
     FT_Long   X, Y;
 
 
     /* Only use low 16bits, then sign extend */
-    S = (FT_Short)args[1];
-    Y = (FT_Long)S;
-    S = (FT_Short)args[0];
-    X = S;
+    Y = (FT_Short)args[1];
+    X = (FT_Short)args[0];
 
     Normalize( X, Y, &exc->GS.freeVector );
     Compute_Funcs( exc );
@@ -4915,7 +4722,7 @@
       /* compatibility hacks and lets them program points to the grid like */
       /* it's 1996.  They might sign a waiver for just one glyph, though.  */
       if ( SUBPIXEL_HINTING_MINIMAL )
-        exc->backward_compatibility = !FT_BOOL( L == 4 );
+        exc->backward_compatibility = ( L & 4 ) ^ 4;
 #endif
     }
     else if ( exc->pedantic_hinting )
@@ -4999,32 +4806,31 @@
    * Stack:        uint32... -->
    */
   static void
-  Ins_FLIPPT( TT_ExecContext  exc )
+  Ins_FLIPPT( TT_ExecContext  exc,
+              FT_Long*        args )
   {
+    FT_Long    loop = exc->GS.loop;
     FT_UShort  point;
 
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-    /* See `ttinterp.h' for details on backward compatibility mode. */
-    if ( SUBPIXEL_HINTING_MINIMAL    &&
-         exc->backward_compatibility &&
-         exc->iupx_called            &&
-         exc->iupy_called            )
-      goto Fail;
-#endif
-
-    if ( exc->top < exc->GS.loop )
+    if ( exc->new_top < loop )
     {
       if ( exc->pedantic_hinting )
         exc->error = FT_THROW( Too_Few_Arguments );
       goto Fail;
     }
 
-    while ( exc->GS.loop > 0 )
-    {
-      exc->args--;
+    exc->new_top -= loop;
 
-      point = (FT_UShort)exc->stack[exc->args];
+#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
+    /* See `ttinterp.h' for details on backward compatibility mode. */
+    if ( exc->backward_compatibility == 0x7 )
+      goto Fail;
+#endif
+
+    while ( loop-- )
+    {
+      point = (FT_UShort)*(--args);
 
       if ( BOUNDS( point, exc->pts.n_points ) )
       {
@@ -5036,13 +4842,10 @@
       }
       else
         exc->pts.tags[point] ^= FT_CURVE_TAG_ON;
-
-      exc->GS.loop--;
     }
 
   Fail:
     exc->GS.loop = 1;
-    exc->new_top = exc->args;
   }
 
 
@@ -5061,10 +4864,7 @@
 
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
     /* See `ttinterp.h' for details on backward compatibility mode. */
-    if ( SUBPIXEL_HINTING_MINIMAL    &&
-         exc->backward_compatibility &&
-         exc->iupx_called            &&
-         exc->iupy_called            )
+    if ( exc->backward_compatibility == 0x7 )
       return;
 #endif
 
@@ -5099,10 +4899,7 @@
 
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
     /* See `ttinterp.h' for details on backward compatibility mode. */
-    if ( SUBPIXEL_HINTING_MINIMAL    &&
-         exc->backward_compatibility &&
-         exc->iupx_called            &&
-         exc->iupy_called            )
+    if ( exc->backward_compatibility == 0x7 )
       return;
 #endif
 
@@ -5158,8 +4955,8 @@
 
     d = PROJECT( zp.cur + p, zp.org + p );
 
-    *x = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.x, exc->F_dot_P );
-    *y = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.y, exc->F_dot_P );
+    *x = FT_MulFix( d, exc->moveVector.x );
+    *y = FT_MulFix( d, exc->moveVector.y );
 
     return SUCCESS;
   }
@@ -5176,8 +4973,8 @@
     if ( exc->GS.freeVector.x != 0 )
     {
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-      if ( !( SUBPIXEL_HINTING_MINIMAL    &&
-              exc->backward_compatibility ) )
+      /* See `ttinterp.h' for details on backward compatibility mode. */
+      if ( !exc->backward_compatibility )
 #endif
         exc->zp2.cur[point].x = ADD_LONG( exc->zp2.cur[point].x, dx );
 
@@ -5188,10 +4985,8 @@
     if ( exc->GS.freeVector.y != 0 )
     {
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-      if ( !( SUBPIXEL_HINTING_MINIMAL    &&
-              exc->backward_compatibility &&
-              exc->iupx_called            &&
-              exc->iupy_called            ) )
+      /* See `ttinterp.h' for details on backward compatibility mode. */
+      if ( exc->backward_compatibility != 0x7 )
 #endif
         exc->zp2.cur[point].y = ADD_LONG( exc->zp2.cur[point].y, dy );
 
@@ -5208,8 +5003,10 @@
    * Stack:        uint32... -->
    */
   static void
-  Ins_SHP( TT_ExecContext  exc )
+  Ins_SHP( TT_ExecContext  exc,
+           FT_Long*        args )
   {
+    FT_Long          loop = exc->GS.loop;
     TT_GlyphZoneRec  zp;
     FT_UShort        refp;
 
@@ -5217,20 +5014,21 @@
     FT_UShort        point;
 
 
-    if ( exc->top < exc->GS.loop )
+    if ( exc->new_top < loop )
     {
       if ( exc->pedantic_hinting )
-        exc->error = FT_THROW( Invalid_Reference );
+        exc->error = FT_THROW( Too_Few_Arguments );
       goto Fail;
     }
 
+    exc->new_top -= loop;
+
     if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) )
       return;
 
-    while ( exc->GS.loop > 0 )
+    while ( loop-- )
     {
-      exc->args--;
-      point = (FT_UShort)exc->stack[exc->args];
+      point = (FT_UShort)*(--args);
 
       if ( BOUNDS( point, exc->zp2.n_points ) )
       {
@@ -5242,13 +5040,10 @@
       }
       else
         Move_Zp2_Point( exc, point, dx, dy, TRUE );
-
-      exc->GS.loop--;
     }
 
   Fail:
     exc->GS.loop = 1;
-    exc->new_top = exc->args;
   }
 
 
@@ -5364,6 +5159,7 @@
   Ins_SHPIX( TT_ExecContext  exc,
              FT_Long*        args )
   {
+    FT_Long     loop = exc->GS.loop;
     FT_F26Dot6  dx, dy;
     FT_UShort   point;
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
@@ -5373,22 +5169,21 @@
 #endif
 
 
-
-    if ( exc->top < exc->GS.loop + 1 )
+    if ( exc->new_top < loop )
     {
       if ( exc->pedantic_hinting )
-        exc->error = FT_THROW( Invalid_Reference );
+        exc->error = FT_THROW( Too_Few_Arguments );
       goto Fail;
     }
 
+    exc->new_top -= loop;
+
     dx = TT_MulFix14( args[0], exc->GS.freeVector.x );
     dy = TT_MulFix14( args[0], exc->GS.freeVector.y );
 
-    while ( exc->GS.loop > 0 )
+    while ( loop-- )
     {
-      exc->args--;
-
-      point = (FT_UShort)exc->stack[exc->args];
+      point = (FT_UShort)*(--args);
 
       if ( BOUNDS( point, exc->zp2.n_points ) )
       {
@@ -5400,8 +5195,7 @@
       }
       else
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-      if ( SUBPIXEL_HINTING_MINIMAL    &&
-           exc->backward_compatibility )
+      if ( exc->backward_compatibility )
       {
         /* Special case: allow SHPIX to move points in the twilight zone.  */
         /* Otherwise, treat SHPIX the same as DELTAP.  Unbreaks various    */
@@ -5409,7 +5203,7 @@
         /* that would glitch severely after calling ALIGNRP after a        */
         /* blocked SHPIX.                                                  */
         if ( in_twilight                                                ||
-             ( !( exc->iupx_called && exc->iupy_called )              &&
+             ( exc->backward_compatibility != 0x7                     &&
                ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
                  ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y )    ) ) )
           Move_Zp2_Point( exc, point, 0, dy, TRUE );
@@ -5417,13 +5211,10 @@
       else
 #endif
         Move_Zp2_Point( exc, point, dx, dy, TRUE );
-
-      exc->GS.loop--;
     }
 
   Fail:
     exc->GS.loop = 1;
-    exc->new_top = exc->args;
   }
 
 
@@ -5502,7 +5293,7 @@
     if ( ( exc->opcode & 1 ) != 0 )
     {
       cur_dist = FAST_PROJECT( &exc->zp0.cur[point] );
-      distance = SUB_LONG( exc->func_round( exc, cur_dist, 3 ), cur_dist );
+      distance = SUB_LONG( exc->func_round( exc, cur_dist, 0 ), cur_dist );
     }
     else
       distance = 0;
@@ -5566,7 +5357,7 @@
     if ( exc->GS.gep0 == 0 )   /* If in twilight zone */
     {
       exc->zp0.org[point].x = TT_MulFix14( distance,
-                                             exc->GS.freeVector.x );
+                                           exc->GS.freeVector.x );
       exc->zp0.org[point].y = TT_MulFix14( distance,
                                            exc->GS.freeVector.y );
       exc->zp0.cur[point]   = exc->zp0.org[point];
@@ -5587,7 +5378,7 @@
       if ( delta > control_value_cutin )
         distance = org_dist;
 
-      distance = exc->func_round( exc, distance, 3 );
+      distance = exc->func_round( exc, distance, 0 );
     }
 
     exc->func_move( exc, &exc->zp0, point, SUB_LONG( distance, org_dist ) );
@@ -5609,7 +5400,7 @@
             FT_Long*        args )
   {
     FT_UShort   point = 0;
-    FT_F26Dot6  org_dist, distance;
+    FT_F26Dot6  org_dist, distance, compensation;
 
 
     point = (FT_UShort)args[0];
@@ -5664,11 +5455,11 @@
     /* single width cut-in test */
 
     /* |org_dist - single_width_value| < single_width_cutin */
-    if ( exc->GS.single_width_cutin > 0          &&
-         org_dist < exc->GS.single_width_value +
-                      exc->GS.single_width_cutin &&
-         org_dist > exc->GS.single_width_value -
-                      exc->GS.single_width_cutin )
+    if ( exc->GS.single_width_cutin > 0                    &&
+         org_dist < ADD_LONG( exc->GS.single_width_value,
+                              exc->GS.single_width_cutin ) &&
+         org_dist > SUB_LONG( exc->GS.single_width_value,
+                              exc->GS.single_width_cutin ) )
     {
       if ( org_dist >= 0 )
         org_dist = exc->GS.single_width_value;
@@ -5678,12 +5469,12 @@
 
     /* round flag */
 
+    compensation = exc->GS.compensation[exc->opcode & 3];
+
     if ( ( exc->opcode & 4 ) != 0 )
-    {
-      distance = exc->func_round( exc, org_dist, exc->opcode & 3 );
-    }
+      distance = exc->func_round( exc, org_dist, compensation );
     else
-      distance = Round_None( exc, org_dist, exc->opcode & 3 );
+      distance = Round_None( exc, org_dist, compensation );
 
     /* minimum distance flag */
 
@@ -5735,7 +5526,8 @@
     FT_F26Dot6  cvt_dist,
                 distance,
                 cur_dist,
-                org_dist;
+                org_dist,
+                compensation;
 
     FT_F26Dot6  delta;
 
@@ -5801,6 +5593,8 @@
 
     /* control value cut-in and round */
 
+    compensation = exc->GS.compensation[exc->opcode & 3];
+
     if ( ( exc->opcode & 4 ) != 0 )
     {
       /* XXX: UNDOCUMENTED!  Only perform cut-in test when both points */
@@ -5831,16 +5625,16 @@
           cvt_dist = org_dist;
       }
 
-      distance = exc->func_round( exc, cvt_dist, exc->opcode & 3 );
+      distance = exc->func_round( exc, cvt_dist, compensation );
     }
     else
-      distance = Round_None( exc, cvt_dist, exc->opcode & 3 );
+      distance = Round_None( exc, cvt_dist, compensation );
 
     /* minimum distance test */
 
     if ( ( exc->opcode & 8 ) != 0 )
     {
-      FT_F26Dot6  minimum_distance    = exc->GS.minimum_distance;
+      FT_F26Dot6  minimum_distance = exc->GS.minimum_distance;
 
 
       if ( org_dist >= 0 )
@@ -5862,11 +5656,10 @@
 
   Fail:
     exc->GS.rp1 = exc->GS.rp0;
+    exc->GS.rp2 = point;
 
     if ( ( exc->opcode & 16 ) != 0 )
       exc->GS.rp0 = point;
-
-    exc->GS.rp2 = point;
   }
 
 
@@ -5877,25 +5670,33 @@
    * Stack:        uint32 uint32... -->
    */
   static void
-  Ins_ALIGNRP( TT_ExecContext  exc )
+  Ins_ALIGNRP( TT_ExecContext  exc,
+               FT_Long*        args )
   {
+    FT_Long     loop = exc->GS.loop;
     FT_UShort   point;
     FT_F26Dot6  distance;
 
 
-    if ( exc->top < exc->GS.loop                  ||
-         BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
+    if ( exc->new_top < loop )
     {
       if ( exc->pedantic_hinting )
-        exc->error = FT_THROW( Invalid_Reference );
+        exc->error = FT_THROW( Too_Few_Arguments );
       goto Fail;
     }
 
-    while ( exc->GS.loop > 0 )
+    exc->new_top -= loop;
+
+    if ( BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
     {
-      exc->args--;
+      if ( exc->pedantic_hinting )
+        exc->error = FT_THROW( Invalid_Reference );
+      goto Fail;
+    }
 
-      point = (FT_UShort)exc->stack[exc->args];
+    while ( loop-- )
+    {
+      point = (FT_UShort)*(--args);
 
       if ( BOUNDS( point, exc->zp1.n_points ) )
       {
@@ -5912,13 +5713,10 @@
 
         exc->func_move( exc, &exc->zp1, point, NEG_LONG( distance ) );
       }
-
-      exc->GS.loop--;
     }
 
   Fail:
     exc->GS.loop = 1;
-    exc->new_top = exc->args;
   }
 
 
@@ -6060,15 +5858,26 @@
   /* SOMETIMES, DUMBER CODE IS BETTER CODE */
 
   static void
-  Ins_IP( TT_ExecContext  exc )
+  Ins_IP( TT_ExecContext  exc,
+          FT_Long*        args )
   {
+    FT_Long     loop = exc->GS.loop;
     FT_F26Dot6  old_range, cur_range;
     FT_Vector*  orus_base;
     FT_Vector*  cur_base;
     FT_Int      twilight;
 
 
-    if ( exc->top < exc->GS.loop )
+    if ( exc->new_top < loop )
+    {
+      if ( exc->pedantic_hinting )
+        exc->error = FT_THROW( Too_Few_Arguments );
+      goto Fail;
+    }
+
+    exc->new_top -= loop;
+
+    if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) )
     {
       if ( exc->pedantic_hinting )
         exc->error = FT_THROW( Invalid_Reference );
@@ -6084,13 +5893,6 @@
                  exc->GS.gep1 == 0 ||
                  exc->GS.gep2 == 0 );
 
-    if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) )
-    {
-      if ( exc->pedantic_hinting )
-        exc->error = FT_THROW( Invalid_Reference );
-      goto Fail;
-    }
-
     if ( twilight )
       orus_base = &exc->zp0.org[exc->GS.rp1];
     else
@@ -6102,8 +5904,7 @@
     /*      fonts out there (e.g. [aeu]grave in monotype.ttf)   */
     /*      calling IP[] with bad values of rp[12].             */
     /*      Do something sane when this odd thing happens.      */
-    if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) ||
-         BOUNDS( exc->GS.rp2, exc->zp1.n_points ) )
+    if ( BOUNDS( exc->GS.rp2, exc->zp1.n_points ) )
     {
       old_range = 0;
       cur_range = 0;
@@ -6132,9 +5933,9 @@
       cur_range = PROJECT( &exc->zp1.cur[exc->GS.rp2], cur_base );
     }
 
-    for ( ; exc->GS.loop > 0; exc->GS.loop-- )
+    while ( loop-- )
     {
-      FT_UInt     point = (FT_UInt)exc->stack[--exc->args];
+      FT_UInt     point = (FT_UInt)*(--args);
       FT_F26Dot6  org_dist, cur_dist, new_dist;
 
 
@@ -6206,7 +6007,6 @@
 
   Fail:
     exc->GS.loop = 1;
-    exc->new_top = exc->args;
   }
 
 
@@ -6405,17 +6205,10 @@
     /* See `ttinterp.h' for details on backward compatibility mode.  */
     /* Allow IUP until it has been called on both axes.  Immediately */
     /* return on subsequent ones.                                    */
-    if ( SUBPIXEL_HINTING_MINIMAL    &&
-         exc->backward_compatibility )
-    {
-      if ( exc->iupx_called && exc->iupy_called )
-        return;
-
-      if ( exc->opcode & 1 )
-        exc->iupx_called = TRUE;
-      else
-        exc->iupy_called = TRUE;
-    }
+    if ( exc->backward_compatibility == 0x7 )
+      return;
+    else if ( exc->backward_compatibility )
+      exc->backward_compatibility |= 1 << ( exc->opcode & 1 );
 #endif
 
     /* ignore empty outlines */
@@ -6507,30 +6300,50 @@
   Ins_DELTAP( TT_ExecContext  exc,
               FT_Long*        args )
   {
-    FT_ULong   nump, k;
+    FT_Long    nump;
     FT_UShort  A;
-    FT_ULong   C, P;
-    FT_Long    B;
+    FT_Long    B, P, F;
 
 
-    P    = (FT_ULong)exc->func_cur_ppem( exc );
-    nump = (FT_ULong)args[0];   /* some points theoretically may occur more
-                                   than once, thus UShort isn't enough */
+    nump = args[0];  /* signed value for convenience */
 
-    for ( k = 1; k <= nump; k++ )
+    if ( nump < 0 || nump > exc->new_top / 2 )
     {
-      if ( exc->args < 2 )
-      {
-        if ( exc->pedantic_hinting )
-          exc->error = FT_THROW( Too_Few_Arguments );
-        exc->args = 0;
-        goto Fail;
-      }
+      if ( exc->pedantic_hinting )
+        exc->error = FT_THROW( Too_Few_Arguments );
+
+      nump = exc->new_top / 2;
+    }
+
+    exc->new_top -= 2 * nump;
+
+    P = exc->func_cur_ppem( exc ) - exc->GS.delta_base;
+
+    switch ( exc->opcode )
+    {
+    case 0x5D:
+      break;
+
+    case 0x71:
+      P -= 16;
+      break;
 
-      exc->args -= 2;
+    case 0x72:
+      P -= 32;
+      break;
+    }
 
-      A = (FT_UShort)exc->stack[exc->args + 1];
-      B = exc->stack[exc->args];
+    /* check applicable range of adjusted ppem */
+    if ( P & ~0xF )         /* P < 0 || P > 15 */
+      return;
+
+    P <<= 4;
+    F   = 1L << ( 6 - exc->GS.delta_shift );
+
+    while ( nump-- )
+    {
+      A = (FT_UShort)*(--args);
+      B = *(--args);
 
       /* XXX: Because some popular fonts contain some invalid DeltaP */
       /*      instructions, we simply ignore them when the stacked   */
@@ -6538,41 +6351,28 @@
       /*      error.  As a delta instruction doesn't change a glyph  */
       /*      in great ways, this shouldn't be a problem.            */
 
-      if ( !BOUNDS( A, exc->zp0.n_points ) )
+      if ( BOUNDS( A, exc->zp0.n_points ) )
       {
-        C = ( (FT_ULong)B & 0xF0 ) >> 4;
-
-        switch ( exc->opcode )
+        if ( exc->pedantic_hinting )
         {
-        case 0x5D:
-          break;
-
-        case 0x71:
-          C += 16;
-          break;
-
-        case 0x72:
-          C += 32;
-          break;
+          exc->error = FT_THROW( Invalid_Reference );
+          return;
         }
-
-        C += exc->GS.delta_base;
-
-        if ( P == C )
+      }
+      else
+      {
+        if ( ( B & 0xF0 ) == P )
         {
-          B = ( (FT_ULong)B & 0xF ) - 8;
+          B = ( B & 0xF ) - 8;
           if ( B >= 0 )
             B++;
-          B *= 1L << ( 6 - exc->GS.delta_shift );
-
+          B *= F;
 
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-          /* See `ttinterp.h' for details on backward compatibility */
-          /* mode.                                                  */
-          if ( SUBPIXEL_HINTING_MINIMAL    &&
-               exc->backward_compatibility )
+          /* See `ttinterp.h' for details on backward compatibility mode. */
+          if ( exc->backward_compatibility )
           {
-            if ( !( exc->iupx_called && exc->iupy_called )              &&
+            if ( exc->backward_compatibility != 0x7                     &&
                  ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
                    ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y )        ) )
               exc->func_move( exc, &exc->zp0, A, B );
@@ -6582,13 +6382,7 @@
             exc->func_move( exc, &exc->zp0, A, B );
         }
       }
-      else
-        if ( exc->pedantic_hinting )
-          exc->error = FT_THROW( Invalid_Reference );
     }
-
-  Fail:
-    exc->new_top = exc->args;
   }
 
 
@@ -6602,28 +6396,50 @@
   Ins_DELTAC( TT_ExecContext  exc,
               FT_Long*        args )
   {
-    FT_ULong  nump, k;
-    FT_ULong  A, C, P;
-    FT_Long   B;
+    FT_Long   nump;
+    FT_ULong  A;
+    FT_Long   B, P, F;
 
 
-    P    = (FT_ULong)exc->func_cur_ppem( exc );
-    nump = (FT_ULong)args[0];
+    nump = args[0];  /* signed value for convenience */
 
-    for ( k = 1; k <= nump; k++ )
+    if ( nump < 0 || nump > exc->new_top / 2 )
     {
-      if ( exc->args < 2 )
-      {
-        if ( exc->pedantic_hinting )
-          exc->error = FT_THROW( Too_Few_Arguments );
-        exc->args = 0;
-        goto Fail;
-      }
+      if ( exc->pedantic_hinting )
+        exc->error = FT_THROW( Too_Few_Arguments );
+
+      nump = exc->new_top / 2;
+    }
+
+    exc->new_top -= 2 * nump;
+
+    P = exc->func_cur_ppem( exc ) - exc->GS.delta_base;
+
+    switch ( exc->opcode )
+    {
+    case 0x73:
+      break;
 
-      exc->args -= 2;
+    case 0x74:
+      P -= 16;
+      break;
+
+    case 0x75:
+      P -= 32;
+      break;
+    }
+
+    /* check applicable range of adjusted ppem */
+    if ( P & ~0xF )         /* P < 0 || P > 15 */
+      return;
 
-      A = (FT_ULong)exc->stack[exc->args + 1];
-      B = exc->stack[exc->args];
+    P <<= 4;
+    F   = 1L << ( 6 - exc->GS.delta_shift );
+
+    while ( nump-- )
+    {
+      A = (FT_ULong)*(--args);
+      B = *(--args);
 
       if ( BOUNDSL( A, exc->cvtSize ) )
       {
@@ -6635,38 +6451,17 @@
       }
       else
       {
-        C = ( (FT_ULong)B & 0xF0 ) >> 4;
-
-        switch ( exc->opcode )
-        {
-        case 0x73:
-          break;
-
-        case 0x74:
-          C += 16;
-          break;
-
-        case 0x75:
-          C += 32;
-          break;
-        }
-
-        C += exc->GS.delta_base;
-
-        if ( P == C )
+        if ( ( B & 0xF0 ) == P )
         {
-          B = ( (FT_ULong)B & 0xF ) - 8;
+          B = ( B & 0xF ) - 8;
           if ( B >= 0 )
             B++;
-          B *= 1L << ( 6 - exc->GS.delta_shift );
+          B *= F;
 
           exc->func_move_cvt( exc, A, B );
         }
       }
     }
-
-  Fail:
-    exc->new_top = exc->args;
   }
 
 
@@ -6736,7 +6531,7 @@
     /* Otherwise, instructions may behave weirdly and rendering results */
     /* may differ between v35 and v40 mode, e.g., in `Times New Roman   */
     /* Bold Italic'. */
-    if ( SUBPIXEL_HINTING_MINIMAL && exc->subpixel_hinting_lean )
+    if ( SUBPIXEL_HINTING_MINIMAL && exc->mode != FT_RENDER_MODE_MONO )
     {
       /*********************************
        * HINTING FOR SUBPIXEL
@@ -6753,7 +6548,7 @@
        * Selector Bit:  8
        * Return Bit(s): 15
        */
-      if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd_lean )
+      if ( ( args[0] & 256 ) != 0 && exc->mode == FT_RENDER_MODE_LCD_V )
         K |= 1 << 15;
 
       /*********************************
@@ -6774,7 +6569,7 @@
        * The only smoothing method FreeType supports unless someone sets
        * FT_LOAD_TARGET_MONO.
        */
-      if ( ( args[0] & 2048 ) != 0 && exc->subpixel_hinting_lean )
+      if ( ( args[0] & 2048 ) != 0 && exc->mode != FT_RENDER_MODE_MONO )
         K |= 1 << 18;
 
       /*********************************
@@ -6786,7 +6581,10 @@
        * Grayscale rendering is what FreeType does anyway unless someone
        * sets FT_LOAD_TARGET_MONO or FT_LOAD_TARGET_LCD(_V)
        */
-      if ( ( args[0] & 4096 ) != 0 && exc->grayscale_cleartype )
+      if ( ( args[0] & 4096 ) != 0           &&
+           exc->mode != FT_RENDER_MODE_MONO  &&
+           exc->mode != FT_RENDER_MODE_LCD   &&
+           exc->mode != FT_RENDER_MODE_LCD_V )
         K |= 1 << 19;
     }
 #endif
@@ -6833,6 +6631,8 @@
       for ( i = 0; i < num_axes; i++ )
         args[i] = 0;
     }
+
+    exc->new_top += num_axes;
   }
 
 
@@ -6883,7 +6683,6 @@
 
         Ins_Goto_CodeRange( exc, def->range, def->start );
 
-        exc->step_ins = FALSE;
         return;
       }
     }
@@ -6928,96 +6727,22 @@
   TT_RunIns( void*  exec )
   {
     TT_ExecContext  exc = (TT_ExecContext)exec;
+    FT_ULong        ins_counter = 0;
 
-    FT_ULong   ins_counter = 0;  /* executed instructions counter */
-    FT_ULong   num_twilight_points;
-    FT_UShort  i;
-
-
-    /* We restrict the number of twilight points to a reasonable,     */
-    /* heuristic value to avoid slow execution of malformed bytecode. */
-    num_twilight_points = FT_MAX( 30,
-                                  2 * ( exc->pts.n_points + exc->cvtSize ) );
-    if ( exc->twilight.n_points > num_twilight_points )
-    {
-      if ( num_twilight_points > 0xFFFFU )
-        num_twilight_points = 0xFFFFU;
-
-      FT_TRACE5(( "TT_RunIns: Resetting number of twilight points\n" ));
-      FT_TRACE5(( "           from %d to the more reasonable value %ld\n",
-                  exc->twilight.n_points,
-                  num_twilight_points ));
-      exc->twilight.n_points = (FT_UShort)num_twilight_points;
-    }
-
-    /* Set up loop detectors.  We restrict the number of LOOPCALL loops */
-    /* and the number of JMPR, JROT, and JROF calls with a negative     */
-    /* argument to values that depend on various parameters like the    */
-    /* size of the CVT table or the number of points in the current     */
-    /* glyph (if applicable).                                           */
-    /*                                                                  */
-    /* The idea is that in real-world bytecode you either iterate over  */
-    /* all CVT entries (in the `prep' table), or over all points (or    */
-    /* contours, in the `glyf' table) of a glyph, and such iterations   */
-    /* don't happen very often.                                         */
-    exc->loopcall_counter = 0;
-    exc->neg_jump_counter = 0;
-
-    /* The maximum values are heuristic. */
-    if ( exc->pts.n_points )
-      exc->loopcall_counter_max = FT_MAX( 50,
-                                          10 * exc->pts.n_points ) +
-                                  FT_MAX( 50,
-                                          exc->cvtSize / 10 );
-    else
-      exc->loopcall_counter_max = 300 + 22 * exc->cvtSize;
-
-    /* as a protection against an unreasonable number of CVT entries  */
-    /* we assume at most 100 control values per glyph for the counter */
-    if ( exc->loopcall_counter_max >
-         100 * (FT_ULong)exc->face->root.num_glyphs )
-      exc->loopcall_counter_max = 100 * (FT_ULong)exc->face->root.num_glyphs;
-
-    FT_TRACE5(( "TT_RunIns: Limiting total number of loops in LOOPCALL"
-                " to %ld\n", exc->loopcall_counter_max ));
-
-    exc->neg_jump_counter_max = exc->loopcall_counter_max;
-    FT_TRACE5(( "TT_RunIns: Limiting total number of backward jumps"
-                " to %ld\n", exc->neg_jump_counter_max ));
-
-    /* set PPEM and CVT functions */
-    exc->tt_metrics.ratio = 0;
-    if ( exc->metrics.x_ppem != exc->metrics.y_ppem )
-    {
-      /* non-square pixels, use the stretched routines */
-      exc->func_cur_ppem  = Current_Ppem_Stretched;
-      exc->func_read_cvt  = Read_CVT_Stretched;
-      exc->func_write_cvt = Write_CVT_Stretched;
-      exc->func_move_cvt  = Move_CVT_Stretched;
-    }
-    else
-    {
-      /* square pixels, use normal routines */
-      exc->func_cur_ppem  = Current_Ppem;
-      exc->func_read_cvt  = Read_CVT;
-      exc->func_write_cvt = Write_CVT;
-      exc->func_move_cvt  = Move_CVT;
-    }
-
-    exc->iniRange    = exc->curRange;
-
-    Compute_Funcs( exc );
-    Compute_Round( exc, (FT_Byte)exc->GS.round_state );
-
-    /* These flags cancel execution of some opcodes after IUP is called */
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-    exc->iupx_called = FALSE;
-    exc->iupy_called = FALSE;
-#endif
 
     do
     {
+      /* increment instruction counter and check if we didn't */
+      /* run this program for too long (e.g. infinite loops). */
+      if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES )
+      {
+        exc->error = FT_THROW( Execution_Too_Long );
+        goto LErrorLabel_;
+      }
+
+      exc->error  = FT_Err_Ok;
       exc->opcode = exc->code[exc->IP];
+      exc->length = 1;
 
 #ifdef FT_DEBUG_LEVEL_TRACE
       if ( ft_trace_levels[trace_ttinterp] >= 6 )
@@ -7041,17 +6766,6 @@
       }
 #endif /* FT_DEBUG_LEVEL_TRACE */
 
-      if ( ( exc->length = opcode_length[exc->opcode] ) < 0 )
-      {
-        if ( exc->IP + 1 >= exc->codeSize )
-          goto LErrorCodeOverflow_;
-
-        exc->length = 2 - exc->length * exc->code[exc->IP + 1];
-      }
-
-      if ( exc->IP + exc->length > exc->codeSize )
-        goto LErrorCodeOverflow_;
-
       /* First, let's check for empty stack and overflow */
       exc->args = exc->top - ( Pop_Push_Count[exc->opcode] >> 4 );
 
@@ -7059,6 +6773,9 @@
       /* One can also interpret it as the index of the last argument.    */
       if ( exc->args < 0 )
       {
+        FT_UShort  i;
+
+
         if ( exc->pedantic_hinting )
         {
           exc->error = FT_THROW( Too_Few_Arguments );
@@ -7071,21 +6788,7 @@
         exc->args = 0;
       }
 
-#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-      if ( exc->opcode == 0x91 )
-      {
-        /* this is very special: GETVARIATION returns */
-        /* a variable number of arguments             */
-
-        /* it is the job of the application to `activate' GX handling, */
-        /* that is, calling any of the GX API functions on the current */
-        /* font to select a variation instance                         */
-        if ( exc->face->blend )
-          exc->new_top = exc->args + exc->face->blend->num_axis;
-      }
-      else
-#endif
-        exc->new_top = exc->args + ( Pop_Push_Count[exc->opcode] & 15 );
+      exc->new_top = exc->args + ( Pop_Push_Count[exc->opcode] & 15 );
 
       /* `new_top' is the new top of the stack, after the instruction's */
       /* execution.  `top' will be set to `new_top' after the `switch'  */
@@ -7096,9 +6799,6 @@
         goto LErrorLabel_;
       }
 
-      exc->step_ins = TRUE;
-      exc->error    = FT_Err_Ok;
-
       {
         FT_Long*  args   = exc->stack + exc->args;
         FT_Byte   opcode = exc->opcode;
@@ -7281,7 +6981,7 @@
 
         case 0x32:  /* SHP */
         case 0x33:  /* SHP */
-          Ins_SHP( exc );
+          Ins_SHP( exc, args );
           break;
 
         case 0x34:  /* SHC */
@@ -7299,7 +6999,7 @@
           break;
 
         case 0x39:  /* IP    */
-          Ins_IP( exc );
+          Ins_IP( exc, args );
           break;
 
         case 0x3A:  /* MSIRP */
@@ -7308,7 +7008,7 @@
           break;
 
         case 0x3C:  /* AlignRP */
-          Ins_ALIGNRP( exc );
+          Ins_ALIGNRP( exc, args );
           break;
 
         case 0x3D:  /* RTDG */
@@ -7544,7 +7244,7 @@
           break;
 
         case 0x80:  /* FLIPPT */
-          Ins_FLIPPT( exc );
+          Ins_FLIPPT( exc, args );
           break;
 
         case 0x81:  /* FLIPRGON */
@@ -7642,13 +7342,13 @@
       {
         switch ( exc->error )
         {
-          /* looking for redefined instructions */
         case FT_ERR( Invalid_Opcode ):
           {
             TT_DefRecord*  def   = exc->IDefs;
             TT_DefRecord*  limit = FT_OFFSET( def, exc->numIDefs );
 
 
+            /* looking for redefined instructions */
             for ( ; def < limit; def++ )
             {
               if ( def->active && exc->opcode == (FT_Byte)def->opc )
@@ -7678,37 +7378,15 @@
               }
             }
           }
-
-          exc->error = FT_THROW( Invalid_Opcode );
-          goto LErrorLabel_;
-
-#if 0
-          break;   /* Unreachable code warning suppression.             */
-                   /* Leave to remind in case a later change the editor */
-                   /* to consider break;                                */
-#endif
+          FALL_THROUGH;
 
         default:
           goto LErrorLabel_;
-
-#if 0
-        break;
-#endif
         }
       }
 
       exc->top = exc->new_top;
-
-      if ( exc->step_ins )
-        exc->IP += exc->length;
-
-      /* increment instruction counter and check if we didn't */
-      /* run this program for too long (e.g. infinite loops). */
-      if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES )
-      {
-        exc->error = FT_THROW( Execution_Too_Long );
-        goto LErrorLabel_;
-      }
+      exc->IP += exc->length;
 
     LSuiteLabel_:
       if ( exc->IP >= exc->codeSize )
@@ -7724,15 +7402,12 @@
     } while ( !exc->instruction_trap );
 
   LNo_Error_:
-    FT_TRACE4(( "  %ld instruction%s executed\n",
+    FT_TRACE4(( "  %lu instruction%s executed\n",
                 ins_counter,
                 ins_counter == 1 ? "" : "s" ));
 
     return FT_Err_Ok;
 
-  LErrorCodeOverflow_:
-    exc->error = FT_THROW( Code_Overflow );
-
   LErrorLabel_:
     if ( exc->error && !exc->instruction_trap )
       FT_TRACE1(( "  The interpreter returned error 0x%x\n", exc->error ));
@@ -7740,6 +7415,126 @@
     return exc->error;
   }
 
+
+  /**************************************************************************
+   *
+   * @Function:
+   *   TT_Run_Context
+   *
+   * @Description:
+   *   Executes one or more instructions in the execution context.
+   *
+   * @Input:
+   *   exec ::
+   *     A handle to the target execution context.
+   *
+   * @Return:
+   *   TrueType error code.  0 means success.
+   */
+  FT_LOCAL_DEF( FT_Error )
+  TT_Run_Context( TT_ExecContext  exec,
+                  TT_Size         size )
+  {
+    FT_ULong   num_twilight_points;
+
+
+    exec->zp0 = exec->pts;
+    exec->zp1 = exec->pts;
+    exec->zp2 = exec->pts;
+
+    /* We restrict the number of twilight points to a reasonable,     */
+    /* heuristic value to avoid slow execution of malformed bytecode. */
+    /* The selected value is large enough to support fonts hinted     */
+    /* with `ttfautohint`, which uses twilight points to store        */
+    /* vertical coordinates of (auto-hinter) segments.                */
+    num_twilight_points = FT_MAX( 30,
+                                  2 * ( exec->pts.n_points + exec->cvtSize ) );
+    if ( exec->twilight.n_points > num_twilight_points )
+    {
+      if ( num_twilight_points > 0xFFFFU )
+        num_twilight_points = 0xFFFFU;
+
+      FT_TRACE5(( "TT_RunIns: Resetting number of twilight points\n" ));
+      FT_TRACE5(( "           from %d to the more reasonable value %lu\n",
+                  exec->twilight.n_points,
+                  num_twilight_points ));
+      exec->twilight.n_points = (FT_UShort)num_twilight_points;
+    }
+
+    /* Set up loop detectors.  We restrict the number of LOOPCALL loops */
+    /* and the number of JMPR, JROT, and JROF calls with a negative     */
+    /* argument to values that depend on various parameters like the    */
+    /* size of the CVT table or the number of points in the current     */
+    /* glyph (if applicable).                                           */
+    /*                                                                  */
+    /* The idea is that in real-world bytecode you either iterate over  */
+    /* all CVT entries (in the `prep' table), or over all points (or    */
+    /* contours, in the `glyf' table) of a glyph, and such iterations   */
+    /* don't happen very often.                                         */
+    exec->loopcall_counter = 0;
+    exec->neg_jump_counter = 0;
+
+    /* The maximum values are heuristic. */
+    if ( exec->pts.n_points )
+      exec->loopcall_counter_max = FT_MAX( 50,
+                                           10 * exec->pts.n_points ) +
+                                   FT_MAX( 50,
+                                           exec->cvtSize / 10 );
+    else
+      exec->loopcall_counter_max = 300 + 22 * exec->cvtSize;
+
+    /* as a protection against an unreasonable number of CVT entries  */
+    /* we assume at most 100 control values per glyph for the counter */
+    if ( exec->loopcall_counter_max >
+         100 * (FT_ULong)exec->face->root.num_glyphs )
+      exec->loopcall_counter_max = 100 * (FT_ULong)exec->face->root.num_glyphs;
+
+    FT_TRACE5(( "TT_RunIns: Limiting total number of loops in LOOPCALL"
+                " to %lu\n", exec->loopcall_counter_max ));
+
+    exec->neg_jump_counter_max = exec->loopcall_counter_max;
+    FT_TRACE5(( "TT_RunIns: Limiting total number of backward jumps"
+                " to %lu\n", exec->neg_jump_counter_max ));
+
+    /* set PPEM and CVT functions */
+    if ( exec->metrics.x_ppem != exec->metrics.y_ppem )
+    {
+      /* non-square pixels, use the stretched routines */
+      exec->func_cur_ppem  = Current_Ppem_Stretched;
+      exec->func_read_cvt  = Read_CVT_Stretched;
+      exec->func_write_cvt = Write_CVT_Stretched;
+      exec->func_move_cvt  = Move_CVT_Stretched;
+    }
+    else
+    {
+      /* square pixels, use normal routines */
+      exec->func_cur_ppem  = Current_Ppem;
+      exec->func_read_cvt  = Read_CVT;
+      exec->func_write_cvt = Write_CVT;
+      exec->func_move_cvt  = Move_CVT;
+    }
+
+    /* reset graphics state */
+    exec->GS         = size->GS;
+    exec->func_round = (TT_Round_Func)Round_To_Grid;
+    Compute_Funcs( exec );
+
+#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
+    /* Reset IUP tracking bits in the backward compatibility mode. */
+    /* See `ttinterp.h' for details.                               */
+    exec->backward_compatibility &= ~0x3;
+#endif
+
+    /* some glyphs leave something on the stack, */
+    /* so we clean it before a new execution.    */
+    exec->top     = 0;
+    exec->callTop = 0;
+
+    exec->instruction_trap = FALSE;
+
+    return exec->interpreter( exec );
+  }
+
 #else /* !TT_USE_BYTECODE_INTERPRETER */
 
   /* ANSI C doesn't like empty source files */
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h
index 4f1a9bbc679..5cdc8f59f1a 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h
@@ -4,7 +4,7 @@
  *
  *   TrueType bytecode interpreter (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -39,6 +39,60 @@ FT_BEGIN_HEADER
 #define TT_Round_Super_45        7
 
 
+  /**************************************************************************
+   *
+   * EXECUTION SUBTABLES
+   *
+   * These sub-tables relate to instruction execution.
+   *
+   */
+
+
+#define TT_MAX_CODE_RANGES  3
+
+
+  /**************************************************************************
+   *
+   * There can only be 3 active code ranges at once:
+   *   - the Font Program
+   *   - the CVT Program
+   *   - a glyph's instructions set
+   */
+  typedef enum  TT_CodeRange_Tag_
+  {
+    tt_coderange_none = 0,
+    tt_coderange_font,
+    tt_coderange_cvt,
+    tt_coderange_glyph
+
+  } TT_CodeRange_Tag;
+
+
+  typedef struct  TT_CodeRange_
+  {
+    FT_Byte*  base;
+    FT_Long   size;
+
+  } TT_CodeRange;
+
+  typedef TT_CodeRange  TT_CodeRangeTable[TT_MAX_CODE_RANGES];
+
+
+  /**************************************************************************
+   *
+   * Defines a function/instruction definition record.
+   */
+  typedef struct  TT_DefRecord_
+  {
+    FT_Int    range;          /* in which code range is it located?     */
+    FT_Long   start;          /* where does it start?                   */
+    FT_Long   end;            /* where does it end?                     */
+    FT_UInt   opc;            /* function #, or instruction code        */
+    FT_Bool   active;         /* is it active?                          */
+
+  } TT_DefRecord, *TT_DefArray;
+
+
   /**************************************************************************
    *
    * Function types used by the interpreter, depending on various modes
@@ -51,7 +105,7 @@ FT_BEGIN_HEADER
   typedef FT_F26Dot6
   (*TT_Round_Func)( TT_ExecContext  exc,
                     FT_F26Dot6      distance,
-                    FT_Int          color );
+                    FT_F26Dot6      compensation );
 
   /* Point displacement along the freedom vector routine */
   typedef void
@@ -111,12 +165,13 @@ FT_BEGIN_HEADER
     TT_Face            face;       /* ! */
     TT_Size            size;       /* ! */
     FT_Memory          memory;
+    TT_Interpreter     interpreter;
 
     /* instructions state */
 
     FT_Error           error;      /* last execution error */
 
-    FT_Long            top;        /* @ top of exec. stack */
+    FT_Long            top;        /* @! top of exec. stack */
 
     FT_Long            stackSize;  /* ! size of exec. stack */
     FT_Long*           stack;      /* ! current exec. stack */
@@ -142,11 +197,9 @@ FT_BEGIN_HEADER
     FT_Long            IP;        /* current instruction pointer */
     FT_Long            codeSize;  /* size of current range       */
 
-    FT_Byte            opcode;    /* current opcode              */
-    FT_Int             length;    /* length of current opcode    */
+    FT_Byte            opcode;    /* current opcode             */
+    FT_Int             length;    /* opcode length or increment */
 
-    FT_Bool            step_ins;  /* true if the interpreter must */
-                                  /* increment IP after ins. exec */
     FT_ULong           cvtSize;   /* ! */
     FT_Long*           cvt;       /* ! */
     FT_ULong           glyfCvtSize;
@@ -166,9 +219,9 @@ FT_BEGIN_HEADER
     FT_UInt            maxFunc;   /* ! maximum function index    */
     FT_UInt            maxIns;    /* ! maximum instruction index */
 
-    FT_Int             callTop,    /* @ top of call stack during execution */
-                       callSize;   /*   size of call stack                 */
-    TT_CallStack       callStack;  /*   call stack                         */
+    FT_Int             callTop,    /* @! top of call stack during execution */
+                       callSize;   /*    size of call stack                 */
+    TT_CallStack       callStack;  /*    call stack                         */
 
     FT_UShort          maxPoints;    /* capacity of this context's `pts' */
     FT_Short           maxContours;  /* record, expressed in points and  */
@@ -189,16 +242,14 @@ FT_BEGIN_HEADER
     FT_Bool            instruction_trap; /* ! If `True', the interpreter   */
                                          /*   exits after each instruction */
 
-    TT_GraphicsState   default_GS;       /* graphics state resulting from   */
-                                         /* the prep program                */
     FT_Bool            is_composite;     /* true if the glyph is composite  */
     FT_Bool            pedantic_hinting; /* true if pedantic interpretation */
 
     /* latest interpreter additions */
 
-    FT_Long            F_dot_P;    /* dot product of freedom and projection */
-                                   /* vectors                               */
-    TT_Round_Func      func_round; /* current rounding function             */
+    TT_Round_Func      func_round;     /* current rounding function   */
+
+    FT_Vector          moveVector;     /* "projected" freedom vector  */
 
     TT_Project_Func    func_project,   /* current projection function */
                        func_dualproj,  /* current dual proj. function */
@@ -327,34 +378,13 @@ FT_BEGIN_HEADER
      *
      */
 
-    /* Using v40 implies subpixel hinting, unless FT_RENDER_MODE_MONO has been
-     * requested.  Used to detect interpreter */
-    /* version switches.  `_lean' to differentiate from the Infinality */
-    /* `subpixel_hinting', which is managed differently.               */
-    FT_Bool            subpixel_hinting_lean;
-
-    /* Long side of a LCD subpixel is vertical (e.g., screen is rotated). */
-    /* `_lean' to differentiate from the Infinality `vertical_lcd', which */
-    /* is managed differently.                                            */
-    FT_Bool            vertical_lcd_lean;
-
-    /* Default to backward compatibility mode in v40 interpreter.  If   */
-    /* this is false, it implies the interpreter is in v35 or in native */
-    /* ClearType mode.                                                  */
-    FT_Bool            backward_compatibility;
-
-    /* Useful for detecting and denying post-IUP trickery that is usually */
-    /* used to fix pixel patterns (`superhinting').                       */
-    FT_Bool            iupx_called;
-    FT_Bool            iupy_called;
-
-    /* ClearType hinting and grayscale rendering, as used by Universal */
-    /* Windows Platform apps (Windows 8 and above).  Like the standard */
-    /* colorful ClearType mode, it utilizes a vastly increased virtual */
-    /* resolution on the x axis.  Different from bi-level hinting and  */
-    /* grayscale rendering, the old mode from Win9x days that roughly  */
-    /* adheres to the physical pixel grid on both axes.                */
-    FT_Bool            grayscale_cleartype;
+    /* Activate backward compatibility (bit 2) and track IUP (bits 0-1). */
+    /* If this is zero, it means that the interpreter is either in v35   */
+    /* or in native ClearType mode.                                      */
+    FT_Int             backward_compatibility;
+
+    FT_Render_Mode     mode;  /* target render mode */
+
 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */
 
     /* We maintain two counters (in addition to the instruction counter) */
@@ -371,22 +401,15 @@ FT_BEGIN_HEADER
   extern const TT_GraphicsState  tt_default_graphics_state;
 
 
-#ifdef TT_USE_BYTECODE_INTERPRETER
-  FT_LOCAL( void )
-  TT_Goto_CodeRange( TT_ExecContext  exec,
-                     FT_Int          range,
-                     FT_Long         IP );
-
   FT_LOCAL( void )
   TT_Set_CodeRange( TT_ExecContext  exec,
                     FT_Int          range,
-                    void*           base,
+                    FT_Byte*        base,
                     FT_Long         length );
 
   FT_LOCAL( void )
   TT_Clear_CodeRange( TT_ExecContext  exec,
                       FT_Int          range );
-#endif /* TT_USE_BYTECODE_INTERPRETER */
 
 
   /**************************************************************************
@@ -413,22 +436,21 @@ FT_BEGIN_HEADER
   TT_New_Context( TT_Driver  driver );
 
 
-#ifdef TT_USE_BYTECODE_INTERPRETER
   FT_LOCAL( void )
   TT_Done_Context( TT_ExecContext  exec );
 
-  FT_LOCAL( FT_Error )
+  FT_LOCAL( void )
   TT_Load_Context( TT_ExecContext  exec,
                    TT_Face         face,
                    TT_Size         size );
 
   FT_LOCAL( void )
   TT_Save_Context( TT_ExecContext  exec,
-                   TT_Size         ins );
+                   TT_Size         size );
 
   FT_LOCAL( FT_Error )
-  TT_Run_Context( TT_ExecContext  exec );
-#endif /* TT_USE_BYTECODE_INTERPRETER */
+  TT_Run_Context( TT_ExecContext  exec,
+                  TT_Size         size );
 
 
   /**************************************************************************
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c
index d0ac3181204..2aedbd842c1 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c
@@ -4,7 +4,7 @@
  *
  *   Objects manager (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -67,23 +67,13 @@
    *     A pointer to the target glyph zone.
    */
   FT_LOCAL_DEF( void )
-  tt_glyphzone_done( TT_GlyphZone  zone )
+  tt_glyphzone_done( FT_Memory     memory,
+                     TT_GlyphZone  zone )
   {
-    FT_Memory  memory = zone->memory;
+    FT_FREE( zone->org );
 
-
-    if ( memory )
-    {
-      FT_FREE( zone->contours );
-      FT_FREE( zone->tags );
-      FT_FREE( zone->cur );
-      FT_FREE( zone->org );
-      FT_FREE( zone->orus );
-
-      zone->max_points   = zone->n_points   = 0;
-      zone->max_contours = zone->n_contours = 0;
-      zone->memory       = NULL;
-    }
+    zone->n_points   = 0;
+    zone->n_contours = 0;
   }
 
 
@@ -119,23 +109,22 @@
                     TT_GlyphZone  zone )
   {
     FT_Error  error;
+    FT_Long   size = 3 * maxPoints * sizeof ( FT_Vector ) +
+                       maxContours * sizeof ( FT_UShort ) +
+                         maxPoints * sizeof ( FT_Byte );
 
 
-    FT_ZERO( zone );
-    zone->memory = memory;
-
-    if ( FT_NEW_ARRAY( zone->org,      maxPoints   ) ||
-         FT_NEW_ARRAY( zone->cur,      maxPoints   ) ||
-         FT_NEW_ARRAY( zone->orus,     maxPoints   ) ||
-         FT_NEW_ARRAY( zone->tags,     maxPoints   ) ||
-         FT_NEW_ARRAY( zone->contours, maxContours ) )
+    if ( !FT_ALLOC( zone->org, size ) )
     {
-      tt_glyphzone_done( zone );
-    }
-    else
-    {
-      zone->max_points   = maxPoints;
-      zone->max_contours = maxContours;
+      zone->n_points   = maxPoints;
+      zone->n_contours = maxContours;
+
+      zone->cur      =               zone->org      + maxPoints;
+      zone->orus     =               zone->cur      + maxPoints;
+      zone->contours = (FT_UShort*)( zone->orus     + maxPoints );
+      zone->tags     =   (FT_Byte*)( zone->contours + maxContours );
+
+      zone->first_point = 0;
     }
 
     return error;
@@ -488,8 +477,7 @@
     int        j, k;
 
 
-    FT_MEM_SET( num_matched_ids, 0,
-                sizeof ( int ) * TRICK_SFNT_IDS_NUM_FACES );
+    FT_ARRAY_ZERO( num_matched_ids, TRICK_SFNT_IDS_NUM_FACES );
     has_cvt  = FALSE;
     has_fpgm = FALSE;
     has_prep = FALSE;
@@ -787,7 +775,7 @@
       FT_UInt  instance_index = (FT_UInt)face_index >> 16;
 
 
-      if ( FT_HAS_MULTIPLE_MASTERS( ttface ) )
+      if ( instance_index && FT_HAS_MULTIPLE_MASTERS( ttface ) )
       {
         error = FT_Set_Named_Instance( ttface, instance_index );
         if ( error )
@@ -885,59 +873,18 @@
    *   size ::
    *     A handle to the size object.
    *
-   *   pedantic ::
-   *     Set if bytecode execution should be pedantic.
-   *
    * @Return:
    *   FreeType error code.  0 means success.
    */
   FT_LOCAL_DEF( FT_Error )
-  tt_size_run_fpgm( TT_Size  size,
-                    FT_Bool  pedantic )
+  tt_size_run_fpgm( TT_Size  size )
   {
     TT_Face         face = (TT_Face)size->root.face;
-    TT_ExecContext  exec;
+    TT_ExecContext  exec = size->context;
     FT_Error        error;
 
 
-    exec = size->context;
-
-    error = TT_Load_Context( exec, face, size );
-    if ( error )
-      return error;
-
-    exec->callTop = 0;
-    exec->top     = 0;
-
-    exec->period    = 64;
-    exec->phase     = 0;
-    exec->threshold = 0;
-
-    exec->instruction_trap = FALSE;
-    exec->F_dot_P          = 0x4000L;
-
-    exec->pedantic_hinting = pedantic;
-
-    {
-      FT_Size_Metrics*  size_metrics = &exec->metrics;
-      TT_Size_Metrics*  tt_metrics   = &exec->tt_metrics;
-
-
-      size_metrics->x_ppem   = 0;
-      size_metrics->y_ppem   = 0;
-      size_metrics->x_scale  = 0;
-      size_metrics->y_scale  = 0;
-
-      tt_metrics->ppem  = 0;
-      tt_metrics->scale = 0;
-      tt_metrics->ratio = 0x10000L;
-    }
-
-    /* allow font program execution */
-    TT_Set_CodeRange( exec,
-                      tt_coderange_font,
-                      face->font_program,
-                      (FT_Long)face->font_program_size );
+    TT_Load_Context( exec, face, size );
 
     /* disable CVT and glyph programs coderange */
     TT_Clear_CodeRange( exec, tt_coderange_cvt );
@@ -945,15 +892,19 @@
 
     if ( face->font_program_size > 0 )
     {
-      TT_Goto_CodeRange( exec, tt_coderange_font, 0 );
+      /* allow font program execution */
+      TT_Set_CodeRange( exec,
+                        tt_coderange_font,
+                        face->font_program,
+                        (FT_Long)face->font_program_size );
+
+      exec->pts.n_points   = 0;
+      exec->pts.n_contours = 0;
 
       FT_TRACE4(( "Executing `fpgm' table.\n" ));
-      error = face->interpreter( exec );
-#ifdef FT_DEBUG_LEVEL_TRACE
-      if ( error )
-        FT_TRACE4(( "  interpretation failed with error code 0x%x\n",
-                    error ));
-#endif
+      error = TT_Run_Context( exec, size );
+      FT_TRACE4(( error ? "  failed (error code 0x%x)\n" : "",
+                  error ));
     }
     else
       error = FT_Err_Ok;
@@ -979,212 +930,146 @@
    *   size ::
    *     A handle to the size object.
    *
-   *   pedantic ::
-   *     Set if bytecode execution should be pedantic.
-   *
    * @Return:
    *   FreeType error code.  0 means success.
    */
   FT_LOCAL_DEF( FT_Error )
-  tt_size_run_prep( TT_Size  size,
-                    FT_Bool  pedantic )
+  tt_size_run_prep( TT_Size  size )
   {
     TT_Face         face = (TT_Face)size->root.face;
-    TT_ExecContext  exec;
+    TT_ExecContext  exec = size->context;
     FT_Error        error;
     FT_UInt         i;
 
 
+    /* set default GS, twilight points, and storage */
+    /* before CV program can modify them.           */
+    size->GS = tt_default_graphics_state;
+
+    /* all twilight points are originally zero */
+    FT_ARRAY_ZERO( size->twilight.org, size->twilight.n_points );
+    FT_ARRAY_ZERO( size->twilight.cur, size->twilight.n_points );
+
+    TT_Load_Context( exec, face, size );
+
+    /* clear storage area */
+    FT_ARRAY_ZERO( exec->storage, exec->storeSize );
+
     /* Scale the cvt values to the new ppem.            */
     /* By default, we use the y ppem value for scaling. */
     FT_TRACE6(( "CVT values:\n" ));
-    for ( i = 0; i < size->cvt_size; i++ )
+    for ( i = 0; i < exec->cvtSize; i++ )
     {
       /* Unscaled CVT values are already stored in 26.6 format.            */
       /* Note that this scaling operation is very sensitive to rounding;   */
       /* the integer division by 64 must be applied to the first argument. */
-      size->cvt[i] = FT_MulFix( face->cvt[i] / 64, size->ttmetrics.scale );
-      FT_TRACE6(( "  %3d: %f (%f)\n",
-                  i, (double)face->cvt[i] / 64, (double)size->cvt[i] / 64 ));
+      exec->cvt[i] = FT_MulFix( face->cvt[i] / 64, size->ttmetrics.scale );
+      FT_TRACE6(( "  %3u: %f (%f)\n",
+                  i, (double)face->cvt[i] / 64, (double)exec->cvt[i] / 64 ));
     }
     FT_TRACE6(( "\n" ));
 
-    exec = size->context;
-
-    error = TT_Load_Context( exec, face, size );
-    if ( error )
-      return error;
-
-    exec->callTop = 0;
-    exec->top     = 0;
-
-    exec->instruction_trap = FALSE;
-
-    exec->pedantic_hinting = pedantic;
-
-    TT_Set_CodeRange( exec,
-                      tt_coderange_cvt,
-                      face->cvt_program,
-                      (FT_Long)face->cvt_program_size );
-
     TT_Clear_CodeRange( exec, tt_coderange_glyph );
 
     if ( face->cvt_program_size > 0 )
     {
-      TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 );
+      /* allow CV program execution */
+      TT_Set_CodeRange( exec,
+                        tt_coderange_cvt,
+                        face->cvt_program,
+                        (FT_Long)face->cvt_program_size );
+
+      exec->pts.n_points   = 0;
+      exec->pts.n_contours = 0;
 
       FT_TRACE4(( "Executing `prep' table.\n" ));
-      error = face->interpreter( exec );
-#ifdef FT_DEBUG_LEVEL_TRACE
-      if ( error )
-        FT_TRACE4(( "  interpretation failed with error code 0x%x\n",
-                    error ));
-#endif
+      error = TT_Run_Context( exec, size );
+      FT_TRACE4(( error ? "  failed (error code 0x%x)\n" : "",
+                  error ));
     }
     else
       error = FT_Err_Ok;
 
     size->cvt_ready = error;
 
-    /* UNDOCUMENTED!  The MS rasterizer doesn't allow the following */
-    /* graphics state variables to be modified by the CVT program.  */
-
-    exec->GS.dualVector.x = 0x4000;
-    exec->GS.dualVector.y = 0;
-    exec->GS.projVector.x = 0x4000;
-    exec->GS.projVector.y = 0x0;
-    exec->GS.freeVector.x = 0x4000;
-    exec->GS.freeVector.y = 0x0;
-
-    exec->GS.rp0 = 0;
-    exec->GS.rp1 = 0;
-    exec->GS.rp2 = 0;
-
-    exec->GS.gep0 = 1;
-    exec->GS.gep1 = 1;
-    exec->GS.gep2 = 1;
-
-    exec->GS.loop = 1;
-
-    /* save as default graphics state */
-    size->GS = exec->GS;
-
-    TT_Save_Context( exec, size );
+    if ( !error )
+      TT_Save_Context( exec, size );
 
     return error;
   }
 
 
   static void
-  tt_size_done_bytecode( FT_Size  ftsize )
+  tt_size_done_bytecode( TT_Size  size )
   {
-    TT_Size    size   = (TT_Size)ftsize;
-    TT_Face    face   = (TT_Face)ftsize->face;
-    FT_Memory  memory = face->root.memory;
+    FT_Memory       memory = size->root.face->memory;
+    TT_ExecContext  exec   = size->context;
 
-    if ( size->context )
+
+    if ( exec )
     {
-      TT_Done_Context( size->context );
+      FT_FREE( exec->stack );
+      FT_FREE( exec->FDefs );
+
+      TT_Done_Context( exec );
       size->context = NULL;
     }
 
-    FT_FREE( size->cvt );
-    size->cvt_size = 0;
-
-    /* free storage area */
-    FT_FREE( size->storage );
-    size->storage_size = 0;
-
     /* twilight zone */
-    tt_glyphzone_done( &size->twilight );
-
-    FT_FREE( size->function_defs );
-    FT_FREE( size->instruction_defs );
-
-    size->num_function_defs    = 0;
-    size->max_function_defs    = 0;
-    size->num_instruction_defs = 0;
-    size->max_instruction_defs = 0;
-
-    size->max_func = 0;
-    size->max_ins  = 0;
-
-    size->bytecode_ready = -1;
-    size->cvt_ready      = -1;
+    tt_glyphzone_done( memory, &size->twilight );
   }
 
 
   /* Initialize bytecode-related fields in the size object.       */
   /* We do this only if bytecode interpretation is really needed. */
-  static FT_Error
-  tt_size_init_bytecode( FT_Size  ftsize,
+  FT_LOCAL_DEF( FT_Error )
+  tt_size_init_bytecode( TT_Size  size,
                          FT_Bool  pedantic )
   {
     FT_Error   error;
-    TT_Size    size = (TT_Size)ftsize;
-    TT_Face    face = (TT_Face)ftsize->face;
-    FT_Memory  memory = face->root.memory;
+    TT_Face    face = (TT_Face)size->root.face;
+    FT_Memory  memory = size->root.face->memory;
 
     FT_UShort       n_twilight;
     TT_MaxProfile*  maxp = &face->max_profile;
+    TT_ExecContext  exec;
 
 
-    /* clean up bytecode related data */
-    FT_FREE( size->function_defs );
-    FT_FREE( size->instruction_defs );
-    FT_FREE( size->cvt );
-    FT_FREE( size->storage );
+    exec = TT_New_Context( (TT_Driver)face->root.driver );
+    if ( !exec )
+      return FT_THROW( Could_Not_Find_Context );
 
-    if ( size->context )
-      TT_Done_Context( size->context );
-    tt_glyphzone_done( &size->twilight );
+    size->context = exec;
 
-    size->bytecode_ready = -1;
-    size->cvt_ready      = -1;
+    exec->pedantic_hinting = pedantic;
 
-    size->context = TT_New_Context( (TT_Driver)face->root.driver );
+    exec->maxFDefs = maxp->maxFunctionDefs;
+    exec->maxIDefs = maxp->maxInstructionDefs;
 
-    size->max_function_defs    = maxp->maxFunctionDefs;
-    size->max_instruction_defs = maxp->maxInstructionDefs;
+    if ( FT_NEW_ARRAY( exec->FDefs, exec->maxFDefs + exec->maxIDefs ) )
+      goto Fail;
 
-    size->num_function_defs    = 0;
-    size->num_instruction_defs = 0;
+    exec->IDefs = exec->FDefs + exec->maxFDefs;
 
-    size->max_func = 0;
-    size->max_ins  = 0;
+    exec->numFDefs = 0;
+    exec->numIDefs = 0;
 
-    size->cvt_size     = face->cvt_size;
-    size->storage_size = maxp->maxStorage;
+    exec->maxFunc = 0;
+    exec->maxIns  = 0;
 
-    /* Set default metrics */
-    {
-      TT_Size_Metrics*  tt_metrics = &size->ttmetrics;
-
-
-      tt_metrics->rotated   = FALSE;
-      tt_metrics->stretched = FALSE;
-
-      /* Set default engine compensation.  Value 3 is not described */
-      /* in the OpenType specification (as of Mai 2019), but Greg   */
-      /* says that MS handles it the same as `gray'.                */
-      /*                                                            */
-      /* The Apple specification says that the compensation for     */
-      /* `gray' is always zero.  FreeType doesn't do any            */
-      /* compensation at all.                                       */
-      tt_metrics->compensations[0] = 0;   /* gray  */
-      tt_metrics->compensations[1] = 0;   /* black */
-      tt_metrics->compensations[2] = 0;   /* white */
-      tt_metrics->compensations[3] = 0;   /* zero  */
-    }
+    /* XXX: We reserve a little more elements on the stack to deal */
+    /*      with broken fonts like arialbs, courbs, timesbs, etc.  */
+    exec->stackSize = maxp->maxStackElements + 32;
+    exec->storeSize = maxp->maxStorage;
+    exec->cvtSize   = face->cvt_size;
 
-    /* allocate function defs, instruction defs, cvt, and storage area */
-    if ( FT_NEW_ARRAY( size->function_defs,    size->max_function_defs    ) ||
-         FT_NEW_ARRAY( size->instruction_defs, size->max_instruction_defs ) ||
-         FT_NEW_ARRAY( size->cvt,              size->cvt_size             ) ||
-         FT_NEW_ARRAY( size->storage,          size->storage_size         ) )
-      goto Exit;
+    if ( FT_NEW_ARRAY( exec->stack,
+                       exec->stackSize +
+                         (FT_Long)( exec->storeSize + exec->cvtSize ) ) )
+      goto Fail;
 
-    /* reserve twilight zone */
+    /* reserve twilight zone and set GS before fpgm is executed, */
+    /* just in case, even though fpgm should not touch them      */
     n_twilight = maxp->maxTwilightPoints;
 
     /* there are 4 phantom points (do we need this?) */
@@ -1192,22 +1077,13 @@
 
     error = tt_glyphzone_new( memory, n_twilight, 0, &size->twilight );
     if ( error )
-      goto Exit;
-
-    size->twilight.n_points = n_twilight;
-
-    size->GS = tt_default_graphics_state;
-
-    /* set `face->interpreter' according to the debug hook present */
-    {
-      FT_Library  library = face->root.driver->root.library;
+      goto Fail;
 
+    size->GS        = tt_default_graphics_state;
+    size->cvt_ready = -1;
 
-      face->interpreter = (TT_Interpreter)
-                            library->debug_hooks[FT_DEBUG_HOOK_TRUETYPE];
-      if ( !face->interpreter )
-        face->interpreter = (TT_Interpreter)TT_RunIns;
-    }
+    size->ttmetrics.rotated   = FALSE;
+    size->ttmetrics.stretched = FALSE;
 
     /* Fine, now run the font program! */
 
@@ -1217,59 +1093,11 @@
     /* to be executed just once; calling it again is completely useless   */
     /* and might even lead to extremely slow behaviour if it is malformed */
     /* (containing an infinite loop, for example).                        */
-    error = tt_size_run_fpgm( size, pedantic );
+    error = tt_size_run_fpgm( size );
     return error;
 
-  Exit:
-    if ( error )
-      tt_size_done_bytecode( ftsize );
-
-    return error;
-  }
-
-
-  FT_LOCAL_DEF( FT_Error )
-  tt_size_ready_bytecode( TT_Size  size,
-                          FT_Bool  pedantic )
-  {
-    FT_Error  error = FT_Err_Ok;
-
-
-    if ( size->bytecode_ready < 0 )
-      error = tt_size_init_bytecode( (FT_Size)size, pedantic );
-    else
-      error = size->bytecode_ready;
-
-    if ( error )
-      goto Exit;
-
-    /* rescale CVT when needed */
-    if ( size->cvt_ready < 0 )
-    {
-      FT_UShort  i;
-
-
-      /* all twilight points are originally zero */
-      for ( i = 0; i < size->twilight.n_points; i++ )
-      {
-        size->twilight.org[i].x = 0;
-        size->twilight.org[i].y = 0;
-        size->twilight.cur[i].x = 0;
-        size->twilight.cur[i].y = 0;
-      }
-
-      /* clear storage area */
-      for ( i = 0; i < size->storage_size; i++ )
-        size->storage[i] = 0;
-
-      size->GS = tt_default_graphics_state;
-
-      error = tt_size_run_prep( size, pedantic );
-    }
-    else
-      error = size->cvt_ready;
-
-  Exit:
+  Fail:
+    tt_size_done_bytecode( size );
     return error;
   }
 
@@ -1300,11 +1128,9 @@
 
 #ifdef TT_USE_BYTECODE_INTERPRETER
     size->bytecode_ready = -1;
-    size->cvt_ready      = -1;
 #endif
 
-    size->ttmetrics.valid = FALSE;
-    size->strike_index    = 0xFFFFFFFFUL;
+    size->strike_index = 0xFFFFFFFFUL;
 
     return error;
   }
@@ -1325,14 +1151,11 @@
   FT_LOCAL_DEF( void )
   tt_size_done( FT_Size  ttsize )           /* TT_Size */
   {
-    TT_Size  size = (TT_Size)ttsize;
-
-
 #ifdef TT_USE_BYTECODE_INTERPRETER
-    tt_size_done_bytecode( ttsize );
+    tt_size_done_bytecode( (TT_Size)ttsize );
+#else
+    FT_UNUSED( ttsize );
 #endif
-
-    size->ttmetrics.valid = FALSE;
   }
 
 
@@ -1353,21 +1176,13 @@
    *     function must take `FT_Size` as a result. The passed `FT_Size` is
    *     expected to point to a `TT_Size`.
    */
-  FT_LOCAL_DEF( FT_Error )
+  FT_LOCAL_DEF( void )
   tt_size_reset_height( FT_Size  ft_size )
   {
     TT_Size           size         = (TT_Size)ft_size;
-    TT_Face           face         = (TT_Face)size->root.face;
+    TT_Face           face         = (TT_Face)ft_size->face;
     FT_Size_Metrics*  size_metrics = &size->hinted_metrics;
 
-    size->ttmetrics.valid = FALSE;
-
-    /* copy the result from base layer */
-    *size_metrics = size->root.metrics;
-
-    if ( size_metrics->x_ppem < 1 || size_metrics->y_ppem < 1 )
-      return FT_THROW( Invalid_PPem );
-
     /* This bit flag, if set, indicates that the ppems must be       */
     /* rounded to integers.  Nearly all TrueType fonts have this bit */
     /* set, as hinting won't work really well otherwise.             */
@@ -1385,10 +1200,6 @@
                                FT_MulFix( face->root.height,
                                           size_metrics->y_scale ) );
     }
-
-    size->ttmetrics.valid = TRUE;
-
-    return FT_Err_Ok;
   }
 
 
@@ -1408,14 +1219,20 @@
   FT_LOCAL_DEF( FT_Error )
   tt_size_reset( TT_Size  size )
   {
-    FT_Error          error;
     TT_Face           face         = (TT_Face)size->root.face;
     FT_Size_Metrics*  size_metrics = &size->hinted_metrics;
 
 
-    error = tt_size_reset_height( (FT_Size)size );
-    if ( error )
-      return error;
+    /* invalidate the size object first */
+    size->ttmetrics.ppem = 0;
+
+    if ( size->root.metrics.x_ppem == 0 || size->root.metrics.y_ppem == 0 )
+      return FT_THROW( Invalid_PPem );
+
+    /* copy the result from base layer */
+    *size_metrics = size->root.metrics;
+
+    tt_size_reset_height( (FT_Size)size );
 
     if ( face->header.Flags & 8 )
     {
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h
index 9c36ca78362..28d6c7d855f 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h
@@ -4,7 +4,7 @@
  *
  *   Objects manager (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -53,6 +53,8 @@ FT_BEGIN_HEADER
   typedef FT_GlyphSlot  TT_GlyphSlot;
 
 
+#ifdef TT_USE_BYTECODE_INTERPRETER
+
   /**************************************************************************
    *
    * @Struct:
@@ -67,21 +69,27 @@ FT_BEGIN_HEADER
     FT_UShort      rp1;
     FT_UShort      rp2;
 
+    FT_UShort      gep0;
+    FT_UShort      gep1;
+    FT_UShort      gep2;
+
     FT_UnitVector  dualVector;
     FT_UnitVector  projVector;
     FT_UnitVector  freeVector;
 
     FT_Long        loop;
-    FT_F26Dot6     minimum_distance;
     FT_Int         round_state;
+    FT_F26Dot6     compensation[4];   /* device-specific compensations  */
 
-    FT_Bool        auto_flip;
+    /* default values below can be modified by 'fpgm' and 'prep' */
+    FT_F26Dot6     minimum_distance;
     FT_F26Dot6     control_value_cutin;
     FT_F26Dot6     single_width_cutin;
     FT_F26Dot6     single_width_value;
     FT_UShort      delta_base;
     FT_UShort      delta_shift;
 
+    FT_Bool        auto_flip;
     FT_Byte        instruct_control;
     /* According to Greg Hitchcock from Microsoft, the `scan_control'     */
     /* variable as documented in the TrueType specification is a 32-bit   */
@@ -90,17 +98,12 @@ FT_BEGIN_HEADER
     FT_Bool        scan_control;
     FT_Int         scan_type;
 
-    FT_UShort      gep0;
-    FT_UShort      gep1;
-    FT_UShort      gep2;
-
   } TT_GraphicsState;
 
 
-#ifdef TT_USE_BYTECODE_INTERPRETER
-
   FT_LOCAL( void )
-  tt_glyphzone_done( TT_GlyphZone  zone );
+  tt_glyphzone_done( FT_Memory     memory,
+                     TT_GlyphZone  zone );
 
   FT_LOCAL( FT_Error )
   tt_glyphzone_new( FT_Memory     memory,
@@ -112,73 +115,6 @@ FT_BEGIN_HEADER
 
 
 
-  /**************************************************************************
-   *
-   * EXECUTION SUBTABLES
-   *
-   * These sub-tables relate to instruction execution.
-   *
-   */
-
-
-#define TT_MAX_CODE_RANGES  3
-
-
-  /**************************************************************************
-   *
-   * There can only be 3 active code ranges at once:
-   *   - the Font Program
-   *   - the CVT Program
-   *   - a glyph's instructions set
-   */
-  typedef enum  TT_CodeRange_Tag_
-  {
-    tt_coderange_none = 0,
-    tt_coderange_font,
-    tt_coderange_cvt,
-    tt_coderange_glyph
-
-  } TT_CodeRange_Tag;
-
-
-  typedef struct  TT_CodeRange_
-  {
-    FT_Byte*  base;
-    FT_Long   size;
-
-  } TT_CodeRange;
-
-  typedef TT_CodeRange  TT_CodeRangeTable[TT_MAX_CODE_RANGES];
-
-
-  /**************************************************************************
-   *
-   * Defines a function/instruction definition record.
-   */
-  typedef struct  TT_DefRecord_
-  {
-    FT_Int    range;          /* in which code range is it located?     */
-    FT_Long   start;          /* where does it start?                   */
-    FT_Long   end;            /* where does it end?                     */
-    FT_UInt   opc;            /* function #, or instruction code        */
-    FT_Bool   active;         /* is it active?                          */
-
-  } TT_DefRecord, *TT_DefArray;
-
-
-  /**************************************************************************
-   *
-   * Subglyph transformation record.
-   */
-  typedef struct  TT_Transform_
-  {
-    FT_Fixed    xx, xy;     /* transformation matrix coefficients */
-    FT_Fixed    yx, yy;
-    FT_F26Dot6  ox, oy;     /* offsets                            */
-
-  } TT_Transform;
-
-
   /**************************************************************************
    *
    * A note regarding non-squared pixels:
@@ -251,13 +187,9 @@ FT_BEGIN_HEADER
     FT_Long     x_ratio;
     FT_Long     y_ratio;
 
-    FT_UShort   ppem;               /* maximum ppem size              */
     FT_Long     ratio;              /* current ratio                  */
     FT_Fixed    scale;
-
-    FT_F26Dot6  compensations[4];   /* device-specific compensations  */
-
-    FT_Bool     valid;
+    FT_UShort   ppem;               /* maximum ppem size              */
 
     FT_Bool     rotated;            /* `is the glyph rotated?'-flag   */
     FT_Bool     stretched;          /* `is the glyph stretched?'-flag */
@@ -288,27 +220,8 @@ FT_BEGIN_HEADER
 
     FT_Long            point_size;    /* for the `MPS' bytecode instruction */
 
-    FT_UInt            num_function_defs; /* number of function definitions */
-    FT_UInt            max_function_defs;
-    TT_DefArray        function_defs;     /* table of function definitions  */
-
-    FT_UInt            num_instruction_defs;  /* number of ins. definitions */
-    FT_UInt            max_instruction_defs;
-    TT_DefArray        instruction_defs;      /* table of ins. definitions  */
-
-    FT_UInt            max_func;
-    FT_UInt            max_ins;
-
-    TT_CodeRangeTable  codeRangeTable;
-
     TT_GraphicsState   GS;
 
-    FT_ULong           cvt_size;      /* the scaled control value table */
-    FT_Long*           cvt;
-
-    FT_UShort          storage_size; /* The storage area is now part of */
-    FT_Long*           storage;      /* the instance                    */
-
     TT_GlyphZoneRec    twilight;     /* The instance's twilight zone    */
 
     TT_ExecContext     context;
@@ -375,20 +288,18 @@ FT_BEGIN_HEADER
 #ifdef TT_USE_BYTECODE_INTERPRETER
 
   FT_LOCAL( FT_Error )
-  tt_size_run_fpgm( TT_Size  size,
-                    FT_Bool  pedantic );
+  tt_size_run_fpgm( TT_Size  size );
 
   FT_LOCAL( FT_Error )
-  tt_size_run_prep( TT_Size  size,
-                    FT_Bool  pedantic );
+  tt_size_run_prep( TT_Size  size );
 
   FT_LOCAL( FT_Error )
-  tt_size_ready_bytecode( TT_Size  size,
-                          FT_Bool  pedantic );
+  tt_size_init_bytecode( TT_Size  size,
+                         FT_Bool  pedantic );
 
 #endif /* TT_USE_BYTECODE_INTERPRETER */
 
-  FT_LOCAL( FT_Error )
+  FT_LOCAL( void )
   tt_size_reset_height( FT_Size  size );
 
   FT_LOCAL( FT_Error )
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c
index 9505b5f179f..827454d8574 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c
@@ -4,7 +4,7 @@
  *
  *   TrueType-specific tables loader (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -110,7 +110,7 @@
 
     if ( face->num_locations != (FT_ULong)face->root.num_glyphs + 1 )
     {
-      FT_TRACE2(( "glyph count mismatch!  loca: %ld, maxp: %ld\n",
+      FT_TRACE2(( "glyph count mismatch!  loca: %lu, maxp: %ld\n",
                   face->num_locations - 1, face->root.num_glyphs ));
 
       /* we only handle the case where `maxp' gives a larger value */
@@ -151,7 +151,7 @@
           face->num_locations = (FT_ULong)face->root.num_glyphs + 1;
           table_len           = new_loca_len;
 
-          FT_TRACE2(( "adjusting num_locations to %ld\n",
+          FT_TRACE2(( "adjusting num_locations to %lu\n",
                       face->num_locations ));
         }
         else
@@ -225,7 +225,7 @@
     if ( pos1 > ttface->glyf_len )
     {
       FT_TRACE1(( "tt_face_get_location:"
-                  " too large offset (0x%08lx) found for glyph index %d,\n",
+                  " too large offset (0x%08lx) found for glyph index %u,\n",
                   pos1, gindex ));
       FT_TRACE1(( "                     "
                   " exceeding the end of `glyf' table (0x%08lx)\n",
@@ -240,17 +240,17 @@
       if ( gindex == ttface->num_locations - 2 )
       {
         FT_TRACE1(( "tt_face_get_location:"
-                    " too large size (%ld bytes) found for glyph index %d,\n",
+                    " too large size (%lu bytes) found for glyph index %u,\n",
                     pos2 - pos1, gindex ));
         FT_TRACE1(( "                     "
-                    " truncating at the end of `glyf' table to %ld bytes\n",
+                    " truncating at the end of `glyf' table to %lu bytes\n",
                     ttface->glyf_len - pos1 ));
         pos2 = ttface->glyf_len;
       }
       else
       {
         FT_TRACE1(( "tt_face_get_location:"
-                    " too large offset (0x%08lx) found for glyph index %d,\n",
+                    " too large offset (0x%08lx) found for glyph index %u,\n",
                     pos2, gindex + 1 ));
         FT_TRACE1(( "                     "
                     " exceeding the end of `glyf' table (0x%08lx)\n",
@@ -419,7 +419,7 @@
       if ( FT_FRAME_EXTRACT( table_len, face->font_program ) )
         goto Exit;
 
-      FT_TRACE2(( "loaded, %12ld bytes\n", face->font_program_size ));
+      FT_TRACE2(( "loaded, %12lu bytes\n", face->font_program_size ));
     }
 
   Exit:
@@ -482,7 +482,7 @@
       if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) )
         goto Exit;
 
-      FT_TRACE2(( "loaded, %12ld bytes\n", face->cvt_program_size ));
+      FT_TRACE2(( "loaded, %12lu bytes\n", face->cvt_program_size ));
     }
 
   Exit:
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h
index bc32b58020c..bb4d3c9cc55 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h
@@ -4,7 +4,7 @@
  *
  *   TrueType-specific tables loader (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.c
deleted file mode 100644
index d811beef0df..00000000000
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.c
+++ /dev/null
@@ -1,1013 +0,0 @@
-/****************************************************************************
- *
- * ttsubpix.c
- *
- *   TrueType Subpixel Hinting.
- *
- * Copyright (C) 2010-2023 by
- * David Turner, Robert Wilhelm, and Werner Lemberg.
- *
- * This file is part of the FreeType project, and may only be used,
- * modified, and distributed under the terms of the FreeType project
- * license, LICENSE.TXT.  By continuing to use, modify, or distribute
- * this file you indicate that you have read the license and
- * understand and accept it fully.
- *
- */
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include "ttsubpix.h"
-
-
-#if defined( TT_USE_BYTECODE_INTERPRETER )            && \
-    defined( TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY )
-
-  /**************************************************************************
-   *
-   * These rules affect how the TT Interpreter does hinting, with the
-   * goal of doing subpixel hinting by (in general) ignoring x moves.
-   * Some of these rules are fixes that go above and beyond the
-   * stated techniques in the MS whitepaper on Cleartype, due to
-   * artifacts in many glyphs.  So, these rules make some glyphs render
-   * better than they do in the MS rasterizer.
-   *
-   * "" string or 0 int/char indicates to apply to all glyphs.
-   * "-" used as dummy placeholders, but any non-matching string works.
-   *
-   * Some of this could arguably be implemented in fontconfig, however:
-   *
-   * - Fontconfig can't set things on a glyph-by-glyph basis.
-   * - The tweaks that happen here are very low-level, from an average
-   *   user's point of view and are best implemented in the hinter.
-   *
-   * The goal is to make the subpixel hinting techniques as generalized
-   * as possible across all fonts to prevent the need for extra rules such
-   * as these.
-   *
-   * The rule structure is designed so that entirely new rules can easily
-   * be added when a new compatibility feature is discovered.
-   *
-   * The rule structures could also use some enhancement to handle ranges.
-   *
-   *     ****************** WORK IN PROGRESS *******************
-   */
-
-  /* These are `classes' of fonts that can be grouped together and used in */
-  /* rules below.  A blank entry "" is required at the end of these!       */
-#define FAMILY_CLASS_RULES_SIZE  7
-
-  static const SPH_Font_Class  FAMILY_CLASS_Rules
-                               [FAMILY_CLASS_RULES_SIZE] =
-  {
-    { "MS Legacy Fonts",
-      { "Aharoni",
-        "Andale Mono",
-        "Andalus",
-        "Angsana New",
-        "AngsanaUPC",
-        "Arabic Transparent",
-        "Arial Black",
-        "Arial Narrow",
-        "Arial Unicode MS",
-        "Arial",
-        "Batang",
-        "Browallia New",
-        "BrowalliaUPC",
-        "Comic Sans MS",
-        "Cordia New",
-        "CordiaUPC",
-        "Courier New",
-        "DFKai-SB",
-        "David Transparent",
-        "David",
-        "DilleniaUPC",
-        "Estrangelo Edessa",
-        "EucrosiaUPC",
-        "FangSong_GB2312",
-        "Fixed Miriam Transparent",
-        "FrankRuehl",
-        "Franklin Gothic Medium",
-        "FreesiaUPC",
-        "Garamond",
-        "Gautami",
-        "Georgia",
-        "Gulim",
-        "Impact",
-        "IrisUPC",
-        "JasmineUPC",
-        "KaiTi_GB2312",
-        "KodchiangUPC",
-        "Latha",
-        "Levenim MT",
-        "LilyUPC",
-        "Lucida Console",
-        "Lucida Sans Unicode",
-        "MS Gothic",
-        "MS Mincho",
-        "MV Boli",
-        "Mangal",
-        "Marlett",
-        "Microsoft Sans Serif",
-        "Mingliu",
-        "Miriam Fixed",
-        "Miriam Transparent",
-        "Miriam",
-        "Narkisim",
-        "Palatino Linotype",
-        "Raavi",
-        "Rod Transparent",
-        "Rod",
-        "Shruti",
-        "SimHei",
-        "Simplified Arabic Fixed",
-        "Simplified Arabic",
-        "Simsun",
-        "Sylfaen",
-        "Symbol",
-        "Tahoma",
-        "Times New Roman",
-        "Traditional Arabic",
-        "Trebuchet MS",
-        "Tunga",
-        "Verdana",
-        "Webdings",
-        "Wingdings",
-        "",
-      },
-    },
-    { "Core MS Legacy Fonts",
-      { "Arial Black",
-        "Arial Narrow",
-        "Arial Unicode MS",
-        "Arial",
-        "Comic Sans MS",
-        "Courier New",
-        "Garamond",
-        "Georgia",
-        "Impact",
-        "Lucida Console",
-        "Lucida Sans Unicode",
-        "Microsoft Sans Serif",
-        "Palatino Linotype",
-        "Tahoma",
-        "Times New Roman",
-        "Trebuchet MS",
-        "Verdana",
-        "",
-      },
-    },
-    { "Apple Legacy Fonts",
-      { "Geneva",
-        "Times",
-        "Monaco",
-        "Century",
-        "Chalkboard",
-        "Lobster",
-        "Century Gothic",
-        "Optima",
-        "Lucida Grande",
-        "Gill Sans",
-        "Baskerville",
-        "Helvetica",
-        "Helvetica Neue",
-        "",
-      },
-    },
-    { "Legacy Sans Fonts",
-      { "Andale Mono",
-        "Arial Unicode MS",
-        "Arial",
-        "Century Gothic",
-        "Comic Sans MS",
-        "Franklin Gothic Medium",
-        "Geneva",
-        "Lucida Console",
-        "Lucida Grande",
-        "Lucida Sans Unicode",
-        "Lucida Sans Typewriter",
-        "Microsoft Sans Serif",
-        "Monaco",
-        "Tahoma",
-        "Trebuchet MS",
-        "Verdana",
-        "",
-      },
-    },
-
-    { "Misc Legacy Fonts",
-      { "Dark Courier", "", }, },
-    { "Verdana Clones",
-      { "DejaVu Sans",
-        "Bitstream Vera Sans", "", }, },
-    { "Verdana and Clones",
-      { "DejaVu Sans",
-        "Bitstream Vera Sans",
-        "Verdana", "", }, },
-  };
-
-
-  /* Define this to force natural (i.e. not bitmap-compatible) widths.     */
-  /* The default leans strongly towards natural widths except for a few    */
-  /* legacy fonts where a selective combination produces nicer results.    */
-/* #define FORCE_NATURAL_WIDTHS   */
-
-
-  /* Define `classes' of styles that can be grouped together and used in   */
-  /* rules below.  A blank entry "" is required at the end of these!       */
-#define STYLE_CLASS_RULES_SIZE  5
-
-  static const SPH_Font_Class  STYLE_CLASS_Rules
-                               [STYLE_CLASS_RULES_SIZE] =
-  {
-    { "Regular Class",
-      { "Regular",
-        "Book",
-        "Medium",
-        "Roman",
-        "Normal",
-        "",
-      },
-    },
-    { "Regular/Italic Class",
-      { "Regular",
-        "Book",
-        "Medium",
-        "Italic",
-        "Oblique",
-        "Roman",
-        "Normal",
-        "",
-      },
-    },
-    { "Bold/BoldItalic Class",
-      { "Bold",
-        "Bold Italic",
-        "Black",
-        "",
-      },
-    },
-    { "Bold/Italic/BoldItalic Class",
-      { "Bold",
-        "Bold Italic",
-        "Black",
-        "Italic",
-        "Oblique",
-        "",
-      },
-    },
-    { "Regular/Bold Class",
-      { "Regular",
-        "Book",
-        "Medium",
-        "Normal",
-        "Roman",
-        "Bold",
-        "Black",
-        "",
-      },
-    },
-  };
-
-
-  /* Force special legacy fixes for fonts.                                 */
-#define COMPATIBILITY_MODE_RULES_SIZE  1
-
-  static const SPH_TweakRule  COMPATIBILITY_MODE_Rules
-                              [COMPATIBILITY_MODE_RULES_SIZE] =
-  {
-    { "Verdana Clones", 0, "", 0 },
-  };
-
-
-  /* Don't do subpixel (ignore_x_mode) hinting; do normal hinting.         */
-#define PIXEL_HINTING_RULES_SIZE  2
-
-  static const SPH_TweakRule  PIXEL_HINTING_Rules
-                              [PIXEL_HINTING_RULES_SIZE] =
-  {
-    /* these characters are almost always safe */
-    { "Courier New", 12, "Italic", 'z' },
-    { "Courier New", 11, "Italic", 'z' },
-  };
-
-
-  /* Subpixel hinting ignores SHPIX rules on X.  Force SHPIX for these.    */
-#define DO_SHPIX_RULES_SIZE  1
-
-  static const SPH_TweakRule  DO_SHPIX_Rules
-                              [DO_SHPIX_RULES_SIZE] =
-  {
-    { "-", 0, "", 0 },
-  };
-
-
-  /* Skip Y moves that start with a point that is not on a Y pixel         */
-  /* boundary and don't move that point to a Y pixel boundary.             */
-#define SKIP_NONPIXEL_Y_MOVES_RULES_SIZE  4
-
-  static const SPH_TweakRule  SKIP_NONPIXEL_Y_MOVES_Rules
-                              [SKIP_NONPIXEL_Y_MOVES_RULES_SIZE] =
-  {
-    /* fix vwxyz thinness */
-    { "Consolas", 0, "", 0 },
-    /* Fix thin middle stems */
-    { "Core MS Legacy Fonts", 0, "Regular", 0 },
-    /* Cyrillic small letter I */
-    { "Legacy Sans Fonts", 0, "", 0 },
-    /* Fix artifacts with some Regular & Bold */
-    { "Verdana Clones", 0, "", 0 },
-  };
-
-
-#define SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE  1
-
-  static const SPH_TweakRule  SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions
-                              [SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
-  {
-    /* Fixes < and > */
-    { "Courier New", 0, "Regular", 0 },
-  };
-
-
-  /* Skip Y moves that start with a point that is not on a Y pixel         */
-  /* boundary and don't move that point to a Y pixel boundary.             */
-#define SKIP_NONPIXEL_Y_MOVES_DELTAP_RULES_SIZE  2
-
-  static const SPH_TweakRule  SKIP_NONPIXEL_Y_MOVES_DELTAP_Rules
-                              [SKIP_NONPIXEL_Y_MOVES_DELTAP_RULES_SIZE] =
-  {
-    /* Maintain thickness of diagonal in 'N' */
-    { "Times New Roman", 0, "Regular/Bold Class", 'N' },
-    { "Georgia", 0, "Regular/Bold Class", 'N' },
-  };
-
-
-  /* Skip Y moves that move a point off a Y pixel boundary.                */
-#define SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE  1
-
-  static const SPH_TweakRule  SKIP_OFFPIXEL_Y_MOVES_Rules
-                              [SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE] =
-  {
-    { "-", 0, "", 0 },
-  };
-
-
-#define SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE  1
-
-  static const SPH_TweakRule  SKIP_OFFPIXEL_Y_MOVES_Rules_Exceptions
-                              [SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
-  {
-    { "-", 0, "", 0 },
-  };
-
-
-  /* Round moves that don't move a point to a Y pixel boundary.            */
-#define ROUND_NONPIXEL_Y_MOVES_RULES_SIZE  2
-
-  static const SPH_TweakRule  ROUND_NONPIXEL_Y_MOVES_Rules
-                              [ROUND_NONPIXEL_Y_MOVES_RULES_SIZE] =
-  {
-    /* Droid font instructions don't snap Y to pixels */
-    { "Droid Sans", 0, "Regular/Italic Class", 0 },
-    { "Droid Sans Mono", 0, "", 0 },
-  };
-
-
-#define ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE  1
-
-  static const SPH_TweakRule  ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions
-                              [ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
-  {
-    { "-", 0, "", 0 },
-  };
-
-
-  /* Allow a Direct_Move along X freedom vector if matched.                */
-#define ALLOW_X_DMOVE_RULES_SIZE  1
-
-  static const SPH_TweakRule  ALLOW_X_DMOVE_Rules
-                              [ALLOW_X_DMOVE_RULES_SIZE] =
-  {
-    /* Fixes vanishing diagonal in 4 */
-    { "Verdana", 0, "Regular", '4' },
-  };
-
-
-  /* Return MS rasterizer version 35 if matched.                           */
-#define RASTERIZER_35_RULES_SIZE  8
-
-  static const SPH_TweakRule  RASTERIZER_35_Rules
-                              [RASTERIZER_35_RULES_SIZE] =
-  {
-    /* This seems to be the only way to make these look good */
-    { "Times New Roman", 0, "Regular", 'i' },
-    { "Times New Roman", 0, "Regular", 'j' },
-    { "Times New Roman", 0, "Regular", 'm' },
-    { "Times New Roman", 0, "Regular", 'r' },
-    { "Times New Roman", 0, "Regular", 'a' },
-    { "Times New Roman", 0, "Regular", 'n' },
-    { "Times New Roman", 0, "Regular", 'p' },
-    { "Times", 0, "", 0 },
-  };
-
-
-  /* Don't round to the subpixel grid.  Round to pixel grid.               */
-#define NORMAL_ROUND_RULES_SIZE  1
-
-  static const SPH_TweakRule  NORMAL_ROUND_Rules
-                              [NORMAL_ROUND_RULES_SIZE] =
-  {
-    /* Fix serif thickness for certain ppems */
-    /* Can probably be generalized somehow   */
-    { "Courier New", 0, "", 0 },
-  };
-
-
-  /* Skip IUP instructions if matched.                                     */
-#define SKIP_IUP_RULES_SIZE  1
-
-  static const SPH_TweakRule  SKIP_IUP_Rules
-                              [SKIP_IUP_RULES_SIZE] =
-  {
-    { "Arial", 13, "Regular", 'a' },
-  };
-
-
-  /* Skip MIAP Twilight hack if matched.                                   */
-#define MIAP_HACK_RULES_SIZE  1
-
-  static const SPH_TweakRule  MIAP_HACK_Rules
-                              [MIAP_HACK_RULES_SIZE] =
-  {
-    { "Geneva", 12, "", 0 },
-  };
-
-
-  /* Skip DELTAP instructions if matched.                                  */
-#define ALWAYS_SKIP_DELTAP_RULES_SIZE  23
-
-  static const SPH_TweakRule  ALWAYS_SKIP_DELTAP_Rules
-                              [ALWAYS_SKIP_DELTAP_RULES_SIZE] =
-  {
-    { "Georgia", 0, "Regular", 'k' },
-    /* fix various problems with e in different versions */
-    { "Trebuchet MS", 14, "Regular", 'e' },
-    { "Trebuchet MS", 13, "Regular", 'e' },
-    { "Trebuchet MS", 15, "Regular", 'e' },
-    { "Trebuchet MS", 0, "Italic", 'v' },
-    { "Trebuchet MS", 0, "Italic", 'w' },
-    { "Trebuchet MS", 0, "Regular", 'Y' },
-    { "Arial", 11, "Regular", 's' },
-    /* prevent problems with '3' and others */
-    { "Verdana", 10, "Regular", 0 },
-    { "Verdana", 9, "Regular", 0 },
-    /* Cyrillic small letter short I */
-    { "Legacy Sans Fonts", 0, "", 0x438 },
-    { "Legacy Sans Fonts", 0, "", 0x439 },
-    { "Arial", 10, "Regular", '6' },
-    { "Arial", 0, "Bold/BoldItalic Class", 'a' },
-    /* Make horizontal stems consistent with the rest */
-    { "Arial", 24, "Bold", 'a' },
-    { "Arial", 25, "Bold", 'a' },
-    { "Arial", 24, "Bold", 's' },
-    { "Arial", 25, "Bold", 's' },
-    { "Arial", 34, "Bold", 's' },
-    { "Arial", 35, "Bold", 's' },
-    { "Arial", 36, "Bold", 's' },
-    { "Arial", 25, "Regular", 's' },
-    { "Arial", 26, "Regular", 's' },
-  };
-
-
-  /* Always do DELTAP instructions if matched.                             */
-#define ALWAYS_DO_DELTAP_RULES_SIZE  1
-
-  static const SPH_TweakRule  ALWAYS_DO_DELTAP_Rules
-                              [ALWAYS_DO_DELTAP_RULES_SIZE] =
-  {
-    { "-", 0, "", 0 },
-  };
-
-
-  /* Don't allow ALIGNRP after IUP.                                        */
-#define NO_ALIGNRP_AFTER_IUP_RULES_SIZE  1
-
-  static const SPH_TweakRule  NO_ALIGNRP_AFTER_IUP_Rules
-                              [NO_ALIGNRP_AFTER_IUP_RULES_SIZE] =
-  {
-    /* Prevent creation of dents in outline */
-    { "-", 0, "", 0 },
-  };
-
-
-  /* Don't allow DELTAP after IUP.                                         */
-#define NO_DELTAP_AFTER_IUP_RULES_SIZE  1
-
-  static const SPH_TweakRule  NO_DELTAP_AFTER_IUP_Rules
-                              [NO_DELTAP_AFTER_IUP_RULES_SIZE] =
-  {
-    { "-", 0, "", 0 },
-  };
-
-
-  /* Don't allow CALL after IUP.                                           */
-#define NO_CALL_AFTER_IUP_RULES_SIZE  1
-
-  static const SPH_TweakRule  NO_CALL_AFTER_IUP_Rules
-                              [NO_CALL_AFTER_IUP_RULES_SIZE] =
-  {
-    /* Prevent creation of dents in outline */
-    { "-", 0, "", 0 },
-  };
-
-
-  /* De-embolden these glyphs slightly.                                    */
-#define DEEMBOLDEN_RULES_SIZE  9
-
-  static const SPH_TweakRule  DEEMBOLDEN_Rules
-                              [DEEMBOLDEN_RULES_SIZE] =
-  {
-    { "Courier New", 0, "Bold", 'A' },
-    { "Courier New", 0, "Bold", 'W' },
-    { "Courier New", 0, "Bold", 'w' },
-    { "Courier New", 0, "Bold", 'M' },
-    { "Courier New", 0, "Bold", 'X' },
-    { "Courier New", 0, "Bold", 'K' },
-    { "Courier New", 0, "Bold", 'x' },
-    { "Courier New", 0, "Bold", 'z' },
-    { "Courier New", 0, "Bold", 'v' },
-  };
-
-
-  /* Embolden these glyphs slightly.                                       */
-#define EMBOLDEN_RULES_SIZE  2
-
-  static const SPH_TweakRule  EMBOLDEN_Rules
-                              [EMBOLDEN_RULES_SIZE] =
-  {
-    { "Courier New", 0, "Regular", 0 },
-    { "Courier New", 0, "Italic", 0 },
-  };
-
-
-  /* This is a CVT hack that makes thick horizontal stems on 2, 5, 7       */
-  /* similar to Windows XP.                                                */
-#define TIMES_NEW_ROMAN_HACK_RULES_SIZE  12
-
-  static const SPH_TweakRule  TIMES_NEW_ROMAN_HACK_Rules
-                              [TIMES_NEW_ROMAN_HACK_RULES_SIZE] =
-  {
-    { "Times New Roman", 16, "Italic", '2' },
-    { "Times New Roman", 16, "Italic", '5' },
-    { "Times New Roman", 16, "Italic", '7' },
-    { "Times New Roman", 16, "Regular", '2' },
-    { "Times New Roman", 16, "Regular", '5' },
-    { "Times New Roman", 16, "Regular", '7' },
-    { "Times New Roman", 17, "Italic", '2' },
-    { "Times New Roman", 17, "Italic", '5' },
-    { "Times New Roman", 17, "Italic", '7' },
-    { "Times New Roman", 17, "Regular", '2' },
-    { "Times New Roman", 17, "Regular", '5' },
-    { "Times New Roman", 17, "Regular", '7' },
-  };
-
-
-  /* This fudges distance on 2 to get rid of the vanishing stem issue.     */
-  /* A real solution to this is certainly welcome.                         */
-#define COURIER_NEW_2_HACK_RULES_SIZE  15
-
-  static const SPH_TweakRule  COURIER_NEW_2_HACK_Rules
-                              [COURIER_NEW_2_HACK_RULES_SIZE] =
-  {
-    { "Courier New", 10, "Regular", '2' },
-    { "Courier New", 11, "Regular", '2' },
-    { "Courier New", 12, "Regular", '2' },
-    { "Courier New", 13, "Regular", '2' },
-    { "Courier New", 14, "Regular", '2' },
-    { "Courier New", 15, "Regular", '2' },
-    { "Courier New", 16, "Regular", '2' },
-    { "Courier New", 17, "Regular", '2' },
-    { "Courier New", 18, "Regular", '2' },
-    { "Courier New", 19, "Regular", '2' },
-    { "Courier New", 20, "Regular", '2' },
-    { "Courier New", 21, "Regular", '2' },
-    { "Courier New", 22, "Regular", '2' },
-    { "Courier New", 23, "Regular", '2' },
-    { "Courier New", 24, "Regular", '2' },
-  };
-
-
-#ifndef FORCE_NATURAL_WIDTHS
-
-  /* Use compatible widths with these glyphs.  Compatible widths is always */
-  /* on when doing B/W TrueType instructing, but is used selectively here, */
-  /* typically on glyphs with 3 or more vertical stems.                    */
-#define COMPATIBLE_WIDTHS_RULES_SIZE  38
-
-  static const SPH_TweakRule  COMPATIBLE_WIDTHS_Rules
-                              [COMPATIBLE_WIDTHS_RULES_SIZE] =
-  {
-    { "Arial Unicode MS", 12, "Regular Class", 'm' },
-    { "Arial Unicode MS", 14, "Regular Class", 'm' },
-    /* Cyrillic small letter sha */
-    { "Arial", 10, "Regular Class", 0x448 },
-    { "Arial", 11, "Regular Class", 'm' },
-    { "Arial", 12, "Regular Class", 'm' },
-    /* Cyrillic small letter sha */
-    { "Arial", 12, "Regular Class", 0x448 },
-    { "Arial", 13, "Regular Class", 0x448 },
-    { "Arial", 14, "Regular Class", 'm' },
-    /* Cyrillic small letter sha */
-    { "Arial", 14, "Regular Class", 0x448 },
-    { "Arial", 15, "Regular Class", 0x448 },
-    { "Arial", 17, "Regular Class", 'm' },
-    { "DejaVu Sans", 15, "Regular Class", 0 },
-    { "Microsoft Sans Serif", 11, "Regular Class", 0 },
-    { "Microsoft Sans Serif", 12, "Regular Class", 0 },
-    { "Segoe UI", 11, "Regular Class", 0 },
-    { "Monaco", 0, "Regular Class", 0 },
-    { "Segoe UI", 12, "Regular Class", 'm' },
-    { "Segoe UI", 14, "Regular Class", 'm' },
-    { "Tahoma", 11, "Regular Class", 0 },
-    { "Times New Roman", 16, "Regular Class", 'c' },
-    { "Times New Roman", 16, "Regular Class", 'm' },
-    { "Times New Roman", 16, "Regular Class", 'o' },
-    { "Times New Roman", 16, "Regular Class", 'w' },
-    { "Trebuchet MS", 11, "Regular Class", 0 },
-    { "Trebuchet MS", 12, "Regular Class", 0 },
-    { "Trebuchet MS", 14, "Regular Class", 0 },
-    { "Trebuchet MS", 15, "Regular Class", 0 },
-    { "Ubuntu", 12, "Regular Class", 'm' },
-    /* Cyrillic small letter sha */
-    { "Verdana", 10, "Regular Class", 0x448 },
-    { "Verdana", 11, "Regular Class", 0x448 },
-    { "Verdana and Clones", 12, "Regular Class", 'i' },
-    { "Verdana and Clones", 12, "Regular Class", 'j' },
-    { "Verdana and Clones", 12, "Regular Class", 'l' },
-    { "Verdana and Clones", 12, "Regular Class", 'm' },
-    { "Verdana and Clones", 13, "Regular Class", 'i' },
-    { "Verdana and Clones", 13, "Regular Class", 'j' },
-    { "Verdana and Clones", 13, "Regular Class", 'l' },
-    { "Verdana and Clones", 14, "Regular Class", 'm' },
-  };
-
-
-  /* Scaling slightly in the x-direction prior to hinting results in       */
-  /* more visually pleasing glyphs in certain cases.                       */
-  /* This sometimes needs to be coordinated with compatible width rules.   */
-  /* A value of 1000 corresponds to a scaled value of 1.0.                 */
-
-#define X_SCALING_RULES_SIZE  50
-
-  static const SPH_ScaleRule  X_SCALING_Rules[X_SCALING_RULES_SIZE] =
-  {
-    { "DejaVu Sans", 12, "Regular Class", 'm', 950 },
-    { "Verdana and Clones", 12, "Regular Class", 'a', 1100 },
-    { "Verdana and Clones", 13, "Regular Class", 'a', 1050 },
-    { "Arial", 11, "Regular Class", 'm', 975 },
-    { "Arial", 12, "Regular Class", 'm', 1050 },
-    /* Cyrillic small letter el */
-    { "Arial", 13, "Regular Class", 0x43B, 950 },
-    { "Arial", 13, "Regular Class", 'o', 950 },
-    { "Arial", 13, "Regular Class", 'e', 950 },
-    { "Arial", 14, "Regular Class", 'm', 950 },
-    /* Cyrillic small letter el */
-    { "Arial", 15, "Regular Class", 0x43B, 925 },
-    { "Bitstream Vera Sans", 10, "Regular/Italic Class", 0, 1100 },
-    { "Bitstream Vera Sans", 12, "Regular/Italic Class", 0, 1050 },
-    { "Bitstream Vera Sans", 16, "Regular Class", 0, 1050 },
-    { "Bitstream Vera Sans", 9, "Regular/Italic Class", 0, 1050 },
-    { "DejaVu Sans", 12, "Regular Class", 'l', 975 },
-    { "DejaVu Sans", 12, "Regular Class", 'i', 975 },
-    { "DejaVu Sans", 12, "Regular Class", 'j', 975 },
-    { "DejaVu Sans", 13, "Regular Class", 'l', 950 },
-    { "DejaVu Sans", 13, "Regular Class", 'i', 950 },
-    { "DejaVu Sans", 13, "Regular Class", 'j', 950 },
-    { "DejaVu Sans", 10, "Regular/Italic Class", 0, 1100 },
-    { "DejaVu Sans", 12, "Regular/Italic Class", 0, 1050 },
-    { "Georgia", 10, "", 0, 1050 },
-    { "Georgia", 11, "", 0, 1100 },
-    { "Georgia", 12, "", 0, 1025 },
-    { "Georgia", 13, "", 0, 1050 },
-    { "Georgia", 16, "", 0, 1050 },
-    { "Georgia", 17, "", 0, 1030 },
-    { "Liberation Sans", 12, "Regular Class", 'm', 1100 },
-    { "Lucida Grande", 11, "Regular Class", 'm', 1100 },
-    { "Microsoft Sans Serif", 11, "Regular Class", 'm', 950 },
-    { "Microsoft Sans Serif", 12, "Regular Class", 'm', 1050 },
-    { "Segoe UI", 12, "Regular Class", 'H', 1050 },
-    { "Segoe UI", 12, "Regular Class", 'm', 1050 },
-    { "Segoe UI", 14, "Regular Class", 'm', 1050 },
-    { "Tahoma", 11, "Regular Class", 'i', 975 },
-    { "Tahoma", 11, "Regular Class", 'l', 975 },
-    { "Tahoma", 11, "Regular Class", 'j', 900 },
-    { "Tahoma", 11, "Regular Class", 'm', 918 },
-    { "Verdana", 10, "Regular/Italic Class", 0, 1100 },
-    { "Verdana", 12, "Regular Class", 'm', 975 },
-    { "Verdana", 12, "Regular/Italic Class", 0, 1050 },
-    { "Verdana", 13, "Regular/Italic Class", 'i', 950 },
-    { "Verdana", 13, "Regular/Italic Class", 'j', 950 },
-    { "Verdana", 13, "Regular/Italic Class", 'l', 950 },
-    { "Verdana", 16, "Regular Class", 0, 1050 },
-    { "Verdana", 9, "Regular/Italic Class", 0, 1050 },
-    { "Times New Roman", 16, "Regular Class", 'm', 918 },
-    { "Trebuchet MS", 11, "Regular Class", 'm', 800 },
-    { "Trebuchet MS", 12, "Regular Class", 'm', 800 },
-  };
-
-#else
-
-#define COMPATIBLE_WIDTHS_RULES_SIZE  1
-
-  static const SPH_TweakRule  COMPATIBLE_WIDTHS_Rules
-                              [COMPATIBLE_WIDTHS_RULES_SIZE] =
-  {
-    { "-", 0, "", 0 },
-  };
-
-
-#define X_SCALING_RULES_SIZE  1
-
-  static const SPH_ScaleRule  X_SCALING_Rules
-                              [X_SCALING_RULES_SIZE] =
-  {
-    { "-", 0, "", 0, 1000 },
-  };
-
-#endif /* FORCE_NATURAL_WIDTHS */
-
-
-  static FT_Bool
-  is_member_of_family_class( const FT_String*  detected_font_name,
-                             const FT_String*  rule_font_name )
-  {
-    FT_UInt  i, j;
-
-
-    /* Does font name match rule family? */
-    if ( ft_strcmp( detected_font_name, rule_font_name ) == 0 )
-      return TRUE;
-
-    /* Is font name a wildcard ""? */
-    if ( ft_strcmp( rule_font_name, "" ) == 0 )
-      return TRUE;
-
-    /* Is font name contained in a class list? */
-    for ( i = 0; i < FAMILY_CLASS_RULES_SIZE; i++ )
-    {
-      if ( ft_strcmp( FAMILY_CLASS_Rules[i].name, rule_font_name ) == 0 )
-      {
-        for ( j = 0; j < SPH_MAX_CLASS_MEMBERS; j++ )
-        {
-          if ( ft_strcmp( FAMILY_CLASS_Rules[i].member[j], "" ) == 0 )
-            continue;
-          if ( ft_strcmp( FAMILY_CLASS_Rules[i].member[j],
-                          detected_font_name ) == 0 )
-            return TRUE;
-        }
-      }
-    }
-
-    return FALSE;
-  }
-
-
-  static FT_Bool
-  is_member_of_style_class( const FT_String*  detected_font_style,
-                            const FT_String*  rule_font_style )
-  {
-    FT_UInt  i, j;
-
-
-    /* Does font style match rule style? */
-    if ( ft_strcmp( detected_font_style, rule_font_style ) == 0 )
-      return TRUE;
-
-    /* Is font style a wildcard ""? */
-    if ( ft_strcmp( rule_font_style, "" ) == 0 )
-      return TRUE;
-
-    /* Is font style contained in a class list? */
-    for ( i = 0; i < STYLE_CLASS_RULES_SIZE; i++ )
-    {
-      if ( ft_strcmp( STYLE_CLASS_Rules[i].name, rule_font_style ) == 0 )
-      {
-        for ( j = 0; j < SPH_MAX_CLASS_MEMBERS; j++ )
-        {
-          if ( ft_strcmp( STYLE_CLASS_Rules[i].member[j], "" ) == 0 )
-            continue;
-          if ( ft_strcmp( STYLE_CLASS_Rules[i].member[j],
-                          detected_font_style ) == 0 )
-            return TRUE;
-        }
-      }
-    }
-
-    return FALSE;
-  }
-
-
-  FT_LOCAL_DEF( FT_Bool )
-  sph_test_tweak( TT_Face               face,
-                  const FT_String*      family,
-                  FT_UInt               ppem,
-                  const FT_String*      style,
-                  FT_UInt               glyph_index,
-                  const SPH_TweakRule*  rule,
-                  FT_UInt               num_rules )
-  {
-    FT_UInt  i;
-
-
-    /* rule checks may be able to be optimized further */
-    for ( i = 0; i < num_rules; i++ )
-    {
-      if ( family                                                   &&
-           ( is_member_of_family_class ( family, rule[i].family ) ) )
-        if ( rule[i].ppem == 0    ||
-             rule[i].ppem == ppem )
-          if ( style                                             &&
-               is_member_of_style_class ( style, rule[i].style ) )
-            if ( rule[i].glyph == 0                                ||
-                 FT_Get_Char_Index( (FT_Face)face,
-                                    rule[i].glyph ) == glyph_index )
-        return TRUE;
-    }
-
-    return FALSE;
-  }
-
-
-  static FT_UInt
-  scale_test_tweak( TT_Face               face,
-                    const FT_String*      family,
-                    FT_UInt               ppem,
-                    const FT_String*      style,
-                    FT_UInt               glyph_index,
-                    const SPH_ScaleRule*  rule,
-                    FT_UInt               num_rules )
-  {
-    FT_UInt  i;
-
-
-    /* rule checks may be able to be optimized further */
-    for ( i = 0; i < num_rules; i++ )
-    {
-      if ( family                                                   &&
-           ( is_member_of_family_class ( family, rule[i].family ) ) )
-        if ( rule[i].ppem == 0    ||
-             rule[i].ppem == ppem )
-          if ( style                                            &&
-               is_member_of_style_class( style, rule[i].style ) )
-            if ( rule[i].glyph == 0                                ||
-                 FT_Get_Char_Index( (FT_Face)face,
-                                    rule[i].glyph ) == glyph_index )
-        return rule[i].scale;
-    }
-
-    return 1000;
-  }
-
-
-  FT_LOCAL_DEF( FT_UInt )
-  sph_test_tweak_x_scaling( TT_Face           face,
-                            const FT_String*  family,
-                            FT_UInt           ppem,
-                            const FT_String*  style,
-                            FT_UInt           glyph_index )
-  {
-    return scale_test_tweak( face, family, ppem, style, glyph_index,
-                             X_SCALING_Rules, X_SCALING_RULES_SIZE );
-  }
-
-
-#define TWEAK_RULES( x )                                       \
-  if ( sph_test_tweak( face, family, ppem, style, glyph_index, \
-                       x##_Rules, x##_RULES_SIZE ) )           \
-    loader->exec->sph_tweak_flags |= SPH_TWEAK_##x
-
-#define TWEAK_RULES_EXCEPTIONS( x )                                        \
-  if ( sph_test_tweak( face, family, ppem, style, glyph_index,             \
-                       x##_Rules_Exceptions, x##_RULES_EXCEPTIONS_SIZE ) ) \
-    loader->exec->sph_tweak_flags &= ~SPH_TWEAK_##x
-
-
-  FT_LOCAL_DEF( void )
-  sph_set_tweaks( TT_Loader  loader,
-                  FT_UInt    glyph_index )
-  {
-    TT_Face     face   = loader->face;
-    FT_String*  family = face->root.family_name;
-    FT_UInt     ppem   = loader->size->metrics->x_ppem;
-    FT_String*  style  = face->root.style_name;
-
-
-    /* don't apply rules if style isn't set */
-    if ( !face->root.style_name )
-      return;
-
-#ifdef SPH_DEBUG_MORE_VERBOSE
-    printf( "%s,%d,%s,%c=%d ",
-            family, ppem, style, glyph_index, glyph_index );
-#endif
-
-    TWEAK_RULES( PIXEL_HINTING );
-
-    if ( loader->exec->sph_tweak_flags & SPH_TWEAK_PIXEL_HINTING )
-    {
-      loader->exec->ignore_x_mode = FALSE;
-      return;
-    }
-
-    TWEAK_RULES( ALLOW_X_DMOVE );
-    TWEAK_RULES( ALWAYS_DO_DELTAP );
-    TWEAK_RULES( ALWAYS_SKIP_DELTAP );
-    TWEAK_RULES( DEEMBOLDEN );
-    TWEAK_RULES( DO_SHPIX );
-    TWEAK_RULES( EMBOLDEN );
-    TWEAK_RULES( MIAP_HACK );
-    TWEAK_RULES( NORMAL_ROUND );
-    TWEAK_RULES( NO_ALIGNRP_AFTER_IUP );
-    TWEAK_RULES( NO_CALL_AFTER_IUP );
-    TWEAK_RULES( NO_DELTAP_AFTER_IUP );
-    TWEAK_RULES( RASTERIZER_35 );
-    TWEAK_RULES( SKIP_IUP );
-
-    TWEAK_RULES( SKIP_OFFPIXEL_Y_MOVES );
-    TWEAK_RULES_EXCEPTIONS( SKIP_OFFPIXEL_Y_MOVES );
-
-    TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES_DELTAP );
-
-    TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES );
-    TWEAK_RULES_EXCEPTIONS( SKIP_NONPIXEL_Y_MOVES );
-
-    TWEAK_RULES( ROUND_NONPIXEL_Y_MOVES );
-    TWEAK_RULES_EXCEPTIONS( ROUND_NONPIXEL_Y_MOVES );
-
-    if ( loader->exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 )
-    {
-      if ( loader->exec->rasterizer_version != TT_INTERPRETER_VERSION_35 )
-      {
-        loader->exec->rasterizer_version = TT_INTERPRETER_VERSION_35;
-        loader->exec->size->cvt_ready    = -1;
-
-        tt_size_ready_bytecode(
-          loader->exec->size,
-          FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) );
-      }
-      else
-        loader->exec->rasterizer_version = TT_INTERPRETER_VERSION_35;
-    }
-    else
-    {
-      if ( loader->exec->rasterizer_version  !=
-           SPH_OPTION_SET_RASTERIZER_VERSION )
-      {
-        loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
-        loader->exec->size->cvt_ready    = -1;
-
-        tt_size_ready_bytecode(
-          loader->exec->size,
-          FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) );
-      }
-      else
-        loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
-    }
-
-    if ( IS_HINTED( loader->load_flags ) )
-    {
-      TWEAK_RULES( TIMES_NEW_ROMAN_HACK );
-      TWEAK_RULES( COURIER_NEW_2_HACK );
-    }
-
-    if ( sph_test_tweak( face, family, ppem, style, glyph_index,
-           COMPATIBILITY_MODE_Rules, COMPATIBILITY_MODE_RULES_SIZE ) )
-      loader->exec->face->sph_compatibility_mode = TRUE;
-
-
-    if ( IS_HINTED( loader->load_flags ) )
-    {
-      if ( sph_test_tweak( face, family, ppem, style, glyph_index,
-             COMPATIBLE_WIDTHS_Rules, COMPATIBLE_WIDTHS_RULES_SIZE ) )
-        loader->exec->compatible_widths |= TRUE;
-    }
-  }
-
-#else /* !(TT_USE_BYTECODE_INTERPRETER &&          */
-      /*   TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY) */
-
-  /* ANSI C doesn't like empty source files */
-  typedef int  _tt_subpix_dummy;
-
-#endif /* !(TT_USE_BYTECODE_INTERPRETER &&          */
-       /*   TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY) */
-
-
-/* END */
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.h
deleted file mode 100644
index 62af4c272d1..00000000000
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/****************************************************************************
- *
- * ttsubpix.h
- *
- *   TrueType Subpixel Hinting.
- *
- * Copyright (C) 2010-2023 by
- * David Turner, Robert Wilhelm, and Werner Lemberg.
- *
- * This file is part of the FreeType project, and may only be used,
- * modified, and distributed under the terms of the FreeType project
- * license, LICENSE.TXT.  By continuing to use, modify, or distribute
- * this file you indicate that you have read the license and
- * understand and accept it fully.
- *
- */
-
-
-#ifndef TTSUBPIX_H_
-#define TTSUBPIX_H_
-
-#include "ttobjs.h"
-#include "ttinterp.h"
-
-
-FT_BEGIN_HEADER
-
-
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-
-  /**************************************************************************
-   *
-   * ID flags to identify special functions at FDEF and runtime.
-   *
-   */
-#define SPH_FDEF_INLINE_DELTA_1       0x0000001
-#define SPH_FDEF_INLINE_DELTA_2       0x0000002
-#define SPH_FDEF_DIAGONAL_STROKE      0x0000004
-#define SPH_FDEF_VACUFORM_ROUND_1     0x0000008
-#define SPH_FDEF_TTFAUTOHINT_1        0x0000010
-#define SPH_FDEF_SPACING_1            0x0000020
-#define SPH_FDEF_SPACING_2            0x0000040
-#define SPH_FDEF_TYPEMAN_STROKES      0x0000080
-#define SPH_FDEF_TYPEMAN_DIAGENDCTRL  0x0000100
-
-
-  /**************************************************************************
-   *
-   * Tweak flags that are set for each glyph by the below rules.
-   *
-   */
-#define SPH_TWEAK_ALLOW_X_DMOVE                   0x0000001UL
-#define SPH_TWEAK_ALWAYS_DO_DELTAP                0x0000002UL
-#define SPH_TWEAK_ALWAYS_SKIP_DELTAP              0x0000004UL
-#define SPH_TWEAK_COURIER_NEW_2_HACK              0x0000008UL
-#define SPH_TWEAK_DEEMBOLDEN                      0x0000010UL
-#define SPH_TWEAK_DO_SHPIX                        0x0000020UL
-#define SPH_TWEAK_EMBOLDEN                        0x0000040UL
-#define SPH_TWEAK_MIAP_HACK                       0x0000080UL
-#define SPH_TWEAK_NORMAL_ROUND                    0x0000100UL
-#define SPH_TWEAK_NO_ALIGNRP_AFTER_IUP            0x0000200UL
-#define SPH_TWEAK_NO_CALL_AFTER_IUP               0x0000400UL
-#define SPH_TWEAK_NO_DELTAP_AFTER_IUP             0x0000800UL
-#define SPH_TWEAK_PIXEL_HINTING                   0x0001000UL
-#define SPH_TWEAK_RASTERIZER_35                   0x0002000UL
-#define SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES          0x0004000UL
-#define SPH_TWEAK_SKIP_IUP                        0x0008000UL
-#define SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES           0x0010000UL
-#define SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES           0x0020000UL
-#define SPH_TWEAK_TIMES_NEW_ROMAN_HACK            0x0040000UL
-#define SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP    0x0080000UL
-
-
-  FT_LOCAL( FT_Bool )
-  sph_test_tweak( TT_Face               face,
-                  const FT_String*      family,
-                  FT_UInt               ppem,
-                  const FT_String*      style,
-                  FT_UInt               glyph_index,
-                  const SPH_TweakRule*  rule,
-                  FT_UInt               num_rules );
-
-  FT_LOCAL( FT_UInt )
-  sph_test_tweak_x_scaling( TT_Face           face,
-                            const FT_String*  family,
-                            FT_UInt           ppem,
-                            const FT_String*  style,
-                            FT_UInt           glyph_index );
-
-  FT_LOCAL( void )
-  sph_set_tweaks( TT_Loader  loader,
-                  FT_UInt    glyph_index );
-
-
-  /* These macros are defined absent a method for setting them */
-#define SPH_OPTION_BITMAP_WIDTHS           FALSE
-#define SPH_OPTION_SET_SUBPIXEL            TRUE
-#define SPH_OPTION_SET_GRAYSCALE           FALSE
-#define SPH_OPTION_SET_COMPATIBLE_WIDTHS   FALSE
-#define SPH_OPTION_SET_RASTERIZER_VERSION  38
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
-
-FT_END_HEADER
-
-#endif /* TTSUBPIX_H_ */
-
-
-/* END */
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c b/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c
index a63cd4dc48a..b1a0d23bed6 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c
@@ -4,7 +4,7 @@
  *
  *   AFM support for Type 1 fonts (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1afm.h b/src/java.desktop/share/native/libfreetype/src/type1/t1afm.h
index 7f5cdda191f..92ff627dd0d 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1afm.h
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1afm.h
@@ -4,7 +4,7 @@
  *
  *   AFM support for Type 1 fonts (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c b/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c
index 8ed01914a5a..5ded7714021 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c
@@ -4,7 +4,7 @@
  *
  *   Type 1 driver interface (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1driver.h b/src/java.desktop/share/native/libfreetype/src/type1/t1driver.h
index 5ff52b55b1a..1cc3d24e7dd 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1driver.h
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1driver.h
@@ -4,7 +4,7 @@
  *
  *   High-level Type 1 driver interface (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1errors.h b/src/java.desktop/share/native/libfreetype/src/type1/t1errors.h
index 8aeb24ae188..46bddbc30fd 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1errors.h
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1errors.h
@@ -4,7 +4,7 @@
  *
  *   Type 1 error codes (specification only).
  *
- * Copyright (C) 2001-2024 by
+ * Copyright (C) 2001-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1gload.c b/src/java.desktop/share/native/libfreetype/src/type1/t1gload.c
index c29e682510c..b9bc0b56ce8 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1gload.c
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1gload.c
@@ -4,7 +4,7 @@
  *
  *   Type 1 Glyph Loader (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -70,8 +70,13 @@
     /* For incremental fonts get the character data using the */
     /* callback function.                                     */
     if ( inc )
+    {
+      /* So `free_glyph_data` knows whether to free it. */
+      char_string->pointer = NULL;
+
       error = inc->funcs->get_glyph_data( inc->object,
                                           glyph_index, char_string );
+    }
     else
 
 #endif /* FT_CONFIG_OPTION_INCREMENTAL */
@@ -155,6 +160,9 @@
       decoder->builder.advance.y      = INT_TO_FIXED( metrics.advance_v );
     }
 
+    if ( error && inc )
+      inc->funcs->free_glyph_data( inc->object, char_string );
+
 #endif /* FT_CONFIG_OPTION_INCREMENTAL */
 
     return error;
@@ -295,7 +303,7 @@
       {
         advances[nn] = 0;
 
-        FT_TRACE5(( "  idx %d: advance height 0 font units\n",
+        FT_TRACE5(( "  idx %u: advance height 0 font units\n",
                     first + nn ));
       }
 
@@ -333,7 +341,7 @@
       else
         advances[nn] = 0;
 
-      FT_TRACE5(( "  idx %d: advance width %ld font unit%s\n",
+      FT_TRACE5(( "  idx %u: advance width %ld font unit%s\n",
                   first + nn,
                   advances[nn],
                   advances[nn] == 1 ? "" : "s" ));
@@ -380,7 +388,7 @@
       goto Exit;
     }
 
-    FT_TRACE1(( "T1_Load_Glyph: glyph index %d\n", glyph_index ));
+    FT_TRACE1(( "T1_Load_Glyph: glyph index %u\n", glyph_index ));
 
     FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) );
 
@@ -398,16 +406,12 @@
       glyph->y_scale = 0x10000L;
     }
 
-    t1glyph->outline.n_points   = 0;
-    t1glyph->outline.n_contours = 0;
-
     hinting = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE   ) &&
                        !( load_flags & FT_LOAD_NO_HINTING ) );
     scaled  = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE   ) );
 
     glyph->hint     = hinting;
     glyph->scaled   = scaled;
-    t1glyph->format = FT_GLYPH_FORMAT_OUTLINE;
 
     error = decoder_funcs->init( &decoder,
                                  t1glyph->face,
@@ -452,16 +456,12 @@
 
     must_finish_decoder = FALSE;
 
-    /* now, set the metrics -- this is rather simple, as   */
-    /* the left side bearing is the xMin, and the top side */
-    /* bearing the yMax                                    */
     if ( !error )
     {
-      t1glyph->outline.flags &= FT_OUTLINE_OWNER;
-      t1glyph->outline.flags |= FT_OUTLINE_REVERSE_FILL;
-
-      /* for composite glyphs, return only left side bearing and */
-      /* advance width                                           */
+      /* now, set the metrics -- this is rather simple, as   */
+      /* the left side bearing is the xMin, and the top side */
+      /* bearing the yMax; for composite glyphs, return only */
+      /* left side bearing and advance width                 */
       if ( load_flags & FT_LOAD_NO_RECURSE )
       {
         FT_Slot_Internal  internal = t1glyph->internal;
@@ -482,6 +482,13 @@
         FT_Glyph_Metrics*  metrics = &t1glyph->metrics;
 
 
+        t1glyph->format = FT_GLYPH_FORMAT_OUTLINE;
+
+        t1glyph->outline.flags &= FT_OUTLINE_OWNER;
+        t1glyph->outline.flags |= FT_OUTLINE_REVERSE_FILL;
+        if ( t1size && t1size->metrics.y_ppem < 24 )
+          t1glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
+
         /* copy the _unscaled_ advance width */
         metrics->horiAdvance =
           FIXED_TO_INT( decoder.builder.advance.x );
@@ -504,11 +511,6 @@
             FIXED_TO_INT( decoder.builder.advance.y );
         }
 
-        t1glyph->format = FT_GLYPH_FORMAT_OUTLINE;
-
-        if ( t1size && t1size->metrics.y_ppem < 24 )
-          t1glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
-
 #if 1
         /* apply the font matrix, if any */
         if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L ||
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1gload.h b/src/java.desktop/share/native/libfreetype/src/type1/t1gload.h
index 17a6a5941e3..6bedd132c5f 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1gload.h
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1gload.h
@@ -4,7 +4,7 @@
  *
  *   Type 1 Glyph Loader (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1load.c b/src/java.desktop/share/native/libfreetype/src/type1/t1load.c
index ee7fb42a517..0f11445bef0 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1load.c
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1load.c
@@ -4,7 +4,7 @@
  *
  *   Type 1 font loader (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -471,7 +471,7 @@
     nc = num_coords;
     if ( num_coords > blend->num_axis )
     {
-      FT_TRACE2(( "T1_Get_MM_Blend: only using first %d of %d coordinates\n",
+      FT_TRACE2(( "T1_Get_MM_Blend: only using first %u of %u coordinates\n",
                   blend->num_axis, num_coords ));
       nc = blend->num_axis;
     }
@@ -640,7 +640,7 @@
   {
     FT_UNUSED( instance_index );
 
-    return T1_Set_MM_Blend( face, 0, NULL );
+    return T1_Set_MM_WeightVector( face, 0, NULL );
   }
 
 
@@ -691,7 +691,7 @@
     if ( num_coords > blend->num_axis )
     {
       FT_TRACE2(( "T1_Get_Var_Design:"
-                  " only using first %d of %d coordinates\n",
+                  " only using first %u of %u coordinates\n",
                   blend->num_axis, num_coords ));
       nc = blend->num_axis;
     }
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1load.h b/src/java.desktop/share/native/libfreetype/src/type1/t1load.h
index a45efa7cb7b..2cd8241968d 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1load.h
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1load.h
@@ -4,7 +4,7 @@
  *
  *   Type 1 font loader (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c b/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c
index b1b27c31fe3..7f25208f875 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c
@@ -4,7 +4,7 @@
  *
  *   Type 1 objects manager (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1objs.h b/src/java.desktop/share/native/libfreetype/src/type1/t1objs.h
index 3809370c1e0..6c71977c154 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1objs.h
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1objs.h
@@ -4,7 +4,7 @@
  *
  *   Type 1 objects manager (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c b/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c
index 3717ea7c572..ef643e298f4 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c
@@ -4,7 +4,7 @@
  *
  *   Type 1 parser (body).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1parse.h b/src/java.desktop/share/native/libfreetype/src/type1/t1parse.h
index a0a2134d45c..f4ad426e9e1 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1parse.h
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1parse.h
@@ -4,7 +4,7 @@
  *
  *   Type 1 parser (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1tokens.h b/src/java.desktop/share/native/libfreetype/src/type1/t1tokens.h
index 5a3d2f1ef08..a526406a411 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1tokens.h
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1tokens.h
@@ -4,7 +4,7 @@
  *
  *   Type 1 tokenizer (specification).
  *
- * Copyright (C) 1996-2024 by
+ * Copyright (C) 1996-2025 by
  * David Turner, Robert Wilhelm, and Werner Lemberg.
  *
  * This file is part of the FreeType project, and may only be used,
@@ -33,7 +33,7 @@
                    T1_FIELD_DICT_FONTDICT )
 
   /* we use pointers to detect modifications made by synthetic fonts */
-  T1_FIELD_NUM   ( "ItalicAngle",        italic_angle,
+  T1_FIELD_FIXED ( "ItalicAngle",        italic_angle,
                    T1_FIELD_DICT_FONTDICT )
   T1_FIELD_BOOL  ( "isFixedPitch",       is_fixed_pitch,
                    T1_FIELD_DICT_FONTDICT )
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh
index 73e6b4c305b..011b5ad5520 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh
@@ -104,7 +104,7 @@ public:
     foreground (foreground_),
     instancer (instancer_)
   {
-    if (font->is_synthetic ())
+    if (font->is_synthetic)
     {
       font = hb_font_create_sub_font (font);
       hb_font_set_synthetic_bold (font, 0, 0, true);
@@ -178,7 +178,10 @@ struct hb_colrv1_closure_context_t :
   { glyphs->add (glyph_id); }
 
   void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers)
-  { layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); }
+  {
+    if (num_of_layers == 0) return;
+    layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1);
+  }
 
   void add_palette_index (unsigned palette_index)
   { palette_indices->add (palette_index); }
@@ -650,10 +653,10 @@ struct PaintColrLayers
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
-    return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers.get (firstLayerIndex),
-                                               HB_SERIALIZE_ERROR_INT_OVERFLOW));
 
-    return_trace (true);
+    uint32_t first_layer_index = numLayers ? c->plan->colrv1_layers.get (firstLayerIndex) : 0;
+    return_trace (c->serializer->check_assign (out->firstLayerIndex, first_layer_index,
+                                               HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1075,9 +1078,9 @@ struct PaintTranslate
     float ddx = dx + c->instancer (varIdxBase, 0);
     float ddy = dy + c->instancer (varIdxBase, 1);
 
-    bool p1 = c->funcs->push_translate (c->data, ddx, ddy);
+    c->funcs->push_translate (c->data, ddx, ddy);
     c->recurse (this+src);
-    if (p1) c->funcs->pop_transform (c->data);
+    c->funcs->pop_transform (c->data);
   }
 
   HBUINT8               format; /* format = 14(noVar) or 15 (Var) */
@@ -1124,9 +1127,9 @@ struct PaintScale
     float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
     float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
 
-    bool p1 = c->funcs->push_scale (c->data, sx, sy);
+    c->funcs->push_scale (c->data, sx, sy);
     c->recurse (this+src);
-    if (p1) c->funcs->pop_transform (c->data);
+    c->funcs->pop_transform (c->data);
   }
 
   HBUINT8               format; /* format = 16 (noVar) or 17(Var) */
@@ -1177,13 +1180,9 @@ struct PaintScaleAroundCenter
     float tCenterX = centerX + c->instancer (varIdxBase, 2);
     float tCenterY = centerY + c->instancer (varIdxBase, 3);
 
-    bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
-    bool p2 = c->funcs->push_scale (c->data, sx, sy);
-    bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
+    c->funcs->push_scale_around_center (c->data, sx, sy, tCenterX, tCenterY);
     c->recurse (this+src);
-    if (p3) c->funcs->pop_transform (c->data);
-    if (p2) c->funcs->pop_transform (c->data);
-    if (p1) c->funcs->pop_transform (c->data);
+    c->funcs->pop_transform (c->data);
   }
 
   HBUINT8               format; /* format = 18 (noVar) or 19(Var) */
@@ -1228,9 +1227,9 @@ struct PaintScaleUniform
     TRACE_PAINT (this);
     float s = scale.to_float (c->instancer (varIdxBase, 0));
 
-    bool p1 = c->funcs->push_scale (c->data, s, s);
+    c->funcs->push_scale (c->data, s, s);
     c->recurse (this+src);
-    if (p1) c->funcs->pop_transform (c->data);
+    c->funcs->pop_transform (c->data);
   }
 
   HBUINT8               format; /* format = 20 (noVar) or 21(Var) */
@@ -1278,13 +1277,9 @@ struct PaintScaleUniformAroundCenter
     float tCenterX = centerX + c->instancer (varIdxBase, 1);
     float tCenterY = centerY + c->instancer (varIdxBase, 2);
 
-    bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
-    bool p2 = c->funcs->push_scale (c->data, s, s);
-    bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
+    c->funcs->push_scale_around_center (c->data, s, s, tCenterX, tCenterY);
     c->recurse (this+src);
-    if (p3) c->funcs->pop_transform (c->data);
-    if (p2) c->funcs->pop_transform (c->data);
-    if (p1) c->funcs->pop_transform (c->data);
+    c->funcs->pop_transform (c->data);
   }
 
   HBUINT8               format; /* format = 22 (noVar) or 23(Var) */
@@ -1328,9 +1323,9 @@ struct PaintRotate
     TRACE_PAINT (this);
     float a = angle.to_float (c->instancer (varIdxBase, 0));
 
-    bool p1 = c->funcs->push_rotate (c->data, a);
+    c->funcs->push_rotate (c->data, a);
     c->recurse (this+src);
-    if (p1) c->funcs->pop_transform (c->data);
+    c->funcs->pop_transform (c->data);
   }
 
   HBUINT8               format; /* format = 24 (noVar) or 25(Var) */
@@ -1378,13 +1373,9 @@ struct PaintRotateAroundCenter
     float tCenterX = centerX + c->instancer (varIdxBase, 1);
     float tCenterY = centerY + c->instancer (varIdxBase, 2);
 
-    bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
-    bool p2 = c->funcs->push_rotate (c->data, a);
-    bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
+    c->funcs->push_rotate_around_center (c->data, a, tCenterX, tCenterY);
     c->recurse (this+src);
-    if (p3) c->funcs->pop_transform (c->data);
-    if (p2) c->funcs->pop_transform (c->data);
-    if (p1) c->funcs->pop_transform (c->data);
+    c->funcs->pop_transform (c->data);
   }
 
   HBUINT8               format; /* format = 26 (noVar) or 27(Var) */
@@ -1432,9 +1423,9 @@ struct PaintSkew
     float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
     float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
 
-    bool p1 = c->funcs->push_skew (c->data, sx, sy);
+    c->funcs->push_skew (c->data, sx, sy);
     c->recurse (this+src);
-    if (p1) c->funcs->pop_transform (c->data);
+    c->funcs->pop_transform (c->data);
   }
 
   HBUINT8               format; /* format = 28(noVar) or 29 (Var) */
@@ -1485,13 +1476,9 @@ struct PaintSkewAroundCenter
     float tCenterX = centerX + c->instancer (varIdxBase, 2);
     float tCenterY = centerY + c->instancer (varIdxBase, 3);
 
-    bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
-    bool p2 = c->funcs->push_skew (c->data, sx, sy);
-    bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
+    c->funcs->push_skew_around_center (c->data, sx, sy, tCenterX, tCenterY);
     c->recurse (this+src);
-    if (p3) c->funcs->pop_transform (c->data);
-    if (p2) c->funcs->pop_transform (c->data);
-    if (p1) c->funcs->pop_transform (c->data);
+    c->funcs->pop_transform (c->data);
   }
 
   HBUINT8               format; /* format = 30(noVar) or 31 (Var) */
@@ -1626,7 +1613,7 @@ struct ClipBox
                const ItemVarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: return_trace (u.format1.subset (c, instancer, VarIdx::NO_VARIATION));
     case 2: return_trace (u.format2.subset (c, instancer));
     default:return_trace (c->default_return_value ());
@@ -1635,7 +1622,7 @@ struct ClipBox
 
   void closurev1 (hb_colrv1_closure_context_t* c) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 2: u.format2.closurev1 (c); return;
     default:return;
     }
@@ -1644,9 +1631,9 @@ struct ClipBox
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...));
     default:return_trace (c->default_return_value ());
@@ -1657,7 +1644,7 @@ struct ClipBox
                     const ItemVarStoreInstancer &instancer) const
   {
     ClipBoxData clip_box;
-    switch (u.format) {
+    switch (u.format.v) {
     case 1:
       u.format1.get_clip_box (clip_box, instancer);
       break;
@@ -1677,7 +1664,7 @@ struct ClipBox
 
   protected:
   union {
-  HBUINT8               format;         /* Format identifier */
+  struct { HBUINT8 v; } format;         /* Format identifier */
   ClipBoxFormat1        format1;
   ClipBoxFormat2        format2;
   } u;
@@ -1857,9 +1844,9 @@ struct Paint
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: return_trace (c->dispatch (u.paintformat1, std::forward (ds)...));
     case 2: return_trace (c->dispatch (u.paintformat2, std::forward (ds)...));
     case 3: return_trace (c->dispatch (u.paintformat3, std::forward (ds)...));
@@ -1898,7 +1885,7 @@ struct Paint
 
   protected:
   union {
-  HBUINT8                                       format;
+  struct { HBUINT8 v; }                         format;
   PaintColrLayers                               paintformat1;
   NoVariable                        paintformat2;
   Variable                          paintformat3;
@@ -2073,7 +2060,7 @@ struct delta_set_index_map_subset_plan_t
     outer_bit_count = 1;
     inner_bit_count = 1;
 
-    if (unlikely (!output_map.resize (map_count, false))) return false;
+    if (unlikely (!output_map.resize_dirty (map_count))) return false;
 
     for (unsigned idx = 0; idx < map_count; idx++)
     {
@@ -2693,7 +2680,8 @@ struct COLR
   {
     ItemVarStoreInstancer instancer (get_var_store_ptr (),
                                      get_delta_set_index_map_ptr (),
-                                     hb_array (font->coords, font->num_coords));
+                                     hb_array (font->coords,
+                                               font->has_nonzero_coords ? font->num_coords : 0));
     hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
 
     hb_decycler_node_t node (c.glyphs_decycler);
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh
index 51fc1b52af4..71417fdf3cf 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh
@@ -307,6 +307,7 @@ struct CPAL
       if (first_color_to_layer_index.has (first_color_record_idx)) continue;
 
       first_color_index_for_layer.push (first_color_record_idx);
+      if (unlikely (!c->serializer->propagate_error (first_color_index_for_layer))) return_trace (false);
       first_color_to_layer_index.set (first_color_record_idx,
                                       first_color_index_for_layer.length - 1);
     }
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh
index 35d73c7b858..28678856373 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh
@@ -46,7 +46,7 @@ struct Coverage
 
   protected:
   union {
-  HBUINT16                      format;         /* Format identifier */
+  struct { HBUINT16 v; }        format;         /* Format identifier */
   CoverageFormat1_3 format1;
   CoverageFormat2_4 format2;
 #ifndef HB_NO_BEYOND_64K
@@ -55,7 +55,7 @@ struct Coverage
 #endif
   } u;
   public:
-  DEFINE_SIZE_UNION (2, format);
+  DEFINE_SIZE_UNION (2, format.v);
 
 #ifndef HB_OPTIMIZE_SIZE
   HB_ALWAYS_INLINE
@@ -63,9 +63,9 @@ struct Coverage
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return_trace (false);
+    if (!u.format.v.sanitize (c)) return_trace (false);
     hb_barrier ();
-    switch (u.format)
+    switch (u.format.v)
     {
     case 1: return_trace (u.format1.sanitize (c));
     case 2: return_trace (u.format2.sanitize (c));
@@ -86,7 +86,7 @@ struct Coverage
   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) {
+    switch (u.format.v) {
     case 1: return u.format1.get_coverage (glyph_id);
     case 2: return u.format2.get_coverage (glyph_id);
 #ifndef HB_NO_BEYOND_64K
@@ -97,18 +97,38 @@ struct Coverage
     }
   }
   unsigned int get_coverage (hb_codepoint_t glyph_id,
-                             hb_ot_lookup_cache_t *cache) const
+                             hb_ot_layout_mapping_cache_t *cache) const
   {
     unsigned coverage;
-    if (cache && cache->get (glyph_id, &coverage)) return coverage;
+    if (cache && cache->get (glyph_id, &coverage)) return coverage < cache->MAX_VALUE ? coverage : NOT_COVERED;
     coverage = get_coverage (glyph_id);
-    if (cache) cache->set (glyph_id, coverage);
+    if (cache) {
+      if (coverage == NOT_COVERED)
+        cache->set_unchecked (glyph_id, cache->MAX_VALUE);
+      else if (likely (coverage < cache->MAX_VALUE))
+        cache->set_unchecked (glyph_id, coverage);
+    }
+    return coverage;
+  }
+
+  unsigned int get_coverage_binary (hb_codepoint_t glyph_id,
+                                    hb_ot_layout_binary_cache_t *cache) const
+  {
+    unsigned coverage;
+    if (cache && cache->get (glyph_id, &coverage)) return coverage < cache->MAX_VALUE ? coverage : NOT_COVERED;
+    coverage = get_coverage (glyph_id);
+    if (cache) {
+      if (coverage == NOT_COVERED)
+        cache->set_unchecked (glyph_id, cache->MAX_VALUE);
+      else
+        cache->set_unchecked (glyph_id, 0);
+    }
     return coverage;
   }
 
   unsigned get_population () const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: return u.format1.get_population ();
     case 2: return u.format2.get_population ();
 #ifndef HB_NO_BEYOND_64K
@@ -140,11 +160,11 @@ struct Coverage
       last = g;
       if (g > max) max = g;
     }
-    u.format = !unsorted && count <= num_ranges * 3 ? 1 : 2;
+    u.format.v = !unsorted && count <= num_ranges * 3 ? 1 : 2;
 
 #ifndef HB_NO_BEYOND_64K
     if (max > 0xFFFFu)
-      u.format += 2;
+      u.format.v += 2;
     if (unlikely (max > 0xFFFFFFu))
 #else
     if (unlikely (max > 0xFFFFu))
@@ -154,7 +174,7 @@ struct Coverage
       return_trace (false);
     }
 
-    switch (u.format)
+    switch (u.format.v)
     {
     case 1: return_trace (u.format1.serialize (c, glyphs));
     case 2: return_trace (u.format2.serialize (c, glyphs));
@@ -185,7 +205,7 @@ struct Coverage
 
   bool intersects (const hb_set_t *glyphs) const
   {
-    switch (u.format)
+    switch (u.format.v)
     {
     case 1: return u.format1.intersects (glyphs);
     case 2: return u.format2.intersects (glyphs);
@@ -198,7 +218,7 @@ struct Coverage
   }
   bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
   {
-    switch (u.format)
+    switch (u.format.v)
     {
     case 1: return u.format1.intersects_coverage (glyphs, index);
     case 2: return u.format2.intersects_coverage (glyphs, index);
@@ -212,7 +232,7 @@ struct Coverage
 
   unsigned cost () const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return u.format1.cost ();
     case 2: hb_barrier (); return u.format2.cost ();
 #ifndef HB_NO_BEYOND_64K
@@ -228,7 +248,7 @@ struct Coverage
   template 
   bool collect_coverage (set_t *glyphs) const
   {
-    switch (u.format)
+    switch (u.format.v)
     {
     case 1: return u.format1.collect_coverage (glyphs);
     case 2: return u.format2.collect_coverage (glyphs);
@@ -244,7 +264,7 @@ struct Coverage
             hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
   void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
   {
-    switch (u.format)
+    switch (u.format.v)
     {
     case 1: return u.format1.intersect_set (glyphs, intersect_glyphs);
     case 2: return u.format2.intersect_set (glyphs, intersect_glyphs);
@@ -262,7 +282,7 @@ struct Coverage
     iter_t (const Coverage &c_ = Null (Coverage))
     {
       hb_memset (this, 0, sizeof (*this));
-      format = c_.u.format;
+      format = c_.u.format.v;
       switch (format)
       {
       case 1: u.format1.init (c_.u.format1); return;
@@ -332,7 +352,7 @@ struct Coverage
     }
     iter_t __end__ () const
     {
-      iter_t it = {};
+      iter_t it;
       it.format = format;
       switch (format)
       {
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh
index 97ea51089ec..122326e3024 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh
@@ -41,11 +41,11 @@ struct CoverageFormat1_3
 {
   friend struct Coverage;
 
-  protected:
+  public:
   HBUINT16      coverageFormat; /* Format identifier--format = 1 */
   SortedArray16Of
                 glyphArray;     /* Array of GlyphIDs--in numerical order */
-  public:
+
   DEFINE_SIZE_ARRAY (4, glyphArray);
 
   private:
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh
index 0c9bd09cbf7..8287c8d4d4d 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh
@@ -40,7 +40,7 @@ struct CoverageFormat2_4
 {
   friend struct Coverage;
 
-  protected:
+  public:
   HBUINT16      coverageFormat; /* Format identifier--format = 2 */
   SortedArray16Of>
                 rangeRecord;    /* Array of glyph ranges--ordered by
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh
index ceba37b0619..89e110990bc 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh
@@ -252,7 +252,7 @@ struct CaretValue
                                  hb_codepoint_t glyph_id,
                                  const ItemVariationStore &var_store) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: return u.format1.get_caret_value (font, direction);
     case 2: return u.format2.get_caret_value (font, direction, glyph_id);
     case 3: return u.format3.get_caret_value (font, direction, var_store);
@@ -263,9 +263,9 @@ struct CaretValue
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...));
     case 3: return_trace (c->dispatch (u.format3, std::forward (ds)...));
@@ -275,7 +275,7 @@ struct CaretValue
 
   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1:
     case 2:
       return;
@@ -289,9 +289,9 @@ struct CaretValue
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return_trace (false);
+    if (!u.format.v.sanitize (c)) return_trace (false);
     hb_barrier ();
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: return_trace (u.format1.sanitize (c));
     case 2: return_trace (u.format2.sanitize (c));
     case 3: return_trace (u.format3.sanitize (c));
@@ -301,13 +301,13 @@ struct CaretValue
 
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
+  struct { HBUINT16 v; }        format;         /* Format identifier */
   CaretValueFormat1     format1;
   CaretValueFormat2     format2;
   CaretValueFormat3     format3;
   } u;
   public:
-  DEFINE_SIZE_UNION (2, format);
+  DEFINE_SIZE_UNION (2, format.v);
 };
 
 struct LigGlyph
@@ -519,7 +519,7 @@ struct MarkGlyphSets
 {
   bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: return u.format1.covers (set_index, glyph_id);
     default:return false;
     }
@@ -528,7 +528,7 @@ struct MarkGlyphSets
   template 
   void collect_coverage (hb_vector_t &sets) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: u.format1.collect_coverage (sets); return;
     default:return;
     }
@@ -537,7 +537,7 @@ struct MarkGlyphSets
   void collect_used_mark_sets (const hb_set_t& glyph_set,
                                hb_set_t& used_mark_sets /* OUT */) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: u.format1.collect_used_mark_sets (glyph_set, used_mark_sets); return;
     default:return;
     }
@@ -546,7 +546,7 @@ struct MarkGlyphSets
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: return_trace (u.format1.subset (c));
     default:return_trace (false);
     }
@@ -555,9 +555,9 @@ struct MarkGlyphSets
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return_trace (false);
+    if (!u.format.v.sanitize (c)) return_trace (false);
     hb_barrier ();
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: return_trace (u.format1.sanitize (c));
     default:return_trace (true);
     }
@@ -565,11 +565,11 @@ struct MarkGlyphSets
 
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
+  struct { HBUINT16 v; }        format;         /* Format identifier */
   MarkGlyphSetsFormat1  format1;
   } u;
   public:
-  DEFINE_SIZE_UNION (2, format);
+  DEFINE_SIZE_UNION (2, format.v);
 };
 
 
@@ -977,7 +977,7 @@ struct GDEF
       }
 
 #ifndef HB_NO_GDEF_CACHE
-      table->get_mark_glyph_sets ().collect_coverage (mark_glyph_set_digests);
+      table->get_mark_glyph_sets ().collect_coverage (mark_glyph_sets);
 #endif
     }
     ~accelerator_t () { table.destroy (); }
@@ -1002,18 +1002,34 @@ struct GDEF
 
     }
 
+    HB_ALWAYS_INLINE
     bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
     {
       return
 #ifndef HB_NO_GDEF_CACHE
-             mark_glyph_set_digests[set_index].may_have (glyph_id) &&
+             // We can access arrayZ directly because of sanitize_lookup_props() guarantee.
+             mark_glyph_sets.arrayZ[set_index].may_have (glyph_id) &&
 #endif
-             table->mark_set_covers (set_index, glyph_id);
+             table->mark_set_covers (set_index, glyph_id)
+      ;
+    }
+
+    unsigned sanitize_lookup_props (unsigned lookup_props) const
+    {
+#ifndef HB_NO_GDEF_CACHE
+      if (lookup_props & LookupFlag::UseMarkFilteringSet &&
+          (lookup_props >> 16) >= mark_glyph_sets.length)
+      {
+        // Invalid mark filtering set index; unset the flag.
+        lookup_props &= ~LookupFlag::UseMarkFilteringSet;
+      }
+#endif
+      return lookup_props;
     }
 
     hb_blob_ptr_t table;
 #ifndef HB_NO_GDEF_CACHE
-    hb_vector_t mark_glyph_set_digests;
+    hb_vector_t mark_glyph_sets;
     mutable hb_cache_t<21, 3> glyph_props_cache;
     static_assert (sizeof (glyph_props_cache) == 512, "");
 #endif
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Anchor.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Anchor.hh
index 7802e397f4c..1938803fa7c 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Anchor.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Anchor.hh
@@ -13,20 +13,20 @@ struct Anchor
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
+  struct { HBUINT16 v; } format;        /* Format identifier */
   AnchorFormat1         format1;
   AnchorFormat2         format2;
   AnchorFormat3         format3;
   } u;
   public:
-  DEFINE_SIZE_UNION (2, format);
+  DEFINE_SIZE_UNION (2, format.v);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return_trace (false);
+    if (!u.format.v.sanitize (c)) return_trace (false);
     hb_barrier ();
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: return_trace (u.format1.sanitize (c));
     case 2: return_trace (u.format2.sanitize (c));
     case 3: return_trace (u.format3.sanitize (c));
@@ -38,7 +38,7 @@ struct Anchor
                    float *x, float *y) const
   {
     *x = *y = 0;
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
     case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
     case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
@@ -49,7 +49,7 @@ struct Anchor
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: return_trace (bool (reinterpret_cast (u.format1.copy (c->serializer))));
     case 2:
       if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
@@ -66,7 +66,7 @@ struct Anchor
 
   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: case 2:
       return;
     case 3:
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh
index 61bd90310a5..c49705bea0e 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh
@@ -37,12 +37,12 @@ struct AnchorFormat3
     *x = font->em_fscale_x (xCoordinate);
     *y = font->em_fscale_y (yCoordinate);
 
-    if ((font->x_ppem || font->num_coords) && xDeviceTable.sanitize (&c->sanitizer, this))
+    if ((font->x_ppem || font->has_nonzero_coords) && xDeviceTable.sanitize (&c->sanitizer, this))
     {
       hb_barrier ();
       *x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache);
     }
-    if ((font->y_ppem || font->num_coords) && yDeviceTable.sanitize (&c->sanitizer, this))
+    if ((font->y_ppem || font->has_nonzero_coords) && yDeviceTable.sanitize (&c->sanitizer, this))
     {
       hb_barrier ();
       *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache);
@@ -91,10 +91,13 @@ struct AnchorFormat3
       }
     }
 
-    /* in case that all axes are pinned or no variations after instantiation,
-     * both var_idxes will be mapped to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */
-    if (x_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX &&
-        y_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
+
+    bool no_downgrade = (!xDeviceTable.is_null () && !(this+xDeviceTable).is_variation_device ()) ||
+                        x_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX ||
+                        y_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX ||
+                        (!yDeviceTable.is_null () && !(this+yDeviceTable).is_variation_device ());
+
+    if (!no_downgrade)
       return_trace (c->serializer->check_assign (out->format, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
 
     if (!c->serializer->embed (xDeviceTable)) return_trace (false);
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorMatrix.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorMatrix.hh
index 9da9fff50ba..128ced6c176 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorMatrix.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorMatrix.hh
@@ -77,6 +77,13 @@ struct AnchorMatrix
 
     return_trace (true);
   }
+
+  bool offset_is_null (unsigned row, unsigned col, unsigned num_cols) const
+  {
+    if (unlikely (row >= rows || col >= num_cols)) return true;
+    auto &offset = matrixZ[row * num_cols + col];
+    return offset.is_null ();
+  }
 };
 
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePos.hh
index 0105a9b8542..38a29dd9ed5 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePos.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePos.hh
@@ -11,7 +11,7 @@ struct CursivePos
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
+  struct { HBUINT16 v; } format;        /* Format identifier */
   CursivePosFormat1     format1;
   } u;
 
@@ -19,9 +19,9 @@ struct CursivePos
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...));
     default:return_trace (c->default_return_value ());
     }
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh
index 361aaed658a..f5a09e07d73 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh
@@ -50,8 +50,9 @@ struct EntryExitRecord
   DEFINE_SIZE_STATIC (4);
 };
 
-static void
-reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent) {
+static inline void
+reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
+{
   int chain = pos[i].attach_chain(), type = pos[i].attach_type();
   if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
     return;
@@ -130,7 +131,7 @@ struct CursivePosFormat1
         unlikely (!this_record.entryAnchor.sanitize (&c->sanitizer, this))) return_trace (false);
     hb_barrier ();
 
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_input;
     skippy_iter.reset_fast (buffer->idx);
     unsigned unsafe_from;
     if (unlikely (!skippy_iter.prev (&unsafe_from)))
@@ -229,8 +230,13 @@ struct CursivePosFormat1
      */
     reverse_cursive_minor_offset (pos, child, c->direction, parent);
 
-    pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
     pos[child].attach_chain() = (int) parent - (int) child;
+    if (pos[child].attach_chain() != (int) parent - (int) child)
+    {
+      pos[child].attach_chain() = 0;
+      goto overflow;
+    }
+    pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
     if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
       pos[child].y_offset = y_offset;
@@ -256,6 +262,7 @@ struct CursivePosFormat1
                           i, j);
     }
 
+  overflow:
     buffer->idx++;
     return_trace (true);
   }
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh
index ce3f74d8c3b..b80f606f7b5 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh
@@ -80,9 +80,8 @@ propagate_attachment_offsets (hb_glyph_position_t *pos,
 {
   /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
    * offset of glyph they are attached to. */
-  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
-  if (likely (!chain))
-    return;
+  int chain = pos[i].attach_chain();
+  int type = pos[i].attach_type();
 
   pos[i].attach_chain() = 0;
 
@@ -94,7 +93,8 @@ propagate_attachment_offsets (hb_glyph_position_t *pos,
   if (unlikely (!nesting_level))
     return;
 
-  propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1);
+  if (pos[j].attach_chain())
+    propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1);
 
   assert (!!(type & GPOS_impl::ATTACH_TYPE_MARK) ^ !!(type & GPOS_impl::ATTACH_TYPE_CURSIVE));
 
@@ -110,17 +110,37 @@ propagate_attachment_offsets (hb_glyph_position_t *pos,
     pos[i].x_offset += pos[j].x_offset;
     pos[i].y_offset += pos[j].y_offset;
 
-    assert (j < i);
-    if (HB_DIRECTION_IS_FORWARD (direction))
-      for (unsigned int k = j; k < i; k++) {
-        pos[i].x_offset -= pos[k].x_advance;
-        pos[i].y_offset -= pos[k].y_advance;
-      }
-    else
-      for (unsigned int k = j + 1; k < i + 1; k++) {
-        pos[i].x_offset += pos[k].x_advance;
-        pos[i].y_offset += pos[k].y_advance;
-      }
+    // i is the position of the mark; j is the base.
+    if (j < i)
+    {
+      /* This is the common case: mark follows base.
+       * And currently the only way in OpenType. */
+      if (HB_DIRECTION_IS_FORWARD (direction))
+        for (unsigned int k = j; k < i; k++) {
+          pos[i].x_offset -= pos[k].x_advance;
+          pos[i].y_offset -= pos[k].y_advance;
+        }
+      else
+        for (unsigned int k = j + 1; k < i + 1; k++) {
+          pos[i].x_offset += pos[k].x_advance;
+          pos[i].y_offset += pos[k].y_advance;
+        }
+    }
+    else // j > i
+    {
+      /* This can happen with `kerx`: a mark attaching
+       * to a base after it in the logical order. */
+      if (HB_DIRECTION_IS_FORWARD (direction))
+        for (unsigned int k = i; k < j; k++) {
+          pos[i].x_offset += pos[k].x_advance;
+          pos[i].y_offset += pos[k].y_advance;
+        }
+      else
+        for (unsigned int k = i + 1; k < j + 1; k++) {
+          pos[i].x_offset -= pos[k].x_advance;
+          pos[i].y_offset -= pos[k].y_advance;
+        }
+    }
   }
 }
 
@@ -149,8 +169,20 @@ GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
 
   /* Handle attachments */
   if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
-    for (unsigned i = 0; i < len; i++)
-      propagate_attachment_offsets (pos, len, i, direction);
+  {
+    auto *pos = buffer->pos;
+    // https://github.com/harfbuzz/harfbuzz/issues/5514
+    if (HB_DIRECTION_IS_FORWARD (direction))
+    {
+      for (unsigned i = 0; i < len; i++)
+        if (pos[i].attach_chain())
+          propagate_attachment_offsets (pos, len, i, direction);
+    } else {
+      for (unsigned i = len; i-- > 0; )
+        if (pos[i].attach_chain())
+          propagate_attachment_offsets (pos, len, i, direction);
+    }
+  }
 
   if (unlikely (font->slant_xy) &&
       HB_DIRECTION_IS_HORIZONTAL (direction))
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh
index eecdb95a95f..113b693dc3e 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh
@@ -19,22 +19,30 @@ struct LigatureArray : List16OfOffset16To
   bool subset (hb_subset_context_t *c,
                Iterator             coverage,
                unsigned             class_count,
-               const hb_map_t      *klass_mapping) const
+               const hb_map_t      *klass_mapping,
+               hb_sorted_vector_t &new_coverage /* OUT */) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = c->plan->glyph_map_gsub;
 
     auto *out = c->serializer->start_embed (this);
     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
 
     bool ret = false;
     for (const auto _ : + hb_zip (coverage, *this)
-                  | hb_filter (glyphset, hb_first))
+                        | hb_filter (glyph_map, hb_first))
     {
+      const LigatureAttach& src = (this + _.second);
+      bool non_empty = + hb_range (src.rows * class_count)
+                       | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
+                       | hb_map ([&] (const unsigned index) { return !src.offset_is_null (index / class_count, index % class_count, class_count); })
+                       | hb_any;
+
+      if (!non_empty) continue;
+
       auto *matrix = out->serialize_append (c->serializer);
       if (unlikely (!matrix)) return_trace (false);
 
-      const LigatureAttach& src = (this + _.second);
       auto indexes =
           + hb_range (src.rows * class_count)
           | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
@@ -44,6 +52,9 @@ struct LigatureArray : List16OfOffset16To
                                        this,
                                        src.rows,
                                        indexes);
+
+      hb_codepoint_t new_gid = glyph_map.get (_.first);
+      new_coverage.push (new_gid);
     }
     return_trace (ret);
   }
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh
index abae8f1c607..bddc5e7fe9e 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh
@@ -47,10 +47,15 @@ struct MarkArray : Array16Of        /* Array of MarkRecords--in Cove
     }
 
     hb_glyph_position_t &o = buffer->cur_pos();
+    o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
+    if (o.attach_chain() != (int) glyph_pos - (int) buffer->idx)
+    {
+      o.attach_chain() = 0;
+      goto overflow;
+    }
+    o.attach_type() = ATTACH_TYPE_MARK;
     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;
 
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
@@ -60,6 +65,7 @@ struct MarkArray : Array16Of        /* Array of MarkRecords--in Cove
                           c->buffer->idx, glyph_pos);
     }
 
+  overflow:
     buffer->idx++;
     return_trace (true);
   }
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh
index b1d1118a86b..65f343bda8b 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh
@@ -11,7 +11,7 @@ struct MarkBasePos
 {
   protected:
   union {
-  HBUINT16                              format;         /* Format identifier */
+  struct { HBUINT16 v; }                format;         /* Format identifier */
   MarkBasePosFormat1_2      format1;
 #ifndef HB_NO_BEYOND_64K
   MarkBasePosFormat1_2     format2;
@@ -22,9 +22,9 @@ struct MarkBasePos
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...));
 #ifndef HB_NO_BEYOND_64K
     case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...));
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh
index e633f7a1be1..ad071f327ea 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh
@@ -119,7 +119,7 @@ struct MarkBasePosFormat1_2
     /* Now we search backwards for a non-mark glyph.
      * We don't use skippy_iter.prev() to avoid O(n^2) behavior. */
 
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_input;
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
 
     if (c->last_base_until > buffer->idx)
@@ -209,19 +209,22 @@ struct MarkBasePosFormat1_2
     ;
 
     new_coverage.reset ();
-    + base_iter
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-
-    if (!out->baseCoverage.serialize_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))
+    auto &base_array = (this+baseArray);
+    for (const auto _ : + base_iter)
     {
+      unsigned row = _.second;
+      bool non_empty = + hb_range ((unsigned) classCount)
+                       | hb_filter (klass_mapping)
+                       | hb_map ([&] (const unsigned col) { return !base_array.offset_is_null (row, col, (unsigned) classCount); })
+                       | hb_any
+                       ;
+
+      if (!non_empty) continue;
+
+      hb_codepoint_t new_g = glyph_map.get ( _.first);
+      new_coverage.push (new_g);
+
       + hb_range ((unsigned) classCount)
       | hb_filter (klass_mapping)
       | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
@@ -229,8 +232,12 @@ struct MarkBasePosFormat1_2
       ;
     }
 
+    if (!new_coverage) return_trace (false);
+    if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
+      return_trace (false);
+
     return_trace (out->baseArray.serialize_subset (c, baseArray, this,
-                                                   base_iter.len (),
+                                                   new_coverage.length,
                                                    base_indexes.iter ()));
   }
 };
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh
index b10102880c0..ee237eb479f 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh
@@ -11,7 +11,7 @@ struct MarkLigPos
 {
   protected:
   union {
-  HBUINT16                              format;         /* Format identifier */
+  struct { HBUINT16 v; }                format;         /* Format identifier */
   MarkLigPosFormat1_2       format1;
 #ifndef HB_NO_BEYOND_64K
   MarkLigPosFormat1_2      format2;
@@ -22,9 +22,9 @@ struct MarkLigPos
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...));
 #ifndef HB_NO_BEYOND_64K
     case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...));
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh
index cf4cbae9a3f..509a26c2485 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh
@@ -101,7 +101,7 @@ struct MarkLigPosFormat1_2
 
     /* Now we search backwards for a non-mark glyph */
 
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_input;
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
 
     if (c->last_base_until > buffer->idx)
@@ -200,19 +200,13 @@ struct MarkLigPosFormat1_2
                                                     &klass_mapping)))
       return_trace (false);
 
-    auto new_ligature_coverage =
-    + hb_iter (this + ligatureCoverage)
-    | hb_take ((this + ligatureArray).len)
-    | hb_map_retains_sorting (glyph_map)
-    | hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; })
-    ;
-
-    if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
+    hb_sorted_vector_t new_lig_coverage;
+    if (!out->ligatureArray.serialize_subset (c, ligatureArray, this,
+                                              hb_iter (this+ligatureCoverage),
+                                              classCount, &klass_mapping, new_lig_coverage))
       return_trace (false);
 
-    return_trace (out->ligatureArray.serialize_subset (c, ligatureArray, this,
-                                                       hb_iter (this+ligatureCoverage),
-                                                       classCount, &klass_mapping));
+    return_trace (out->ligatureCoverage.serialize_serialize (c->serializer, new_lig_coverage.iter ()));
   }
 
 };
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh
index e0d9eca0280..c06f013cdce 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh
@@ -11,7 +11,7 @@ struct MarkMarkPos
 {
   protected:
   union {
-  HBUINT16                              format;         /* Format identifier */
+  struct { HBUINT16 v; }                format;         /* Format identifier */
   MarkMarkPosFormat1_2      format1;
 #ifndef HB_NO_BEYOND_64K
   MarkMarkPosFormat1_2     format2;
@@ -22,9 +22,9 @@ struct MarkMarkPos
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...));
 #ifndef HB_NO_BEYOND_64K
     case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...));
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh
index 6519e79b443..c93dbbb3f06 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh
@@ -100,7 +100,7 @@ struct MarkMarkPosFormat1_2
     if (likely (mark1_index == NOT_COVERED)) return_trace (false);
 
     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_input;
     skippy_iter.reset_fast (buffer->idx);
     skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags);
     unsigned unsafe_from;
@@ -196,19 +196,23 @@ struct MarkMarkPosFormat1_2
     ;
 
     new_coverage.reset ();
-    + mark2_iter
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-
-    if (!out->mark2Coverage.serialize_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))
+    auto &mark2_array = (this+mark2Array);
+    for (const auto _ : + mark2_iter)
     {
+      unsigned row = _.second;
+
+      bool non_empty = + hb_range ((unsigned) classCount)
+                       | hb_filter (klass_mapping)
+                       | hb_map ([&] (const unsigned col) { return !mark2_array.offset_is_null (row, col, (unsigned) classCount); })
+                       | hb_any
+                       ;
+
+      if (!non_empty) continue;
+
+      hb_codepoint_t new_g = glyph_map.get ( _.first);
+      new_coverage.push (new_g);
+
       + hb_range ((unsigned) classCount)
       | hb_filter (klass_mapping)
       | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
@@ -216,6 +220,10 @@ struct MarkMarkPosFormat1_2
       ;
     }
 
+    if (!new_coverage) return_trace (false);
+    if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
+      return_trace (false);
+
     return_trace (out->mark2Array.serialize_subset (c, mark2Array, this,
                                                     mark2_iter.len (),
                                                     mark2_indexes.iter ()));
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPos.hh
index e3794ea9ed5..bf7fff7face 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPos.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPos.hh
@@ -12,7 +12,7 @@ struct PairPos
 {
   protected:
   union {
-  HBUINT16                      format;         /* Format identifier */
+  struct { HBUINT16 v; }        format;         /* Format identifier */
   PairPosFormat1_3  format1;
   PairPosFormat2_4  format2;
 #ifndef HB_NO_BEYOND_64K
@@ -25,9 +25,9 @@ struct PairPos
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...));
 #ifndef HB_NO_BEYOND_64K
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh
index 2748882f527..1c067bde86f 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh
@@ -103,52 +103,35 @@ struct PairPosFormat1_3
 
   const Coverage &get_coverage () const { return this+coverage; }
 
-  unsigned cache_cost () const
+  struct external_cache_t
   {
-    return (this+coverage).cost ();
-  }
-  static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
+    hb_ot_layout_mapping_cache_t coverage;
+  };
+  void *external_cache_create () const
   {
-    switch (op)
+    external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t));
+    if (likely (cache))
     {
-      case hb_ot_lookup_cache_op_t::CREATE:
-      {
-        hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t));
-        if (likely (cache))
-          cache->clear ();
-        return cache;
-      }
-      case hb_ot_lookup_cache_op_t::ENTER:
-        return (void *) true;
-      case hb_ot_lookup_cache_op_t::LEAVE:
-        return nullptr;
-      case hb_ot_lookup_cache_op_t::DESTROY:
-      {
-        hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p;
-        hb_free (cache);
-        return nullptr;
-      }
+      cache->coverage.clear ();
     }
-    return nullptr;
+    return cache;
   }
 
-  bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
-  bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
-  bool _apply (hb_ot_apply_context_t *c, bool cached) const
+  bool apply (hb_ot_apply_context_t *c, void *external_cache) const
   {
     TRACE_APPLY (this);
 
     hb_buffer_t *buffer = c->buffer;
 
 #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
-    hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr;
-    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint, cache);
+    external_cache_t *cache = (external_cache_t *) external_cache;
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint, cache ? &cache->coverage : nullptr);
 #else
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
 #endif
     if (index == NOT_COVERED) return_trace (false);
 
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_input;
     skippy_iter.reset_fast (buffer->idx);
     unsigned unsafe_to;
     if (unlikely (!skippy_iter.next (&unsafe_to)))
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh
index d85b1ac2c17..ce731450f41 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh
@@ -123,63 +123,39 @@ struct PairPosFormat2_4 : ValueBase
 
   const Coverage &get_coverage () const { return this+coverage; }
 
-  struct pair_pos_cache_t
+  struct external_cache_t
   {
-    hb_ot_lookup_cache_t coverage;
-    hb_ot_lookup_cache_t first;
-    hb_ot_lookup_cache_t second;
+    hb_ot_layout_mapping_cache_t coverage;
+    hb_ot_layout_mapping_cache_t first;
+    hb_ot_layout_mapping_cache_t second;
   };
-
-  unsigned cache_cost () const
-  {
-    return (this+coverage).cost () + (this+classDef1).cost () + (this+classDef2).cost ();
-  }
-  static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
+  void *external_cache_create () const
   {
-    switch (op)
+    external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t));
+    if (likely (cache))
     {
-      case hb_ot_lookup_cache_op_t::CREATE:
-      {
-        pair_pos_cache_t *cache = (pair_pos_cache_t *) hb_malloc (sizeof (pair_pos_cache_t));
-        if (likely (cache))
-        {
-          cache->coverage.clear ();
-          cache->first.clear ();
-          cache->second.clear ();
-        }
-        return cache;
-      }
-      case hb_ot_lookup_cache_op_t::ENTER:
-        return (void *) true;
-      case hb_ot_lookup_cache_op_t::LEAVE:
-        return nullptr;
-      case hb_ot_lookup_cache_op_t::DESTROY:
-        {
-          pair_pos_cache_t *cache = (pair_pos_cache_t *) p;
-          hb_free (cache);
-          return nullptr;
-        }
+      cache->coverage.clear ();
+      cache->first.clear ();
+      cache->second.clear ();
     }
-    return nullptr;
+    return cache;
   }
 
-  bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
-  bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
-  bool _apply (hb_ot_apply_context_t *c, bool cached) const
+  bool apply (hb_ot_apply_context_t *c, void *external_cache) const
   {
     TRACE_APPLY (this);
 
     hb_buffer_t *buffer = c->buffer;
 
 #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
-    pair_pos_cache_t *cache = cached ? (pair_pos_cache_t *) c->lookup_accel->cache : nullptr;
+    external_cache_t *cache = (external_cache_t *) external_cache;
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint, cache ? &cache->coverage : nullptr);
 #else
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
 #endif
     if (index == NOT_COVERED) return_trace (false);
 
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_input;
     skippy_iter.reset_fast (buffer->idx);
     unsigned unsafe_to;
     if (unlikely (!skippy_iter.next (&unsafe_to)))
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePos.hh
index a0243a218c5..30fc1aacda8 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePos.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePos.hh
@@ -12,7 +12,7 @@ struct SinglePos
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
+  struct { HBUINT16 v; } format;        /* Format identifier */
   SinglePosFormat1      format1;
   SinglePosFormat2      format2;
   } u;
@@ -41,7 +41,7 @@ struct SinglePos
                   const hb_hashmap_t> *layout_variation_idx_delta_map,
                   unsigned newFormat)
   {
-    if (unlikely (!c->extend_min (u.format))) return;
+    if (unlikely (!c->extend_min (u.format.v))) return;
     unsigned format = 2;
     ValueFormat new_format;
     new_format = newFormat;
@@ -49,8 +49,8 @@ struct SinglePos
     if (glyph_val_iter_pairs)
       format = get_format (glyph_val_iter_pairs);
 
-    u.format = format;
-    switch (u.format) {
+    u.format.v = format;
+    switch (u.format.v) {
     case 1: u.format1.serialize (c,
                                  src,
                                  glyph_val_iter_pairs,
@@ -70,9 +70,9 @@ struct SinglePos
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...));
     default:return_trace (c->default_return_value ());
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh
index 731d1ffca1a..b961a5139d8 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh
@@ -56,9 +56,14 @@ struct ValueFormat : HBUINT16
                                          * PosTable (may be NULL) */
 #endif
 
-  IntType& operator = (uint16_t i) { v = i; return *this; }
-
-  unsigned int get_len () const  { return hb_popcount ((unsigned int) *this); }
+  NumType& operator = (uint16_t i) { v = i; return *this; }
+
+  // Note: spec says skip 2 bytes per bit in the valueformat. But reports
+  // from Microsoft developers indicate that only the fields that are
+  // currently defined are counted. We don't expect any new fields to
+  // be added to ValueFormat. As such, we use the faster hb_popcount8
+  // that only processes the lowest 8 bits.
+  unsigned int get_len () const  { return hb_popcount8 ((uint8_t) *this); }
   unsigned int get_size () const { return get_len () * Value::static_size; }
 
   hb_vector_t get_device_table_indices () const {
@@ -111,8 +116,8 @@ struct ValueFormat : HBUINT16
 
     if (!has_device ()) return ret;
 
-    bool use_x_device = font->x_ppem || font->num_coords;
-    bool use_y_device = font->y_ppem || font->num_coords;
+    bool use_x_device = font->x_ppem || font->has_nonzero_coords;
+    bool use_y_device = font->y_ppem || font->has_nonzero_coords;
 
     if (!use_x_device && !use_y_device) return ret;
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSet.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSet.hh
index b5d506f36f9..f13c5e7e251 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSet.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSet.hh
@@ -91,6 +91,19 @@ struct AlternateSet
     return alternates.len;
   }
 
+  void
+  collect_alternates (hb_codepoint_t gid,
+                      hb_map_t  *alternate_count /* IN/OUT */,
+                      hb_map_t  *alternate_glyphs /* IN/OUT */) const
+  {
+    + hb_enumerate (alternates)
+    | hb_map ([gid] (hb_pair_t _) { return hb_pair (gid + (_.first << 24), _.second); })
+    | hb_apply ([&] (const hb_pair_t &p) -> void
+                { _hb_collect_glyph_alternates_add (p.first, p.second,
+                                                    alternate_count, alternate_glyphs); })
+    ;
+  }
+
   template 
   bool serialize (hb_serialize_context_t *c,
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubst.hh
index 8951f5a7a17..a43c75c8f4e 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubst.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubst.hh
@@ -12,7 +12,7 @@ struct AlternateSubst
 {
   protected:
   union {
-  HBUINT16                              format;         /* Format identifier */
+  struct { HBUINT16 v; }                format;         /* Format identifier */
   AlternateSubstFormat1_2   format1;
 #ifndef HB_NO_BEYOND_64K
   AlternateSubstFormat1_2  format2;
@@ -23,9 +23,9 @@ struct AlternateSubst
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...));
 #ifndef HB_NO_BEYOND_64K
     case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...));
@@ -42,10 +42,10 @@ struct AlternateSubst
                   hb_array_t alternate_glyphs_list)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (u.format))) return_trace (false);
+    if (unlikely (!c->extend_min (u.format.v))) return_trace (false);
     unsigned int format = 1;
-    u.format = format;
-    switch (u.format) {
+    u.format.v = format;
+    switch (u.format.v) {
     case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
     default:return_trace (false);
     }
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubstFormat1.hh
index 421a6e06627..7a3a2511b7f 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubstFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubstFormat1.hh
@@ -69,6 +69,19 @@ struct AlternateSubstFormat1_2
   { return (this+alternateSet[(this+coverage).get_coverage (gid)])
            .get_alternates (start_offset, alternate_count, alternate_glyphs); }
 
+  void
+  collect_glyph_alternates (hb_map_t  *alternate_count /* IN/OUT */,
+                            hb_map_t  *alternate_glyphs /* IN/OUT */) const
+  {
+    + hb_iter (alternateSet)
+    | hb_map (hb_add (this))
+    | hb_zip (this+coverage)
+    | hb_apply ([&] (const hb_pair_t &, hb_codepoint_t> _) {
+                  _.first.collect_alternates (_.second, alternate_count, alternate_glyphs);
+                })
+    ;
+  }
+
   bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh
index 726da458fac..7bc98d31f32 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh
@@ -44,6 +44,18 @@ struct Ligature
     c->output->add (ligGlyph);
   }
 
+  template 
+  void collect_second (set_t &s) const
+  {
+    if (unlikely (!component.get_length ()))
+    {
+      // A ligature without any components. Anything matches.
+      s = set_t::full ();
+      return;
+    }
+    s.add (component.arrayZ[0]);
+  }
+
   bool would_apply (hb_would_apply_context_t *c) const
   {
     if (c->len != component.lenP1)
@@ -91,15 +103,6 @@ struct Ligature
     unsigned int total_component_count = 0;
 
     if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return false;
-    unsigned match_positions_stack[4];
-    unsigned *match_positions = match_positions_stack;
-    if (unlikely (count > ARRAY_LENGTH (match_positions_stack)))
-    {
-      match_positions = (unsigned *) hb_malloc (hb_max (count, 1u) * sizeof (unsigned));
-      if (unlikely (!match_positions))
-        return_trace (false);
-    }
-
     unsigned int match_end = 0;
 
     if (likely (!match_input (c, count,
@@ -107,12 +110,9 @@ struct Ligature
                               match_glyph,
                               nullptr,
                               &match_end,
-                              match_positions,
                               &total_component_count)))
     {
       c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
-      if (match_positions != match_positions_stack)
-        hb_free (match_positions);
       return_trace (false);
     }
 
@@ -129,10 +129,10 @@ struct Ligature
       match_end += delta;
       for (unsigned i = 0; i < count; i++)
       {
-        match_positions[i] += delta;
+        c->match_positions[i] += delta;
         if (i)
           *p++ = ',';
-        snprintf (p, sizeof(buf) - (p - buf), "%u", match_positions[i]);
+        snprintf (p, sizeof(buf) - (p - buf), "%u", c->match_positions[i]);
         p += strlen(p);
       }
 
@@ -143,7 +143,6 @@ struct Ligature
 
     ligate_input (c,
                   count,
-                  match_positions,
                   match_end,
                   ligGlyph,
                   total_component_count);
@@ -156,8 +155,6 @@ struct Ligature
                           pos);
     }
 
-    if (match_positions != match_positions_stack)
-      hb_free (match_positions);
     return_trace (true);
   }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh
index ff0ffce94d7..81c5c2bcfe4 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh
@@ -11,11 +11,11 @@ namespace GSUB_impl {
 template 
 struct LigatureSet
 {
-  protected:
+  public:
   Array16OfOffset16To>
                 ligature;               /* Array LigatureSet tables
                                          * ordered by preference */
-  public:
+
   DEFINE_SIZE_ARRAY (2, ligature);
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -62,6 +62,15 @@ struct LigatureSet
     ;
   }
 
+  template 
+  void collect_seconds (set_t &s) const
+  {
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_apply ([&s] (const Ligature &_) { _.collect_second (s); })
+    ;
+  }
+
   bool would_apply (hb_would_apply_context_t *c) const
   {
     return
@@ -72,14 +81,14 @@ struct LigatureSet
     ;
   }
 
-  bool apply (hb_ot_apply_context_t *c) const
+  bool apply (hb_ot_apply_context_t *c, const hb_set_digest_t *seconds = nullptr) const
   {
     TRACE_APPLY (this);
 
     unsigned int num_ligs = ligature.len;
 
 #ifndef HB_NO_OT_RULESETS_FAST_PATH
-    if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 4)
+    if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 1)
 #endif
     {
     slow:
@@ -91,21 +100,21 @@ struct LigatureSet
       return_trace (false);
     }
 
-    /* This version is optimized for speed by matching the first component
+    /* This version is optimized for speed by matching the second component
      * of the ligature here, instead of calling into the ligation code.
      *
      * This is replicated in ChainRuleSet and RuleSet. */
 
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_context;
     skippy_iter.reset (c->buffer->idx);
     skippy_iter.set_match_func (match_always, nullptr);
     skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
     unsigned unsafe_to;
-    hb_codepoint_t first = (unsigned) -1;
+    hb_codepoint_t second = (unsigned) -1;
     bool matched = skippy_iter.next (&unsafe_to);
     if (likely (matched))
     {
-      first = c->buffer->info[skippy_iter.idx].codepoint;
+      second = c->buffer->info[skippy_iter.idx].codepoint;
       unsafe_to = skippy_iter.idx + 1;
 
       if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
@@ -118,13 +127,14 @@ struct LigatureSet
     else
       goto slow;
 
+    if (seconds && !seconds->may_have (second))
+      return_trace (false);
     bool unsafe_to_concat = false;
-
     for (unsigned int i = 0; i < num_ligs; i++)
     {
       const auto &lig = this+ligature.arrayZ[i];
       if (unlikely (lig.component.lenP1 <= 1) ||
-          lig.component.arrayZ[0] == first)
+          lig.component.arrayZ[0] == second)
       {
         if (lig.apply (c))
         {
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubst.hh
index cffa910295f..22ce9b79d7f 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubst.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubst.hh
@@ -12,7 +12,7 @@ struct LigatureSubst
 {
   protected:
   union {
-  HBUINT16                              format;         /* Format identifier */
+  struct { HBUINT16 v; }                format;         /* Format identifier */
   LigatureSubstFormat1_2    format1;
 #ifndef HB_NO_BEYOND_64K
   LigatureSubstFormat1_2   format2;
@@ -23,9 +23,9 @@ struct LigatureSubst
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...));
 #ifndef HB_NO_BEYOND_64K
     case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...));
@@ -45,10 +45,10 @@ struct LigatureSubst
                   hb_array_t component_list /* Starting from second for each ligature */)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (u.format))) return_trace (false);
+    if (unlikely (!c->extend_min (u.format.v))) return_trace (false);
     unsigned int format = 1;
-    u.format = format;
-    switch (u.format) {
+    u.format.v = format;
+    switch (u.format.v) {
     case 1: return_trace (u.format1.serialize (c,
                                                first_glyphs,
                                                ligature_per_first_glyph_count_list,
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubstFormat1.hh
index 6ae24b33754..909ddca220f 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubstFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubstFormat1.hh
@@ -78,52 +78,44 @@ struct LigatureSubstFormat1_2
     return lig_set.would_apply (c);
   }
 
-  unsigned cache_cost () const
+  struct external_cache_t
   {
-    return (this+coverage).cost ();
-  }
-  static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
+    hb_ot_layout_mapping_cache_t coverage;
+    hb_set_digest_t seconds;
+  };
+  void *external_cache_create () const
   {
-    switch (op)
+    external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t));
+    if (likely (cache))
     {
-      case hb_ot_lookup_cache_op_t::CREATE:
-      {
-        hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t));
-        if (likely (cache))
-          cache->clear ();
-        return cache;
-      }
-      case hb_ot_lookup_cache_op_t::ENTER:
-        return (void *) true;
-      case hb_ot_lookup_cache_op_t::LEAVE:
-        return nullptr;
-      case hb_ot_lookup_cache_op_t::DESTROY:
-      {
-        hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p;
-        hb_free (cache);
-        return nullptr;
-      }
+      cache->coverage.clear ();
+
+      cache->seconds.init ();
+      + hb_iter (ligatureSet)
+      | hb_map (hb_add (this))
+      | hb_apply ([cache] (const LigatureSet &_) { _.collect_seconds (cache->seconds); })
+      ;
     }
-    return nullptr;
+    return cache;
   }
 
-  bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
-  bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
-  bool _apply (hb_ot_apply_context_t *c, bool cached) const
+  bool apply (hb_ot_apply_context_t *c, void *external_cache) const
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
 
 #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
-    hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr;
-    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint, cache);
+    external_cache_t *cache = (external_cache_t *) external_cache;
+    const hb_set_digest_t *seconds = cache ? &cache->seconds : nullptr;
+    unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache ? &cache->coverage : nullptr);
 #else
-    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
+    const hb_set_digest_t *seconds = nullptr;
+    unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
 #endif
     if (index == NOT_COVERED) return_trace (false);
 
     const auto &lig_set = this+ligatureSet[index];
-    return_trace (lig_set.apply (c));
+    return_trace (lig_set.apply (c, seconds));
   }
 
   bool serialize (hb_serialize_context_t *c,
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubst.hh
index cf3d754e3cc..8fb663825b5 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubst.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubst.hh
@@ -12,7 +12,7 @@ struct MultipleSubst
 {
   protected:
   union {
-  HBUINT16                              format;         /* Format identifier */
+  struct { HBUINT16 v; }                format;         /* Format identifier */
   MultipleSubstFormat1_2    format1;
 #ifndef HB_NO_BEYOND_64K
   MultipleSubstFormat1_2   format2;
@@ -24,9 +24,9 @@ struct MultipleSubst
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...));
 #ifndef HB_NO_BEYOND_64K
     case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...));
@@ -41,10 +41,10 @@ struct MultipleSubst
                   Iterator it)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (u.format))) return_trace (false);
+    if (unlikely (!c->extend_min (u.format.v))) return_trace (false);
     unsigned int format = 1;
-    u.format = format;
-    switch (u.format) {
+    u.format.v = format;
+    switch (u.format.v) {
     case 1: return_trace (u.format1.serialize (c, it));
     default:return_trace (false);
     }
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubst.hh
index 5ad463fea79..e33148d770b 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubst.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubst.hh
@@ -12,7 +12,7 @@ struct ReverseChainSingleSubst
 {
   protected:
   union {
-  HBUINT16                              format;         /* Format identifier */
+  struct { HBUINT16 v; }                format;         /* Format identifier */
   ReverseChainSingleSubstFormat1        format1;
   } u;
 
@@ -20,9 +20,9 @@ struct ReverseChainSingleSubst
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...));
     default:return_trace (c->default_return_value ());
     }
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh
index a5e93a98bef..b3295bee16d 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh
@@ -115,7 +115,7 @@ struct Sequence
 
       for (unsigned i = c->buffer->idx - count; i < c->buffer->idx; i++)
       {
-        if (buf < p)
+        if (buf < p && sizeof(buf) - 1u > unsigned (p - buf))
           *p++ = ',';
         snprintf (p, sizeof(buf) - (p - buf), "%u", i);
         p += strlen(p);
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh
index b84259e7f00..323eb4d0f90 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh
@@ -13,7 +13,7 @@ struct SingleSubst
 {
   protected:
   union {
-  HBUINT16                              format;         /* Format identifier */
+  struct { HBUINT16 v; }                format;         /* Format identifier */
   SingleSubstFormat1_3      format1;
   SingleSubstFormat2_4      format2;
 #ifndef HB_NO_BEYOND_64K
@@ -27,9 +27,9 @@ struct SingleSubst
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...));
 #ifndef HB_NO_BEYOND_64K
@@ -47,7 +47,7 @@ struct SingleSubst
                   Iterator glyphs)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (u.format))) return_trace (false);
+    if (unlikely (!c->extend_min (u.format.v))) return_trace (false);
     unsigned format = 2;
     unsigned delta = 0;
     if (glyphs)
@@ -71,8 +71,8 @@ struct SingleSubst
       if (!hb_all (++(+glyphs), delta, get_delta)) format += 1;
     }
 
-    u.format = format;
-    switch (u.format) {
+    u.format.v = format;
+    switch (u.format.v) {
     case 1: return_trace (u.format1.serialize (c,
                                                + glyphs
                                                | hb_map_retains_sorting (hb_first),
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat1.hh
index be6cd820d28..5ee2c1d1f46 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat1.hh
@@ -123,6 +123,21 @@ struct SingleSubstFormat1_3
     return 1;
   }
 
+  void
+  collect_glyph_alternates (hb_map_t  *alternate_count /* IN/OUT */,
+                            hb_map_t  *alternate_glyphs /* IN/OUT */) const
+  {
+    hb_codepoint_t d = deltaGlyphID;
+    hb_codepoint_t mask = get_mask ();
+
+    + hb_iter (this+coverage)
+    | hb_map ([d, mask] (hb_codepoint_t g) { return hb_pair (g, (g + d) & mask); })
+    | hb_apply ([&] (const hb_pair_t &p) -> void
+                { _hb_collect_glyph_alternates_add (p.first, p.second,
+                                                    alternate_count, alternate_glyphs); })
+    ;
+  }
+
   bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat2.hh
index e9096460451..0d51d130fee 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat2.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat2.hh
@@ -100,6 +100,17 @@ struct SingleSubstFormat2_4
     return 1;
   }
 
+  void
+  collect_glyph_alternates (hb_map_t  *alternate_count /* IN/OUT */,
+                            hb_map_t  *alternate_glyphs /* IN/OUT */) const
+  {
+    + hb_zip (this+coverage, substitute)
+    | hb_apply ([&] (const hb_pair_t &p) -> void
+                { _hb_collect_glyph_alternates_add (p.first, p.second,
+                                                    alternate_count, alternate_glyphs); })
+    ;
+  }
+
   bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/types.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/types.hh
index 527f64114b4..5cf9eb368aa 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/types.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/types.hh
@@ -29,8 +29,11 @@
 #ifndef OT_LAYOUT_TYPES_HH
 #define OT_LAYOUT_TYPES_HH
 
-using hb_ot_lookup_cache_t = hb_cache_t<15, 8, 7>;
-static_assert (sizeof (hb_ot_lookup_cache_t) == 256, "");
+using hb_ot_layout_mapping_cache_t = hb_cache_t<16, 8, 8>;
+static_assert (sizeof (hb_ot_layout_mapping_cache_t) == 512, "");
+
+using hb_ot_layout_binary_cache_t = hb_cache_t<14, 1, 8>;
+static_assert (sizeof (hb_ot_layout_binary_cache_t) == 256, "");
 
 namespace OT {
 namespace Layout {
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.cc b/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.cc
new file mode 100644
index 00000000000..f0e7f934579
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.cc
@@ -0,0 +1,421 @@
+#include "VARC.hh"
+
+#ifndef HB_NO_VAR_COMPOSITES
+
+#include "../../../hb-draw.hh"
+#include "../../../hb-ot-layout-common.hh"
+#include "../../../hb-ot-layout-gdef-table.hh"
+
+namespace OT {
+
+//namespace Var {
+
+
+#ifndef HB_NO_DRAW
+
+struct hb_transforming_pen_context_t
+{
+  hb_transform_t<> transform;
+  hb_draw_funcs_t *dfuncs;
+  void *data;
+  hb_draw_state_t *st;
+};
+
+static void
+hb_transforming_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                             void *data,
+                             hb_draw_state_t *st,
+                             float to_x, float to_y,
+                             void *user_data HB_UNUSED)
+{
+  hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
+
+  c->transform.transform_point (to_x, to_y);
+
+  c->dfuncs->move_to (c->data, *c->st, to_x, to_y);
+}
+
+static void
+hb_transforming_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                             void *data,
+                             hb_draw_state_t *st,
+                             float to_x, float to_y,
+                             void *user_data HB_UNUSED)
+{
+  hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
+
+  c->transform.transform_point (to_x, to_y);
+
+  c->dfuncs->line_to (c->data, *c->st, to_x, to_y);
+}
+
+static void
+hb_transforming_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                                  void *data,
+                                  hb_draw_state_t *st,
+                                  float control_x, float control_y,
+                                  float to_x, float to_y,
+                                  void *user_data HB_UNUSED)
+{
+  hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
+
+  c->transform.transform_point (control_x, control_y);
+  c->transform.transform_point (to_x, to_y);
+
+  c->dfuncs->quadratic_to (c->data, *c->st, control_x, control_y, to_x, to_y);
+}
+
+static void
+hb_transforming_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                              void *data,
+                              hb_draw_state_t *st,
+                              float control1_x, float control1_y,
+                              float control2_x, float control2_y,
+                              float to_x, float to_y,
+                              void *user_data HB_UNUSED)
+{
+  hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
+
+  c->transform.transform_point (control1_x, control1_y);
+  c->transform.transform_point (control2_x, control2_y);
+  c->transform.transform_point (to_x, to_y);
+
+  c->dfuncs->cubic_to (c->data, *c->st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
+}
+
+static void
+hb_transforming_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                                void *data,
+                                hb_draw_state_t *st,
+                                void *user_data HB_UNUSED)
+{
+  hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
+
+  c->dfuncs->close_path (c->data, *c->st);
+}
+
+static inline void free_static_transforming_pen_funcs ();
+
+static struct hb_transforming_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t
+{
+  static hb_draw_funcs_t *create ()
+  {
+    hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
+
+    hb_draw_funcs_set_move_to_func (funcs, hb_transforming_pen_move_to, nullptr, nullptr);
+    hb_draw_funcs_set_line_to_func (funcs, hb_transforming_pen_line_to, nullptr, nullptr);
+    hb_draw_funcs_set_quadratic_to_func (funcs, hb_transforming_pen_quadratic_to, nullptr, nullptr);
+    hb_draw_funcs_set_cubic_to_func (funcs, hb_transforming_pen_cubic_to, nullptr, nullptr);
+    hb_draw_funcs_set_close_path_func (funcs, hb_transforming_pen_close_path, nullptr, nullptr);
+
+    hb_draw_funcs_make_immutable (funcs);
+
+    hb_atexit (free_static_transforming_pen_funcs);
+
+    return funcs;
+  }
+} static_transforming_pen_funcs;
+
+static inline
+void free_static_transforming_pen_funcs ()
+{
+  static_transforming_pen_funcs.free_instance ();
+}
+
+static hb_draw_funcs_t *
+hb_transforming_pen_get_funcs ()
+{
+  return static_transforming_pen_funcs.get_unconst ();
+}
+
+hb_ubytes_t
+VarComponent::get_path_at (const hb_varc_context_t &c,
+                           hb_codepoint_t parent_gid,
+                           hb_array_t coords,
+                           hb_transform_t<> total_transform,
+                           hb_ubytes_t total_record,
+                           hb_scalar_cache_t *cache) const
+{
+  const unsigned char *end = total_record.arrayZ + total_record.length;
+  const unsigned char *record = total_record.arrayZ;
+
+  auto &VARC = *c.font->face->table.VARC->table;
+  auto &varStore = &VARC+VARC.varStore;
+
+#define READ_UINT32VAR(name) \
+  HB_STMT_START { \
+    if (unlikely (unsigned (end - record) < HBUINT32VAR::min_size)) return hb_ubytes_t (); \
+    hb_barrier (); \
+    auto &varint = * (const HBUINT32VAR *) record; \
+    unsigned size = varint.get_size (); \
+    if (unlikely (unsigned (end - record) < size)) return hb_ubytes_t (); \
+    name = (uint32_t) varint; \
+    record += size; \
+  } HB_STMT_END
+
+  uint32_t flags;
+  READ_UINT32VAR (flags);
+
+  // gid
+
+  hb_codepoint_t gid = 0;
+  if (flags & (unsigned) flags_t::GID_IS_24BIT)
+  {
+    if (unlikely (unsigned (end - record) < HBGlyphID24::static_size))
+      return hb_ubytes_t ();
+    hb_barrier ();
+    gid = * (const HBGlyphID24 *) record;
+    record += HBGlyphID24::static_size;
+  }
+  else
+  {
+    if (unlikely (unsigned (end - record) < HBGlyphID16::static_size))
+      return hb_ubytes_t ();
+    hb_barrier ();
+    gid = * (const HBGlyphID16 *) record;
+    record += HBGlyphID16::static_size;
+  }
+
+  // Condition
+  bool show = true;
+  if (flags & (unsigned) flags_t::HAVE_CONDITION)
+  {
+    unsigned conditionIndex;
+    READ_UINT32VAR (conditionIndex);
+    const auto &condition = (&VARC+VARC.conditionList)[conditionIndex];
+    auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache);
+    show = condition.evaluate (coords.arrayZ, coords.length, &instancer);
+  }
+
+  // Axis values
+
+  auto &axisIndices = c.scratch.axisIndices;
+  axisIndices.clear ();
+  auto &axisValues = c.scratch.axisValues;
+  axisValues.clear ();
+  if (flags & (unsigned) flags_t::HAVE_AXES)
+  {
+    unsigned axisIndicesIndex;
+    READ_UINT32VAR (axisIndicesIndex);
+    axisIndices.extend ((&VARC+VARC.axisIndicesList)[axisIndicesIndex]);
+    axisValues.resize (axisIndices.length);
+    const HBUINT8 *p = (const HBUINT8 *) record;
+    TupleValues::decompile (p, axisValues, (const HBUINT8 *) end);
+    record = (const unsigned char *) p;
+  }
+
+  // Apply variations if any
+  if (flags & (unsigned) flags_t::AXIS_VALUES_HAVE_VARIATION)
+  {
+    uint32_t axisValuesVarIdx;
+    READ_UINT32VAR (axisValuesVarIdx);
+    if (show && coords && !axisValues.in_error ())
+      varStore.get_delta (axisValuesVarIdx, coords, axisValues.as_array (), cache);
+  }
+
+  auto component_coords = coords;
+  /* Copying coords is expensive; so we have put an arbitrary
+   * limit on the max number of coords for now. */
+  if ((flags & (unsigned) flags_t::RESET_UNSPECIFIED_AXES) ||
+      coords.length > HB_VAR_COMPOSITE_MAX_AXES)
+    component_coords = hb_array (c.font->coords, c.font->num_coords);
+
+  // Transform
+
+  uint32_t transformVarIdx = VarIdx::NO_VARIATION;
+  if (flags & (unsigned) flags_t::TRANSFORM_HAS_VARIATION)
+    READ_UINT32VAR (transformVarIdx);
+
+#define PROCESS_TRANSFORM_COMPONENTS \
+        HB_STMT_START { \
+        PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TRANSLATE_X, translateX); \
+        PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TRANSLATE_Y, translateY); \
+        PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_ROTATION, rotation); \
+        PROCESS_TRANSFORM_COMPONENT (F6DOT10, 1.0f, HAVE_SCALE_X, scaleX); \
+        PROCESS_TRANSFORM_COMPONENT (F6DOT10, 1.0f, HAVE_SCALE_Y, scaleY); \
+        PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_SKEW_X, skewX); \
+        PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_SKEW_Y, skewY); \
+        PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TCENTER_X, tCenterX); \
+        PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TCENTER_Y, tCenterY); \
+        } HB_STMT_END
+
+  hb_transform_decomposed_t<> transform;
+
+  // Read transform components
+#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \
+        if (flags & (unsigned) flags_t::flag) \
+        { \
+          static_assert (type::static_size == HBINT16::static_size, ""); \
+          if (unlikely (unsigned (end - record) < HBINT16::static_size)) \
+            return hb_ubytes_t (); \
+          hb_barrier (); \
+          transform.name = mult * * (const HBINT16 *) record; \
+          record += HBINT16::static_size; \
+        }
+  PROCESS_TRANSFORM_COMPONENTS;
+#undef PROCESS_TRANSFORM_COMPONENT
+
+  // Read reserved records
+  unsigned i = flags & (unsigned) flags_t::RESERVED_MASK;
+  while (i)
+  {
+    HB_UNUSED uint32_t discard;
+    READ_UINT32VAR (discard);
+    i &= i - 1;
+  }
+
+  /* Parsing is over now. */
+
+  if (show)
+  {
+    // Only use coord_setter if there's actually any axis overrides.
+    coord_setter_t coord_setter (axisIndices ? component_coords : hb_array ());
+    // Go backwards, to reduce coord_setter vector reallocations.
+    for (unsigned i = axisIndices.length; i; i--)
+      coord_setter[axisIndices[i - 1]] = axisValues[i - 1];
+    if (axisIndices)
+      component_coords = coord_setter.get_coords ();
+
+    // Apply transform variations if any
+    if (transformVarIdx != VarIdx::NO_VARIATION && coords)
+    {
+      float transformValues[9];
+      unsigned numTransformValues = 0;
+#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \
+          if (flags & (unsigned) flags_t::flag) \
+            transformValues[numTransformValues++] = transform.name / mult;
+      PROCESS_TRANSFORM_COMPONENTS;
+#undef PROCESS_TRANSFORM_COMPONENT
+      varStore.get_delta (transformVarIdx, coords, hb_array (transformValues, numTransformValues), cache);
+      numTransformValues = 0;
+#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \
+          if (flags & (unsigned) flags_t::flag) \
+            transform.name = transformValues[numTransformValues++] * mult;
+      PROCESS_TRANSFORM_COMPONENTS;
+#undef PROCESS_TRANSFORM_COMPONENT
+    }
+
+    // Divide them by their divisors
+#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \
+          if (flags & (unsigned) flags_t::flag) \
+          { \
+            HBINT16 int_v; \
+            int_v = roundf (transform.name); \
+            type typed_v = * (const type *) &int_v; \
+            float float_v = (float) typed_v; \
+            transform.name = float_v; \
+          }
+    PROCESS_TRANSFORM_COMPONENTS;
+#undef PROCESS_TRANSFORM_COMPONENT
+
+    if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y))
+      transform.scaleY = transform.scaleX;
+
+    total_transform.transform (transform.to_transform ());
+    total_transform.scale (c.font->x_mult ? 1.f / c.font->x_multf : 0.f,
+                           c.font->y_mult ? 1.f / c.font->y_multf : 0.f);
+
+    bool same_coords = component_coords.length == coords.length &&
+                       component_coords.arrayZ == coords.arrayZ;
+
+    c.depth_left--;
+    VARC.get_path_at (c, gid,
+                      component_coords, total_transform,
+                      parent_gid,
+                      same_coords ? cache : nullptr);
+    c.depth_left++;
+  }
+
+#undef PROCESS_TRANSFORM_COMPONENTS
+#undef READ_UINT32VAR
+
+  return hb_ubytes_t (record, end - record);
+}
+
+bool
+VARC::get_path_at (const hb_varc_context_t &c,
+                   hb_codepoint_t glyph,
+                   hb_array_t coords,
+                   hb_transform_t<> transform,
+                   hb_codepoint_t parent_glyph,
+                   hb_scalar_cache_t *parent_cache) const
+{
+  // Don't recurse on the same glyph.
+  unsigned idx = glyph == parent_glyph ?
+                 NOT_COVERED :
+                 (this+coverage).get_coverage (glyph);
+  if (idx == NOT_COVERED)
+  {
+    if (c.draw_session)
+    {
+      // Build a transforming pen to apply the transform.
+      hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs ();
+      hb_transforming_pen_context_t context {transform,
+                                             c.draw_session->funcs,
+                                             c.draw_session->draw_data,
+                                             &c.draw_session->st};
+      hb_draw_session_t transformer_session {transformer_funcs, &context};
+      hb_draw_session_t &shape_draw_session = transform.is_identity () ? *c.draw_session : transformer_session;
+
+      if (c.font->face->table.glyf->get_path_at (c.font, glyph, shape_draw_session, coords, c.scratch.glyf_scratch)) return true;
+#ifndef HB_NO_CFF
+      if (c.font->face->table.cff2->get_path_at (c.font, glyph, shape_draw_session, coords)) return true;
+      if (c.font->face->table.cff1->get_path (c.font, glyph, shape_draw_session)) return true; // Doesn't have variations
+#endif
+      return false;
+    }
+    else if (c.extents)
+    {
+      hb_glyph_extents_t glyph_extents;
+      if (!c.font->face->table.glyf->get_extents_at (c.font, glyph, &glyph_extents, coords))
+#ifndef HB_NO_CFF
+      if (!c.font->face->table.cff2->get_extents_at (c.font, glyph, &glyph_extents, coords))
+      if (!c.font->face->table.cff1->get_extents (c.font, glyph, &glyph_extents)) // Doesn't have variations
+#endif
+        return false;
+
+      hb_extents_t<> comp_extents (glyph_extents);
+      transform.transform_extents (comp_extents);
+      c.extents->union_ (comp_extents);
+    }
+    return true;
+  }
+
+  if (c.depth_left <= 0)
+    return true;
+
+  if (c.edges_left <= 0)
+    return true;
+  (c.edges_left)--;
+
+  hb_decycler_node_t node (c.decycler);
+  if (unlikely (!node.visit (glyph)))
+    return true;
+
+  hb_ubytes_t record = (this+glyphRecords)[idx];
+
+  hb_scalar_cache_t static_cache;
+  hb_scalar_cache_t *cache = parent_cache ?
+                                  parent_cache :
+                                  (this+varStore).create_cache (&static_cache);
+
+  transform.scale (c.font->x_multf, c.font->y_multf);
+
+  VarCompositeGlyph::get_path_at (c,
+                                  glyph,
+                                  coords, transform,
+                                  record,
+                                  cache);
+
+  if (cache != parent_cache)
+    (this+varStore).destroy_cache (cache, &static_cache);
+
+  return true;
+}
+
+#endif
+
+//} // namespace Var
+} // namespace OT
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh b/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh
index 2ea1b6bca32..6b40f044556 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh
@@ -32,7 +32,7 @@ struct hb_varc_context_t
 {
   hb_font_t *font;
   hb_draw_session_t *draw_session;
-  hb_extents_t *extents;
+  hb_extents_t<> *extents;
   mutable hb_decycler_t decycler;
   mutable signed edges_left;
   mutable signed depth_left;
@@ -65,9 +65,9 @@ struct VarComponent
   get_path_at (const hb_varc_context_t &c,
                hb_codepoint_t parent_gid,
                hb_array_t coords,
-               hb_transform_t transform,
+               hb_transform_t<> transform,
                hb_ubytes_t record,
-               VarRegionList::cache_t *cache = nullptr) const;
+               hb_scalar_cache_t *cache = nullptr) const;
 };
 
 struct VarCompositeGlyph
@@ -76,9 +76,9 @@ struct VarCompositeGlyph
   get_path_at (const hb_varc_context_t &c,
                hb_codepoint_t gid,
                hb_array_t coords,
-               hb_transform_t transform,
+               hb_transform_t<> transform,
                hb_ubytes_t record,
-               VarRegionList::cache_t *cache)
+               hb_scalar_cache_t *cache)
   {
     while (record)
     {
@@ -104,9 +104,9 @@ struct VARC
   get_path_at (const hb_varc_context_t &c,
                hb_codepoint_t gid,
                hb_array_t coords,
-               hb_transform_t transform = HB_TRANSFORM_IDENTITY,
+               hb_transform_t<> transform = HB_TRANSFORM_IDENTITY,
                hb_codepoint_t parent_gid = HB_CODEPOINT_INVALID,
-               VarRegionList::cache_t *parent_cache = nullptr) const;
+               hb_scalar_cache_t *parent_cache = nullptr) const;
 
   bool
   get_path (hb_font_t *font,
@@ -129,7 +129,7 @@ struct VARC
   bool
   get_extents (hb_font_t *font,
                hb_codepoint_t gid,
-               hb_extents_t *extents,
+               hb_extents_t<> *extents,
                hb_varc_scratch_t &scratch) const
   {
     hb_varc_context_t c {font,
@@ -194,9 +194,10 @@ struct VARC
                  hb_codepoint_t gid,
                  hb_glyph_extents_t *extents) const
     {
+#ifndef HB_NO_DRAW
       if (!table->has_data ()) return false;
 
-      hb_extents_t f_extents;
+      hb_extents_t<> f_extents;
 
       auto *scratch = acquire_scratch ();
       if (unlikely (!scratch)) return true;
@@ -207,6 +208,9 @@ struct VARC
         *extents = f_extents.to_glyph_extents (font->x_scale < 0, font->y_scale < 0);
 
       return ret;
+#else
+      return false;
+#endif
     }
 
     private:
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh
index 1805df262aa..8f5287e9457 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh
@@ -102,17 +102,15 @@ struct Glyph
     if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
     hb_array_t phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
     {
+      // Duplicated code.
       int lsb = 0;
-      int h_delta = face->table.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
-                    (int) header->xMin - lsb : 0;
+      face->table.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb);
+      int h_delta = (int) header->xMin - lsb;
       HB_UNUSED int tsb = 0;
-      int v_orig  = (int) header->yMax +
 #ifndef HB_NO_VERTICAL
-                    ((void) face->table.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
-#else
-                    0
+      face->table.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb);
 #endif
-                    ;
+      int v_orig  = (int) header->yMax + tsb;
       unsigned h_adv = face->table.hmtx->get_advance_without_var_unscaled (gid);
       unsigned v_adv =
 #ifndef HB_NO_VERTICAL
@@ -314,6 +312,7 @@ struct Glyph
                    bool use_my_metrics = true,
                    bool phantom_only = false,
                    hb_array_t coords = hb_array_t (),
+                   hb_scalar_cache_t *gvar_cache = nullptr,
                    unsigned int depth = 0,
                    unsigned *edge_count = nullptr) const
   {
@@ -328,7 +327,7 @@ struct Glyph
       head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
     }
 
-    if (!coords)
+    if (!coords && font->has_nonzero_coords)
       coords = hb_array (font->coords, font->num_coords);
 
     contour_point_vector_t &points = type == SIMPLE ? all_points : scratch.comp_points;
@@ -357,17 +356,15 @@ struct Glyph
     if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
     hb_array_t phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
     {
+      // Duplicated code.
       int lsb = 0;
-      int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
-                    (int) header->xMin - lsb : 0;
+      glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb);
+      int h_delta = (int) header->xMin - lsb;
       HB_UNUSED int tsb = 0;
-      int v_orig  = (int) header->yMax +
 #ifndef HB_NO_VERTICAL
-                    ((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
-#else
-                    0
+      glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb);
 #endif
-                    ;
+      int v_orig  = (int) header->yMax + tsb;
       unsigned h_adv = glyf_accelerator.hmtx->get_advance_without_var_unscaled (gid);
       unsigned v_adv =
 #ifndef HB_NO_VERTICAL
@@ -383,7 +380,7 @@ struct Glyph
     }
 
 #ifndef HB_NO_VAR
-    if (coords)
+    if (hb_any (coords))
     {
 #ifndef HB_NO_BEYOND_64K
       if (glyf_accelerator.GVAR->has_data ())
@@ -391,6 +388,7 @@ struct Glyph
                                                        coords,
                                                        points.as_array ().sub_array (old_length),
                                                        scratch,
+                                                       gvar_cache,
                                                        phantom_only && type == SIMPLE);
       else
 #endif
@@ -398,6 +396,7 @@ struct Glyph
                                                        coords,
                                                        points.as_array ().sub_array (old_length),
                                                        scratch,
+                                                       gvar_cache,
                                                        phantom_only && type == SIMPLE);
     }
 #endif
@@ -447,6 +446,7 @@ struct Glyph
                                                     use_my_metrics,
                                                     phantom_only,
                                                     coords,
+                                                    gvar_cache,
                                                     depth + 1,
                                                     edge_count)))
         {
@@ -533,7 +533,11 @@ struct Glyph
   bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator,
                                        hb_glyph_extents_t *extents) const
   {
-    if (type == EMPTY) return true; /* Empty glyph; zero extents. */
+    if (type == EMPTY)
+    {
+      *extents = {0, 0, 0, 0};
+      return true; /* Empty glyph; zero extents. */
+    }
     return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents);
   }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh
index 601e1303792..507c94f7f3d 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh
@@ -189,7 +189,7 @@ struct SimpleGlyph
 
     unsigned old_length = points.length;
     points.alloc (points.length + num_points + 4); // Allocate for phantom points, to avoid a possible copy
-    if (unlikely (!points.resize (points.length + num_points, false))) return false;
+    if (unlikely (!points.resize_dirty (points.length + num_points))) return false;
     auto points_ = points.as_array ().sub_array (old_length);
     if (!phantom_only)
       hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points);
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh
index d9e5fedfa92..3fe2506bec9 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh
@@ -220,7 +220,8 @@ struct glyf_accelerator_t
   template
   bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer,
                    hb_array_t coords,
-                   hb_glyf_scratch_t &scratch) const
+                   hb_glyf_scratch_t &scratch,
+                   hb_scalar_cache_t *gvar_cache = nullptr) const
   {
     if (gid >= num_glyphs) return false;
 
@@ -228,7 +229,7 @@ struct glyf_accelerator_t
     all_points.resize (0);
 
     bool phantom_only = !consumer.is_consuming_contour_points ();
-    if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords)))
+    if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords, gvar_cache)))
       return false;
 
     unsigned count = all_points.length;
@@ -371,69 +372,67 @@ struct glyf_accelerator_t
     contour_point_t *get_phantoms_sink () { return phantoms; }
   };
 
+#ifndef HB_NO_VAR
   unsigned
-  get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
+  get_advance_with_var_unscaled (hb_codepoint_t gid,
+                                 hb_font_t *font,
+                                 bool is_vertical,
+                                  hb_glyf_scratch_t &scratch,
+                                 hb_scalar_cache_t *gvar_cache = nullptr) const
   {
     if (unlikely (gid >= num_glyphs)) return 0;
 
     bool success = false;
 
     contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
-    if (font->num_coords)
+    success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false),
+                          hb_array (font->coords,
+                                    font->has_nonzero_coords ? font->num_coords : 0),
+                          scratch, gvar_cache);
+    if (unlikely (!success))
     {
-      hb_glyf_scratch_t scratch;
-      success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false),
-                            hb_array (font->coords, font->num_coords),
-                            scratch);
+      unsigned upem = font->face->get_upem ();
+      return is_vertical ? upem : upem / 2;
     }
 
-    if (unlikely (!success))
-      return
-#ifndef HB_NO_VERTICAL
-        is_vertical ? vmtx->get_advance_without_var_unscaled (gid) :
-#endif
-        hmtx->get_advance_without_var_unscaled (gid);
-
     float result = is_vertical
                  ? phantoms[glyf_impl::PHANTOM_TOP].y - phantoms[glyf_impl::PHANTOM_BOTTOM].y
                  : phantoms[glyf_impl::PHANTOM_RIGHT].x - phantoms[glyf_impl::PHANTOM_LEFT].x;
     return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2);
   }
 
-  bool get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical, int *lsb) const
+  float
+  get_v_origin_with_var_unscaled (hb_codepoint_t gid,
+                                  hb_font_t *font,
+                                  hb_glyf_scratch_t &scratch,
+                                  hb_scalar_cache_t *gvar_cache = nullptr) const
   {
-    if (unlikely (gid >= num_glyphs)) return false;
+    if (unlikely (gid >= num_glyphs)) return 0;
+
+    bool success = false;
 
-    hb_glyph_extents_t extents;
-    hb_glyf_scratch_t scratch;
     contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
-    if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms, false),
-                               hb_array (font->coords, font->num_coords),
-                               scratch)))
-      return false;
+    success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false),
+                          hb_array (font->coords,
+                                    font->has_nonzero_coords ? font->num_coords : 0),
+                          scratch, gvar_cache);
+    if (unlikely (!success))
+    {
+      return font->face->get_upem ();
+    }
 
-    *lsb = is_vertical
-         ? roundf (phantoms[glyf_impl::PHANTOM_TOP].y) - extents.y_bearing
-         : roundf (phantoms[glyf_impl::PHANTOM_LEFT].x);
-    return true;
+    return phantoms[glyf_impl::PHANTOM_TOP].y;
   }
 #endif
-
-  bool get_leading_bearing_without_var_unscaled (hb_codepoint_t gid, bool is_vertical, int *lsb) const
-  {
-    if (unlikely (gid >= num_glyphs)) return false;
-    if (is_vertical) return false; // TODO Humm, what to do here?
-
-    *lsb = glyph_for_gid (gid).get_header ()->xMin;
-    return true;
-  }
+#endif
 
   public:
 
   bool get_extents (hb_font_t *font,
                     hb_codepoint_t gid,
                     hb_glyph_extents_t *extents) const
-  { return get_extents_at (font, gid, extents, hb_array (font->coords, font->num_coords)); }
+  { return get_extents_at (font, gid, extents, hb_array (font->coords,
+                                                         font->has_nonzero_coords ? font->num_coords : 0)); }
 
   bool get_extents_at (hb_font_t *font,
                        hb_codepoint_t gid,
@@ -445,12 +444,15 @@ struct glyf_accelerator_t
 #ifndef HB_NO_VAR
     if (coords)
     {
-      hb_glyf_scratch_t scratch;
-      return get_points (font,
-                         gid,
-                         points_aggregator_t (font, extents, nullptr, true),
-                         coords,
-                         scratch);
+      hb_glyf_scratch_t *scratch = acquire_scratch ();
+      if (unlikely (!scratch)) return false;
+      bool ret = get_points (font,
+                             gid,
+                             points_aggregator_t (font, extents, nullptr, true),
+                             coords,
+                             *scratch);
+      release_scratch (scratch);
+      return ret;
     }
 #endif
     return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents);
@@ -485,33 +487,20 @@ struct glyf_accelerator_t
   }
 
   bool
-  get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
+  get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session, hb_scalar_cache_t *gvar_cache = nullptr) const
   {
     if (!has_data ()) return false;
 
-    hb_glyf_scratch_t *scratch;
-
-    // Borrow the cached strach buffer.
-    {
-      scratch = cached_scratch.get_acquire ();
-      if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
-      {
-        scratch = (hb_glyf_scratch_t *) hb_calloc (1, sizeof (hb_glyf_scratch_t));
-        if (unlikely (!scratch))
-          return true;
-      }
-    }
+    hb_glyf_scratch_t *scratch = acquire_scratch ();
+    if (unlikely (!scratch)) return true;
 
     bool ret = get_points (font, gid, glyf_impl::path_builder_t (font, draw_session),
-                           hb_array (font->coords, font->num_coords),
-                           *scratch);
+                           hb_array (font->coords,
+                                     font->has_nonzero_coords ? font->num_coords : 0),
+                           *scratch,
+                            gvar_cache);
 
-    // Put it back.
-    if (!cached_scratch.cmpexch (nullptr, scratch))
-    {
-      scratch->~hb_glyf_scratch_t ();
-      hb_free (scratch);
-    }
+    release_scratch (scratch);
 
     return ret;
   }
@@ -519,12 +508,38 @@ struct glyf_accelerator_t
   bool
   get_path_at (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session,
                hb_array_t coords,
-               hb_glyf_scratch_t &scratch) const
+               hb_glyf_scratch_t &scratch,
+               hb_scalar_cache_t *gvar_cache = nullptr) const
   {
     if (!has_data ()) return false;
     return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session),
                        coords,
-                       scratch);
+                       scratch,
+                       gvar_cache);
+  }
+
+
+  hb_glyf_scratch_t *acquire_scratch () const
+  {
+    if (!has_data ()) return nullptr;
+    hb_glyf_scratch_t *scratch = cached_scratch.get_acquire ();
+    if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
+    {
+      scratch = (hb_glyf_scratch_t *) hb_calloc (1, sizeof (hb_glyf_scratch_t));
+      if (unlikely (!scratch))
+        return nullptr;
+    }
+    return scratch;
+  }
+  void release_scratch (hb_glyf_scratch_t *scratch) const
+  {
+    if (!scratch)
+      return;
+    if (!cached_scratch.cmpexch (nullptr, scratch))
+    {
+      scratch->~hb_glyf_scratch_t ();
+      hb_free (scratch);
+    }
   }
 
 #ifndef HB_NO_VAR
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh
index da6378820bb..d1f38b9de8a 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh
@@ -74,7 +74,7 @@ struct ClassDef : public OT::ClassDef
     class_def_link->width = SmallTypes::size;
     class_def_link->objidx = class_def_prime_id;
     class_def_link->position = link_position;
-    class_def_prime_vertex.add_parent (parent_id);
+    class_def_prime_vertex.add_parent (parent_id, false);
 
     return true;
   }
@@ -117,7 +117,7 @@ struct ClassDef : public OT::ClassDef
     int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
     if (vertex_len < OT::ClassDef::min_size) return false;
     hb_barrier ();
-    switch (u.format)
+    switch (u.format.v)
     {
     case 1: return ((ClassDefFormat1*)this)->sanitize (vertex);
     case 2: return ((ClassDefFormat2*)this)->sanitize (vertex);
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh
index 61ca063e345..46c703524d9 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh
@@ -32,29 +32,27 @@
 
 namespace graph {
 
-struct CoverageFormat1 : public OT::Layout::Common::CoverageFormat1_3
-{
-  bool sanitize (graph_t::vertex_t& vertex) const
-  {
-    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
-    constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3::min_size;
-    if (vertex_len < min_size) return false;
-    hb_barrier ();
-    return vertex_len >= min_size + glyphArray.get_size () - glyphArray.len.get_size ();
-  }
-};
+static bool sanitize (
+  const OT::Layout::Common::CoverageFormat1_3* thiz,
+  graph_t::vertex_t& vertex
+) {
+  int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+  constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3::min_size;
+  if (vertex_len < min_size) return false;
+  hb_barrier ();
+  return vertex_len >= min_size + thiz->glyphArray.get_size () - thiz->glyphArray.len.get_size ();
+}
 
-struct CoverageFormat2 : public OT::Layout::Common::CoverageFormat2_4
-{
-  bool sanitize (graph_t::vertex_t& vertex) const
-  {
-    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
-    constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4::min_size;
-    if (vertex_len < min_size) return false;
-    hb_barrier ();
-    return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
-  }
-};
+static bool sanitize (
+  const OT::Layout::Common::CoverageFormat2_4* thiz,
+  graph_t::vertex_t& vertex
+) {
+  int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+  constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4::min_size;
+  if (vertex_len < min_size) return false;
+  hb_barrier ();
+  return vertex_len >= min_size + thiz->rangeRecord.get_size () - thiz->rangeRecord.len.get_size ();
+}
 
 struct Coverage : public OT::Layout::Common::Coverage
 {
@@ -98,11 +96,33 @@ struct Coverage : public OT::Layout::Common::Coverage
     coverage_link->width = SmallTypes::size;
     coverage_link->objidx = coverage_prime_id;
     coverage_link->position = link_position;
-    coverage_prime_vertex.add_parent (parent_id);
+    coverage_prime_vertex.add_parent (parent_id, false);
 
     return (Coverage*) coverage_prime_vertex.obj.head;
   }
 
+  // Filter an existing coverage table to glyphs at indices [start, end) and replace it with the filtered version.
+  static bool filter_coverage (gsubgpos_graph_context_t& c,
+                               unsigned existing_coverage,
+                               unsigned start, unsigned end) {
+    unsigned coverage_size = c.graph.vertices_[existing_coverage].table_size ();
+    auto& coverage_v = c.graph.vertices_[existing_coverage];
+    Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
+    if (!coverage_table || !coverage_table->sanitize (coverage_v))
+      return false;
+
+    auto new_coverage =
+        + hb_zip (coverage_table->iter (), hb_range ())
+        | hb_filter ([&] (hb_pair_t p) {
+          return p.second >= start && p.second < end;
+        })
+        | hb_map_retains_sorting (hb_first)
+        ;
+
+    return make_coverage (c, new_coverage, existing_coverage, coverage_size * 2 + 100);
+  }
+
+  // Replace the coverage table at dest obj with one covering 'glyphs'.
   template
   static bool make_coverage (gsubgpos_graph_context_t& c,
                              It glyphs,
@@ -141,10 +161,10 @@ struct Coverage : public OT::Layout::Common::Coverage
     int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
     if (vertex_len < OT::Layout::Common::Coverage::min_size) return false;
     hb_barrier ();
-    switch (u.format)
+    switch (u.format.v)
     {
-    case 1: return ((CoverageFormat1*)this)->sanitize (vertex);
-    case 2: return ((CoverageFormat2*)this)->sanitize (vertex);
+    case 1: return graph::sanitize ((const OT::Layout::Common::CoverageFormat1_3*) this, vertex);
+    case 2: return graph::sanitize ((const OT::Layout::Common::CoverageFormat2_4*) this, vertex);
 #ifndef HB_NO_BEYOND_64K
     // Not currently supported
     case 3:
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/graph.hh
index ed1026f5866..78ae1a9dd5b 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/graph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/graph.hh
@@ -50,6 +50,7 @@ struct graph_t
     private:
     unsigned incoming_edges_ = 0;
     unsigned single_parent = (unsigned) -1;
+    bool has_incoming_virtual_edges_ = false;
     hb_hashmap_t parents;
     public:
 
@@ -66,6 +67,11 @@ struct graph_t
       return parents.in_error ();
     }
 
+    bool has_incoming_virtual_edges () const
+    {
+      return has_incoming_virtual_edges_;
+    }
+
     bool link_positions_valid (unsigned num_objects, bool removed_nil)
     {
       hb_set_t assigned_bytes;
@@ -121,7 +127,9 @@ struct graph_t
       }
     }
 
-    bool equals (const vertex_t& other,
+    bool equals (unsigned this_index,
+                 unsigned other_index,
+                 const vertex_t& other,
                  const graph_t& graph,
                  const graph_t& other_graph,
                  unsigned depth) const
@@ -129,8 +137,10 @@ struct graph_t
       if (!(as_bytes () == other.as_bytes ()))
       {
         DEBUG_MSG (SUBSET_REPACK, nullptr,
-                   "vertex [%lu] bytes != [%lu] bytes, depth = %u",
+                   "vertex %u [%lu bytes] != %u [%lu bytes], depth = %u",
+                   this_index,
                    (unsigned long) table_size (),
+                   other_index,
                    (unsigned long) other.table_size (),
                    depth);
 
@@ -162,6 +172,7 @@ struct graph_t
       hb_swap (a.single_parent, b.single_parent);
       hb_swap (a.parents, b.parents);
       hb_swap (a.incoming_edges_, b.incoming_edges_);
+      hb_swap (a.has_incoming_virtual_edges_, b.has_incoming_virtual_edges_);
       hb_swap (a.start, b.start);
       hb_swap (a.end, b.end);
       hb_swap (a.priority, b.priority);
@@ -207,13 +218,16 @@ struct graph_t
     void reset_parents ()
     {
       incoming_edges_ = 0;
+      has_incoming_virtual_edges_ = false;
       single_parent = (unsigned) -1;
       parents.reset ();
     }
 
-    void add_parent (unsigned parent_index)
+    void add_parent (unsigned parent_index, bool is_virtual)
     {
       assert (parent_index != (unsigned) -1);
+      has_incoming_virtual_edges_ |= is_virtual;
+
       if (incoming_edges_ == 0)
       {
         single_parent = parent_index;
@@ -408,7 +422,7 @@ struct graph_t
             link_a.bias != link_b.bias)
           return false;
 
-        if (!graph.vertices_[link_a.objidx].equals (
+        if (!graph.vertices_[link_a.objidx].equals (link_a.objidx, link_b.objidx,
                 other_graph.vertices_[link_b.objidx], graph, other_graph, depth + 1))
           return false;
 
@@ -456,8 +470,12 @@ struct graph_t
     num_roots_for_space_.push (1);
     bool removed_nil = false;
     vertices_.alloc (objects.length);
-    vertices_scratch_.alloc (objects.length);
+    ordering_.resize (objects.length);
+    ordering_scratch_.alloc (objects.length);
+
     unsigned count = objects.length;
+    unsigned order = objects.length;
+    unsigned skip = 0;
     for (unsigned i = 0; i < count; i++)
     {
       // If this graph came from a serialization buffer object 0 is the
@@ -465,6 +483,9 @@ struct graph_t
       if (i == 0 && !objects.arrayZ[i])
       {
         removed_nil = true;
+        order--;
+        ordering_.resize(objects.length - 1);
+        skip++;
         continue;
       }
 
@@ -474,6 +495,12 @@ struct graph_t
 
       check_success (v->link_positions_valid (count, removed_nil));
 
+      // To start we set the ordering to match the provided objects
+      // list. Note: objects are provided to us in reverse order (ie.
+      // the last object is the root).
+      unsigned obj_idx = i - skip;
+      ordering_[--order] = obj_idx;
+
       if (!removed_nil) continue;
       // Fix indices to account for removed nil object.
       for (auto& l : v->obj.all_links_writer ()) {
@@ -490,17 +517,20 @@ struct graph_t
 
   bool operator== (const graph_t& other) const
   {
-    return root ().equals (other.root (), *this, other, 0);
+    return root ().equals (root_idx(), other.root_idx(), other.root (), *this, other, 0);
   }
 
   void print () const {
-    for (int i = vertices_.length - 1; i >= 0; i--)
+    for (unsigned id : ordering_)
     {
-      const auto& v = vertices_[i];
-      printf("%d: %u [", i, (unsigned int)v.table_size());
+      const auto& v = vertices_[id];
+      printf("%u: %u [", id, (unsigned int)v.table_size());
       for (const auto &l : v.obj.real_links) {
         printf("%u, ", l.objidx);
       }
+      for (const auto &l : v.obj.virtual_links) {
+        printf("v%u, ", l.objidx);
+      }
       printf("]\n");
     }
   }
@@ -516,6 +546,7 @@ struct graph_t
   {
     return !successful ||
         vertices_.in_error () ||
+        ordering_.in_error() ||
         num_roots_for_space_.in_error ();
   }
 
@@ -526,10 +557,10 @@ struct graph_t
 
   unsigned root_idx () const
   {
-    // Object graphs are in reverse order, the first object is at the end
-    // of the vector. Since the graph is topologically sorted it's safe to
+    // First element of ordering_ is the root.
+    // Since the graph is topologically sorted it's safe to
     // assume the first object has no incoming edges.
-    return vertices_.length - 1;
+    return ordering_[0];
   }
 
   const hb_serialize_context_t::object_t& object (unsigned i) const
@@ -556,7 +587,7 @@ struct graph_t
     link->width = 2;
     link->objidx = child_id;
     link->position = (char*) offset - (char*) v.obj.head;
-    vertices_[child_id].add_parent (parent_id);
+    vertices_[child_id].add_parent (parent_id, false);
   }
 
   /*
@@ -587,55 +618,51 @@ struct graph_t
 
     hb_priority_queue_t queue;
     queue.alloc (vertices_.length);
-    hb_vector_t &sorted_graph = vertices_scratch_;
-    if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return;
-    hb_vector_t id_map;
-    if (unlikely (!check_success (id_map.resize (vertices_.length)))) return;
+    hb_vector_t &new_ordering = ordering_scratch_;
+    if (unlikely (!check_success (new_ordering.resize (vertices_.length)))) return;
 
     hb_vector_t removed_edges;
     if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return;
     update_parents ();
 
     queue.insert (root ().modified_distance (0), root_idx ());
-    int new_id = root_idx ();
     unsigned order = 1;
+    unsigned pos = 0;
     while (!queue.in_error () && !queue.is_empty ())
     {
       unsigned next_id = queue.pop_minimum().second;
 
-      sorted_graph[new_id] = std::move (vertices_[next_id]);
-      const vertex_t& next = sorted_graph[new_id];
-
-      if (unlikely (!check_success(new_id >= 0))) {
+      if (unlikely (!check_success(pos < new_ordering.length))) {
         // We are out of ids. Which means we've visited a node more than once.
         // This graph contains a cycle which is not allowed.
         DEBUG_MSG (SUBSET_REPACK, nullptr, "Invalid graph. Contains cycle.");
         return;
       }
-
-      id_map[next_id] = new_id--;
+      new_ordering[pos++] = next_id;
+      const vertex_t& next = vertices_[next_id];
 
       for (const auto& link : next.obj.all_links ()) {
         removed_edges[link.objidx]++;
-        if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
+        const auto& v = vertices_[link.objidx];
+        if (!(v.incoming_edges () - removed_edges[link.objidx]))
           // Add the order that the links were encountered to the priority.
           // This ensures that ties between priorities objects are broken in a consistent
           // way. More specifically this is set up so that if a set of objects have the same
           // distance they'll be added to the topological order in the order that they are
           // referenced from the parent object.
-          queue.insert (vertices_[link.objidx].modified_distance (order++),
+          queue.insert (v.modified_distance (order++),
                         link.objidx);
       }
     }
 
     check_success (!queue.in_error ());
-    check_success (!sorted_graph.in_error ());
+    check_success (!new_ordering.in_error ());
 
-    check_success (remap_all_obj_indices (id_map, &sorted_graph));
-    vertices_ = std::move (sorted_graph);
+    hb_swap (ordering_, new_ordering);
 
-    if (!check_success (new_id == -1))
+    if (!check_success (pos == vertices_.length)) {
       print_orphaned_nodes ();
+    }
   }
 
   /*
@@ -645,8 +672,8 @@ struct graph_t
    */
   void find_space_roots (hb_set_t& visited, hb_set_t& roots)
   {
-    int root_index = (int) root_idx ();
-    for (int i = root_index; i >= 0; i--)
+    unsigned root_index = root_idx ();
+    for (unsigned i : ordering_)
     {
       if (visited.has (i)) continue;
 
@@ -829,7 +856,6 @@ struct graph_t
     if (subgraph.in_error ())
       return false;
 
-    unsigned original_root_idx = root_idx ();
     hb_map_t index_map;
     bool made_changes = false;
     for (auto entry : subgraph.iter ())
@@ -852,14 +878,6 @@ struct graph_t
     if (!made_changes)
       return false;
 
-    if (original_root_idx != root_idx ()
-        && parents.has (original_root_idx))
-    {
-      // If the root idx has changed since parents was determined, update root idx in parents
-      parents.add (root_idx ());
-      parents.del (original_root_idx);
-    }
-
     auto new_subgraph =
         + subgraph.keys ()
         | hb_map([&] (uint32_t node_idx) {
@@ -943,12 +961,14 @@ struct graph_t
   /*
    * Moves the child of old_parent_idx pointed to by old_offset to a new
    * vertex at the new_offset.
+   *
+   * Returns the id of the child node that was moved.
    */
   template
-  void move_child (unsigned old_parent_idx,
-                   const O* old_offset,
-                   unsigned new_parent_idx,
-                   const O* new_offset)
+  unsigned move_child (unsigned old_parent_idx,
+                       const O* old_offset,
+                       unsigned new_parent_idx,
+                       const O* new_offset)
   {
     distance_invalid = true;
     positions_invalid = true;
@@ -965,10 +985,56 @@ struct graph_t
     new_link->position = (const char*) new_offset - (const char*) new_v.obj.head;
 
     auto& child = vertices_[child_id];
-    child.add_parent (new_parent_idx);
+    child.add_parent (new_parent_idx, false);
 
     old_v.remove_real_link (child_id, old_offset);
     child.remove_parent (old_parent_idx);
+
+    return child_id;
+  }
+
+  /*
+   * Moves all outgoing links in old parent that have
+   * a link position between [old_post_start, old_pos_end)
+   * to the new parent. Links are placed serially in the new
+   * parent starting at new_pos_start.
+   */
+  template
+  void move_children (unsigned old_parent_idx,
+                      unsigned old_pos_start,
+                      unsigned old_pos_end,
+                      unsigned new_parent_idx,
+                      unsigned new_pos_start)
+  {
+    distance_invalid = true;
+    positions_invalid = true;
+
+    auto& old_v = vertices_[old_parent_idx];
+    auto& new_v = vertices_[new_parent_idx];
+
+    hb_vector_t old_links;
+    for (const auto& l : old_v.obj.real_links)
+    {
+      if (l.position < old_pos_start || l.position >= old_pos_end)
+      {
+        old_links.push(l);
+        continue;
+      }
+
+      unsigned array_pos = l.position - old_pos_start;
+
+      unsigned child_id = l.objidx;
+      auto* new_link = new_v.obj.real_links.push ();
+      new_link->width = O::static_size;
+      new_link->objidx = child_id;
+      new_link->position = new_pos_start + array_pos;
+
+      auto& child = vertices_[child_id];
+      child.add_parent (new_parent_idx, false);
+      child.remove_parent (old_parent_idx);
+    }
+
+    old_v.obj.real_links = std::move (old_links);
   }
 
   /*
@@ -1000,8 +1066,11 @@ struct graph_t
     distance_invalid = true;
 
     auto* clone = vertices_.push ();
+    unsigned clone_idx = vertices_.length - 1;
+    ordering_.push(clone_idx);
+
     auto& child = vertices_[node_idx];
-    if (vertices_.in_error ()) {
+    if (vertices_.in_error () || ordering_.in_error()) {
       return -1;
     }
 
@@ -1011,51 +1080,23 @@ struct graph_t
     clone->space = child.space;
     clone->reset_parents ();
 
-    unsigned clone_idx = vertices_.length - 2;
     for (const auto& l : child.obj.real_links)
     {
       clone->obj.real_links.push (l);
-      vertices_[l.objidx].add_parent (clone_idx);
+      vertices_[l.objidx].add_parent (clone_idx, false);
     }
     for (const auto& l : child.obj.virtual_links)
     {
       clone->obj.virtual_links.push (l);
-      vertices_[l.objidx].add_parent (clone_idx);
+      vertices_[l.objidx].add_parent (clone_idx, true);
     }
 
     check_success (!clone->obj.real_links.in_error ());
     check_success (!clone->obj.virtual_links.in_error ());
 
-    // The last object is the root of the graph, so swap back the root to the end.
-    // The root's obj idx does change, however since it's root nothing else refers to it.
-    // all other obj idx's will be unaffected.
-    hb_swap (vertices_[vertices_.length - 2], *clone);
-
-    // Since the root moved, update the parents arrays of all children on the root.
-    for (const auto& l : root ().obj.all_links ())
-      vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
-
     return clone_idx;
   }
 
-  /*
-   * Creates a copy of child and re-assigns the link from
-   * parent to the clone. The copy is a shallow copy, objects
-   * linked from child are not duplicated.
-   *
-   * Returns the index of the newly created duplicate.
-   *
-   * If the child_idx only has incoming edges from parent_idx, this
-   * will do nothing and return the original child_idx.
-   */
-  unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx)
-  {
-    unsigned new_idx = duplicate (parent_idx, child_idx);
-    if (new_idx == (unsigned) -1) return child_idx;
-    return new_idx;
-  }
-
-
   /*
    * Creates a copy of child and re-assigns the link from
    * parent to the clone. The copy is a shallow copy, objects
@@ -1073,10 +1114,15 @@ struct graph_t
     const auto& child = vertices_[child_idx];
     unsigned links_to_child = child.incoming_edges_from_parent(parent_idx);
 
-    if (child.incoming_edges () <= links_to_child)
+    if (child.incoming_edges () <= links_to_child || child.has_incoming_virtual_edges())
     {
       // Can't duplicate this node, doing so would orphan the original one as all remaining links
       // to child are from parent.
+      //
+      // We don't allow duplication of nodes with incoming virtual edges because we don't track
+      // the number of virtual vs real incoming edges. As a result we can't tell if a node
+      // with virtual edges may end up orphaned by duplication (ie. where one copy is only pointed
+      // to by virtual edges).
       DEBUG_MSG (SUBSET_REPACK, nullptr, "  Not duplicating %u => %u",
                  parent_idx, child_idx);
       return -1;
@@ -1091,12 +1137,15 @@ struct graph_t
     if (parent_idx == clone_idx) parent_idx++;
 
     auto& parent = vertices_[parent_idx];
+    unsigned count = 0;
+    unsigned num_real = parent.obj.real_links.length;
     for (auto& l : parent.obj.all_links_writer ())
     {
+      count++;
       if (l.objidx != child_idx)
         continue;
 
-      reassign_link (l, parent_idx, clone_idx);
+      reassign_link (l, parent_idx, clone_idx, count > num_real);
     }
 
     return clone_idx;
@@ -1129,10 +1178,15 @@ struct graph_t
       links_to_child += child.incoming_edges_from_parent(parent_idx);
     }
 
-    if (child.incoming_edges () <= links_to_child)
+    if (child.incoming_edges () <= links_to_child || child.has_incoming_virtual_edges())
     {
       // Can't duplicate this node, doing so would orphan the original one as all remaining links
       // to child are from parent.
+      //
+      // We don't allow duplication of nodes with incoming virtual edges because we don't track
+      // the number of virtual vs real incoming edges. As a result we can't tell if a node
+      // with virtual edges may end up orphaned by duplication (ie. where one copy is only pointed
+      // to by virtual edges).
       DEBUG_MSG (SUBSET_REPACK, nullptr, "  Not duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx);
       return -1;
     }
@@ -1146,12 +1200,15 @@ struct graph_t
       // duplicate shifts the root node idx, so if parent_idx was root update it.
       if (parent_idx == clone_idx) parent_idx++;
       auto& parent = vertices_[parent_idx];
+      unsigned count = 0;
+      unsigned num_real = parent.obj.real_links.length;
       for (auto& l : parent.obj.all_links_writer ())
       {
+        count++;
         if (l.objidx != child_idx)
           continue;
 
-        reassign_link (l, parent_idx, clone_idx);
+        reassign_link (l, parent_idx, clone_idx, count > num_real);
       }
     }
 
@@ -1168,7 +1225,10 @@ struct graph_t
     distance_invalid = true;
 
     auto* clone = vertices_.push ();
-    if (vertices_.in_error ()) {
+    unsigned clone_idx = vertices_.length - 1;
+    ordering_.push(clone_idx);
+
+    if (vertices_.in_error () || ordering_.in_error()) {
       return -1;
     }
 
@@ -1177,18 +1237,35 @@ struct graph_t
     clone->distance = 0;
     clone->space = 0;
 
-    unsigned clone_idx = vertices_.length - 2;
+    return clone_idx;
+  }
 
-    // The last object is the root of the graph, so swap back the root to the end.
-    // The root's obj idx does change, however since it's root nothing else refers to it.
-    // all other obj idx's will be unaffected.
-    hb_swap (vertices_[vertices_.length - 2], *clone);
+  /*
+   * Creates a new child node and remap the old child to it.
+   *
+   * Returns the index of the newly created child.
+   *
+   */
+  unsigned remap_child (unsigned parent_idx, unsigned old_child_idx)
+  {
+    unsigned new_child_idx = duplicate (old_child_idx);
+    if (new_child_idx == (unsigned) -1) return -1;
 
-    // Since the root moved, update the parents arrays of all children on the root.
-    for (const auto& l : root ().obj.all_links ())
-      vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
+    auto& parent = vertices_[parent_idx];
+    for (auto& l : parent.obj.real_links)
+    {
+      if (l.objidx != old_child_idx)
+        continue;
+      reassign_link (l, parent_idx, new_child_idx, false);
+    }
 
-    return clone_idx;
+    for (auto& l : parent.obj.virtual_links)
+    {
+      if (l.objidx != old_child_idx)
+        continue;
+      reassign_link (l, parent_idx, new_child_idx, true);
+    }
+    return new_child_idx;
   }
 
   /*
@@ -1279,6 +1356,7 @@ struct graph_t
     if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
 
     DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected.");
+
     parents_invalid = true;
     update_parents();
 
@@ -1348,7 +1426,8 @@ struct graph_t
     size_t total_size = 0;
     unsigned count = vertices_.length;
     for (unsigned i = 0; i < count; i++) {
-      size_t size = vertices_.arrayZ[i].obj.tail - vertices_.arrayZ[i].obj.head;
+      const auto& obj = vertices_.arrayZ[i].obj;
+      size_t size = obj.tail - obj.head;
       total_size += size;
     }
     return total_size;
@@ -1398,8 +1477,11 @@ struct graph_t
 
     for (unsigned p = 0; p < count; p++)
     {
-      for (auto& l : vertices_.arrayZ[p].obj.all_links ())
-        vertices_[l.objidx].add_parent (p);
+      for (auto& l : vertices_.arrayZ[p].obj.real_links)
+        vertices_[l.objidx].add_parent (p, false);
+
+      for (auto& l : vertices_.arrayZ[p].obj.virtual_links)
+        vertices_[l.objidx].add_parent (p, true);
     }
 
     for (unsigned i = 0; i < count; i++)
@@ -1418,7 +1500,7 @@ struct graph_t
     if (!positions_invalid) return;
 
     unsigned current_pos = 0;
-    for (int i = root_idx (); i >= 0; i--)
+    for (unsigned i : ordering_)
     {
       auto& v = vertices_[i];
       v.start = current_pos;
@@ -1450,11 +1532,11 @@ struct graph_t
     unsigned count = vertices_.length;
     for (unsigned i = 0; i < count; i++)
       vertices_.arrayZ[i].distance = hb_int_max (int64_t);
-    vertices_.tail ().distance = 0;
+    vertices_[root_idx ()].distance = 0;
 
     hb_priority_queue_t queue;
     queue.alloc (count);
-    queue.insert (0, vertices_.length - 1);
+    queue.insert (0, root_idx ());
 
     hb_vector_t visited;
     visited.resize (vertices_.length);
@@ -1464,22 +1546,23 @@ struct graph_t
       unsigned next_idx = queue.pop_minimum ().second;
       if (visited[next_idx]) continue;
       const auto& next = vertices_[next_idx];
-      int64_t next_distance = vertices_[next_idx].distance;
+      int64_t next_distance = next.distance;
       visited[next_idx] = true;
 
       for (const auto& link : next.obj.all_links ())
       {
         if (visited[link.objidx]) continue;
 
-        const auto& child = vertices_.arrayZ[link.objidx].obj;
+        auto& child_v = vertices_.arrayZ[link.objidx];
+        const auto& child = child_v.obj;
         unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide
         int64_t child_weight = (child.tail - child.head) +
-                               ((int64_t) 1 << (link_width * 8)) * (vertices_.arrayZ[link.objidx].space + 1);
+                               ((int64_t) 1 << (link_width * 8)) * (child_v.space + 1);
         int64_t child_distance = next_distance + child_weight;
 
-        if (child_distance < vertices_.arrayZ[link.objidx].distance)
+        if (child_distance < child_v.distance)
         {
-          vertices_.arrayZ[link.objidx].distance = child_distance;
+          child_v.distance = child_distance;
           queue.insert (child_distance, link.objidx);
         }
       }
@@ -1502,12 +1585,13 @@ struct graph_t
    */
   void reassign_link (hb_serialize_context_t::object_t::link_t& link,
                       unsigned parent_idx,
-                      unsigned new_idx)
+                      unsigned new_idx,
+                      bool is_virtual)
   {
     unsigned old_idx = link.objidx;
     link.objidx = new_idx;
     vertices_[old_idx].remove_parent (parent_idx);
-    vertices_[new_idx].add_parent (parent_idx);
+    vertices_[new_idx].add_parent (parent_idx, is_virtual);
   }
 
   /*
@@ -1521,36 +1605,21 @@ struct graph_t
     if (!id_map) return;
     for (unsigned i : subgraph)
     {
-      for (auto& link : vertices_[i].obj.all_links_writer ())
+      auto& obj = vertices_[i].obj;
+      unsigned num_real = obj.real_links.length;
+      unsigned count = 0;
+      for (auto& link : obj.all_links_writer ())
       {
+        count++;
         const uint32_t *v;
         if (!id_map.has (link.objidx, &v)) continue;
-        if (only_wide && !(link.width == 4 && !link.is_signed)) continue;
+        if (only_wide && (link.is_signed || (link.width != 4 && link.width != 3))) continue;
 
-        reassign_link (link, i, *v);
+        reassign_link (link, i, *v, count > num_real);
       }
     }
   }
 
-  /*
-   * Updates all objidx's in all links using the provided mapping.
-   */
-  bool remap_all_obj_indices (const hb_vector_t& id_map,
-                              hb_vector_t* sorted_graph) const
-  {
-    unsigned count = sorted_graph->length;
-    for (unsigned i = 0; i < count; i++)
-    {
-      if (!(*sorted_graph)[i].remap_parents (id_map))
-        return false;
-      for (auto& link : sorted_graph->arrayZ[i].obj.all_links_writer ())
-      {
-        link.objidx = id_map[link.objidx];
-      }
-    }
-    return true;
-  }
-
   /*
    * Finds all nodes in targets that are reachable from start_idx, nodes in visited will be skipped.
    * For this search the graph is treated as being undirected.
@@ -1586,7 +1655,16 @@ struct graph_t
  public:
   // TODO(garretrieger): make private, will need to move most of offset overflow code into graph.
   hb_vector_t vertices_;
-  hb_vector_t vertices_scratch_;
+
+  // Specifies the current topological ordering of this graph
+  //
+  // ordering_[pos] = obj index
+  //
+  // specifies that the 'pos'th spot is filled by the object
+  // given by obj index.
+  hb_vector_t ordering_;
+  hb_vector_t ordering_scratch_;
+
  private:
   bool parents_invalid;
   bool distance_invalid;
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh
index b25d538fe3d..8969d007879 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh
@@ -41,6 +41,7 @@ struct gsubgpos_graph_context_t
   unsigned lookup_list_index;
   hb_hashmap_t lookups;
   hb_hashmap_t subtable_to_extension;
+  hb_hashmap_t> split_subtables;
 
   HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_,
                                         graph_t& graph_);
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh
index 7ad2ba430b7..ea6bcd239a0 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh
@@ -27,9 +27,11 @@
 #include "graph.hh"
 #include "../hb-ot-layout-gsubgpos.hh"
 #include "../OT/Layout/GSUB/ExtensionSubst.hh"
+#include "../OT/Layout/GSUB/SubstLookupSubTable.hh"
 #include "gsubgpos-context.hh"
 #include "pairpos-graph.hh"
 #include "markbasepos-graph.hh"
+#include "ligature-graph.hh"
 
 #ifndef GRAPH_GSUBGPOS_GRAPH_HH
 #define GRAPH_GSUBGPOS_GRAPH_HH
@@ -85,6 +87,12 @@ struct Lookup : public OT::Lookup
     return lookupType == extension_type (table_tag);
   }
 
+  bool use_mark_filtering_set () const
+  {
+    unsigned flag = lookupFlag;
+    return flag & 0x0010u;
+  }
+
   bool make_extension (gsubgpos_graph_context_t& c,
                        unsigned this_index)
   {
@@ -120,22 +128,18 @@ struct Lookup : public OT::Lookup
     unsigned type = lookupType;
     bool is_ext = is_extension (c.table_tag);
 
-    if (c.table_tag != HB_OT_TAG_GPOS)
+    if (c.table_tag != HB_OT_TAG_GPOS && c.table_tag != HB_OT_TAG_GSUB)
       return true;
 
-    if (!is_ext &&
-        type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair &&
-        type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase)
+    if (!is_ext && !is_supported_gpos_type(type, c) && !is_supported_gsub_type(type, c))
       return true;
 
     hb_vector_t>> all_new_subtables;
     for (unsigned i = 0; i < subTable.len; i++)
     {
       unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
-      unsigned parent_index = this_index;
       if (is_ext) {
         unsigned ext_subtable_index = subtable_index;
-        parent_index = ext_subtable_index;
         ExtensionFormat1* extension =
             (ExtensionFormat1*)
             c.graph.object (ext_subtable_index).head;
@@ -144,26 +148,47 @@ struct Lookup : public OT::Lookup
 
         subtable_index = extension->get_subtable_index (c.graph, ext_subtable_index);
         type = extension->get_lookup_type ();
-        if (type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair
-            && type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase)
+        if (!is_supported_gpos_type(type, c) && !is_supported_gsub_type(type, c))
           continue;
       }
 
-      hb_vector_t new_sub_tables;
-      switch (type)
+      hb_vector_t* split_result;
+      if (c.split_subtables.has (subtable_index, &split_result))
+      {
+        if (split_result->length == 0)
+          continue;
+        all_new_subtables.push (hb_pair(i, *split_result));
+      }
+      else
       {
-      case 2:
-        new_sub_tables = split_subtable (c, parent_index, subtable_index); break;
-      case 4:
-        new_sub_tables = split_subtable (c, parent_index, subtable_index); break;
-      default:
-        break;
+        hb_vector_t new_sub_tables;
+
+        if (c.table_tag == HB_OT_TAG_GPOS) {
+          switch (type)
+          {
+          case 2:
+            new_sub_tables = split_subtable (c, subtable_index); break;
+          case 4:
+            new_sub_tables = split_subtable (c, subtable_index); break;
+          default:
+            break;
+          }
+        } else if (c.table_tag == HB_OT_TAG_GSUB) {
+          switch (type)
+          {
+          case 4:
+            new_sub_tables = split_subtable (c, subtable_index); break;
+          default:
+            break;
+          }
+        }
+
+        if (new_sub_tables.in_error ()) return false;
+
+        c.split_subtables.set (subtable_index, new_sub_tables);
+        if (new_sub_tables)
+          all_new_subtables.push (hb_pair (i, std::move (new_sub_tables)));
       }
-      if (new_sub_tables.in_error ()) return false;
-      if (!new_sub_tables) continue;
-      hb_pair_t>* entry = all_new_subtables.push ();
-      entry->first = i;
-      entry->second = std::move (new_sub_tables);
     }
 
     if (all_new_subtables) {
@@ -175,30 +200,29 @@ struct Lookup : public OT::Lookup
 
   template
   hb_vector_t split_subtable (gsubgpos_graph_context_t& c,
-                                        unsigned parent_idx,
                                         unsigned objidx)
   {
     T* sub_table = (T*) c.graph.object (objidx).head;
     if (!sub_table || !sub_table->sanitize (c.graph.vertices_[objidx]))
       return hb_vector_t ();
 
-    return sub_table->split_subtables (c, parent_idx, objidx);
+    return sub_table->split_subtables (c, objidx);
   }
 
   bool add_sub_tables (gsubgpos_graph_context_t& c,
                        unsigned this_index,
                        unsigned type,
-                       hb_vector_t>>& subtable_ids)
+                       const hb_vector_t>>& subtable_ids)
   {
     bool is_ext = is_extension (c.table_tag);
-    auto& v = c.graph.vertices_[this_index];
+    auto* v = &c.graph.vertices_[this_index];
     fix_existing_subtable_links (c, this_index, subtable_ids);
 
     unsigned new_subtable_count = 0;
     for (const auto& p : subtable_ids)
       new_subtable_count += p.second.length;
 
-    size_t new_size = v.table_size ()
+    size_t new_size = v->table_size ()
                       + new_subtable_count * OT::Offset16::static_size;
     char* buffer = (char*) hb_calloc (1, new_size);
     if (!buffer) return false;
@@ -207,10 +231,13 @@ struct Lookup : public OT::Lookup
       hb_free (buffer);
      return false;
     }
-    hb_memcpy (buffer, v.obj.head, v.table_size());
+    hb_memcpy (buffer, v->obj.head, v->table_size());
 
-    v.obj.head = buffer;
-    v.obj.tail = buffer + new_size;
+    if (use_mark_filtering_set ())
+      hb_memcpy (buffer + new_size - 2, v->obj.tail - 2, 2);
+
+    v->obj.head = buffer;
+    v->obj.tail = buffer + new_size;
 
     Lookup* new_lookup = (Lookup*) buffer;
 
@@ -226,21 +253,23 @@ struct Lookup : public OT::Lookup
         if (is_ext)
         {
           unsigned ext_id = create_extension_subtable (c, subtable_id, type);
-          c.graph.vertices_[subtable_id].add_parent (ext_id);
+          c.graph.vertices_[subtable_id].add_parent (ext_id, false);
           subtable_id = ext_id;
+          // the reference to v may have changed on adding a node, so reassign it.
+          v = &c.graph.vertices_[this_index];
         }
 
-        auto* link = v.obj.real_links.push ();
+        auto* link = v->obj.real_links.push ();
         link->width = 2;
         link->objidx = subtable_id;
         link->position = (char*) &new_lookup->subTable[offset_index++] -
                          (char*) new_lookup;
-        c.graph.vertices_[subtable_id].add_parent (this_index);
+        c.graph.vertices_[subtable_id].add_parent (this_index, false);
       }
     }
 
     // Repacker sort order depends on link order, which we've messed up so resort it.
-    v.obj.real_links.qsort ();
+    v->obj.real_links.qsort ();
 
     // The head location of the lookup has changed, invalidating the lookups map entry
     // in the context. Update the map.
@@ -250,17 +279,15 @@ struct Lookup : public OT::Lookup
 
   void fix_existing_subtable_links (gsubgpos_graph_context_t& c,
                                     unsigned this_index,
-                                    hb_vector_t>>& subtable_ids)
+                                    const hb_vector_t>>& subtable_ids)
   {
     auto& v = c.graph.vertices_[this_index];
-    Lookup* lookup = (Lookup*) v.obj.head;
-
     unsigned shift = 0;
     for (const auto& p : subtable_ids)
     {
       unsigned insert_index = p.first + shift;
       unsigned pos_offset = p.second.length * OT::Offset16::static_size;
-      unsigned insert_offset = (char*) &lookup->subTable[insert_index] - (char*) lookup;
+      unsigned insert_offset = Lookup::min_size + insert_index * OT::Offset16::static_size;
       shift += p.second.length;
 
       for (auto& l : v.obj.all_links_writer ())
@@ -326,7 +353,7 @@ struct Lookup : public OT::Lookup
 
     // Make extension point at the subtable.
     auto& ext_vertex = c.graph.vertices_[ext_index];
-    ext_vertex.add_parent (lookup_index);
+    ext_vertex.add_parent (lookup_index, false);
     if (!existing_ext_index)
       subtable_vertex.remap_parent (lookup_index, ext_index);
 
@@ -334,6 +361,19 @@ struct Lookup : public OT::Lookup
   }
 
  private:
+  bool is_supported_gsub_type(unsigned type, gsubgpos_graph_context_t& c) const {
+    return (c.table_tag == HB_OT_TAG_GSUB) && (
+      type == OT::Layout::GSUB_impl::SubstLookupSubTable::Type::Ligature
+    );
+  }
+
+  bool is_supported_gpos_type(unsigned type, gsubgpos_graph_context_t& c) const {
+   return (c.table_tag == HB_OT_TAG_GPOS) && (
+      type == OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair ||
+      type == OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase
+    );
+  }
+
   unsigned extension_type (hb_tag_t table_tag) const
   {
     switch (table_tag)
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh
index fb4166128a9..6d1a3d4ae4b 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh
@@ -212,7 +212,6 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2 split_subtables (gsubgpos_graph_context_t& c,
-                                         unsigned parent_index,
                                          unsigned this_index)
   {
     hb_set_t visited;
@@ -265,7 +264,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2 split_subtables (gsubgpos_graph_context_t& c,
-                                         unsigned parent_index,
                                          unsigned this_index)
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1:
-      return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
+      return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, this_index);
 #ifndef HB_NO_BEYOND_64K
     case 2: HB_FALLTHROUGH;
       // Don't split 24bit MarkBasePos's.
@@ -496,10 +494,10 @@ struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
   bool sanitize (graph_t::vertex_t& vertex) const
   {
     int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
-    if (vertex_len < u.format.get_size ()) return false;
+    if (vertex_len < u.format.v.get_size ()) return false;
     hb_barrier ();
 
-    switch (u.format) {
+    switch (u.format.v) {
     case 1:
       return ((MarkBasePosFormat1*)(&u.format1))->sanitize (vertex);
 #ifndef HB_NO_BEYOND_64K
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh
index fd46861de46..85950b63457 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh
@@ -49,7 +49,6 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3 split_subtables (gsubgpos_graph_context_t& c,
-                                         unsigned parent_index,
                                          unsigned this_index)
   {
     hb_set_t visited;
@@ -84,7 +83,7 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3 (split_context, split_points);
@@ -207,7 +206,6 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4 split_subtables (gsubgpos_graph_context_t& c,
-                                         unsigned parent_index,
                                          unsigned this_index)
   {
     const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4::min_size;
@@ -291,7 +289,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4width = SmallTypes::size;
     class_def_link->objidx = class_def_2_id;
     class_def_link->position = 10;
-    graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id);
+    graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id, false);
     graph.duplicate (pair_pos_prime_id, class_def_2_id);
 
     return pair_pos_prime_id;
@@ -607,14 +605,13 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4 split_subtables (gsubgpos_graph_context_t& c,
-                                         unsigned parent_index,
                                          unsigned this_index)
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1:
-      return ((PairPosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
+      return ((PairPosFormat1*)(&u.format1))->split_subtables (c, this_index);
     case 2:
-      return ((PairPosFormat2*)(&u.format2))->split_subtables (c, parent_index, this_index);
+      return ((PairPosFormat2*)(&u.format2))->split_subtables (c, this_index);
 #ifndef HB_NO_BEYOND_64K
     case 3: HB_FALLTHROUGH;
     case 4: HB_FALLTHROUGH;
@@ -628,10 +625,10 @@ struct PairPos : public OT::Layout::GPOS_impl::PairPos
   bool sanitize (graph_t::vertex_t& vertex) const
   {
     int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
-    if (vertex_len < u.format.get_size ()) return false;
+    if (vertex_len < u.format.v.get_size ()) return false;
     hb_barrier ();
 
-    switch (u.format) {
+    switch (u.format.v) {
     case 1:
       return ((PairPosFormat1*)(&u.format1))->sanitize (vertex);
     case 2:
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh b/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh
index 06e4bf44d8e..37fac8909e5 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh
@@ -113,7 +113,7 @@ will_overflow (graph_t& graph,
 
   hb_hashmap_t record_set;
   const auto& vertices = graph.vertices_;
-  for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--)
+  for (unsigned parent_idx : graph.ordering_)
   {
     // Don't need to check virtual links for overflow
     for (const auto& link : vertices.arrayZ[parent_idx].obj.real_links)
@@ -172,14 +172,16 @@ void print_overflows (graph_t& graph,
 template  inline void
 serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link,
                         char* head,
+                        unsigned size,
+                        const hb_vector_t& id_map,
                         hb_serialize_context_t* c)
 {
+  assert(link.position + link.width <= size);
+
   OT::Offset* offset = reinterpret_cast*> (head + link.position);
   *offset = 0;
   c->add_link (*offset,
-               // serializer has an extra nil object at the start of the
-               // object array. So all id's are +1 of what our id's are.
-               link.objidx + 1,
+               id_map[link.objidx],
                (hb_serialize_context_t::whence_t) link.whence,
                link.bias);
 }
@@ -187,6 +189,8 @@ serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link,
 inline
 void serialize_link (const hb_serialize_context_t::object_t::link_t& link,
                      char* head,
+                     unsigned size,
+                     const hb_vector_t& id_map,
                      hb_serialize_context_t* c)
 {
   switch (link.width)
@@ -197,21 +201,21 @@ void serialize_link (const hb_serialize_context_t::object_t::link_t& link,
     case 4:
       if (link.is_signed)
       {
-        serialize_link_of_type (link, head, c);
+        serialize_link_of_type (link, head, size, id_map, c);
       } else {
-        serialize_link_of_type (link, head, c);
+        serialize_link_of_type (link, head, size, id_map, c);
       }
       return;
     case 2:
       if (link.is_signed)
       {
-        serialize_link_of_type (link, head, c);
+        serialize_link_of_type (link, head, size, id_map, c);
       } else {
-        serialize_link_of_type (link, head, c);
+        serialize_link_of_type (link, head, size, id_map, c);
       }
       return;
     case 3:
-      serialize_link_of_type (link, head, c);
+      serialize_link_of_type (link, head, size, id_map, c);
       return;
     default:
       // Unexpected link width.
@@ -237,25 +241,36 @@ inline hb_blob_t* serialize (const graph_t& graph)
 
   c.start_serialize ();
   const auto& vertices = graph.vertices_;
-  for (unsigned i = 0; i < vertices.length; i++) {
+
+  // Objects are placed in the serializer in reverse order since children need
+  // to be inserted before their parents.
+
+  // Maps from our obj id's to the id's used during this serialization.
+  hb_vector_t id_map;
+  id_map.resize(graph.ordering_.length);
+  for (int pos = graph.ordering_.length - 1; pos >= 0; pos--) {
+    unsigned i = graph.ordering_[pos];
     c.push ();
 
-    size_t size = vertices[i].obj.tail - vertices[i].obj.head;
+    auto& v = vertices[i];
+
+    size_t size = v.obj.tail - v.obj.head;
+
     char* start = c.allocate_size  (size);
     if (!start) {
       DEBUG_MSG (SUBSET_REPACK, nullptr, "Buffer out of space.");
       return nullptr;
     }
 
-    hb_memcpy (start, vertices[i].obj.head, size);
+    hb_memcpy (start, v.obj.head, size);
 
     // Only real links needs to be serialized.
-    for (const auto& link : vertices[i].obj.real_links)
-      serialize_link (link, start, &c);
+    for (const auto& link : v.obj.real_links)
+      serialize_link (link, start, size, id_map, &c);
 
     // All duplications are already encoded in the graph, so don't
     // enable sharing during packing.
-    c.pop_pack (false);
+    id_map[i] = c.pop_pack (false);
   }
   c.end_serialize ();
 
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/split-helpers.hh b/src/java.desktop/share/native/libharfbuzz/graph/split-helpers.hh
index 61fd7c2d2ff..f1f86e332db 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/split-helpers.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/split-helpers.hh
@@ -49,7 +49,7 @@ hb_vector_t actuate_subtable_split (Context& split_context,
     if (id == (unsigned) -1)
     {
       new_objects.reset ();
-      new_objects.allocated = -1; // mark error
+      new_objects.ensure_error ();
       return new_objects;
     }
     new_objects.push (id);
@@ -58,7 +58,7 @@ hb_vector_t actuate_subtable_split (Context& split_context,
   if (!split_context.shrink (split_points[0]))
   {
     new_objects.reset ();
-    new_objects.allocated = -1; // mark error
+    new_objects.ensure_error ();
   }
 
   return new_objects;
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 d5a44bf473c..d2ce32616be 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
@@ -47,8 +47,7 @@ using namespace OT;
 
 struct ankr;
 
-using hb_aat_class_cache_t = hb_cache_t<15, 8, 7>;
-static_assert (sizeof (hb_aat_class_cache_t) == 256, "");
+using hb_aat_class_cache_t = hb_ot_layout_mapping_cache_t;
 
 struct hb_aat_scratch_t
 {
@@ -79,7 +78,10 @@ struct hb_aat_scratch_t
   {
     hb_bit_set_t *s = buffer_glyph_set.get_acquire ();
     if (s && buffer_glyph_set.cmpexch (s, nullptr))
+    {
+      s->clear ();
       return s;
+    }
 
     s = (hb_bit_set_t *) hb_calloc (1, sizeof (hb_bit_set_t));
     if (unlikely (!s))
@@ -124,13 +126,14 @@ struct hb_aat_apply_context_t :
   const OT::GDEF &gdef;
   bool has_glyph_classes;
   const hb_sorted_vector_t *range_flags = nullptr;
+  hb_mask_t subtable_flags = 0;
+  bool buffer_is_reversed = false;
+  // Caches
   bool using_buffer_glyph_set = false;
   hb_bit_set_t *buffer_glyph_set = nullptr;
-  const hb_bit_set_t *left_set = nullptr;
-  const hb_bit_set_t *right_set = nullptr;
-  const hb_bit_set_t *machine_glyph_set = nullptr;
+  const hb_bit_set_t *first_set = nullptr;
+  const hb_bit_set_t *second_set = nullptr;
   hb_aat_class_cache_t *machine_class_cache = nullptr;
-  hb_mask_t subtable_flags = 0;
 
   /* Unused. For debug tracing only. */
   unsigned int lookup_index;
@@ -146,6 +149,12 @@ struct hb_aat_apply_context_t :
 
   void set_lookup_index (unsigned int i) { lookup_index = i; }
 
+  void reverse_buffer ()
+  {
+    buffer->reverse ();
+    buffer_is_reversed = !buffer_is_reversed;
+  }
+
   void setup_buffer_glyph_set ()
   {
     using_buffer_glyph_set = buffer->len >= 4 && buffer_glyph_set;
@@ -156,11 +165,11 @@ struct hb_aat_apply_context_t :
   bool buffer_intersects_machine () const
   {
     if (likely (using_buffer_glyph_set))
-      return buffer_glyph_set->intersects (*machine_glyph_set);
+      return buffer_glyph_set->intersects (*first_set);
 
     // Faster for shorter buffers.
     for (unsigned i = 0; i < buffer->len; i++)
-      if (machine_glyph_set->has (buffer->info[i].codepoint))
+      if (first_set->has (buffer->info[i].codepoint))
         return true;
     return false;
   }
@@ -639,6 +648,23 @@ struct LookupFormat10
     glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1);
   }
 
+  template 
+  void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
+  {
+    if (unlikely (!glyphCount)) return;
+    if (firstGlyph == DELETED_GLYPH) return;
+    const HBUINT8 *p = valueArrayZ.arrayZ;
+    for (unsigned i = 0; i < glyphCount; i++)
+    {
+      unsigned int v = 0;
+      unsigned int count = valueSize;
+      for (unsigned int j = 0; j < count; j++)
+        v = (v << 8) | *p++;
+      if (filter (v))
+        glyphs.add (firstGlyph + i);
+    }
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -666,7 +692,7 @@ struct Lookup
 {
   const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 0: hb_barrier (); return u.format0.get_value (glyph_id, num_glyphs);
     case 2: hb_barrier (); return u.format2.get_value (glyph_id);
     case 4: hb_barrier (); return u.format4.get_value (glyph_id);
@@ -678,7 +704,7 @@ struct Lookup
 
   const typename T::type get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
       /* Format 10 cannot return a pointer. */
       case 10: hb_barrier (); return u.format10.get_value_or_null (glyph_id);
       default:
@@ -690,7 +716,7 @@ struct Lookup
   template 
   void collect_glyphs (set_t &glyphs, unsigned int num_glyphs) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 0: hb_barrier (); u.format0.collect_glyphs (glyphs, num_glyphs); return;
     case 2: hb_barrier (); u.format2.collect_glyphs (glyphs); return;
     case 4: hb_barrier (); u.format4.collect_glyphs (glyphs); return;
@@ -703,12 +729,13 @@ struct Lookup
   template 
   void collect_glyphs_filtered (set_t &glyphs, unsigned num_glyphs, const filter_t &filter) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 0: hb_barrier (); u.format0.collect_glyphs_filtered (glyphs, num_glyphs, filter); return;
     case 2: hb_barrier (); u.format2.collect_glyphs_filtered (glyphs, filter); return;
     case 4: hb_barrier (); u.format4.collect_glyphs_filtered (glyphs, filter); return;
     case 6: hb_barrier (); u.format6.collect_glyphs_filtered (glyphs, filter); return;
     case 8: hb_barrier (); u.format8.collect_glyphs_filtered (glyphs, filter); return;
+    case 10: hb_barrier (); u.format10.collect_glyphs_filtered (glyphs, filter); return;
     default:return;
     }
   }
@@ -724,9 +751,9 @@ struct Lookup
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return_trace (false);
+    if (!u.format.v.sanitize (c)) return_trace (false);
     hb_barrier ();
-    switch (u.format) {
+    switch (u.format.v) {
     case 0: hb_barrier (); return_trace (u.format0.sanitize (c));
     case 2: hb_barrier (); return_trace (u.format2.sanitize (c));
     case 4: hb_barrier (); return_trace (u.format4.sanitize (c));
@@ -739,9 +766,9 @@ struct Lookup
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return_trace (false);
+    if (!u.format.v.sanitize (c)) return_trace (false);
     hb_barrier ();
-    switch (u.format) {
+    switch (u.format.v) {
     case 0: hb_barrier (); return_trace (u.format0.sanitize (c, base));
     case 2: hb_barrier (); return_trace (u.format2.sanitize (c, base));
     case 4: hb_barrier (); return_trace (u.format4.sanitize (c, base));
@@ -754,7 +781,7 @@ struct Lookup
 
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
+  struct { HBUINT16 v; }        format;         /* Format identifier */
   LookupFormat0      format0;
   LookupFormat2      format2;
   LookupFormat4      format4;
@@ -763,7 +790,7 @@ struct Lookup
   LookupFormat10     format10;
   } u;
   public:
-  DEFINE_SIZE_UNION (2, format);
+  DEFINE_SIZE_UNION (2, format.v);
 };
 DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2);
 
@@ -838,11 +865,6 @@ struct StateTable
     STATE_START_OF_LINE = 1,
   };
 
-  template 
-  void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
-  {
-    (this+classTable).collect_glyphs (glyphs, num_glyphs);
-  }
   template 
   void collect_initial_glyphs (set_t &glyphs, unsigned num_glyphs, const table_t &table) const
   {
@@ -1082,6 +1104,8 @@ struct SubtableGlyphCoverage
     for (unsigned i = 0; i < subtable_count; i++)
     {
       uint32_t offset = (uint32_t) subtableOffsets[i];
+      // A font file called SFNSDisplay.ttf has value 0xFFFFFFFF in the offsets.
+      // Just ignore it.
       if (offset == 0 || offset == 0xFFFFFFFF)
         continue;
       if (unlikely (!subtableOffsets[i].sanitize (c, this, bytes)))
@@ -1192,11 +1216,24 @@ struct StateTableDriver
     int state = StateTableT::STATE_START_OF_TEXT;
     // If there's only one range, we already checked the flag.
     auto *last_range = ac->range_flags && (ac->range_flags->length > 1) ? &(*ac->range_flags)[0] : nullptr;
+    const bool start_state_safe_to_break_eot =
+      !c->table->is_actionable (machine.get_entry (StateTableT::STATE_START_OF_TEXT, CLASS_END_OF_TEXT));
     for (buffer->idx = 0; buffer->successful;)
     {
-      /* This block is copied in NoncontextualSubtable::apply. Keep in sync. */
-      if (last_range)
+      unsigned int klass = likely (buffer->idx < buffer->len) ?
+                           machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_class_cache) :
+                           (unsigned) CLASS_END_OF_TEXT;
+    resume:
+      DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
+      const EntryT &entry = machine.get_entry (state, klass);
+      const int next_state = machine.new_state (entry.newState);
+
+      bool is_not_epsilon_transition = !(entry.flags & Flags::DontAdvance);
+      bool is_not_actionable = !c->table->is_actionable (entry);
+
+      if (unlikely (last_range))
       {
+        /* This block is copied in NoncontextualSubtable::apply. Keep in sync. */
         auto *range = last_range;
         if (buffer->idx < buffer->len)
         {
@@ -1211,7 +1248,7 @@ struct StateTableDriver
         }
         if (!(range->flags & ac->subtable_flags))
         {
-          if (buffer->idx == buffer->len || unlikely (!buffer->successful))
+          if (buffer->idx == buffer->len)
             break;
 
           state = StateTableT::STATE_START_OF_TEXT;
@@ -1219,13 +1256,42 @@ struct StateTableDriver
           continue;
         }
       }
+      else
+      {
+        // Fast path for when transitioning from start-state to start-state with
+        // no action and advancing. Do so as long as the class remains the same.
+        // This is common with runs of non-actionable glyphs.
+
+        bool is_null_transition = state == StateTableT::STATE_START_OF_TEXT &&
+                                  next_state == StateTableT::STATE_START_OF_TEXT &&
+                                  start_state_safe_to_break_eot &&
+                                  is_not_actionable &&
+                                  is_not_epsilon_transition &&
+                                  !last_range;
+
+        if (is_null_transition)
+        {
+          unsigned old_klass = klass;
+          do
+          {
+            c->transition (buffer, this, entry);
 
-      unsigned int klass = likely (buffer->idx < buffer->len) ?
-                           machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_class_cache) :
-                           (unsigned) CLASS_END_OF_TEXT;
-      DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
-      const EntryT &entry = machine.get_entry (state, klass);
-      const int next_state = machine.new_state (entry.newState);
+            if (buffer->idx == buffer->len || !buffer->successful)
+              break;
+
+            (void) buffer->next_glyph ();
+
+            klass = likely (buffer->idx < buffer->len) ?
+                     machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_class_cache) :
+                     (unsigned) CLASS_END_OF_TEXT;
+          } while (klass == old_klass);
+
+          if (buffer->idx == buffer->len || !buffer->successful)
+            break;
+
+          goto resume;
+        }
+      }
 
       /* Conditions under which it's guaranteed safe-to-break before current glyph:
        *
@@ -1292,10 +1358,10 @@ struct StateTableDriver
       state = next_state;
       DEBUG_MSG (APPLY, nullptr, "s%d", state);
 
-      if (buffer->idx == buffer->len || unlikely (!buffer->successful))
+      if (buffer->idx == buffer->len)
         break;
 
-      if (!(entry.flags & Flags::DontAdvance) || buffer->max_ops-- <= 0)
+      if (is_not_epsilon_transition || buffer->max_ops-- <= 0)
         (void) buffer->next_glyph ();
     }
 
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 ca4f2243346..2a6b813972f 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
@@ -120,12 +120,12 @@ struct KerxSubTableFormat0
   }
 
   template 
-  void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
+  void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
   {
     for (const KernPair& pair : pairs)
     {
-      left_set.add (pair.left);
-      right_set.add (pair.right);
+      first_set.add (pair.left);
+      second_set.add (pair.right);
     }
   }
 
@@ -140,7 +140,7 @@ struct KerxSubTableFormat0
 
     int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
     {
-      if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
+      if (!(*c->first_set)[left] || !(*c->second_set)[right]) return 0;
       return table.get_kerning (left, right, c);
     }
   };
@@ -396,10 +396,10 @@ struct KerxSubTableFormat1
   }
 
   template 
-  void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
+  void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
   {
-    machine.collect_initial_glyphs (left_set, num_glyphs, *this);
-    //machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
+    machine.collect_initial_glyphs (first_set, num_glyphs, *this);
+    //machine.collect_glyphs (second_set, num_glyphs); // second_set is unused for machine kerning
   }
 
   protected:
@@ -451,10 +451,10 @@ struct KerxSubTableFormat2
   }
 
   template 
-  void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
+  void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
   {
-    (this+leftClassTable).collect_glyphs (left_set, num_glyphs);
-    (this+rightClassTable).collect_glyphs (right_set, num_glyphs);
+    (this+leftClassTable).collect_glyphs (first_set, num_glyphs);
+    (this+rightClassTable).collect_glyphs (second_set, num_glyphs);
   }
 
   struct accelerator_t
@@ -468,7 +468,7 @@ struct KerxSubTableFormat2
 
     int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
     {
-      if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
+      if (!(*c->first_set)[left] || !(*c->second_set)[right]) return 0;
       return table.get_kerning (left, right, c);
     }
   };
@@ -629,6 +629,8 @@ struct KerxSubTableFormat4
         }
         o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_MARK;
         o.attach_chain() = (int) mark - (int) buffer->idx;
+        if (c->buffer_is_reversed)
+          o.attach_chain() = -o.attach_chain();
         buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
       }
 
@@ -671,10 +673,10 @@ struct KerxSubTableFormat4
   }
 
   template 
-  void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
+  void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
   {
-    machine.collect_initial_glyphs (left_set, num_glyphs, *this);
-    //machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
+    machine.collect_initial_glyphs (first_set, num_glyphs, *this);
+    //machine.collect_glyphs (second_set, num_glyphs); // second_set is unused for machine kerning
   }
 
   protected:
@@ -762,19 +764,19 @@ struct KerxSubTableFormat6
   }
 
   template 
-  void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
+  void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
   {
     if (is_long ())
     {
       const auto &t = u.l;
-      (this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs);
-      (this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs);
+      (this+t.rowIndexTable).collect_glyphs (first_set, num_glyphs);
+      (this+t.columnIndexTable).collect_glyphs (second_set, num_glyphs);
     }
     else
     {
       const auto &t = u.s;
-      (this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs);
-      (this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs);
+      (this+t.rowIndexTable).collect_glyphs (first_set, num_glyphs);
+      (this+t.columnIndexTable).collect_glyphs (second_set, num_glyphs);
     }
   }
 
@@ -789,7 +791,7 @@ struct KerxSubTableFormat6
 
     int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
     {
-      if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
+      if (!(*c->first_set)[left] || !(*c->second_set)[right]) return 0;
       return table.get_kerning (left, right, c);
     }
   };
@@ -878,15 +880,15 @@ struct KerxSubTable
   }
 
   template 
-  void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
+  void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
   {
     unsigned int subtable_type = get_type ();
     switch (subtable_type) {
-    case 0:     u.format0.collect_glyphs (left_set, right_set, num_glyphs); return;
-    case 1:     u.format1.collect_glyphs (left_set, right_set, num_glyphs); return;
-    case 2:     u.format2.collect_glyphs (left_set, right_set, num_glyphs); return;
-    case 4:     u.format4.collect_glyphs (left_set, right_set, num_glyphs); return;
-    case 6:     u.format6.collect_glyphs (left_set, right_set, num_glyphs); return;
+    case 0:     u.format0.collect_glyphs (first_set, second_set, num_glyphs); return;
+    case 1:     u.format1.collect_glyphs (first_set, second_set, num_glyphs); return;
+    case 2:     u.format2.collect_glyphs (first_set, second_set, num_glyphs); return;
+    case 4:     u.format4.collect_glyphs (first_set, second_set, num_glyphs); return;
+    case 6:     u.format6.collect_glyphs (first_set, second_set, num_glyphs); return;
     default:    return;
     }
   }
@@ -923,8 +925,8 @@ struct KerxSubTable
 
 struct kern_subtable_accelerator_data_t
 {
-  hb_bit_set_t left_set;
-  hb_bit_set_t right_set;
+  hb_bit_set_t first_set;
+  hb_bit_set_t second_set;
   mutable hb_aat_class_cache_t class_cache;
 };
 
@@ -1017,9 +1019,8 @@ struct KerxTable
       if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ())
         goto skip;
 
-      c->left_set = &subtable_accel.left_set;
-      c->right_set = &subtable_accel.right_set;
-      c->machine_glyph_set = &subtable_accel.left_set;
+      c->first_set = &subtable_accel.first_set;
+      c->second_set = &subtable_accel.second_set;
       c->machine_class_cache = &subtable_accel.class_cache;
 
       if (!c->buffer_intersects_machine ())
@@ -1051,8 +1052,8 @@ struct KerxTable
         }
       }
 
-      if (reverse)
-        c->buffer->reverse ();
+      if (reverse != c->buffer_is_reversed)
+        c->reverse_buffer ();
 
       {
         /* See comment in sanitize() for conditional here. */
@@ -1060,15 +1061,14 @@ struct KerxTable
         ret |= st->dispatch (c);
       }
 
-      if (reverse)
-        c->buffer->reverse ();
-
       (void) c->buffer->message (c->font, "end subtable %u", c->lookup_index);
 
     skip:
       st = &StructAfter (*st);
       c->set_lookup_index (c->lookup_index + 1);
     }
+    if (c->buffer_is_reversed)
+      c->reverse_buffer ();
 
     return ret;
   }
@@ -1133,7 +1133,7 @@ struct KerxTable
       if (unlikely (accel_data.subtable_accels.in_error ()))
           return accel_data;
 
-      st->collect_glyphs (subtable_accel.left_set, subtable_accel.right_set, num_glyphs);
+      st->collect_glyphs (subtable_accel.first_set, subtable_accel.second_set, num_glyphs);
       subtable_accel.class_cache.clear ();
 
       st = &StructAfter (*st);
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 92b07eec6e5..2cbb86c7566 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
@@ -487,7 +487,7 @@ struct LigatureSubtable
       if (entry.flags & LigatureEntryT::SetComponent)
       {
         /* Never mark same index twice, in case DontAdvance was used... */
-        if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len)
+        if (unlikely (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len))
           match_length--;
 
         match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
@@ -640,7 +640,7 @@ struct NoncontextualSubtable
     for (unsigned int i = 0; i < count; i++)
     {
       /* This block copied from StateTableDriver::drive. Keep in sync. */
-      if (last_range)
+      if (unlikely (last_range))
       {
         auto *range = last_range;
         {
@@ -1169,15 +1169,15 @@ struct Chain
                    hb_map ([subtable_flags] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable_flags & (_.flags); })))
         goto skip;
 
-      c->subtable_flags = subtable_flags;
-      c->machine_glyph_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t);
-      c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr;
-
       if (!(coverage & ChainSubtable::AllDirections) &&
           HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
           bool (coverage & ChainSubtable::Vertical))
         goto skip;
 
+      c->subtable_flags = subtable_flags;
+      c->first_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t);
+      c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr;
+
       if (!c->buffer_intersects_machine ())
       {
         (void) c->buffer->message (c->font, "skipped chainsubtable %u because no glyph matches", c->lookup_index);
@@ -1219,22 +1219,21 @@ struct Chain
       if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
         goto skip;
 
-      if (reverse)
-        c->buffer->reverse ();
+      if (reverse != c->buffer_is_reversed)
+        c->reverse_buffer ();
 
       subtable->apply (c);
 
-      if (reverse)
-        c->buffer->reverse ();
-
       (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index);
 
-      if (unlikely (!c->buffer->successful)) return;
+      if (unlikely (!c->buffer->successful)) break;
 
     skip:
       subtable = &StructAfter> (*subtable);
       c->set_lookup_index (c->lookup_index + 1);
     }
+    if (c->buffer_is_reversed)
+      c->reverse_buffer ();
   }
 
   unsigned int get_size () const { return length; }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-algs.hh b/src/java.desktop/share/native/libharfbuzz/hb-algs.hh
index 6e250bfdef0..651ffcda01d 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-algs.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-algs.hh
@@ -78,129 +78,246 @@
 
 
 /*
- * Big-endian integers.
+ * Fixed-endian integers / floats.
  */
 
+
 /* Endian swap, used in Windows related backends */
 static inline constexpr uint16_t hb_uint16_swap (uint16_t v)
 { return (v >> 8) | (v << 8); }
 static inline constexpr uint32_t hb_uint32_swap (uint32_t v)
 { return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
 
-#ifndef HB_FAST_INT_ACCESS
+template 
+struct __attribute__((packed)) hb_packed_t { Type v; };
+
+#ifndef HB_FAST_NUM_ACCESS
+
 #if defined(__OPTIMIZE__) && \
     defined(__BYTE_ORDER) && \
     (__BYTE_ORDER == __BIG_ENDIAN || \
      (__BYTE_ORDER == __LITTLE_ENDIAN && \
       hb_has_builtin(__builtin_bswap16) && \
-      hb_has_builtin(__builtin_bswap32)))
-#define HB_FAST_INT_ACCESS 1
+      hb_has_builtin(__builtin_bswap32) && \
+      hb_has_builtin(__builtin_bswap64)))
+#define HB_FAST_NUM_ACCESS 1
 #else
-#define HB_FAST_INT_ACCESS 0
+#define HB_FAST_NUM_ACCESS 0
+#endif
+
+// https://github.com/harfbuzz/harfbuzz/issues/5456
+#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ <= 12)
+#undef HB_FAST_NUM_ACCESS
+#define HB_FAST_NUM_ACCESS 0
 #endif
+
 #endif
 
-template 
-struct BEInt;
-template 
-struct BEInt
+template 
+struct HBInt;
+template 
+struct HBInt
 {
   public:
-  BEInt () = default;
-  constexpr BEInt (Type V) : v {uint8_t (V)} {}
+  HBInt () = default;
+  constexpr HBInt (Type V) : v {uint8_t (V)} {}
   constexpr operator Type () const { return v; }
   private: uint8_t v;
 };
-template 
-struct BEInt
+template 
+struct HBInt
 {
-  struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
-
   public:
-  BEInt () = default;
-
-  BEInt (Type V)
-#if HB_FAST_INT_ACCESS
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-  { ((packed_uint16_t *) v)->v = __builtin_bswap16 (V); }
-#else /* __BYTE_ORDER == __BIG_ENDIAN */
-  { ((packed_uint16_t *) v)->v = V; }
-#endif
+  HBInt () = default;
+
+  HBInt (Type V)
+#if HB_FAST_NUM_ACCESS
+  {
+    if (BE == (__BYTE_ORDER == __BIG_ENDIAN))
+      ((hb_packed_t *) v)->v = V;
+    else
+      ((hb_packed_t *) v)->v = __builtin_bswap16 (V);
+  }
 #else
-    : v {uint8_t ((V >>  8) & 0xFF),
-         uint8_t ((V      ) & 0xFF)} {}
+    : v {BE ? uint8_t ((V >>  8) & 0xFF) : uint8_t ((V      ) & 0xFF),
+         BE ? uint8_t ((V      ) & 0xFF) : uint8_t ((V >>  8) & 0xFF)} {}
 #endif
 
-  constexpr operator Type () const {
-#if HB_FAST_INT_ACCESS
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-    return __builtin_bswap16 (((packed_uint16_t *) v)->v);
-#else /* __BYTE_ORDER == __BIG_ENDIAN */
-    return ((packed_uint16_t *) v)->v;
-#endif
+  constexpr operator Type () const
+  {
+#if HB_FAST_NUM_ACCESS
+    return (BE == (__BYTE_ORDER == __BIG_ENDIAN)) ?
+      ((const hb_packed_t *) v)->v
+    :
+      __builtin_bswap16 (((const hb_packed_t *) v)->v)
+    ;
 #else
-    return (v[0] <<  8)
-         + (v[1]      );
+    return (BE ? (v[0] <<  8) : (v[0]      ))
+         + (BE ? (v[1]      ) : (v[1] <<  8));
 #endif
   }
   private: uint8_t v[2];
 };
-template 
-struct BEInt
+template 
+struct HBInt
 {
   static_assert (!std::is_signed::value, "");
   public:
-  BEInt () = default;
-  constexpr BEInt (Type V) : v {uint8_t ((V >> 16) & 0xFF),
-                                uint8_t ((V >>  8) & 0xFF),
-                                uint8_t ((V      ) & 0xFF)} {}
-
-  constexpr operator Type () const { return (v[0] << 16)
-                                          + (v[1] <<  8)
-                                          + (v[2]      ); }
+  HBInt () = default;
+  constexpr HBInt (Type V) : v {BE ? uint8_t ((V >> 16) & 0xFF) : uint8_t ((V >> 16) & 0xFF),
+                                BE ? uint8_t ((V >>  8) & 0xFF) : uint8_t ((V >>  8) & 0xFF),
+                                BE ? uint8_t ((V      ) & 0xFF) : uint8_t ((V      ) & 0xFF)} {}
+
+  constexpr operator Type () const { return (BE ? (v[0] << 16) : (v[0]      ))
+                                          + (BE ? (v[1] <<  8) : (v[1] <<  8))
+                                          + (BE ? (v[2]      ) : (v[2] << 16)); }
   private: uint8_t v[3];
 };
-template 
-struct BEInt
+template 
+struct HBInt
 {
-  struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
+  template 
+  friend struct HBFloat;
 
   public:
-  BEInt () = default;
-
-  BEInt (Type V)
-#if HB_FAST_INT_ACCESS
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-  { ((packed_uint32_t *) v)->v = __builtin_bswap32 (V); }
-#else /* __BYTE_ORDER == __BIG_ENDIAN */
-  { ((packed_uint32_t *) v)->v = V; }
-#endif
+  HBInt () = default;
+
+  HBInt (Type V)
+#if HB_FAST_NUM_ACCESS
+  {
+    if (BE == (__BYTE_ORDER == __BIG_ENDIAN))
+      ((hb_packed_t *) v)->v = V;
+    else
+      ((hb_packed_t *) v)->v = __builtin_bswap32 (V);
+  }
 #else
-    : v {uint8_t ((V >> 24) & 0xFF),
-         uint8_t ((V >> 16) & 0xFF),
-         uint8_t ((V >>  8) & 0xFF),
-         uint8_t ((V      ) & 0xFF)} {}
+    : v {BE ? uint8_t ((V >> 24) & 0xFF) : uint8_t ((V      ) & 0xFF),
+         BE ? uint8_t ((V >> 16) & 0xFF) : uint8_t ((V >>  8) & 0xFF),
+         BE ? uint8_t ((V >>  8) & 0xFF) : uint8_t ((V >> 16) & 0xFF),
+         BE ? uint8_t ((V      ) & 0xFF) : uint8_t ((V >> 24) & 0xFF)} {}
 #endif
 
   constexpr operator Type () const {
-#if HB_FAST_INT_ACCESS
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-    return __builtin_bswap32 (((packed_uint32_t *) v)->v);
-#else /* __BYTE_ORDER == __BIG_ENDIAN */
-    return ((packed_uint32_t *) v)->v;
-#endif
+#if HB_FAST_NUM_ACCESS
+    return (BE == (__BYTE_ORDER == __BIG_ENDIAN)) ?
+      ((const hb_packed_t *) v)->v
+    :
+      __builtin_bswap32 (((const hb_packed_t *) v)->v)
+    ;
 #else
-    return (v[0] << 24)
-         + (v[1] << 16)
-         + (v[2] <<  8)
-         + (v[3]      );
+    return (BE ? (v[0] << 24) : (v[0]      ))
+         + (BE ? (v[1] << 16) : (v[1] <<  8))
+         + (BE ? (v[2] <<  8) : (v[2] << 16))
+         + (BE ? (v[3]      ) : (v[3] << 24));
 #endif
   }
   private: uint8_t v[4];
 };
+template 
+struct HBInt
+{
+  template 
+  friend struct HBFloat;
+
+  public:
+  HBInt () = default;
+
+  HBInt (Type V)
+#if HB_FAST_NUM_ACCESS
+  {
+    if (BE == (__BYTE_ORDER == __BIG_ENDIAN))
+      ((hb_packed_t *) v)->v = V;
+    else
+      ((hb_packed_t *) v)->v = __builtin_bswap64 (V);
+  }
+#else
+    : v {BE ? uint8_t ((V >> 56) & 0xFF) : uint8_t ((V      ) & 0xFF),
+         BE ? uint8_t ((V >> 48) & 0xFF) : uint8_t ((V >>  8) & 0xFF),
+         BE ? uint8_t ((V >> 40) & 0xFF) : uint8_t ((V >> 16) & 0xFF),
+         BE ? uint8_t ((V >> 32) & 0xFF) : uint8_t ((V >> 24) & 0xFF),
+         BE ? uint8_t ((V >> 24) & 0xFF) : uint8_t ((V >> 32) & 0xFF),
+         BE ? uint8_t ((V >> 16) & 0xFF) : uint8_t ((V >> 40) & 0xFF),
+         BE ? uint8_t ((V >>  8) & 0xFF) : uint8_t ((V >> 48) & 0xFF),
+         BE ? uint8_t ((V      ) & 0xFF) : uint8_t ((V >> 56) & 0xFF)} {}
+#endif
+
+  constexpr operator Type () const {
+#if HB_FAST_NUM_ACCESS
+    return (BE == (__BYTE_ORDER == __BIG_ENDIAN)) ?
+      ((const hb_packed_t *) v)->v
+    :
+      __builtin_bswap64 (((const hb_packed_t *) v)->v)
+    ;
+#else
+    return (BE ? (uint64_t (v[0]) << 56) : (uint64_t (v[0])      ))
+         + (BE ? (uint64_t (v[1]) << 48) : (uint64_t (v[1]) <<  8))
+         + (BE ? (uint64_t (v[2]) << 40) : (uint64_t (v[2]) << 16))
+         + (BE ? (uint64_t (v[3]) << 32) : (uint64_t (v[3]) << 24))
+         + (BE ? (uint64_t (v[4]) << 24) : (uint64_t (v[4]) << 32))
+         + (BE ? (uint64_t (v[5]) << 16) : (uint64_t (v[5]) << 40))
+         + (BE ? (uint64_t (v[6]) <<  8) : (uint64_t (v[6]) << 48))
+         + (BE ? (uint64_t (v[7])      ) : (uint64_t (v[7]) << 56));
+#endif
+  }
+  private: uint8_t v[8];
+};
 
 /* Floats. */
 
+template 
+struct HBFloat
+{
+  using IntType = typename std::conditional::type;
+
+  public:
+  HBFloat () = default;
+
+  HBFloat (Type V)
+  {
+#if HB_FAST_NUM_ACCESS
+    {
+      if (BE == (__BYTE_ORDER == __BIG_ENDIAN))
+      {
+        ((hb_packed_t *) v)->v = V;
+        return;
+      }
+    }
+#endif
+
+    union {
+      hb_packed_t f;
+      hb_packed_t i;
+    } u = {{V}};
+
+    const HBInt I = u.i.v;
+    for (unsigned i = 0; i < Bytes; i++)
+      v[i] = I.v[i];
+  }
+
+  /* c++14 constexpr */ operator Type () const
+  {
+#if HB_FAST_NUM_ACCESS
+    {
+      if (BE == (__BYTE_ORDER == __BIG_ENDIAN))
+        return ((const hb_packed_t *) v)->v;
+    }
+#endif
+
+    HBInt I;
+    for (unsigned i = 0; i < Bytes; i++)
+      I.v[i] = v[i];
+
+    union {
+      hb_packed_t i;
+      hb_packed_t f;
+    } u = {{I}};
+
+    return u.f.v;
+  }
+  private: uint8_t v[Bytes];
+};
+
+
 /* We want our rounding towards +infinity. */
 static inline double
 _hb_roundf (double x) { return floor (x + .5); }
@@ -210,6 +327,27 @@ _hb_roundf (float x) { return floorf (x + .5f); }
 
 #define roundf(x) _hb_roundf(x)
 
+static inline void
+hb_sincos (float rotation, float &s, float &c)
+{
+#ifdef HAVE_SINCOSF
+  sincosf (rotation, &s, &c);
+#else
+  c = cosf (rotation);
+  s = sinf (rotation);
+#endif
+}
+static inline void
+hb_sincos (double rotation, double &s, double &c)
+{
+#ifdef HAVE_SINCOS
+  sincos (rotation, &s, &c);
+#else
+  c = cos (rotation);
+  s = sin (rotation);
+#endif
+}
+
 
 /* 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. */
@@ -734,6 +872,17 @@ HB_FUNCOBJ (hb_clamp);
  * Bithacks.
  */
 
+/* Return the number of 1 bits in a uint8_t; faster than hb_popcount() */
+static inline unsigned
+hb_popcount8 (uint8_t v)
+{
+  static const uint8_t popcount4[16] = {
+    0, 1, 1, 2, 1, 2, 2, 3,
+    1, 2, 2, 3, 2, 3, 3, 4
+  };
+  return popcount4[v & 0xF] + popcount4[v >> 4];
+}
+
 /* Return the number of 1 bits in v. */
 template 
 static inline unsigned int
@@ -1070,6 +1219,7 @@ _hb_cmp_operator (const void *pkey, const void *pval)
 }
 
 template 
+HB_HOT
 static inline bool
 hb_bsearch_impl (unsigned *pos, /* Out */
                  const K& key,
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-alloc-pool.hh b/src/java.desktop/share/native/libharfbuzz/hb-alloc-pool.hh
new file mode 100644
index 00000000000..cb0d7aa7acd
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-alloc-pool.hh
@@ -0,0 +1,105 @@
+/*
+ *  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.
+ *
+ * Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_ALLOC_POOL_HH
+#define HB_ALLOC_POOL_HH
+
+#include "hb-vector.hh"
+
+/* Memory pool for persistent small- to medium-sized allocations.
+ *
+ * Some AI musings on this, not necessarily true:
+ *
+ * This is a very simple implementation, but it's good enough for our
+ * purposes.  It's not thread-safe.  It's not very fast.  It's not
+ * very memory efficient.  It's not very cache efficient.  It's not
+ * very anything efficient.  But it's simple and it works.  And it's
+ * good enough for our purposes.  If you need something more
+ * sophisticated, use a real allocator.  Or use a real language. */
+
+struct hb_alloc_pool_t
+{
+  unsigned ChunkSize = 65536 - 2 * sizeof (void *);
+
+  void *alloc (size_t size, unsigned alignment = 2 * sizeof (void *))
+  {
+    if (unlikely (chunks.in_error ())) return nullptr;
+
+    assert (alignment > 0);
+    assert (alignment <= 2 * sizeof (void *));
+    assert ((alignment & (alignment - 1)) == 0); /* power of two */
+
+    if (size > (ChunkSize) / 4)
+    {
+      /* Big chunk, allocate separately.  */
+      hb_vector_t chunk;
+      if (unlikely (!chunk.resize (size))) return nullptr;
+      void *ret = chunk.arrayZ;
+      chunks.push (std::move (chunk));
+      if (chunks.in_error ()) return nullptr;
+      if (chunks.length > 1)
+      {
+        // Bring back the previous last chunk to the end, so that
+        // we can continue to allocate from it.
+        hb_swap (chunks.arrayZ[chunks.length - 1], chunks.arrayZ[chunks.length - 2]);
+      }
+      return ret;
+    }
+
+    unsigned pad = (unsigned) ((alignment - ((uintptr_t) current_chunk.arrayZ & (alignment - 1))) & (alignment - 1));
+
+    // Small chunk, allocate from the last chunk.
+    if (current_chunk.length < pad + size)
+    {
+      chunks.push ();
+      if (unlikely (chunks.in_error ())) return nullptr;
+      hb_vector_t &chunk = chunks.arrayZ[chunks.length - 1];
+      if (unlikely (!chunk.resize (ChunkSize))) return nullptr;
+      current_chunk = chunk;
+      pad = (unsigned) ((alignment - ((uintptr_t) current_chunk.arrayZ & (alignment - 1))) & (alignment - 1));
+    }
+
+    current_chunk += pad;
+
+    assert (current_chunk.length >= size);
+    void *ret = current_chunk.arrayZ;
+    current_chunk += size;
+    return ret;
+  }
+
+  void discard (void *p_, size_t size)
+  {
+    // Reclaim memory if we can.
+    char *p = (char *) p_;
+    if (current_chunk.arrayZ == p + size && current_chunk.backwards_length >= size)
+      current_chunk -= size;
+  }
+
+  private:
+  hb_vector_t> chunks;
+  hb_array_t current_chunk;
+};
+
+
+#endif /* HB_ALLOC_POOL_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-array.hh b/src/java.desktop/share/native/libharfbuzz/hb-array.hh
index d65bbc5c711..71d3bcdf1ea 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-array.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-array.hh
@@ -291,6 +291,13 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&>
         && (unsigned int) (arrayZ + length - (const char *) p) >= size;
   }
 
+  template 
+  bool check_end (const void *p) const
+  {
+    return (uintptr_t) (((const char *) p) - arrayZ) <= length;
+  }
+
   /* Only call if you allocated the underlying array using hb_malloc() or similar. */
   void fini ()
   { hb_free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh b/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh
index 80bd90e87dc..05aaf5a155e 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh
@@ -40,7 +40,6 @@
  * Atomic integers and pointers.
  */
 
-
 /* We need external help for these */
 
 #if defined(hb_atomic_int_impl_add) \
@@ -80,27 +79,11 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
 
 #include 
 
+#define HB_STL_ATOMIC_IMPL
+
 #define _hb_memory_r_barrier()                  std::atomic_thread_fence(std::memory_order_acquire)
 #define _hb_memory_w_barrier()                  std::atomic_thread_fence(std::memory_order_release)
 
-#define hb_atomic_int_impl_add(AI, V)           (reinterpret_cast::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
-#define hb_atomic_int_impl_set_relaxed(AI, V)   (reinterpret_cast::type> *> (AI)->store ((V), std::memory_order_relaxed))
-#define hb_atomic_int_impl_set(AI, V)           (reinterpret_cast::type> *> (AI)->store ((V), std::memory_order_release))
-#define hb_atomic_int_impl_get_relaxed(AI)      (reinterpret_cast::type> const *> (AI)->load (std::memory_order_relaxed))
-#define hb_atomic_int_impl_get(AI)              (reinterpret_cast::type> 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 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)
-{
-  const void *O = O_; // Need lvalue
-  return reinterpret_cast *> (P)->compare_exchange_weak (O, N, std::memory_order_acq_rel, std::memory_order_relaxed);
-}
-#define hb_atomic_ptr_impl_cmpexch(P,O,N)       _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
-
-
 #else /* defined(HB_NO_MT) */
 
 #define hb_atomic_int_impl_add(AI, V)           ((*(AI) += (V)) - (V))
@@ -159,6 +142,76 @@ inline T hb_atomic_int_impl_get (const T *AI)   { T v = *AI; _hb_memory_r_barrie
 inline void *hb_atomic_ptr_impl_get (void ** const P)   { void *v = *P; _hb_memory_r_barrier (); return v; }
 #endif
 
+#ifdef HB_STL_ATOMIC_IMPL
+template 
+struct hb_atomic_t
+{
+  hb_atomic_t () = default;
+  constexpr hb_atomic_t (T v) : v (v) {}
+  constexpr hb_atomic_t (const hb_atomic_t& o) : v (o.get_relaxed ()) {}
+  constexpr hb_atomic_t (hb_atomic_t&& o) : v (o.get_relaxed ()) { o.set_relaxed ({}); }
+
+  hb_atomic_t &operator= (const hb_atomic_t& o) { set_relaxed (o.get_relaxed ()); return *this; }
+  hb_atomic_t &operator= (hb_atomic_t&& o){ set_relaxed (o.get_relaxed ()); o.set_relaxed ({}); return *this; }
+  hb_atomic_t &operator= (T v_)
+  {
+    set_relaxed (v_);
+    return *this;
+  }
+  operator T () const { return get_relaxed (); }
+
+  void set_relaxed (T v_) { v.store (v_, std::memory_order_relaxed); }
+  void set_release (T v_) { v.store (v_, std::memory_order_release); }
+  T get_relaxed () const { return v.load (std::memory_order_relaxed); }
+  T get_acquire () const { return v.load (std::memory_order_acquire); }
+  T inc () { return v.fetch_add (1, std::memory_order_acq_rel); }
+  T dec () { return v.fetch_add (-1, std::memory_order_acq_rel); }
+
+  int operator++ (int) { return inc (); }
+  int operator-- (int) { return dec (); }
+
+  friend void swap (hb_atomic_t &a, hb_atomic_t &b) noexcept
+  {
+    T v = a.get_acquire ();
+    a.set_relaxed (b.get_acquire ());
+    b.set_relaxed (v);
+  }
+
+  std::atomic v = 0;
+};
+
+template 
+struct hb_atomic_t
+{
+  hb_atomic_t () = default;
+  constexpr hb_atomic_t (T *v) : v (v) {}
+  hb_atomic_t (const hb_atomic_t &other) = delete;
+
+  void init (T *v_ = nullptr) { set_relaxed (v_); }
+  void set_relaxed (T *v_) { v.store (v_, std::memory_order_relaxed); }
+  T *get_relaxed () const { return v.load (std::memory_order_relaxed); }
+  T *get_acquire () const { return v.load (std::memory_order_acquire); }
+  bool cmpexch (T *old, T *new_) { return v.compare_exchange_weak (old, new_, std::memory_order_acq_rel, std::memory_order_relaxed); }
+
+  operator bool () const { return get_acquire () != nullptr; }
+  T *operator->() const { return get_acquire (); }
+  template 
+  operator C * () const
+  {
+    return get_acquire ();
+  }
+
+  friend void swap (hb_atomic_t &a, hb_atomic_t &b) noexcept
+  {
+    T *p = a.get_acquire ();
+    a.set_relaxed (b.get_acquire ());
+    b.set_relaxed (p);
+  }
+
+  std::atomic v = nullptr;
+};
+
+#else
 
 template 
 struct hb_atomic_t
@@ -178,7 +231,6 @@ struct hb_atomic_t
 
   int operator ++ (int) { return inc (); }
   int operator -- (int) { return dec (); }
-  long operator |= (long v_) { set_relaxed (get_relaxed () | v_); return *this; }
 
   T v = 0;
 };
@@ -194,7 +246,7 @@ struct hb_atomic_t
   void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
   T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
   T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
-  bool cmpexch (const T *old, T *new_) { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
+  bool cmpexch (T *old, T *new_) { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
 
   operator bool () const { return get_acquire () != nullptr; }
   T * operator -> () const                    { return get_acquire (); }
@@ -203,6 +255,8 @@ struct hb_atomic_t
   T *v = nullptr;
 };
 
+#endif
+
 static inline bool hb_barrier ()
 {
   _hb_compiler_memory_r_barrier ();
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh b/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh
index f541472544a..f9c0e8870ff 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh
@@ -176,7 +176,7 @@ struct hb_inc_bimap_t
   {
     hb_codepoint_t  count = get_population ();
     hb_vector_t  work;
-    if (unlikely (!work.resize (count, false))) return;
+    if (unlikely (!work.resize_dirty  (count))) return;
 
     for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
       work.arrayZ[rhs] = back_map[rhs];
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh
index 9562a9674a5..902db195507 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh
@@ -142,6 +142,7 @@ struct hb_bit_page_t
 
   bool operator [] (hb_codepoint_t g) const { return get (g); }
   bool operator () (hb_codepoint_t g) const { return get (g); }
+  bool has (hb_codepoint_t g) const { return get (g); }
 
   void add_range (hb_codepoint_t a, hb_codepoint_t b)
   {
@@ -290,7 +291,7 @@ struct hb_bit_page_t
     unsigned int j = m & ELT_MASK;
 
     const elt_t vv = v[i] & ~((elt_t (1) << j) - 1);
-    for (const elt_t *p = &vv; i < len (); p = &v[++i])
+    for (const elt_t *p = &vv; i < len (); p = ((const elt_t *) &v[0]) + (++i))
       if (*p)
       {
         *codepoint = i * ELT_BITS + elt_get_min (*p);
@@ -346,6 +347,36 @@ struct hb_bit_page_t
     return 0;
   }
 
+  /*
+   * Iterator implementation.
+   */
+  struct iter_t : hb_iter_with_fallback_t
+  {
+    static constexpr bool is_sorted_iterator = true;
+    iter_t (const hb_bit_page_t &s_ = Null (hb_bit_page_t), bool init = true) : s (&s_), v (INVALID)
+    {
+      if (init)
+        v = s->get_min ();
+    }
+
+    typedef hb_codepoint_t __item_t__;
+    hb_codepoint_t __item__ () const { return v; }
+    bool __more__ () const { return v != INVALID; }
+    void __next__ () {
+       s->next (&v);
+    }
+    void __prev__ () { s->previous (&v); }
+    iter_t end () const { return iter_t (*s, false); }
+    bool operator != (const iter_t& o) const
+    { return v != o.v; }
+
+    protected:
+    const hb_bit_page_t *s;
+    hb_codepoint_t v;
+  };
+  iter_t iter () const { return iter_t (*this); }
+  operator iter_t () const { return iter (); }
+
   static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
 
   typedef unsigned long long elt_t;
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh
index 740a2437671..4028dd63531 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh
@@ -368,7 +368,7 @@ struct hb_bit_set_invertible_t
     unsigned __len__ () const { return l; }
     iter_t end () const { return iter_t (*s, false); }
     bool operator != (const iter_t& o) const
-    { return v != o.v || s != o.s; }
+    { return v != o.v; }
 
     protected:
     const hb_bit_set_invertible_t *s;
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh
index 799c3607599..f86d5750854 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh
@@ -91,10 +91,10 @@ struct hb_bit_set_t
     if (pages.length < count && (unsigned) pages.allocated < count && count <= 2)
       exact_size = true; // Most sets are small and local
 
-    if (unlikely (!pages.resize (count, clear, exact_size) ||
-        !page_map.resize (count, clear)))
+    if (unlikely (!pages.resize_full (count, clear, exact_size) ||
+        !page_map.resize_full (count, clear, false)))
     {
-      pages.resize (page_map.length, clear, exact_size);
+      pages.resize_full (page_map.length, clear, exact_size);
       successful = false;
       return false;
     }
@@ -108,10 +108,11 @@ struct hb_bit_set_t
     page_map.alloc (sz);
   }
 
-  void reset ()
+  hb_bit_set_t& reset ()
   {
     successful = true;
     clear ();
+    return *this;
   }
 
   void clear ()
@@ -394,7 +395,7 @@ struct hb_bit_set_t
   {
     if (unlikely (!successful)) return;
     unsigned int count = other.pages.length;
-    if (unlikely (!resize (count, false, exact_size)))
+    if (unlikely (!resize  (count, false, exact_size)))
       return;
     population = other.population;
 
@@ -922,7 +923,7 @@ struct hb_bit_set_t
     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; }
+    { return v != o.v; }
 
     protected:
     const hb_bit_set_t *s;
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh
index 9e21beebd34..87c1524df6f 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh
@@ -32,7 +32,7 @@
 #include "hb.hh"
 
 
-#line 36 "hb-buffer-deserialize-text-unicode.hh"
+#line 33 "hb-buffer-deserialize-text-unicode.hh"
 static const unsigned char _deserialize_text_unicode_trans_keys[] = {
         0u, 0u, 43u, 102u, 48u, 102u, 48u, 124u, 48u, 57u, 62u, 124u, 48u, 124u, 60u, 117u,
         85u, 117u, 85u, 117u, 0
@@ -150,12 +150,12 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
   hb_glyph_info_t info = {0};
   const hb_glyph_position_t pos = {0};
 
-#line 154 "hb-buffer-deserialize-text-unicode.hh"
+#line 147 "hb-buffer-deserialize-text-unicode.hh"
         {
         cs = deserialize_text_unicode_start;
         }
 
-#line 159 "hb-buffer-deserialize-text-unicode.hh"
+#line 150 "hb-buffer-deserialize-text-unicode.hh"
         {
         int _slen;
         int _trans;
@@ -215,7 +215,7 @@ _resume:
         hb_memset (&info, 0, sizeof (info));
 }
         break;
-#line 219 "hb-buffer-deserialize-text-unicode.hh"
+#line 203 "hb-buffer-deserialize-text-unicode.hh"
         }
 
 _again:
@@ -238,7 +238,7 @@ _again:
         *end_ptr = p;
 }
         break;
-#line 242 "hb-buffer-deserialize-text-unicode.hh"
+#line 224 "hb-buffer-deserialize-text-unicode.hh"
         }
         }
 
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 763172818c4..6787da6f65f 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc
@@ -427,7 +427,7 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer,
  *   #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set. Then,
  *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, `=` then #hb_glyph_info_t.cluster.
  *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format:
- *     - If both #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not 0, `@x_offset,y_offset`. Then,
+ *     - If #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not both 0, `@x_offset,y_offset`. Then,
  *     - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then,
  *   - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the #hb_glyph_extents_t in the format ``
  *
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc
index 56299d9b7e0..0c9190bf6f8 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc
@@ -163,7 +163,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t  *buffer,
 
     hb_buffer_append (fragment, text_buffer, text_start, text_end);
     if (!hb_shape_full (font, fragment, features, num_features, shapers) ||
-        fragment->successful || fragment->shaping_failed)
+        fragment->successful)
     {
       hb_buffer_destroy (reconstruction);
       hb_buffer_destroy (fragment);
@@ -313,11 +313,11 @@ buffer_verify_unsafe_to_concat (hb_buffer_t        *buffer,
    * Shape the two fragment streams.
    */
   if (!hb_shape_full (font, fragments[0], features, num_features, shapers) ||
-      !fragments[0]->successful || fragments[0]->shaping_failed)
+      !fragments[0]->successful)
     goto out;
 
   if (!hb_shape_full (font, fragments[1], features, num_features, shapers) ||
-      !fragments[1]->successful || fragments[1]->shaping_failed)
+      !fragments[1]->successful)
     goto out;
 
   if (!forward)
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc
index c0600fd839b..8f6da312cdd 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc
@@ -158,14 +158,15 @@ hb_segment_properties_overlay (hb_segment_properties_t *p,
 bool
 hb_buffer_t::enlarge (unsigned int size)
 {
-  if (unlikely (!successful))
-    return false;
   if (unlikely (size > max_len))
   {
     successful = false;
     return false;
   }
 
+  if (unlikely (!successful))
+    return false;
+
   unsigned int new_allocated = allocated;
   hb_glyph_position_t *new_pos = nullptr;
   hb_glyph_info_t *new_info = nullptr;
@@ -226,6 +227,13 @@ hb_buffer_t::shift_forward (unsigned int count)
   assert (have_output);
   if (unlikely (!ensure (len + count))) return false;
 
+  max_ops -= len - idx;
+  if (unlikely (max_ops < 0))
+  {
+    successful = false;
+    return false;
+  }
+
   memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));
   if (idx + count > len)
   {
@@ -297,7 +305,6 @@ hb_buffer_t::clear ()
   props = default_props;
 
   successful = true;
-  shaping_failed = false;
   have_output = false;
   have_positions = false;
 
@@ -320,7 +327,6 @@ hb_buffer_t::enter ()
 {
   deallocate_var_all ();
   serial = 0;
-  shaping_failed = false;
   scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
   unsigned mul;
   if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR, &mul)))
@@ -339,7 +345,6 @@ hb_buffer_t::leave ()
   max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
   deallocate_var_all ();
   serial = 0;
-  // Intentionally not reseting shaping_failed, such that it can be inspected.
 }
 
 
@@ -520,7 +525,19 @@ hb_buffer_t::set_masks (hb_mask_t    value,
   hb_mask_t not_mask = ~mask;
   value &= mask;
 
+  max_ops -= len;
+  if (unlikely (max_ops < 0))
+    successful = false;
+
   unsigned int count = len;
+
+  if (cluster_start == 0 && cluster_end == (unsigned int) -1)
+  {
+    for (unsigned int i = 0; i < count; i++)
+      info[i].mask = (info[i].mask & not_mask) | value;
+    return;
+  }
+
   for (unsigned int i = 0; i < count; i++)
     if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
       info[i].mask = (info[i].mask & not_mask) | value;
@@ -536,6 +553,10 @@ hb_buffer_t::merge_clusters_impl (unsigned int start,
     return;
   }
 
+  max_ops -= end - start;
+  if (unlikely (max_ops < 0))
+    successful = false;
+
   unsigned int cluster = info[start].cluster;
 
   for (unsigned int i = start + 1; i < end; i++)
@@ -569,6 +590,10 @@ hb_buffer_t::merge_out_clusters (unsigned int start,
   if (unlikely (end - start < 2))
     return;
 
+  max_ops -= end - start;
+  if (unlikely (max_ops < 0))
+    successful = false;
+
   unsigned int cluster = out_info[start].cluster;
 
   for (unsigned int i = start + 1; i < end; i++)
@@ -726,7 +751,6 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
   HB_SEGMENT_PROPERTIES_DEFAULT,
 
   false, /* successful */
-  true, /* shaping_failed */
   false, /* have_output */
   true  /* have_positions */
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh
index 81c0f4a72e3..1c46981cc9c 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh
@@ -32,6 +32,7 @@
 
 #include "hb.hh"
 #include "hb-unicode.hh"
+#include "hb-set-digest.hh"
 
 
 static_assert ((sizeof (hb_glyph_info_t) == 20), "");
@@ -44,14 +45,14 @@ HB_MARK_AS_FLAG_T (hb_buffer_diff_flags_t);
 
 enum hb_buffer_scratch_flags_t {
   HB_BUFFER_SCRATCH_FLAG_DEFAULT                        = 0x00000000u,
-  HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII                  = 0x00000001u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_FRACTION_SLASH             = 0x00000001u,
   HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES         = 0x00000002u,
   HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK             = 0x00000004u,
   HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT            = 0x00000008u,
   HB_BUFFER_SCRATCH_FLAG_HAS_CGJ                        = 0x00000010u,
-  HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS                = 0x00000020u,
-  HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE            = 0x00000040u,
-  HB_BUFFER_SCRATCH_FLAG_HAS_VARIATION_SELECTOR_FALLBACK= 0x00000080u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE            = 0x00000020u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_VARIATION_SELECTOR_FALLBACK= 0x00000040u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_CONTINUATIONS              = 0x00000080u,
 
   /* Reserved for shapers' internal use. */
   HB_BUFFER_SCRATCH_FLAG_SHAPER0                        = 0x01000000u,
@@ -90,7 +91,6 @@ struct hb_buffer_t
   hb_segment_properties_t props; /* Script, language, direction */
 
   bool successful; /* Allocations successful */
-  bool shaping_failed; /* Shaping failure */
   bool have_output; /* Whether we have an output buffer going on */
   bool have_positions; /* Whether we have positions */
 
@@ -110,6 +110,7 @@ struct hb_buffer_t
   hb_codepoint_t context[2][CONTEXT_LENGTH];
   unsigned int context_len[2];
 
+  hb_set_digest_t digest; /* Manually updated sometimes */
 
   /*
    * Managed by enter / leave
@@ -200,6 +201,12 @@ struct hb_buffer_t
   void collect_codepoints (set_t &d) const
   { d.clear (); d.add_array (&info[0].codepoint, len, sizeof (info[0])); }
 
+  void update_digest ()
+  {
+    digest = hb_set_digest_t ();
+    collect_codepoints (digest);
+  }
+
   HB_INTERNAL void similar (const hb_buffer_t &src);
   HB_INTERNAL void reset ();
   HB_INTERNAL void clear ();
@@ -346,7 +353,7 @@ struct hb_buffer_t
     {
       if (out_info != info || out_len != idx)
       {
-        if (unlikely (!make_room_for (1, 1))) return false;
+        if (unlikely (!ensure (out_len + 1))) return false;
         out_info[out_len] = info[idx];
       }
       out_len++;
@@ -363,7 +370,7 @@ struct hb_buffer_t
     {
       if (out_info != info || out_len != idx)
       {
-        if (unlikely (!make_room_for (n, n))) return false;
+        if (unlikely (!ensure (out_len + n))) return false;
         memmove (out_info + out_len, info + idx, n * sizeof (out_info[0]));
       }
       out_len += n;
@@ -404,22 +411,12 @@ struct hb_buffer_t
   /* Adds glyph flags in mask to infos with clusters between start and end.
    * The start index will be from out-buffer if from_out_buffer is true.
    * If interior is true, then the cluster having the minimum value is skipped. */
-  void _set_glyph_flags (hb_mask_t mask,
-                         unsigned start = 0,
-                         unsigned end = (unsigned) -1,
-                         bool interior = false,
-                         bool from_out_buffer = false)
+  void _set_glyph_flags_impl (hb_mask_t mask,
+                              unsigned start,
+                              unsigned end,
+                              bool interior,
+                              bool from_out_buffer)
   {
-    end = hb_min (end, len);
-
-    if (unlikely (end - start > 255))
-      return;
-
-    if (interior && !from_out_buffer && end - start < 2)
-      return;
-
-    scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
-
     if (!from_out_buffer || !have_output)
     {
       if (!interior)
@@ -456,6 +453,25 @@ struct hb_buffer_t
     }
   }
 
+  HB_ALWAYS_INLINE
+  void _set_glyph_flags (hb_mask_t mask,
+                         unsigned start = 0,
+                         unsigned end = (unsigned) -1,
+                         bool interior = false,
+                         bool from_out_buffer = false)
+  {
+    if (unlikely (end != (unsigned) -1 && end - start > 255))
+      return;
+
+    end = hb_min (end, len);
+
+    if (interior && !from_out_buffer && end - start < 2)
+      return;
+
+    _set_glyph_flags_impl (mask, start, end, interior, from_out_buffer);
+  }
+
+
   void unsafe_to_break (unsigned int start = 0, unsigned int end = -1)
   {
     _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
@@ -606,6 +622,10 @@ struct hb_buffer_t
     if (unlikely (start == end))
       return;
 
+    max_ops -= end - start;
+    if (unlikely (max_ops < 0))
+      successful = false;
+
     unsigned cluster_first = infos[start].cluster;
     unsigned cluster_last = infos[end - 1].cluster;
 
@@ -614,10 +634,7 @@ struct hb_buffer_t
     {
       for (unsigned int i = start; i < end; i++)
         if (cluster != infos[i].cluster)
-        {
-          scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
           infos[i].mask |= mask;
-        }
       return;
     }
 
@@ -626,18 +643,12 @@ struct hb_buffer_t
     if (cluster == cluster_first)
     {
       for (unsigned int i = end; start < i && infos[i - 1].cluster != cluster_first; i--)
-      {
-        scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
         infos[i - 1].mask |= mask;
-      }
     }
     else /* cluster == cluster_last */
     {
       for (unsigned int i = start; i < end && infos[i].cluster != cluster_last; i++)
-      {
-        scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
         infos[i].mask |= mask;
-      }
     }
   }
   unsigned
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cache.hh b/src/java.desktop/share/native/libharfbuzz/hb-cache.hh
index 7d09ca89d7f..3609ccecc71 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-cache.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-cache.hh
@@ -64,17 +64,23 @@ template ,
-                                                                     hb_atomic_t>::type,
-                                           typename std::conditional::type
+                                           typename std::conditional,
+                                                                     typename std::conditional,
+                                                                                               hb_atomic_t>::type>::type,
+                                           typename std::conditional::type>::type
                                           >::type;
 
   static_assert ((key_bits >= cache_bits), "");
   static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), "");
 
+  static constexpr unsigned MAX_VALUE = (1u << value_bits) - 1;
+
   hb_cache_t () { clear (); }
 
   void clear ()
@@ -83,25 +89,32 @@ struct hb_cache_t
       v = -1;
   }
 
+  HB_HOT
   bool get (unsigned int key, unsigned int *value) const
   {
     unsigned int k = key & ((1u<> value_bits) != (key >> cache_bits))
       return false;
     *value = v & ((1u<> key_bits) || (value >> value_bits)))
-      return false; /* Overflows */
+      return; /* Overflows */
+    set_unchecked (key, value);
+  }
+
+  HB_HOT
+  void set_unchecked (unsigned int key, unsigned int value)
+  {
     unsigned int k = key & ((1u<>cache_bits)<
   cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd,
                         const int *coords_=nullptr, unsigned int num_coords_=0)
     : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs),
-      cached_scalars_vector (&acc.cached_scalars_vector)
+      region_count (0), cached_scalars_vector (&acc.cached_scalars_vector)
   {
     coords = coords_;
     num_coords = num_coords_;
     varStore = acc.varStore;
-    do_blend = num_coords && coords && varStore->size;
+    do_blend = num_coords && varStore->size;
     set_ivs (acc.privateDicts[fd].ivs);
   }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-common.cc b/src/java.desktop/share/native/libharfbuzz/hb-common.cc
index 5c8546a378c..9eeae358a75 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-common.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-common.cc
@@ -40,43 +40,6 @@
  **/
 
 
-/* hb_options_t */
-
-hb_atomic_t _hb_options;
-
-void
-_hb_options_init ()
-{
-  hb_options_union_t u;
-  u.i = 0;
-  u.opts.initialized = true;
-
-  const char *c = getenv ("HB_OPTIONS");
-  if (c)
-  {
-    while (*c)
-    {
-      const char *p = strchr (c, ':');
-      if (!p)
-        p = c + strlen (c);
-
-#define OPTION(name, symbol) \
-        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);
-
-#undef OPTION
-
-      c = *p ? p + 1 : p;
-    }
-
-  }
-
-  /* This is idempotent and threadsafe. */
-  _hb_options = u.i;
-}
-
-
 /* hb_tag_t */
 
 /**
@@ -545,8 +508,11 @@ hb_script_to_iso15924_tag (hb_script_t script)
  * Fetches the #hb_direction_t of a script when it is
  * set horizontally. All right-to-left scripts will return
  * #HB_DIRECTION_RTL. All left-to-right scripts will return
- * #HB_DIRECTION_LTR.  Scripts that can be written either
- * horizontally or vertically will return #HB_DIRECTION_INVALID.
+ * #HB_DIRECTION_LTR.
+ *
+ * Scripts that can be written either right-to-left or
+ * left-to-right will return #HB_DIRECTION_INVALID.
+ *
  * Unknown scripts will return #HB_DIRECTION_LTR.
  *
  * Return value: The horizontal #hb_direction_t of @script
@@ -628,6 +594,9 @@ hb_script_get_horizontal_direction (hb_script_t script)
     /* Unicode-16.0 additions */
     case HB_SCRIPT_GARAY:
 
+    /* Unicode-17.0 additions */
+    case HB_SCRIPT_SIDETIC:
+
       return HB_DIRECTION_RTL;
 
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-config.hh b/src/java.desktop/share/native/libharfbuzz/hb-config.hh
index 3956690da35..c522eeea2ea 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-config.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-config.hh
@@ -38,7 +38,6 @@
 #ifndef HB_EXPERIMENTAL_API
 #define HB_NO_BEYOND_64K
 #define HB_NO_CUBIC_GLYF
-#define HB_NO_VAR_COMPOSITES
 #endif
 
 #ifdef HB_TINY
@@ -91,7 +90,10 @@
 #ifdef HB_MINI
 #define HB_NO_AAT
 #define HB_NO_LEGACY
-#define HB_NO_BORING_EXPANSION
+#define HB_NO_BEYOND_64K
+#define HB_NO_CUBIC_GLYF
+#define HB_NO_VAR_COMPOSITES
+#define HB_NO_VAR_HVF
 #endif
 
 #ifdef __OPTIMIZE_SIZE__
@@ -109,12 +111,6 @@
 
 /* Closure of options. */
 
-#ifdef HB_NO_BORING_EXPANSION
-#define HB_NO_BEYOND_64K
-#define HB_NO_CUBIC_GLYF
-#define HB_NO_VAR_COMPOSITES
-#endif
-
 #ifdef HB_NO_VAR
 #define HB_NO_VAR_COMPOSITES
 #endif
@@ -149,10 +145,6 @@
 #define HB_NO_PAINT
 #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
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-debug.hh b/src/java.desktop/share/native/libharfbuzz/hb-debug.hh
index 1e9a18b9326..87d30d9ded1 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-debug.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-debug.hh
@@ -37,48 +37,6 @@
 #endif
 
 
-/*
- * Global runtime options.
- */
-
-struct hb_options_t
-{
-  bool unused : 1; /* In-case sign bit is here. */
-  bool initialized : 1;
-  bool uniscribe_bug_compatible : 1;
-};
-
-union hb_options_union_t {
-  unsigned i;
-  hb_options_t opts;
-};
-static_assert ((sizeof (hb_atomic_t) >= sizeof (hb_options_union_t)), "");
-
-HB_INTERNAL void
-_hb_options_init ();
-
-extern HB_INTERNAL hb_atomic_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;
-
-  if (unlikely (!u.i))
-  {
-    _hb_options_init ();
-    u.i = _hb_options;
-  }
-
-  return u.opts;
-}
-
-
 /*
  * Debug output (needs enabling at compile time.)
  */
@@ -394,6 +352,10 @@ struct hb_no_trace_t {
 #define HB_DEBUG_WASM (HB_DEBUG+0)
 #endif
 
+#ifndef HB_DEBUG_KBTS
+#define HB_DEBUG_KBTS (HB_DEBUG+0)
+#endif
+
 /*
  * With tracing.
  */
@@ -484,7 +446,7 @@ struct hb_no_trace_t {
 
 
 #ifndef HB_BUFFER_MESSAGE_MORE
-#define HB_BUFFER_MESSAGE_MORE (HB_DEBUG+1)
+#define HB_BUFFER_MESSAGE_MORE (HB_DEBUG+0)
 #endif
 
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h b/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h
index 927563c4c40..a87a53d0e30 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h
@@ -287,7 +287,7 @@ typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data
  * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
  *
  * Since: 7.0.0
- * XDeprecated: REPLACEME: Use hb_font_draw_glyph_func_or_fail_t instead.
+ * Deprecated: 11.2.0: Use hb_font_draw_glyph_func_or_fail_t instead.
  **/
 typedef void (*hb_font_draw_glyph_func_t) (hb_font_t *font, void *font_data,
                                            hb_codepoint_t glyph,
@@ -308,7 +308,7 @@ typedef void (*hb_font_draw_glyph_func_t) (hb_font_t *font, void *font_data,
  * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
  *
  * Since: 7.0.0
- * XDeprecated: REPLACEME: Use hb_font_paint_glyph_or_fail_func_t instead.
+ * Deprecated: 11.2.0: Use hb_font_paint_glyph_or_fail_func_t instead.
  */
 typedef hb_bool_t (*hb_font_paint_glyph_func_t) (hb_font_t *font, void *font_data,
                                                  hb_codepoint_t glyph,
@@ -346,7 +346,7 @@ hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
  * Sets the implementation function for #hb_font_draw_glyph_func_t.
  *
  * Since: 7.0.0
- * XDeprecated: REPLACEME: Use hb_font_funcs_set_draw_glyph_or_fail_func instead.
+ * Deprecated: 11.2.0: Use hb_font_funcs_set_draw_glyph_or_fail_func instead.
  **/
 HB_DEPRECATED_FOR (hb_font_funcs_set_draw_glyph_or_fail_func)
 HB_EXTERN void
@@ -364,7 +364,7 @@ hb_font_funcs_set_draw_glyph_func (hb_font_funcs_t *ffuncs,
  * Sets the implementation function for #hb_font_paint_glyph_func_t.
  *
  * Since: 7.0.0
- * XDeprecated: REPLACEME: Use hb_font_funcs_set_paint_glyph_or_fail_func() instead.
+ * Deprecated: 11.2.0: Use hb_font_funcs_set_paint_glyph_or_fail_func() instead.
  */
 HB_DEPRECATED_FOR (hb_font_funcs_set_paint_glyph_or_fail_func)
 HB_EXTERN void
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-draw.cc b/src/java.desktop/share/native/libharfbuzz/hb-draw.cc
index 8764ffe7129..c243d12f7ae 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-draw.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-draw.cc
@@ -63,14 +63,14 @@ hb_draw_quadratic_to_nil (hb_draw_funcs_t *dfuncs, void *draw_data,
                           float to_x, float to_y,
                           void *user_data HB_UNUSED)
 {
-#define HB_ONE_THIRD 0.33333333f
+#define HB_TWO_THIRD 0.66666666666666666666666667f
   dfuncs->emit_cubic_to (draw_data, *st,
-                         (st->current_x + 2.f * control_x) * HB_ONE_THIRD,
-                         (st->current_y + 2.f * control_y) * HB_ONE_THIRD,
-                         (to_x + 2.f * control_x) * HB_ONE_THIRD,
-                         (to_y + 2.f * control_y) * HB_ONE_THIRD,
+                         st->current_x + (control_x - st->current_x) * HB_TWO_THIRD,
+                         st->current_y + (control_y - st->current_y) * HB_TWO_THIRD,
+                         to_x + (control_x - to_x) * HB_TWO_THIRD,
+                         to_y + (control_y - to_y) * HB_TWO_THIRD,
                          to_x, to_y);
-#undef HB_ONE_THIRD
+#undef HB_TWO_THIRD
 }
 
 static void
@@ -467,7 +467,7 @@ hb_draw_extents_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
                          float to_x, float to_y,
                          void *user_data HB_UNUSED)
 {
-  hb_extents_t *extents = (hb_extents_t *) data;
+  hb_extents_t<> *extents = (hb_extents_t<> *) data;
 
   extents->add_point (to_x, to_y);
 }
@@ -479,7 +479,7 @@ hb_draw_extents_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
                          float to_x, float to_y,
                          void *user_data HB_UNUSED)
 {
-  hb_extents_t *extents = (hb_extents_t *) data;
+  hb_extents_t<> *extents = (hb_extents_t<> *) data;
 
   extents->add_point (to_x, to_y);
 }
@@ -492,7 +492,7 @@ hb_draw_extents_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
                               float to_x, float to_y,
                               void *user_data HB_UNUSED)
 {
-  hb_extents_t *extents = (hb_extents_t *) data;
+  hb_extents_t<> *extents = (hb_extents_t<> *) data;
 
   extents->add_point (control_x, control_y);
   extents->add_point (to_x, to_y);
@@ -507,7 +507,7 @@ hb_draw_extents_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
                           float to_x, float to_y,
                           void *user_data HB_UNUSED)
 {
-  hb_extents_t *extents = (hb_extents_t *) data;
+  hb_extents_t<> *extents = (hb_extents_t<> *) data;
 
   extents->add_point (control1_x, control1_y);
   extents->add_point (control2_x, control2_y);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc b/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc
index 6b7e1913024..c1feaac6280 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc
@@ -169,8 +169,7 @@ _hb_face_builder_get_table_tags (const hb_face_t *face HB_UNUSED,
 
   if (unlikely (start_offset >= population))
   {
-    if (table_count)
-      *table_count = 0;
+    *table_count = 0;
     return population;
   }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-face.cc b/src/java.desktop/share/native/libharfbuzz/hb-face.cc
index 9d59d7c9468..a0f497eea7f 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-face.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-face.cc
@@ -84,8 +84,7 @@ hb_face_count (hb_blob_t *blob)
 
   hb_sanitize_context_t c (blob);
 
-  const char *start = hb_blob_get_data (blob, nullptr);
-  auto *ot = reinterpret_cast (const_cast (start));
+  auto *ot = blob->as ();
   if (unlikely (!ot->sanitize (&c)))
     return 0;
 
@@ -329,7 +328,7 @@ hb_face_create_from_file_or_fail (const char   *file_name,
   return face;
 }
 
-static struct supported_face_loaders_t {
+static const struct supported_face_loaders_t {
         char name[16];
         hb_face_t * (*from_file) (const char *font_file, unsigned face_index);
         hb_face_t * (*from_blob) (hb_blob_t *blob, unsigned face_index);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.cc b/src/java.desktop/share/native/libharfbuzz/hb-font.cc
index 849855e2c22..6c636e23567 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-font.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-font.cc
@@ -246,7 +246,6 @@ hb_font_get_glyph_v_advance_nil (hb_font_t      *font,
                                  hb_codepoint_t  glyph HB_UNUSED,
                                  void           *user_data HB_UNUSED)
 {
-  /* TODO use font_extents.ascender+descender */
   return -font->y_scale;
 }
 
@@ -352,6 +351,10 @@ hb_font_get_glyph_h_origin_default (hb_font_t      *font,
                                     hb_position_t  *y,
                                     void           *user_data HB_UNUSED)
 {
+  if (font->has_glyph_h_origins_func_set ())
+  {
+    return font->get_glyph_h_origins (1, &glyph, 0, x, 0, y, 0, false);
+  }
   hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
   if (ret)
     font->parent_scale_position (x, y);
@@ -366,7 +369,6 @@ hb_font_get_glyph_v_origin_nil (hb_font_t      *font HB_UNUSED,
                                 hb_position_t  *y,
                                 void           *user_data HB_UNUSED)
 {
-  *x = *y = 0;
   return false;
 }
 
@@ -378,12 +380,100 @@ hb_font_get_glyph_v_origin_default (hb_font_t      *font,
                                     hb_position_t  *y,
                                     void           *user_data HB_UNUSED)
 {
+  if (font->has_glyph_v_origins_func_set ())
+  {
+    return font->get_glyph_v_origins (1, &glyph, 0, x, 0, y, 0, false);
+  }
   hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
   if (ret)
     font->parent_scale_position (x, y);
   return ret;
 }
 
+#define hb_font_get_glyph_h_origins_nil hb_font_get_glyph_h_origins_default
+
+static hb_bool_t
+hb_font_get_glyph_h_origins_default (hb_font_t *font HB_UNUSED,
+                                     void *font_data HB_UNUSED,
+                                     unsigned int count,
+                                     const hb_codepoint_t *first_glyph HB_UNUSED,
+                                     unsigned glyph_stride HB_UNUSED,
+                                     hb_position_t *first_x,
+                                     unsigned x_stride,
+                                     hb_position_t *first_y,
+                                     unsigned y_stride,
+                                     void *user_data HB_UNUSED)
+{
+  if (font->has_glyph_h_origin_func_set ())
+  {
+    for (unsigned int i = 0; i < count; i++)
+    {
+      font->get_glyph_h_origin (*first_glyph, first_x, first_y, false);
+      first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride);
+      first_x = &StructAtOffsetUnaligned (first_x, x_stride);
+      first_y = &StructAtOffsetUnaligned (first_y, y_stride);
+    }
+    return true;
+  }
+
+  hb_bool_t ret = font->parent->get_glyph_h_origins (count,
+                                                     first_glyph, glyph_stride,
+                                                     first_x, x_stride,
+                                                     first_y, y_stride);
+  if (ret)
+  {
+    for (unsigned i = 0; i < count; i++)
+    {
+      font->parent_scale_position (first_x, first_y);
+      first_x = &StructAtOffsetUnaligned (first_x, x_stride);
+      first_y = &StructAtOffsetUnaligned (first_y, y_stride);
+    }
+  }
+  return ret;
+}
+
+#define hb_font_get_glyph_v_origins_nil hb_font_get_glyph_v_origins_default
+
+static hb_bool_t
+hb_font_get_glyph_v_origins_default (hb_font_t *font HB_UNUSED,
+                                     void *font_data HB_UNUSED,
+                                     unsigned int count,
+                                     const hb_codepoint_t *first_glyph HB_UNUSED,
+                                     unsigned glyph_stride HB_UNUSED,
+                                     hb_position_t *first_x,
+                                     unsigned x_stride,
+                                     hb_position_t *first_y,
+                                     unsigned y_stride,
+                                     void *user_data HB_UNUSED)
+{
+  if (font->has_glyph_v_origin_func_set ())
+  {
+    for (unsigned int i = 0; i < count; i++)
+    {
+      font->get_glyph_v_origin (*first_glyph, first_x, first_y, false);
+      first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride);
+      first_x = &StructAtOffsetUnaligned (first_x, x_stride);
+      first_y = &StructAtOffsetUnaligned (first_y, y_stride);
+    }
+    return true;
+  }
+
+  hb_bool_t ret = font->parent->get_glyph_v_origins (count,
+                                                     first_glyph, glyph_stride,
+                                                     first_x, x_stride,
+                                                     first_y, y_stride);
+  if (ret)
+  {
+    for (unsigned i = 0; i < count; i++)
+    {
+      font->parent_scale_position (first_x, first_y);
+      first_x = &StructAtOffsetUnaligned (first_x, x_stride);
+      first_y = &StructAtOffsetUnaligned (first_y, y_stride);
+    }
+  }
+  return ret;
+}
+
 static hb_position_t
 hb_font_get_glyph_h_kerning_nil (hb_font_t      *font HB_UNUSED,
                                  void           *font_data HB_UNUSED,
@@ -1256,6 +1346,77 @@ hb_font_get_glyph_v_origin (hb_font_t      *font,
   return font->get_glyph_v_origin (glyph, x, y);
 }
 
+/**
+ * hb_font_get_glyph_h_origins:
+ * @font: #hb_font_t to work upon
+ * @count: The number of glyph IDs in the sequence queried
+ * @first_glyph: The first glyph ID to query
+ * @glyph_stride: The stride between successive glyph IDs
+ * @first_x: (out): The first X coordinate of the origin retrieved
+ * @x_stride: The stride between successive X coordinates
+ * @first_y: (out): The first Y coordinate of the origin retrieved
+ * @y_stride: The stride between successive Y coordinates
+ *
+ * Fetches the (X,Y) coordinates of the origin for requested glyph IDs
+ * in the specified font, for horizontal text segments.
+ *
+ * Return value: `true` if data found, `false` otherwise
+ *
+ * Since: 11.3.0
+ **/
+hb_bool_t
+hb_font_get_glyph_h_origins (hb_font_t      *font,
+                             unsigned int    count,
+                             const hb_codepoint_t *first_glyph,
+                             unsigned int    glyph_stride,
+                             hb_position_t  *first_x,
+                             unsigned int    x_stride,
+                             hb_position_t  *first_y,
+                             unsigned int    y_stride)
+
+{
+  return font->get_glyph_h_origins (count,
+                                    first_glyph, glyph_stride,
+                                    first_x, x_stride,
+                                    first_y, y_stride);
+}
+
+/**
+ * hb_font_get_glyph_v_origins:
+ * @font: #hb_font_t to work upon
+ * @count: The number of glyph IDs in the sequence queried
+ * @first_glyph: The first glyph ID to query
+ * @glyph_stride: The stride between successive glyph IDs
+ * @first_x: (out): The first X coordinate of the origin retrieved
+ * @x_stride: The stride between successive X coordinates
+ * @first_y: (out): The first Y coordinate of the origin retrieved
+ * @y_stride: The stride between successive Y coordinates
+ *
+ * Fetches the (X,Y) coordinates of the origin for requested glyph IDs
+ * in the specified font, for vertical text segments.
+ *
+ * Return value: `true` if data found, `false` otherwise
+ *
+ * Since: 11.3.0
+ **/
+hb_bool_t
+hb_font_get_glyph_v_origins (hb_font_t      *font,
+                             unsigned int    count,
+                             const hb_codepoint_t *first_glyph,
+                             unsigned int    glyph_stride,
+                             hb_position_t  *first_x,
+                             unsigned int    x_stride,
+                             hb_position_t  *first_y,
+                             unsigned int    y_stride)
+
+{
+  return font->get_glyph_v_origins (count,
+                                    first_glyph, glyph_stride,
+                                    first_x, x_stride,
+                                    first_y, y_stride);
+}
+
+
 /**
  * hb_font_get_glyph_h_kerning:
  * @font: #hb_font_t to work upon
@@ -1443,7 +1604,7 @@ hb_font_get_glyph_shape (hb_font_t *font,
  *
  * Return value: `true` if glyph was drawn, `false` otherwise
  *
- * XSince: REPLACEME
+ * Since: 11.2.0
  **/
 hb_bool_t
 hb_font_draw_glyph_or_fail (hb_font_t *font,
@@ -1480,7 +1641,7 @@ hb_font_draw_glyph_or_fail (hb_font_t *font,
  *
  * Return value: `true` if glyph was painted, `false` otherwise
  *
- * XSince: REPLACEME
+ * Since: 11.2.0
  */
 hb_bool_t
 hb_font_paint_glyph_or_fail (hb_font_t *font,
@@ -1883,6 +2044,7 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
 
   1000, /* x_scale */
   1000, /* y_scale */
+  false, /* is_synthetic */
   0.f, /* x_embolden */
   0.f, /* y_embolden */
   true, /* embolden_in_place */
@@ -1900,6 +2062,7 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
   0, /* ptem */
 
   HB_FONT_NO_VAR_NAMED_INSTANCE, /* instance_index */
+  false, /* has_nonzero_coords */
   0, /* num_coords */
   nullptr, /* coords */
   nullptr, /* design_coords */
@@ -1960,8 +2123,14 @@ hb_font_create (hb_face_t *face)
   hb_font_set_funcs_using (font, nullptr);
 
 #ifndef HB_NO_VAR
-  if (face && face->index >> 16)
-    hb_font_set_var_named_instance (font, (face->index >> 16) - 1);
+  // Initialize variations.
+  if (likely (face))
+  {
+    if (face->index >> 16)
+      hb_font_set_var_named_instance (font, (face->index >> 16) - 1);
+    else
+      hb_font_set_variations (font, nullptr, 0);
+  }
 #endif
 
   return font;
@@ -1979,6 +2148,7 @@ _hb_font_adopt_var_coords (hb_font_t *font,
   font->coords = coords;
   font->design_coords = design_coords;
   font->num_coords = coords_length;
+  font->has_nonzero_coords = hb_any (hb_array (coords, coords_length));
 
   font->changed ();
   font->serial_coords = font->serial;
@@ -2393,7 +2563,7 @@ hb_font_set_funcs_data (hb_font_t         *font,
   font->changed ();
 }
 
-static struct supported_font_funcs_t {
+static const struct supported_font_funcs_t {
         char name[16];
         void (*func) (hb_font_t *);
 } supported_font_funcs[] =
@@ -2450,6 +2620,9 @@ hb_bool_t
 hb_font_set_funcs_using (hb_font_t  *font,
                          const char *name)
 {
+  if (unlikely (hb_object_is_immutable (font)))
+    return false;
+
   bool retry = false;
 
   if (!name || !*name)
@@ -2704,12 +2877,12 @@ hb_font_get_ptem (hb_font_t *font)
  *
  * Return value: `true` if the font is synthetic, `false` otherwise.
  *
- * XSince: REPLACEME
+ * Since: 11.2.0
  */
 hb_bool_t
 hb_font_is_synthetic (hb_font_t *font)
 {
-  return font->is_synthetic ();
+  return font->is_synthetic;
 }
 
 /**
@@ -2858,12 +3031,6 @@ hb_font_set_variations (hb_font_t            *font,
   if (hb_object_is_immutable (font))
     return;
 
-  if (!variations_length && font->instance_index == HB_FONT_NO_VAR_NAMED_INSTANCE)
-  {
-    hb_font_set_var_coords_normalized (font, nullptr, 0);
-    return;
-  }
-
   const OT::fvar &fvar = *font->face->table.fvar;
   auto axes = fvar.get_axes ();
   const unsigned coords_length = axes.length;
@@ -2970,7 +3137,6 @@ hb_font_set_variation (hb_font_t *font,
 
   hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized);
   _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
-
 }
 
 /**
@@ -2991,11 +3157,16 @@ hb_font_set_variation (hb_font_t *font,
 void
 hb_font_set_var_coords_design (hb_font_t    *font,
                                const float  *coords,
-                               unsigned int  coords_length)
+                               unsigned int  input_coords_length)
 {
   if (hb_object_is_immutable (font))
     return;
 
+  const OT::fvar &fvar = *font->face->table.fvar;
+  auto axes = fvar.get_axes ();
+  const unsigned coords_length = axes.length;
+
+  input_coords_length = hb_min (input_coords_length, coords_length);
   int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr;
   float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
 
@@ -3006,8 +3177,11 @@ hb_font_set_var_coords_design (hb_font_t    *font,
     return;
   }
 
-  if (coords_length)
-    hb_memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0]));
+  if (input_coords_length)
+    hb_memcpy (design_coords, coords, input_coords_length * sizeof (font->design_coords[0]));
+  // Fill in the rest with default values
+  for (unsigned int i = input_coords_length; i < coords_length; i++)
+    design_coords[i] = axes[i].get_default ();
 
   hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized);
   _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
@@ -3072,34 +3246,31 @@ hb_font_get_var_named_instance (hb_font_t *font)
 void
 hb_font_set_var_coords_normalized (hb_font_t    *font,
                                    const int    *coords, /* 2.14 normalized */
-                                   unsigned int  coords_length)
+                                   unsigned int  input_coords_length)
 {
   if (hb_object_is_immutable (font))
     return;
 
+  const OT::fvar &fvar = *font->face->table.fvar;
+  auto axes = fvar.get_axes ();
+  unsigned coords_length = axes.length;
+
+  input_coords_length = hb_min (input_coords_length, coords_length);
   int *copy = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr;
-  int *unmapped = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr;
   float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (design_coords[0])) : nullptr;
 
-  if (unlikely (coords_length && !(copy && unmapped && design_coords)))
+  if (unlikely (coords_length && !(copy && design_coords)))
   {
     hb_free (copy);
-    hb_free (unmapped);
     hb_free (design_coords);
     return;
   }
 
-  if (coords_length)
-  {
-    hb_memcpy (copy, coords, coords_length * sizeof (coords[0]));
-    hb_memcpy (unmapped, coords, coords_length * sizeof (coords[0]));
-  }
+  if (input_coords_length)
+    hb_memcpy (copy, coords, input_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]);
-  hb_free (unmapped);
+    design_coords[i] = NAN;
 
   _hb_font_adopt_var_coords (font, copy, design_coords, coords_length);
 }
@@ -3112,8 +3283,8 @@ hb_font_set_var_coords_normalized (hb_font_t    *font,
  * Fetches the list of normalized variation coordinates currently
  * set on a font.
  *
- * Note that this returned array may only contain values for some
- * (or none) of the axes; omitted axes effectively have zero values.
+ * Note that if no variation coordinates are set, this function may
+ * return %NULL.
  *
  * Return value is valid as long as variation coordinates of the font
  * are not modified.
@@ -3140,9 +3311,12 @@ hb_font_get_var_coords_normalized (hb_font_t    *font,
  * Fetches the list of variation coordinates (in design-space units) currently
  * set on a font.
  *
- * Note that this returned array may only contain values for some
- * (or none) of the axes; omitted axes effectively have their default
- * values.
+ * Note that if no variation coordinates are set, this function may
+ * return %NULL.
+ *
+ * If variations have been set on the font using normalized coordinates
+ * (i.e. via hb_font_set_var_coords_normalized()), the design coordinates will
+ * have NaN (Not a Number) values.
  *
  * Return value is valid as long as variation coordinates of the font
  * are not modified.
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.h b/src/java.desktop/share/native/libharfbuzz/hb-font.h
index 4e267ba6a80..2d06b659278 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-font.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-font.h
@@ -97,7 +97,7 @@ hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs);
  * @descender: The depth of typographic descenders.
  * @line_gap: The suggested line-spacing gap.
  *
- * Font-wide extent values, measured in font units.
+ * Font-wide extent values, measured in scaled units.
  *
  * Note that typically @ascender is positive and @descender
  * negative, in coordinate systems that grow up.
@@ -332,7 +332,7 @@ typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t;
  *
  * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
  *
- * This method should retrieve the (X,Y) coordinates (in font units) of the
+ * This method should retrieve the (X,Y) coordinates (in scaled units) of the
  * origin for a glyph. Each coordinate must be returned in an #hb_position_t
  * output parameter.
  *
@@ -349,7 +349,7 @@ typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *fon
  *
  * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
  *
- * This method should retrieve the (X,Y) coordinates (in font units) of the
+ * This method should retrieve the (X,Y) coordinates (in scaled units) of the
  * origin for a glyph, for horizontal-direction text segments. Each
  * coordinate must be returned in an #hb_position_t output parameter.
  *
@@ -361,13 +361,72 @@ typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t;
  *
  * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
  *
- * This method should retrieve the (X,Y) coordinates (in font units) of the
+ * This method should retrieve the (X,Y) coordinates (in scaled units) of the
  * origin for a glyph, for vertical-direction text segments. Each coordinate
  * must be returned in an #hb_position_t output parameter.
  *
  **/
 typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t;
 
+/**
+ * hb_font_get_glyph_origins_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @first_glyph: The first glyph ID to query
+ * @count: number of glyphs to query
+ * @glyph_stride: The stride between successive glyph IDs
+ * @first_x: (out): The first origin X coordinate retrieved
+ * @x_stride: The stride between successive origin X coordinates
+ * @first_y: (out): The first origin Y coordinate retrieved
+ * @y_stride: The stride between successive origin Y coordinates
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the (X,Y) coordinates (in scaled units) of the
+ * origin for each requested glyph. Each coordinate value must be returned in
+ * an #hb_position_t in the two output parameters.
+ *
+ * Return value: `true` if data found, `false` otherwise
+ *
+ * Since: 11.3.0
+ **/
+typedef hb_bool_t (*hb_font_get_glyph_origins_func_t) (hb_font_t *font, void *font_data,
+                                                       unsigned int count,
+                                                       const hb_codepoint_t *first_glyph,
+                                                       unsigned glyph_stride,
+                                                       hb_position_t *first_x,
+                                                       unsigned x_stride,
+                                                       hb_position_t *first_y,
+                                                       unsigned y_stride,
+                                                       void *user_data);
+
+/**
+ * hb_font_get_glyph_h_origins_func_t:
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the (X,Y) coordinates (in scaled units) of the
+ * origin for requested glyph, for horizontal-direction text segments. Each
+ * coordinate must be returned in a the x/y #hb_position_t output parameters.
+ *
+ * Since: 11.3.0
+ **/
+typedef hb_font_get_glyph_origins_func_t hb_font_get_glyph_h_origins_func_t;
+
+/**
+ * hb_font_get_glyph_v_origins_func_t:
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the (X,Y) coordinates (in scaled units) of the
+ * origin for requested glyph, for vertical-direction text segments. Each
+ * coordinate must be returned in a the x/y #hb_position_t output parameters.
+ *
+ * Since: 11.3.0
+ **/
+typedef hb_font_get_glyph_origins_func_t hb_font_get_glyph_v_origins_func_t;
+
 /**
  * hb_font_get_glyph_kerning_func_t:
  * @font: #hb_font_t to work upon
@@ -428,7 +487,7 @@ typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *fo
  *
  * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
  *
- * This method should retrieve the (X,Y) coordinates (in font units) for a
+ * This method should retrieve the (X,Y) coordinates (in scaled units) for a
  * specified contour point in a glyph. Each coordinate must be returned as
  * an #hb_position_t output parameter.
  *
@@ -498,7 +557,7 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
  *
  * Return value: `true` if glyph was drawn, `false` otherwise
  *
- * XSince: REPLACEME
+ * Since: 11.2.0
  **/
 typedef hb_bool_t (*hb_font_draw_glyph_or_fail_func_t) (hb_font_t *font, void *font_data,
                                                         hb_codepoint_t glyph,
@@ -520,7 +579,7 @@ typedef hb_bool_t (*hb_font_draw_glyph_or_fail_func_t) (hb_font_t *font, void *f
  *
  * Return value: `true` if glyph was painted, `false` otherwise
  *
- * XSince: REPLACEME
+ * Since: 11.2.0
  */
 typedef hb_bool_t (*hb_font_paint_glyph_or_fail_func_t) (hb_font_t *font, void *font_data,
                                                          hb_codepoint_t glyph,
@@ -707,6 +766,38 @@ 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_origins_func:
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets the implementation function for #hb_font_get_glyph_h_origins_func_t.
+ *
+ * Since: 11.3.0
+ **/
+HB_EXTERN void
+hb_font_funcs_set_glyph_h_origins_func (hb_font_funcs_t *ffuncs,
+                                        hb_font_get_glyph_h_origins_func_t func,
+                                        void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_v_origins_func:
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets the implementation function for #hb_font_get_glyph_v_origins_func_t.
+ *
+ * Since: 11.3.0
+ **/
+HB_EXTERN void
+hb_font_funcs_set_glyph_v_origins_func (hb_font_funcs_t *ffuncs,
+                                        hb_font_get_glyph_v_origins_func_t func,
+                                        void *user_data, hb_destroy_func_t destroy);
+
 /**
  * hb_font_funcs_set_glyph_h_kerning_func:
  * @ffuncs: A font-function structure
@@ -796,7 +887,7 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
  *
  * Sets the implementation function for #hb_font_draw_glyph_or_fail_func_t.
  *
- * XSince: REPLACEME
+ * Since: 11.2.0
  **/
 HB_EXTERN void
 hb_font_funcs_set_draw_glyph_or_fail_func (hb_font_funcs_t *ffuncs,
@@ -812,7 +903,7 @@ hb_font_funcs_set_draw_glyph_or_fail_func (hb_font_funcs_t *ffuncs,
  *
  * Sets the implementation function for #hb_font_paint_glyph_or_fail_func_t.
  *
- * XSince: REPLACEME
+ * Since: 11.2.0
  */
 HB_EXTERN void
 hb_font_funcs_set_paint_glyph_or_fail_func (hb_font_funcs_t *ffuncs,
@@ -876,6 +967,26 @@ 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_bool_t
+hb_font_get_glyph_h_origins (hb_font_t *font,
+                             unsigned int count,
+                             const hb_codepoint_t *first_glyph,
+                             unsigned glyph_stride,
+                             hb_position_t *first_x,
+                             unsigned x_stride,
+                             hb_position_t *first_y,
+                             unsigned y_stride);
+
+HB_EXTERN hb_bool_t
+hb_font_get_glyph_v_origins (hb_font_t *font,
+                             unsigned int count,
+                             const hb_codepoint_t *first_glyph,
+                             unsigned glyph_stride,
+                             hb_position_t *first_x,
+                             unsigned x_stride,
+                             hb_position_t *first_y,
+                             unsigned y_stride);
+
 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);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.hh b/src/java.desktop/share/native/libharfbuzz/hb-font.hh
index 69d8d4b09df..9dd54466d7f 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-font.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-font.hh
@@ -55,6 +55,8 @@
   HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_advances) \
   HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_origin) \
   HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_origin) \
+  HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_origins) \
+  HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_origins) \
   HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_kerning) \
   HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_kerning)) \
   HB_FONT_FUNC_IMPLEMENT (get_,glyph_extents) \
@@ -118,6 +120,8 @@ struct hb_font_t
   int32_t x_scale;
   int32_t y_scale;
 
+  bool is_synthetic;
+
   float x_embolden;
   float y_embolden;
   bool embolden_in_place;
@@ -139,6 +143,7 @@ struct hb_font_t
 
   /* Font variation coordinates. */
   unsigned int instance_index;
+  bool has_nonzero_coords;
   unsigned int num_coords;
   int *coords;
   float *design_coords;
@@ -430,21 +435,127 @@ 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,
+                                bool synthetic = true)
   {
     *x = *y = 0;
-    return klass->get.f.glyph_h_origin (this, user_data,
-                                        glyph, x, y,
-                                        !klass->user_data ? nullptr : klass->user_data->glyph_h_origin);
+    bool ret = klass->get.f.glyph_h_origin (this, user_data,
+                                            glyph, x, y,
+                                            !klass->user_data ? nullptr : klass->user_data->glyph_h_origin);
+
+    if (synthetic && ret)
+    {
+      /* Slant is ignored as it does not affect glyph origin */
+
+      /* Embolden */
+      if (!embolden_in_place)
+      {
+        *x += x_scale < 0 ? -x_strength : x_strength;
+        *y += y_scale < 0 ? -y_strength : y_strength;
+      }
+    }
+
+    return ret;
   }
 
   hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
-                                hb_position_t *x, hb_position_t *y)
+                                hb_position_t *x, hb_position_t *y,
+                                bool synthetic = true)
   {
     *x = *y = 0;
-    return klass->get.f.glyph_v_origin (this, user_data,
-                                        glyph, x, y,
-                                        !klass->user_data ? nullptr : klass->user_data->glyph_v_origin);
+    bool ret = klass->get.f.glyph_v_origin (this, user_data,
+                                            glyph, x, y,
+                                            !klass->user_data ? nullptr : klass->user_data->glyph_v_origin);
+
+    if (synthetic && ret)
+    {
+      /* Slant is ignored as it does not affect glyph origin */
+
+      /* Embolden */
+      if (!embolden_in_place)
+      {
+        *x += x_scale < 0 ? -x_strength : x_strength;
+        *y += y_scale < 0 ? -y_strength : y_strength;
+      }
+    }
+
+    return ret;
+  }
+
+  hb_bool_t get_glyph_h_origins (unsigned int count,
+                                 const hb_codepoint_t *first_glyph,
+                                 unsigned int glyph_stride,
+                                 hb_position_t *first_x,
+                                 unsigned int x_stride,
+                                 hb_position_t *first_y,
+                                 unsigned int y_stride,
+                                 bool synthetic = true)
+
+  {
+    bool ret = klass->get.f.glyph_h_origins (this, user_data,
+                                             count,
+                                             first_glyph, glyph_stride,
+                                             first_x, x_stride, first_y, y_stride,
+                                             !klass->user_data ? nullptr : klass->user_data->glyph_h_origins);
+
+    if (synthetic && ret)
+    {
+      hb_position_t x_shift = x_scale < 0 ? -x_strength : x_strength;
+      hb_position_t y_shift = y_scale < 0 ? -y_strength : y_strength;
+      for (unsigned i = 0; i < count; i++)
+      {
+        /* Slant is ignored as it does not affect glyph origin */
+
+        /* Embolden */
+        if (!embolden_in_place)
+        {
+          *first_x += x_shift;
+          *first_y += y_shift;
+        }
+        first_x = &StructAtOffsetUnaligned (first_x, x_stride);
+        first_y = &StructAtOffsetUnaligned (first_y, y_stride);
+      }
+    }
+
+    return ret;
+  }
+
+  hb_bool_t get_glyph_v_origins (unsigned int count,
+                                 const hb_codepoint_t *first_glyph,
+                                 unsigned int glyph_stride,
+                                 hb_position_t *first_x,
+                                 unsigned int x_stride,
+                                 hb_position_t *first_y,
+                                 unsigned int y_stride,
+                                 bool synthetic = true)
+
+  {
+    bool ret = klass->get.f.glyph_v_origins (this, user_data,
+                                             count,
+                                             first_glyph, glyph_stride,
+                                             first_x, x_stride, first_y, y_stride,
+                                             !klass->user_data ? nullptr : klass->user_data->glyph_v_origins);
+
+    if (synthetic && is_synthetic && ret)
+    {
+      hb_position_t x_shift = x_scale < 0 ? -x_strength : x_strength;
+      hb_position_t y_shift = y_scale < 0 ? -y_strength : y_strength;
+      for (unsigned i = 0; i < count; i++)
+      {
+        /* Slant is ignored as it does not affect glyph origin */
+
+        /* Embolden */
+        if (!embolden_in_place)
+        {
+          *first_x += x_shift;
+          *first_y += y_shift;
+        }
+        first_x = &StructAtOffsetUnaligned (first_x, x_stride);
+        first_y = &StructAtOffsetUnaligned (first_y, y_stride);
+      }
+    }
+
+    return ret;
   }
 
   hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph,
@@ -486,7 +597,7 @@ struct hb_font_t
                                          extents,
                                          !klass->user_data ? nullptr : klass->user_data->glyph_extents);
     }
-    if (!is_synthetic () &&
+    if (!is_synthetic &&
         klass->get.f.glyph_extents (this, user_data,
                                     glyph,
                                     extents,
@@ -496,6 +607,7 @@ struct hb_font_t
     /* Try getting extents from paint(), then draw(), *then* get_extents()
      * and apply synthetic settings in the last case. */
 
+#ifndef HB_NO_PAINT
     hb_paint_extents_context_t paint_extents;
     if (paint_glyph_or_fail (glyph,
                              hb_paint_extents_get_funcs (), &paint_extents,
@@ -504,14 +616,17 @@ struct hb_font_t
       *extents = paint_extents.get_extents ().to_glyph_extents ();
       return true;
     }
+#endif
 
-    hb_extents_t draw_extents;
+#ifndef HB_NO_DRAW
+    hb_extents_t<> draw_extents;
     if (draw_glyph_or_fail (glyph,
                             hb_draw_extents_get_funcs (), &draw_extents))
     {
       *extents = draw_extents.to_glyph_extents ();
       return true;
     }
+#endif
 
     bool ret = klass->get.f.glyph_extents (this, user_data,
                                            glyph,
@@ -575,6 +690,7 @@ struct hb_font_t
                            hb_draw_funcs_t *draw_funcs, void *draw_data,
                            bool synthetic = true)
   {
+#ifndef HB_NO_DRAW
 #ifndef HB_NO_OUTLINE
     bool embolden = x_strength || y_strength;
     bool slanted = slant_xy;
@@ -603,7 +719,13 @@ struct hb_font_t
     // Slant before embolden; produces nicer results.
 
     if (slanted)
+    {
+      hb_position_t xo = 0, yo = 0;
+      get_glyph_h_origin (glyph, &xo, &yo, false);
+      outline.translate (-xo, -yo);
       outline.slant (slant_xy);
+      outline.translate (xo, yo);
+    }
 
     if (embolden)
     {
@@ -618,6 +740,8 @@ struct hb_font_t
 
     return true;
 #endif
+#endif
+    return false;
   }
 
   bool paint_glyph_or_fail (hb_codepoint_t glyph,
@@ -626,6 +750,7 @@ struct hb_font_t
                             hb_color_t foreground,
                             bool synthetic = true)
   {
+#ifndef HB_NO_PAINT
     /* Slant */
     if (synthetic && slant_xy)
       hb_paint_push_transform (paint_funcs, paint_data,
@@ -643,6 +768,8 @@ struct hb_font_t
       hb_paint_pop_transform (paint_funcs, paint_data);
 
     return ret;
+#endif
+    return false;
   }
 
   /* A bit higher-level, and with fallback */
@@ -704,6 +831,28 @@ struct hb_font_t
       get_glyph_v_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
   }
 
+  void apply_offset (hb_position_t *x, hb_position_t *y,
+                     hb_position_t dx, hb_position_t dy,
+                     signed mult)
+  {
+    assert (mult == -1 || mult == +1);
+
+    *x += dx * mult;
+    *y += dy * mult;
+  }
+  void add_offset (hb_position_t *x, hb_position_t *y,
+                   hb_position_t dx, hb_position_t dy)
+  {
+    *x += dx;
+    *y += dy;
+  }
+  void subtract_offset (hb_position_t *x, hb_position_t *y,
+                        hb_position_t dx, hb_position_t dy)
+  {
+    *x -= dx;
+    *y -= dy;
+  }
+
   void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
                                       hb_position_t *x, hb_position_t *y)
   {
@@ -714,6 +863,141 @@ struct hb_font_t
     *y = extents.ascender;
   }
 
+  void apply_glyph_h_origins_with_fallback (hb_buffer_t *buf, int mult)
+  {
+    bool has_ascender = false;
+    hb_position_t ascender = 0;
+
+    struct { hb_position_t x, y; } origins[32];
+
+    unsigned int offset = 0;
+    unsigned int count = buf->len;
+    while (offset < count)
+    {
+      unsigned n = hb_min (count - offset, ARRAY_LENGTH (origins));
+      if (!get_glyph_h_origins (n,
+                                &buf->info[offset].codepoint, sizeof (hb_glyph_info_t),
+                                &origins[0].x, sizeof (origins[0]),
+                                &origins[0].y, sizeof (origins[0])))
+      {
+        if (get_glyph_v_origins (n,
+                                  &buf->info[offset].codepoint, sizeof (hb_glyph_info_t),
+                                  &origins[0].x, sizeof (origins[0]),
+                                  &origins[0].y, sizeof (origins[0])))
+        {
+          if (!has_ascender)
+          {
+            hb_font_extents_t extents;
+            get_h_extents_with_fallback (&extents);
+            ascender = extents.ascender;
+            has_ascender = true;
+          }
+
+          /* We got the v_origins, adjust them to h_origins. */
+          for (unsigned j = 0; j < n; j++)
+          {
+            hb_codepoint_t glyph = buf->info[offset + j].codepoint;
+            origins[j].x -= get_glyph_h_advance (glyph) / 2;
+            origins[j].y -= ascender;
+          }
+        }
+        else
+        {
+          for (unsigned j = 0; j < n; j++)
+          {
+            origins[j].x = 0;
+            origins[j].y = 0;
+          }
+        }
+      }
+
+      assert (mult == -1 || mult == +1);
+      if (mult == +1)
+        for (unsigned j = 0; j < n; j++)
+        {
+          hb_glyph_position_t *pos = &buf->pos[offset + j];
+          add_offset (&pos->x_offset, &pos->y_offset,
+                      origins[j].x, origins[j].y);
+        }
+      else /* mult == -1 */
+        for (unsigned j = 0; j < n; j++)
+        {
+          hb_glyph_position_t *pos = &buf->pos[offset + j];
+          subtract_offset (&pos->x_offset, &pos->y_offset,
+                           origins[j].x, origins[j].y);
+        }
+
+      offset += n;
+    }
+  }
+  void apply_glyph_v_origins_with_fallback (hb_buffer_t *buf, int mult)
+  {
+    bool has_ascender = false;
+    hb_position_t ascender = 0;
+
+    struct { hb_position_t x, y; } origins[32];
+
+    unsigned int offset = 0;
+    unsigned int count = buf->len;
+    while (offset < count)
+    {
+      unsigned n = hb_min (count - offset, ARRAY_LENGTH (origins));
+      if (!get_glyph_v_origins (n,
+                                &buf->info[offset].codepoint, sizeof (hb_glyph_info_t),
+                                &origins[0].x, sizeof (origins[0]),
+                                &origins[0].y, sizeof (origins[0])))
+      {
+        if (get_glyph_h_origins (n,
+                                 &buf->info[offset].codepoint, sizeof (hb_glyph_info_t),
+                                 &origins[0].x, sizeof (origins[0]),
+                                 &origins[0].y, sizeof (origins[0])))
+        {
+          if (!has_ascender)
+          {
+            hb_font_extents_t extents;
+            get_h_extents_with_fallback (&extents);
+            ascender = extents.ascender;
+            has_ascender = true;
+          }
+
+          /* We got the h_origins, adjust them to v_origins. */
+          for (unsigned j = 0; j < n; j++)
+          {
+            hb_codepoint_t glyph = buf->info[offset + j].codepoint;
+            origins[j].x += get_glyph_h_advance (glyph) / 2;
+            origins[j].y += ascender;
+          }
+        }
+        else
+        {
+          for (unsigned j = 0; j < n; j++)
+          {
+            origins[j].x = 0;
+            origins[j].y = 0;
+          }
+        }
+      }
+
+      assert (mult == -1 || mult == +1);
+      if (mult == +1)
+        for (unsigned j = 0; j < n; j++)
+        {
+          hb_glyph_position_t *pos = &buf->pos[offset + j];
+          add_offset (&pos->x_offset, &pos->y_offset,
+                      origins[j].x, origins[j].y);
+        }
+      else /* mult == -1 */
+        for (unsigned j = 0; j < n; j++)
+        {
+          hb_glyph_position_t *pos = &buf->pos[offset + j];
+          subtract_offset (&pos->x_offset, &pos->y_offset,
+                           origins[j].x, origins[j].y);
+        }
+
+      offset += n;
+    }
+  }
+
   void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph,
                                          hb_position_t *x, hb_position_t *y)
   {
@@ -722,7 +1006,7 @@ struct hb_font_t
     {
       hb_position_t dx, dy;
       guess_v_origin_minus_h_origin (glyph, &dx, &dy);
-      *x -= dx; *y -= dy;
+      subtract_offset (x, y, dx, dy);
     }
   }
   void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph,
@@ -733,7 +1017,7 @@ struct hb_font_t
     {
       hb_position_t dx, dy;
       guess_v_origin_minus_h_origin (glyph, &dx, &dy);
-      *x += dx; *y += dy;
+      add_offset (x, y, dx, dy);
     }
   }
 
@@ -747,68 +1031,38 @@ struct hb_font_t
       get_glyph_v_origin_with_fallback (glyph, x, y);
   }
 
-  void add_glyph_h_origin (hb_codepoint_t glyph,
-                           hb_position_t *x, hb_position_t *y)
+  void add_glyph_h_origins (hb_buffer_t *buf)
   {
-    hb_position_t origin_x, origin_y;
-
-    get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
-
-    *x += origin_x;
-    *y += origin_y;
+    apply_glyph_h_origins_with_fallback (buf, +1);
   }
-  void add_glyph_v_origin (hb_codepoint_t glyph,
-                           hb_position_t *x, hb_position_t *y)
+  void add_glyph_v_origins (hb_buffer_t *buf)
   {
-    hb_position_t origin_x, origin_y;
-
-    get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
-
-    *x += origin_x;
-    *y += origin_y;
+    apply_glyph_v_origins_with_fallback (buf, +1);
   }
   void add_glyph_origin_for_direction (hb_codepoint_t glyph,
                                        hb_direction_t direction,
                                        hb_position_t *x, hb_position_t *y)
   {
     hb_position_t origin_x, origin_y;
-
     get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
-
-    *x += origin_x;
-    *y += origin_y;
+    add_offset (x, y, origin_x, origin_y);
   }
 
-  void subtract_glyph_h_origin (hb_codepoint_t glyph,
-                                hb_position_t *x, hb_position_t *y)
+  void subtract_glyph_h_origins (hb_buffer_t *buf)
   {
-    hb_position_t origin_x, origin_y;
-
-    get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
-
-    *x -= origin_x;
-    *y -= origin_y;
+    apply_glyph_h_origins_with_fallback (buf, -1);
   }
-  void subtract_glyph_v_origin (hb_codepoint_t glyph,
-                                hb_position_t *x, hb_position_t *y)
+  void subtract_glyph_v_origins (hb_buffer_t *buf)
   {
-    hb_position_t origin_x, origin_y;
-
-    get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
-
-    *x -= origin_x;
-    *y -= origin_y;
+    apply_glyph_v_origins_with_fallback (buf, -1);
   }
   void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
                                             hb_direction_t direction,
                                             hb_position_t *x, hb_position_t *y)
   {
     hb_position_t origin_x, origin_y;
-
     get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
-
-    *x -= origin_x;
-    *y -= origin_y;
+    subtract_offset (x, y, origin_x, origin_y);
   }
 
   void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
@@ -890,11 +1144,6 @@ struct hb_font_t
     return false;
   }
 
-  bool is_synthetic () const
-  {
-    return x_embolden || y_embolden || slant;
-  }
-
   void changed ()
   {
     float upem = face->get_upem ();
@@ -906,6 +1155,8 @@ struct hb_font_t
     bool y_neg = y_scale < 0;
     y_mult = (y_neg ? -((int64_t) -y_scale << 16) : ((int64_t) y_scale << 16)) / upem;
 
+    is_synthetic =  x_embolden || y_embolden || slant;
+
     x_strength = roundf (abs (x_scale) * x_embolden);
     y_strength = roundf (abs (y_scale) * y_embolden);
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-pool.hh b/src/java.desktop/share/native/libharfbuzz/hb-free-pool.hh
similarity index 92%
rename from src/java.desktop/share/native/libharfbuzz/hb-pool.hh
rename to src/java.desktop/share/native/libharfbuzz/hb-free-pool.hh
index 613c78d1973..3acd144a857 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-pool.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-free-pool.hh
@@ -24,12 +24,12 @@
  * Facebook Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_POOL_HH
-#define HB_POOL_HH
+#ifndef HB_FREE_POOL_HH
+#define HB_FREE_POOL_HH
 
 #include "hb.hh"
 
-/* Memory pool for persistent allocation of small objects.
+/* Memory pool for persistent alloc/free of small objects.
  *
  * Some AI musings on this, not necessarily true:
  *
@@ -41,10 +41,10 @@
  * sophisticated, use a real allocator.  Or use a real language. */
 
 template 
-struct hb_pool_t
+struct hb_free_pool_t
 {
-  hb_pool_t () : next (nullptr) {}
-  ~hb_pool_t ()
+  hb_free_pool_t () : next (nullptr) {}
+  ~hb_free_pool_t ()
   {
     next = nullptr;
 
@@ -104,4 +104,4 @@ struct hb_pool_t
 };
 
 
-#endif /* HB_POOL_HH */
+#endif /* HB_FREE_POOL_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ft.cc b/src/java.desktop/share/native/libharfbuzz/hb-ft.cc
index e9c0e734a53..b90f966c57c 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ft.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ft.cc
@@ -143,6 +143,9 @@ _hb_ft_font_destroy (void *data)
 /* hb_font changed, update FT_Face. */
 static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face)
 {
+  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;
 
   float x_mult = 1.f, y_mult = 1.f;
@@ -184,12 +187,14 @@ static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face)
     FT_Set_Transform (ft_face, &matrix, nullptr);
     ft_font->transform = true;
   }
+  else
+    FT_Set_Transform (ft_face, nullptr, nullptr);
 
 #if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
-  unsigned int num_coords;
-  const float *coords = hb_font_get_var_coords_design (font, &num_coords);
-  if (num_coords)
+  if (font->has_nonzero_coords)
   {
+    unsigned int num_coords;
+    const float *coords = hb_font_get_var_coords_design (font, &num_coords);
     FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (num_coords, sizeof (FT_Fixed));
     if (ft_coords)
     {
@@ -199,6 +204,12 @@ static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face)
       hb_free (ft_coords);
     }
   }
+  else if (font->num_coords)
+  {
+    // Some old versions of FreeType crash if we
+    // call this function on non-variable fonts.
+    FT_Set_Var_Design_Coordinates (ft_face, 0, nullptr);
+  }
 #endif
 }
 
@@ -1093,6 +1104,10 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data
   FT_ULong  length = 0;
   FT_Error error;
 
+  /* In new FreeType, a tag value of 1 loads the SFNT table directory. Reject it. */
+  if (tag == 1)
+    return nullptr;
+
   /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
 
   error = FT_Load_Sfnt_Table (ft_face, tag, 0, nullptr, &length);
@@ -1366,7 +1381,7 @@ hb_ft_font_changed (hb_font_t *font)
 
         for (unsigned int i = 0; i < mm_var->num_axis; ++i)
          {
-          coords[i] = ft_coords[i] >>= 2;
+          coords[i] = (ft_coords[i] + 2) >> 2;
           nonzero = nonzero || coords[i];
          }
 
@@ -1717,7 +1732,12 @@ hb_ft_font_set_funcs (hb_font_t *font)
   ft_face->generic.finalizer = _release_blob;
 
   // And the FT_Library to the blob
-  hb_blob_set_user_data (blob, &ft_library_key, ft_library, destroy_ft_library, true);
+  if (unlikely (!hb_blob_set_user_data (blob, &ft_library_key, ft_library, destroy_ft_library, true)))
+  {
+    DEBUG_MSG (FT, font, "hb_blob_set_user_data() failed");
+    FT_Done_Face (ft_face);
+    return;
+  }
 
   _hb_ft_font_set_funcs (font, ft_face, true);
   hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh b/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh
index 795f29f6ab0..0de062df68e 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh
@@ -26,7 +26,10 @@
 
 #include "hb.hh"
 
+#include "hb-algs.hh"
 
+
+template 
 struct hb_extents_t
 {
   hb_extents_t () {}
@@ -35,7 +38,7 @@ struct hb_extents_t
                 ymin (hb_min (extents.y_bearing, extents.y_bearing + extents.height)),
                 xmax (hb_max (extents.x_bearing, extents.x_bearing + extents.width)),
                 ymax (hb_max (extents.y_bearing, extents.y_bearing + extents.height)) {}
-  hb_extents_t (float xmin, float ymin, float xmax, float ymax) :
+  hb_extents_t (Float xmin, Float ymin, Float xmax, Float ymax) :
     xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {}
 
   bool is_empty () const { return xmin >= xmax || ymin >= ymax; }
@@ -69,7 +72,7 @@ struct hb_extents_t
   }
 
   void
-  add_point (float x, float y)
+  add_point (Float x, Float y)
   {
     if (unlikely (is_void ()))
     {
@@ -97,62 +100,69 @@ struct hb_extents_t
                                yneg ? y1 - y0 : y0 - y1};
   }
 
-  float xmin = 0.f;
-  float ymin = 0.f;
-  float xmax = -1.f;
-  float ymax = -1.f;
+  Float xmin = 0;
+  Float ymin = 0;
+  Float xmax = -1;
+  Float ymax = -1;
 };
 
+template 
 struct hb_transform_t
 {
   hb_transform_t () {}
-  hb_transform_t (float xx, float yx,
-                  float xy, float yy,
-                  float x0, float y0) :
+  hb_transform_t (Float xx, Float yx,
+                  Float xy, Float yy,
+                  Float x0, Float y0) :
     xx (xx), yx (yx), xy (xy), yy (yy), x0 (x0), y0 (y0) {}
 
   bool is_identity () const
   {
-    return xx == 1.f && yx == 0.f &&
-           xy == 0.f && yy == 1.f &&
-           x0 == 0.f && y0 == 0.f;
+    return xx == 1 && yx == 0 &&
+           xy == 0 && yy == 1 &&
+           x0 == 0 && y0 == 0;
   }
-
-  void multiply (const hb_transform_t &o)
+  bool is_translation () const
   {
-    /* Copied from cairo, with "o" being "a" there and "this" being "b" there. */
-    hb_transform_t r;
-
-    r.xx = o.xx * xx + o.yx * xy;
-    r.yx = o.xx * yx + o.yx * yy;
-
-    r.xy = o.xy * xx + o.yy * xy;
-    r.yy = o.xy * yx + o.yy * yy;
-
-    r.x0 = o.x0 * xx + o.y0 * xy + x0;
-    r.y0 = o.x0 * yx + o.y0 * yy + y0;
+    return xx == 1 && yx == 0 &&
+           xy == 0 && yy == 1;
+  }
 
-    *this = r;
+  void multiply (const hb_transform_t &o, bool before=false)
+  {
+    // Copied from cairo-matrix.c
+    const hb_transform_t &a = before ? o : *this;
+    const hb_transform_t &b = before ? *this : o;
+    *this = {
+      a.xx * b.xx + a.xy * b.yx,
+      a.yx * b.xx + a.yy * b.yx,
+      a.xx * b.xy + a.xy * b.yy,
+      a.yx * b.xy + a.yy * b.yy,
+      a.xx * b.x0 + a.xy * b.y0 + a.x0,
+      a.yx * b.x0 + a.yy * b.y0 + a.y0
+    };
   }
 
-  void transform_distance (float &dx, float &dy) const
+  HB_ALWAYS_INLINE
+  void transform_distance (Float &dx, Float &dy) const
   {
-    float new_x = xx * dx + xy * dy;
-    float new_y = yx * dx + yy * dy;
+    Float new_x = xx * dx + xy * dy;
+    Float new_y = yx * dx + yy * dy;
     dx = new_x;
     dy = new_y;
   }
 
-  void transform_point (float &x, float &y) const
+  HB_ALWAYS_INLINE
+  void transform_point (Float &x, Float &y) const
   {
-    transform_distance (x, y);
-    x += x0;
-    y += y0;
+    Float new_x = x0 + xx * x + xy * y;
+    Float new_y = y0 + yx * x + yy * y;
+    x = new_x;
+    y = new_y;
   }
 
-  void transform_extents (hb_extents_t &extents) const
+  void transform_extents (hb_extents_t &extents) const
   {
-    float quad_x[4], quad_y[4];
+    Float quad_x[4], quad_y[4];
 
     quad_x[0] = extents.xmin;
     quad_y[0] = extents.ymin;
@@ -163,7 +173,7 @@ struct hb_transform_t
     quad_x[3] = extents.xmax;
     quad_y[3] = extents.ymax;
 
-    extents = hb_extents_t {};
+    extents = hb_extents_t {};
     for (unsigned i = 0; i < 4; i++)
     {
       transform_point (quad_x[i], quad_y[i]);
@@ -171,20 +181,36 @@ struct hb_transform_t
     }
   }
 
-  void transform (const hb_transform_t &o) { multiply (o); }
+  void transform (const hb_transform_t &o, bool before=false) { multiply (o, before); }
 
-  void translate (float x, float y)
+  static hb_transform_t translation (Float x, Float y)
   {
-    if (x == 0.f && y == 0.f)
-      return;
+    return {1, 0, 0, 1, x, y};
+  }
+  void translate (Float x, Float y, bool before=false)
+  {
+    if (before)
+    {
+      x0 += x;
+      y0 += y;
+    }
+    else
+    {
+      if (x == 0 && y == 0)
+        return;
 
-    x0 += xx * x + xy * y;
-    y0 += yx * x + yy * y;
+      x0 += xx * x + xy * y;
+      y0 += yx * x + yy * y;
+    }
   }
 
-  void scale (float scaleX, float scaleY)
+  static hb_transform_t scaling (Float scaleX, Float scaleY)
+  {
+    return {scaleX, 0, 0, scaleY, 0, 0};
+  }
+  void scale (Float scaleX, Float scaleY)
   {
-    if (scaleX == 1.f && scaleY == 1.f)
+    if (scaleX == 1 && scaleY == 1)
       return;
 
     xx *= scaleX;
@@ -192,52 +218,94 @@ struct hb_transform_t
     xy *= scaleY;
     yy *= scaleY;
   }
-
-  void rotate (float rotation)
+  static hb_transform_t scaling_around_center (Float scaleX, Float scaleY, Float center_x, Float center_y)
   {
-    if (rotation == 0.f)
+    return {scaleX, 0, 0, scaleY,
+            center_x ? (1 - scaleX) * center_x : 0,
+            center_y ? (1 - scaleY) * center_y : 0};
+  }
+  void scale_around_center (Float scaleX, Float scaleY, Float center_x, Float center_y)
+  {
+    if (scaleX == 1 && scaleY == 1)
       return;
 
+    transform (scaling_around_center (scaleX, scaleY, center_x, center_y));
+  }
+
+  static hb_transform_t rotation (Float radians)
+  {
     // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240
-    rotation = rotation * HB_PI;
-    float c;
-    float s;
-#ifdef HAVE_SINCOSF
-    sincosf (rotation, &s, &c);
-#else
-    c = cosf (rotation);
-    s = sinf (rotation);
-#endif
-    auto other = hb_transform_t{c, s, -s, c, 0.f, 0.f};
-    transform (other);
+    Float c;
+    Float s;
+    hb_sincos (radians, s, c);
+    return {c, s, -s, c, 0, 0};
+  }
+  void rotate (Float radians, bool before=false)
+  {
+    if (radians == 0)
+      return;
+
+    transform (rotation (radians), before);
+  }
+
+  static hb_transform_t rotation_around_center (Float radians, Float center_x, Float center_y)
+  {
+    Float s, c;
+    hb_sincos (radians, s, c);
+    return {
+      c, s, -s, c,
+      (1 - c) * center_x + s * center_y,
+      -s * center_x +  (1 - c) * center_y
+    };
+  }
+  void rotate_around_center (Float radians, Float center_x, Float center_y, bool before=false)
+  {
+    if (radians == 0)
+      return;
+
+    transform (rotation_around_center (radians, center_x, center_y), before);
   }
 
-  void skew (float skewX, float skewY)
+  static hb_transform_t skewing (Float skewX, Float skewY)
+  {
+    return {1, skewY ? tanf (skewY) : 0, skewX ? tanf (skewX) : 0, 1, 0, 0};
+  }
+  void skew (Float skewX, Float skewY)
   {
-    if (skewX == 0.f && skewY == 0.f)
+    if (skewX == 0 && skewY == 0)
       return;
 
-    // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255
-    skewX = skewX * HB_PI;
-    skewY = skewY * HB_PI;
-    auto other = hb_transform_t{1.f,
-                                skewY ? tanf (skewY) : 0.f,
-                                skewX ? tanf (skewX) : 0.f,
-                                1.f,
-                                0.f, 0.f};
-    transform (other);
+    transform (skewing (skewX, skewY));
+  }
+  static hb_transform_t skewing_around_center (Float skewX, Float skewY, Float center_x, Float center_y)
+  {
+    skewX = skewX ? tanf (skewX) : 0;
+    skewY = skewY ? tanf (skewY) : 0;
+    return {
+            1, skewY, skewX, 1,
+            center_y ? -skewX * center_y : 0,
+            center_x ? -skewY * center_x : 0
+    };
+  }
+  void skew_around_center (Float skewX, Float skewY, Float center_x, Float center_y)
+  {
+    if (skewX == 0 && skewY == 0)
+            return;
+
+    transform (skewing_around_center (skewX, skewY, center_x, center_y));
   }
 
-  float xx = 1.f;
-  float yx = 0.f;
-  float xy = 0.f;
-  float yy = 1.f;
-  float x0 = 0.f;
-  float y0 = 0.f;
+  Float xx = 1;
+  Float yx = 0;
+  Float xy = 0;
+  Float yy = 1;
+  Float x0 = 0;
+  Float y0 = 0;
 };
 
-#define HB_TRANSFORM_IDENTITY hb_transform_t{1.f, 0.f, 0.f, 1.f, 0.f, 0.f}
+#define HB_TRANSFORM_IDENTITY {1, 0, 0, 1, 0, 0}
 
+template 
 struct hb_bounds_t
 {
   enum status_t {
@@ -247,7 +315,7 @@ struct hb_bounds_t
   };
 
   hb_bounds_t (status_t status = UNBOUNDED) : status (status) {}
-  hb_bounds_t (const hb_extents_t &extents) :
+  hb_bounds_t (const hb_extents_t &extents) :
     status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {}
 
   void union_ (const hb_bounds_t &o)
@@ -281,20 +349,21 @@ struct hb_bounds_t
   }
 
   status_t status;
-  hb_extents_t extents;
+  hb_extents_t extents;
 };
 
+template 
 struct hb_transform_decomposed_t
 {
-  float translateX = 0;
-  float translateY = 0;
-  float rotation = 0;  // in degrees, counter-clockwise
-  float scaleX = 1;
-  float scaleY = 1;
-  float skewX = 0;  // in degrees, counter-clockwise
-  float skewY = 0;  // in degrees, counter-clockwise
-  float tCenterX = 0;
-  float tCenterY = 0;
+  Float translateX = 0;
+  Float translateY = 0;
+  Float rotation = 0;  // in radians, counter-clockwise
+  Float scaleX = 1;
+  Float scaleY = 1;
+  Float skewX = 0;  // in radians, counter-clockwise
+  Float skewY = 0;  // in radians, counter-clockwise
+  Float tCenterX = 0;
+  Float tCenterY = 0;
 
   operator bool () const
   {
@@ -305,9 +374,9 @@ struct hb_transform_decomposed_t
            tCenterX || tCenterY;
   }
 
-  hb_transform_t to_transform () const
+  hb_transform_t to_transform () const
   {
-    hb_transform_t t;
+    hb_transform_t t;
     t.translate (translateX + tCenterX, translateY + tCenterY);
     t.rotate (rotation);
     t.scale (scaleX, scaleY);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-iter.hh b/src/java.desktop/share/native/libharfbuzz/hb-iter.hh
index 21d9544a74b..661e6771a4a 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-iter.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-iter.hh
@@ -772,8 +772,9 @@ struct hb_iota_iter_t :
   template 
   auto
   inc (hb_type_identity s, hb_priority<1>)
-    -> hb_void_t (s), hb_declval ()))>
-  { v = hb_invoke (std::forward (s), v); }
+    -> hb_void_t> (s),
+                                      hb_declval ()))>
+  { v = hb_invoke (std::forward> (s), v); }
 
   void
   inc (S s, hb_priority<0>)
@@ -972,7 +973,7 @@ struct
                     Proj&& f = hb_identity) const
   {
     for (auto it = hb_iter (c); it; ++it)
-      if (!hb_match (std::forward (p), hb_get (std::forward (f), *it)))
+      if (!hb_match (p, hb_get (f, *it)))
         return false;
     return true;
   }
@@ -989,7 +990,7 @@ struct
                     Proj&& f = hb_identity) const
   {
     for (auto it = hb_iter (c); it; ++it)
-      if (hb_match (std::forward (p), hb_get (std::forward (f), *it)))
+      if (hb_match (p, hb_get (f, *it)))
         return true;
     return false;
   }
@@ -1006,7 +1007,7 @@ struct
                     Proj&& f = hb_identity) const
   {
     for (auto it = hb_iter (c); it; ++it)
-      if (hb_match (std::forward (p), hb_get (std::forward (f), *it)))
+      if (hb_match (p, hb_get (f, *it)))
         return false;
     return true;
   }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-kern.hh b/src/java.desktop/share/native/libharfbuzz/hb-kern.hh
index 1f2c8d5811b..cf08c16689f 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-kern.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-kern.hh
@@ -70,7 +70,7 @@ struct hb_kern_machine_t
         continue;
       }
 
-      skippy_iter.reset (idx);
+      skippy_iter.reset_fast (idx);
       unsigned unsafe_to;
       if (!skippy_iter.next (&unsafe_to))
       {
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-limits.hh b/src/java.desktop/share/native/libharfbuzz/hb-limits.hh
index fbc7bbe764e..857e183737f 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-limits.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-limits.hh
@@ -29,20 +29,20 @@
 
 
 #ifndef HB_BUFFER_MAX_LEN_FACTOR
-#define HB_BUFFER_MAX_LEN_FACTOR 64
+#define HB_BUFFER_MAX_LEN_FACTOR 256
 #endif
 #ifndef HB_BUFFER_MAX_LEN_MIN
-#define HB_BUFFER_MAX_LEN_MIN 16384
+#define HB_BUFFER_MAX_LEN_MIN 65536
 #endif
 #ifndef HB_BUFFER_MAX_LEN_DEFAULT
 #define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */
 #endif
 
 #ifndef HB_BUFFER_MAX_OPS_FACTOR
-#define HB_BUFFER_MAX_OPS_FACTOR 1024
+#define HB_BUFFER_MAX_OPS_FACTOR 4096
 #endif
 #ifndef HB_BUFFER_MAX_OPS_MIN
-#define HB_BUFFER_MAX_OPS_MIN 16384
+#define HB_BUFFER_MAX_OPS_MIN 65536
 #endif
 #ifndef HB_BUFFER_MAX_OPS_DEFAULT
 #define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh b/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh
index ffbb8f3d301..8fa32ea8eaa 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh
@@ -66,13 +66,22 @@ static inline Type& StructAtOffsetUnaligned(void *P, unsigned int offset)
 }
 
 /* StructAfter(X) returns the struct T& that is placed after X.
- * Works with X of variable size also.  X must implement get_size() */
-template
-static inline const Type& StructAfter(const TObject &X)
-{ return StructAtOffset(&X, X.get_size()); }
-template
-static inline Type& StructAfter(TObject &X)
-{ return StructAtOffset(&X, X.get_size()); }
+ * Works with X of variable size also.  X must implement get_size().
+ * Any extra arguments are forwarded to get_size, so for example
+ * it can work with UnsizedArrayOf<> as well. */
+template 
+static inline auto StructAfter(const TObject &X, Ts... args) HB_AUTO_RETURN((
+  StructAtOffset(&X, X.get_size(std::forward (args)...))
+))
+/* The is_const shenanigans is to avoid ambiguous overload with gcc-8.
+ * It disables this path when TObject is const.
+ * See: https://github.com/harfbuzz/harfbuzz/issues/5429 */
+template 
+static inline auto StructAfter(TObject &X, Ts... args) HB_AUTO_RETURN((
+  sizeof(int[std::is_const::value ? -1 : +1]) > 0 ?
+  StructAtOffset(&X, X.get_size(std::forward (args)...))
+  : *reinterpret_cast (0)
+))
 
 
 /*
@@ -132,7 +141,6 @@ static inline Type& StructAfter(TObject &X)
   DEFINE_SIZE_ARRAY(size, array)
 
 
-
 /*
  * Lazy loaders.
  *
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-map.hh b/src/java.desktop/share/native/libharfbuzz/hb-map.hh
index 76206342f57..4c76622df7a 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-map.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-map.hh
@@ -47,11 +47,11 @@ struct hb_hashmap_t
   hb_hashmap_t ()  { init (); }
   ~hb_hashmap_t () { fini (); }
 
-  hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t ()
+  void _copy (const hb_hashmap_t& o)
   {
     if (unlikely (!o.mask)) return;
 
-    if (item_t::is_trivial)
+    if (hb_is_trivially_copy_assignable (item_t))
     {
       items = (item_t *) hb_malloc (sizeof (item_t) * (o.mask + 1));
       if (unlikely (!items))
@@ -70,8 +70,16 @@ struct hb_hashmap_t
 
     alloc (o.population); hb_copy (o, *this);
   }
+
+  hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { _copy (o); }
+  hb_hashmap_t& operator= (const hb_hashmap_t& o)
+  {
+    reset ();
+    if (!items) { _copy (o); return *this; }
+    alloc (o.population); hb_copy (o, *this); return *this;
+  }
+
   hb_hashmap_t (hb_hashmap_t&& o)  noexcept : hb_hashmap_t () { hb_swap (*this, o); }
-  hb_hashmap_t& operator= (const hb_hashmap_t& o)  { reset (); alloc (o.population); hb_copy (o, *this); return *this; }
   hb_hashmap_t& operator= (hb_hashmap_t&& o)   noexcept { hb_swap (*this, o); return *this; }
 
   hb_hashmap_t (std::initializer_list> lst) : hb_hashmap_t ()
@@ -130,10 +138,7 @@ struct hb_hashmap_t
     uint32_t total_hash () const
     { return (hash * 31u) + hb_hash (value); }
 
-    static constexpr bool is_trivial = hb_is_trivially_constructible(K) &&
-                                       hb_is_trivially_destructible(K) &&
-                                       hb_is_trivially_constructible(V) &&
-                                       hb_is_trivially_destructible(V);
+    static constexpr bool is_trivially_constructible = (hb_is_trivially_constructible(K) && hb_is_trivially_constructible(V));
   };
 
   hb_object_header_t header;
@@ -174,19 +179,19 @@ struct hb_hashmap_t
     if (likely (items))
     {
       unsigned size = mask + 1;
-      if (!item_t::is_trivial)
-        for (unsigned i = 0; i < size; i++)
-          items[i].~item_t ();
+      for (unsigned i = 0; i < size; i++)
+        items[i].~item_t ();
       hb_free (items);
       items = nullptr;
     }
     population = occupancy = 0;
   }
 
-  void reset ()
+  hb_hashmap_t& reset ()
   {
     successful = true;
     clear ();
+    return *this;
   }
 
   bool in_error () const { return !successful; }
@@ -197,7 +202,7 @@ struct hb_hashmap_t
 
     if (new_population != 0 && (new_population + new_population / 2) < mask) return true;
 
-    unsigned int power = hb_bit_storage (hb_max ((unsigned) population, new_population) * 2 + 8);
+    unsigned int power = hb_bit_storage (hb_max (hb_max ((unsigned) population, new_population) * 2, 4u));
     unsigned int new_size = 1u << power;
     item_t *new_items = (item_t *) hb_malloc ((size_t) new_size * sizeof (item_t));
     if (unlikely (!new_items))
@@ -205,7 +210,7 @@ struct hb_hashmap_t
       successful = false;
       return false;
     }
-    if (!item_t::is_trivial)
+    if (!item_t::is_trivially_constructible)
       for (auto &_ : hb_iter (new_items, new_size))
         new (&_) item_t ();
     else
@@ -231,9 +236,8 @@ struct hb_hashmap_t
                        std::move (old_items[i].value));
       }
     }
-    if (!item_t::is_trivial)
-      for (unsigned int i = 0; i < old_size; i++)
-        old_items[i].~item_t ();
+    for (unsigned int i = 0; i < old_size; i++)
+      old_items[i].~item_t ();
 
     hb_free (old_items);
 
@@ -335,7 +339,13 @@ struct hb_hashmap_t
   bool has (const K &key, VV **vp = nullptr) const
   {
     if (!items) return false;
-    auto *item = fetch_item (key, hb_hash (key));
+    return has_with_hash (key, hb_hash (key), vp);
+  }
+  template 
+  bool has_with_hash (const K &key, uint32_t hash, VV **vp = nullptr) const
+  {
+    if (!items) return false;
+    auto *item = fetch_item (key, hash);
     if (item)
     {
       if (vp) *vp = std::addressof (item->value);
@@ -481,10 +491,17 @@ struct hb_hashmap_t
   /* Sink interface. */
   hb_hashmap_t& operator << (const hb_pair_t& v)
   { set (v.first, v.second); return *this; }
+  template 
   hb_hashmap_t& operator << (const hb_pair_t& v)
   { set (v.first, std::move (v.second)); return *this; }
+  template 
   hb_hashmap_t& operator << (const hb_pair_t& v)
   { set (std::move (v.first), v.second); return *this; }
+  template 
   hb_hashmap_t& operator << (const hb_pair_t& v)
   { set (std::move (v.first), std::move (v.second)); return *this; }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh b/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh
index 9d2867e4835..07f3ebe0c7d 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh
@@ -31,7 +31,7 @@
 #include "hb.hh"
 
 
-#line 35 "hb-number-parser.hh"
+#line 32 "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
@@ -135,12 +135,12 @@ strtod_rl (const char *p, const char **end_ptr /* IN/OUT */)
 
   int cs;
 
-#line 139 "hb-number-parser.hh"
+#line 132 "hb-number-parser.hh"
         {
         cs = double_parser_start;
         }
 
-#line 144 "hb-number-parser.hh"
+#line 135 "hb-number-parser.hh"
         {
         int _slen;
         int _trans;
@@ -198,7 +198,7 @@ _resume:
           exp_overflow = true;
 }
         break;
-#line 202 "hb-number-parser.hh"
+#line 187 "hb-number-parser.hh"
         }
 
 _again:
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 382ee2ddaf2..538240b6416 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh
@@ -465,11 +465,11 @@ struct OpenTypeFontFile
     Typ1Tag             = HB_TAG ('t','y','p','1')  /* Obsolete Apple Type1 font in SFNT container */
   };
 
-  hb_tag_t get_tag () const { return u.tag; }
+  hb_tag_t get_tag () const { return u.tag.v; }
 
   unsigned int get_face_count () const
   {
-    switch (u.tag) {
+    switch (u.tag.v) {
     case CFFTag:        /* All the non-collection tags */
     case TrueTag:
     case Typ1Tag:
@@ -483,7 +483,7 @@ struct OpenTypeFontFile
   {
     if (base_offset)
       *base_offset = 0;
-    switch (u.tag) {
+    switch (u.tag.v) {
     /* Note: for non-collection SFNT data we ignore index.  This is because
      * Apple dfont container is a container of SFNT's.  So each SFNT is a
      * non-TTC, but the index is more than zero. */
@@ -512,9 +512,9 @@ struct OpenTypeFontFile
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (unlikely (!u.tag.sanitize (c))) return_trace (false);
+    if (unlikely (!u.tag.v.sanitize (c))) return_trace (false);
     hb_barrier ();
-    switch (u.tag) {
+    switch (u.tag.v) {
     case CFFTag:        /* All the non-collection tags */
     case TrueTag:
     case Typ1Tag:
@@ -527,13 +527,13 @@ struct OpenTypeFontFile
 
   protected:
   union {
-  Tag                   tag;            /* 4-byte identifier. */
+  struct { Tag v; }     tag;            /* 4-byte identifier. */
   OpenTypeFontFace      fontFace;
   TTCHeader             ttcHeader;
   ResourceForkHeader    rfHeader;
   } u;
   public:
-  DEFINE_SIZE_UNION (4, tag);
+  DEFINE_SIZE_UNION (4, tag.v);
 };
 
 
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 75d87f11ea5..ad831b66d56 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh
@@ -54,35 +54,41 @@ namespace OT {
  */
 
 /* Integer types in big-endian order and no alignment requirement */
-template 
-struct IntType
+struct NumType
 {
   typedef Type type;
-
-  IntType () = default;
-  explicit constexpr IntType (Type V) : v {V} {}
-  IntType& operator = (Type i) { v = i; return *this; }
   /* For reason we define cast out operator for signed/unsigned, instead of Type, see:
    * https://github.com/harfbuzz/harfbuzz/pull/2875/commits/09836013995cab2b9f07577a179ad7b024130467 */
-  operator typename std::conditional::value, signed, unsigned>::type () const { return v; }
+  typedef typename std::conditional::value && sizeof (Type) <= sizeof(int),
+                                     typename std::conditional::value, signed, unsigned>::type,
+                                     Type>::type WideType;
+
+  NumType () = default;
+  explicit constexpr NumType (Type V) : v {V} {}
+  NumType& operator = (Type V) { v = V; return *this; }
+
+  operator WideType () const { return v; }
 
-  bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; }
-  bool operator != (const IntType &o) const { return !(*this == o); }
+  bool operator == (const NumType &o) const { return (Type) v == (Type) o.v; }
+  bool operator != (const NumType &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; }
+  NumType& operator += (WideType count) { *this = *this + count; return *this; }
+  NumType& operator -= (WideType count) { *this = *this - count; return *this; }
+  NumType& operator ++ () { *this += 1; return *this; }
+  NumType& operator -- () { *this -= 1; return *this; }
+  NumType operator ++ (int) { NumType c (*this); ++*this; return c; }
+  NumType operator -- (int) { NumType c (*this); --*this; return c; }
 
-  HB_INTERNAL static int cmp (const IntType *a, const IntType *b)
+  uint32_t hash () const { return hb_array ((const char *) &v, sizeof (v)).hash (); }
+  HB_INTERNAL static int cmp (const NumType *a, const NumType *b)
   { return b->cmp (*a); }
   HB_INTERNAL static int cmp (const void *a, const void *b)
   {
-    IntType *pa = (IntType *) a;
-    IntType *pb = (IntType *) b;
+    NumType *pa = (NumType *) a;
+    NumType *pb = (NumType *) b;
 
     return pb->cmp (*pa);
   }
@@ -99,20 +105,36 @@ struct IntType
     return_trace (c->check_struct (this));
   }
   protected:
-  BEInt v;
+  typename std::conditional::value,
+                            HBInt,
+                            HBFloat>::type v;
   public:
   DEFINE_SIZE_STATIC (Size);
 };
 
-typedef IntType  HBUINT8;      /* 8-bit unsigned integer. */
-typedef IntType   HBINT8;       /* 8-bit signed integer. */
-typedef IntType HBUINT16;     /* 16-bit unsigned integer. */
-typedef IntType  HBINT16;      /* 16-bit signed integer. */
-typedef IntType HBUINT32;     /* 32-bit unsigned integer. */
-typedef IntType  HBINT32;      /* 32-bit signed integer. */
+typedef NumType  HBUINT8;        /* 8-bit big-endian unsigned integer. */
+typedef NumType   HBINT8;         /* 8-bit big-endian signed integer. */
+typedef NumType HBUINT16;       /* 16-bit big-endian unsigned integer. */
+typedef NumType  HBINT16;        /* 16-bit big-endian signed integer. */
+typedef NumType HBUINT32;       /* 32-bit big-endian unsigned integer. */
+typedef NumType  HBINT32;        /* 32-bit big-endian signed integer. */
+typedef NumType HBUINT64;       /* 64-bit big-endian unsigned integer. */
+typedef NumType  HBINT64;        /* 64-bit big-endian signed integer. */
 /* Note: we cannot defined a signed HBINT24 because there's no corresponding C type.
  * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */
-typedef IntType HBUINT24;  /* 24-bit unsigned integer. */
+typedef NumType HBUINT24;    /* 24-bit big-endian unsigned integer. */
+
+typedef NumType HBUINT16LE;    /* 16-bit little-endian unsigned integer. */
+typedef NumType  HBINT16LE;     /* 16-bit little-endian signed integer. */
+typedef NumType HBUINT32LE;    /* 32-bit little-endian unsigned integer. */
+typedef NumType  HBINT32LE;     /* 32-bit little-endian signed integer. */
+typedef NumType HBUINT64LE;    /* 64-bit little-endian unsigned integer. */
+typedef NumType  HBINT64LE;     /* 64-bit little-endian signed integer. */
+
+typedef NumType  HBFLOAT32BE;     /* 32-bit little-endian floating point number. */
+typedef NumType HBFLOAT64BE;     /* 64-bit little-endian floating point number. */
+typedef NumType  HBFLOAT32LE;     /* 32-bit little-endian floating point number. */
+typedef NumType HBFLOAT64LE;     /* 64-bit little-endian floating point number. */
 
 /* 15-bit unsigned number; top bit used for extension. */
 struct HBUINT15 : HBUINT16
@@ -218,7 +240,7 @@ typedef HBUINT16 UFWORD;
 template 
 struct HBFixed : Type
 {
-  static constexpr float shift = (float) (1 << fraction_bits);
+  static constexpr float mult = 1.f / (1 << fraction_bits);
   static_assert (Type::static_size * 8 > fraction_bits, "");
 
   operator signed () const = delete;
@@ -226,8 +248,8 @@ struct HBFixed : Type
   explicit operator float () const { return to_float (); }
   typename Type::type to_int () const { return Type::v; }
   void set_int (typename Type::type i ) { Type::v = i; }
-  float to_float (float offset = 0) const  { return ((int32_t) Type::v + offset) / shift; }
-  void set_float (float f) { Type::v = roundf (f * shift); }
+  float to_float (float offset = 0) const  { return ((int32_t) Type::v + offset) * mult; }
+  void set_float (float f) { Type::v = roundf (f / mult); }
   public:
   DEFINE_SIZE_STATIC (Type::static_size);
 };
@@ -504,16 +526,9 @@ struct OffsetTo : Offset
     return_trace (sanitize_shallow (c, base) &&
                   hb_barrier () &&
                   (this->is_null () ||
-                   c->dispatch (StructAtOffset (base, *this), std::forward (ds)...) ||
-                   neuter (c)));
+                   c->dispatch (StructAtOffset (base, *this), std::forward (ds)...)));
   }
 
-  /* Set the offset to Null */
-  bool neuter (hb_sanitize_context_t *c) const
-  {
-    if (!has_null) return false;
-    return c->try_set (this, 0);
-  }
   DEFINE_SIZE_STATIC (sizeof (OffsetType));
 };
 /* Partial specializations. */
@@ -1481,8 +1496,8 @@ struct TupleValues
     VALUE_RUN_COUNT_MASK = 0x3F
   };
 
-  static unsigned compile (hb_array_t values, /* IN */
-                           hb_array_t encoded_bytes /* OUT */)
+  static unsigned compile_unsafe (hb_array_t values, /* IN */
+                                  unsigned char *encoded_bytes /* OUT */)
   {
     unsigned num_values = values.length;
     unsigned encoded_len = 0;
@@ -1491,24 +1506,23 @@ struct TupleValues
     {
       int val = values.arrayZ[i];
       if (val == 0)
-        encoded_len += encode_value_run_as_zeroes (i, encoded_bytes.sub_array (encoded_len), values);
-      else if (val >= -128 && val <= 127)
-        encoded_len += encode_value_run_as_bytes (i, encoded_bytes.sub_array (encoded_len), values);
-      else if (val >= -32768 && val <= 32767)
-        encoded_len += encode_value_run_as_words (i, encoded_bytes.sub_array (encoded_len), values);
+        encoded_len += encode_value_run_as_zeroes (i, encoded_bytes + encoded_len, values);
+      else if ((int8_t) val == val)
+        encoded_len += encode_value_run_as_bytes (i, encoded_bytes + encoded_len, values);
+      else if ((int16_t) val == val)
+        encoded_len += encode_value_run_as_words (i, encoded_bytes + encoded_len, values);
       else
-        encoded_len += encode_value_run_as_longs (i, encoded_bytes.sub_array (encoded_len), values);
+        encoded_len += encode_value_run_as_longs (i, encoded_bytes + encoded_len, values);
     }
     return encoded_len;
   }
 
   static unsigned encode_value_run_as_zeroes (unsigned& i,
-                                              hb_array_t encoded_bytes,
+                                              unsigned char *it,
                                               hb_array_t values)
   {
     unsigned num_values = values.length;
     unsigned run_length = 0;
-    auto it = encoded_bytes.iter ();
     unsigned encoded_len = 0;
     while (i < num_values && values.arrayZ[i] == 0)
     {
@@ -1532,7 +1546,7 @@ struct TupleValues
   }
 
   static unsigned encode_value_run_as_bytes (unsigned &i,
-                                             hb_array_t encoded_bytes,
+                                             unsigned char *it,
                                              hb_array_t values)
   {
     unsigned start = i;
@@ -1540,7 +1554,7 @@ struct TupleValues
     while (i < num_values)
     {
       int val = values.arrayZ[i];
-      if (val > 127 || val < -128)
+      if ((int8_t) val != val)
         break;
 
       /* from fonttools: if there're 2 or more zeros in a sequence,
@@ -1553,7 +1567,6 @@ struct TupleValues
     unsigned run_length = i - start;
 
     unsigned encoded_len = 0;
-    auto it = encoded_bytes.iter ();
 
     while (run_length >= 64)
     {
@@ -1561,10 +1574,9 @@ struct TupleValues
       encoded_len++;
 
       for (unsigned j = 0; j < 64; j++)
-      {
-        *it++ = static_cast (values.arrayZ[start + j]);
-        encoded_len++;
-      }
+        it[j] = static_cast (values.arrayZ[start + j]);
+      it += 64;
+      encoded_len += 64;
 
       start += 64;
       run_length -= 64;
@@ -1575,18 +1587,16 @@ struct TupleValues
       *it++ = (VALUES_ARE_BYTES | (run_length - 1));
       encoded_len++;
 
-      while (start < i)
-      {
-        *it++ = static_cast (values.arrayZ[start++]);
-        encoded_len++;
-      }
+      for (unsigned j = 0; j < run_length; j++)
+        it[j] = static_cast (values.arrayZ[start + j]);
+      encoded_len += run_length;
     }
 
     return encoded_len;
   }
 
   static unsigned encode_value_run_as_words (unsigned &i,
-                                             hb_array_t encoded_bytes,
+                                             unsigned char *it,
                                              hb_array_t values)
   {
     unsigned start = i;
@@ -1595,22 +1605,24 @@ struct TupleValues
     {
       int val = values.arrayZ[i];
 
-      /* start a new run for a single zero value*/
+      if ((int16_t) val != val)
+        break;
+
+      /* start a new run for a single zero value. */
       if (val == 0) break;
 
-      /* from fonttools: continue word-encoded run if there's only one
+      /* From fonttools: continue word-encoded run if there's only one
        * single value in the range [-128, 127] because it is more compact.
        * Only start a new run when there're 2 continuous such values. */
-      if (val >= -128 && val <= 127 &&
+      if ((int8_t) val == val &&
           i + 1 < num_values &&
-          values.arrayZ[i+1] >= -128 && values.arrayZ[i+1] <= 127)
+          (int8_t) values.arrayZ[i+1] == values.arrayZ[i+1])
         break;
 
       i++;
     }
 
     unsigned run_length = i - start;
-    auto it = encoded_bytes.iter ();
     unsigned encoded_len = 0;
     while (run_length >= 64)
     {
@@ -1647,7 +1659,7 @@ struct TupleValues
   }
 
   static unsigned encode_value_run_as_longs (unsigned &i,
-                                             hb_array_t encoded_bytes,
+                                             unsigned char *it,
                                              hb_array_t values)
   {
     unsigned start = i;
@@ -1656,14 +1668,13 @@ struct TupleValues
     {
       int val = values.arrayZ[i];
 
-      if (val >= -32768 && val <= 32767)
+      if ((int16_t) val == val)
         break;
 
       i++;
     }
 
     unsigned run_length = i - start;
-    auto it = encoded_bytes.iter ();
     unsigned encoded_len = 0;
     while (run_length >= 64)
     {
@@ -1704,10 +1715,14 @@ struct TupleValues
   }
 
   template 
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
   static bool decompile (const HBUINT8 *&p /* IN/OUT */,
                          hb_vector_t &values /* IN/OUT */,
                          const HBUINT8 *end,
-                         bool consume_all = false)
+                         bool consume_all = false,
+                         unsigned start = 0)
   {
     unsigned i = 0;
     unsigned count = consume_all ? UINT_MAX : values.length;
@@ -1720,19 +1735,24 @@ struct TupleValues
       unsigned run_count = (control & VALUE_RUN_COUNT_MASK) + 1;
       if (consume_all)
       {
-        if (unlikely (!values.resize (values.length + run_count, false)))
+        if (unlikely (!values.resize_dirty  (values.length + run_count)))
           return false;
       }
       unsigned stop = i + run_count;
       if (unlikely (stop > count)) return false;
+
+      unsigned skip = i < start ? hb_min (start - i, run_count) : 0;
+      i += skip;
+
       if ((control & VALUES_SIZE_MASK) == VALUES_ARE_ZEROS)
       {
-        for (; i < stop; i++)
-          values.arrayZ[i] = 0;
+        hb_memset (&values.arrayZ[i], 0, (stop - i) * sizeof (T));
+        i = stop;
       }
       else if ((control & VALUES_SIZE_MASK) ==  VALUES_ARE_WORDS)
       {
         if (unlikely (p + run_count * HBINT16::static_size > end)) return false;
+        p += skip * HBINT16::static_size;
 #ifndef HB_OPTIMIZE_SIZE
         for (; i + 3 < stop; i += 4)
         {
@@ -1755,6 +1775,7 @@ struct TupleValues
       else if ((control & VALUES_SIZE_MASK) ==  VALUES_ARE_LONGS)
       {
         if (unlikely (p + run_count * HBINT32::static_size > end)) return false;
+        p += skip * HBINT32::static_size;
         for (; i < stop; i++)
         {
           values.arrayZ[i] = * (const HBINT32 *) p;
@@ -1764,6 +1785,7 @@ struct TupleValues
       else if ((control & VALUES_SIZE_MASK) ==  VALUES_ARE_BYTES)
       {
         if (unlikely (p + run_count > end)) return false;
+        p += skip * HBINT8::static_size;
 #ifndef HB_OPTIMIZE_SIZE
         for (; i + 3 < stop; i += 4)
         {
@@ -1784,7 +1806,7 @@ struct TupleValues
   {
     iter_t (const unsigned char *p_, unsigned len_)
             : p (p_), endp (p_ + len_)
-    { if (ensure_run ()) read_value (); }
+    { if (likely (ensure_run ())) read_value (); }
 
     private:
     const unsigned char *p;
@@ -1793,10 +1815,14 @@ struct TupleValues
     signed run_count = 0;
     unsigned width = 0;
 
+    HB_ALWAYS_INLINE
     bool ensure_run ()
     {
       if (likely (run_count > 0)) return true;
-
+      return _ensure_run ();
+    }
+    bool _ensure_run ()
+    {
       if (unlikely (p >= endp))
       {
         run_count = 0;
@@ -1886,10 +1912,15 @@ struct TupleValues
     signed run_count = 0;
     unsigned width = 0;
 
+    HB_ALWAYS_INLINE
     bool ensure_run ()
     {
-      if (run_count > 0) return true;
+      if (likely (run_count > 0)) return true;
+      return _ensure_run ();
+    }
 
+    bool _ensure_run ()
+    {
       if (unlikely (p >= end))
       {
         run_count = 0;
@@ -2013,7 +2044,10 @@ struct TupleValues
       }
 
 #ifndef HB_OPTIMIZE_SIZE
-      if (scale == 1.0f)
+      // The following branch is supposed to speed things up by avoiding
+      // the multiplication in _add_to<> if scale is 1.0f.
+      // But in practice it seems to bloat the code and slow things down.
+      if (false && scale == 1.0f)
         _add_to (out);
       else
 #endif
@@ -2038,6 +2072,23 @@ struct TupleList : CFF2Index
 };
 
 
+// Alignment
+
+template 
+struct Align
+{
+  unsigned get_size (const void *base) const
+  {
+    unsigned offset = (const char *) this - (const char *) base;
+    return (alignment - offset) & (alignment - 1);
+  }
+
+  public:
+  DEFINE_SIZE_MIN (0);
+};
+
+
+
 } /* namespace OT */
 
 
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 1e3e0be5106..ec018efe645 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
@@ -79,7 +79,7 @@ struct Dict : UnsizedByteStr
   {
     TRACE_SERIALIZE (this);
     for (unsigned int i = 0; i < dictval.get_count (); i++)
-      if (unlikely (!opszr.serialize (c, dictval[i], std::forward (ds)...)))
+      if (unlikely (!opszr.serialize (c, dictval[i], ds...)))
         return_trace (false);
 
     return_trace (true);
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
index 65d56ae18b5..bf56abb975c 100644
--- 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
@@ -30,396 +30,396 @@
 #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")
+HB_STR(".notdef")
+HB_STR("space")
+HB_STR("exclam")
+HB_STR("quotedbl")
+HB_STR("numbersign")
+HB_STR("dollar")
+HB_STR("percent")
+HB_STR("ampersand")
+HB_STR("quoteright")
+HB_STR("parenleft")
+HB_STR("parenright")
+HB_STR("asterisk")
+HB_STR("plus")
+HB_STR("comma")
+HB_STR("hyphen")
+HB_STR("period")
+HB_STR("slash")
+HB_STR("zero")
+HB_STR("one")
+HB_STR("two")
+HB_STR("three")
+HB_STR("four")
+HB_STR("five")
+HB_STR("six")
+HB_STR("seven")
+HB_STR("eight")
+HB_STR("nine")
+HB_STR("colon")
+HB_STR("semicolon")
+HB_STR("less")
+HB_STR("equal")
+HB_STR("greater")
+HB_STR("question")
+HB_STR("at")
+HB_STR("A")
+HB_STR("B")
+HB_STR("C")
+HB_STR("D")
+HB_STR("E")
+HB_STR("F")
+HB_STR("G")
+HB_STR("H")
+HB_STR("I")
+HB_STR("J")
+HB_STR("K")
+HB_STR("L")
+HB_STR("M")
+HB_STR("N")
+HB_STR("O")
+HB_STR("P")
+HB_STR("Q")
+HB_STR("R")
+HB_STR("S")
+HB_STR("T")
+HB_STR("U")
+HB_STR("V")
+HB_STR("W")
+HB_STR("X")
+HB_STR("Y")
+HB_STR("Z")
+HB_STR("bracketleft")
+HB_STR("backslash")
+HB_STR("bracketright")
+HB_STR("asciicircum")
+HB_STR("underscore")
+HB_STR("quoteleft")
+HB_STR("a")
+HB_STR("b")
+HB_STR("c")
+HB_STR("d")
+HB_STR("e")
+HB_STR("f")
+HB_STR("g")
+HB_STR("h")
+HB_STR("i")
+HB_STR("j")
+HB_STR("k")
+HB_STR("l")
+HB_STR("m")
+HB_STR("n")
+HB_STR("o")
+HB_STR("p")
+HB_STR("q")
+HB_STR("r")
+HB_STR("s")
+HB_STR("t")
+HB_STR("u")
+HB_STR("v")
+HB_STR("w")
+HB_STR("x")
+HB_STR("y")
+HB_STR("z")
+HB_STR("braceleft")
+HB_STR("bar")
+HB_STR("braceright")
+HB_STR("asciitilde")
+HB_STR("exclamdown")
+HB_STR("cent")
+HB_STR("sterling")
+HB_STR("fraction")
+HB_STR("yen")
+HB_STR("florin")
+HB_STR("section")
+HB_STR("currency")
+HB_STR("quotesingle")
+HB_STR("quotedblleft")
+HB_STR("guillemotleft")
+HB_STR("guilsinglleft")
+HB_STR("guilsinglright")
+HB_STR("fi")
+HB_STR("fl")
+HB_STR("endash")
+HB_STR("dagger")
+HB_STR("daggerdbl")
+HB_STR("periodcentered")
+HB_STR("paragraph")
+HB_STR("bullet")
+HB_STR("quotesinglbase")
+HB_STR("quotedblbase")
+HB_STR("quotedblright")
+HB_STR("guillemotright")
+HB_STR("ellipsis")
+HB_STR("perthousand")
+HB_STR("questiondown")
+HB_STR("grave")
+HB_STR("acute")
+HB_STR("circumflex")
+HB_STR("tilde")
+HB_STR("macron")
+HB_STR("breve")
+HB_STR("dotaccent")
+HB_STR("dieresis")
+HB_STR("ring")
+HB_STR("cedilla")
+HB_STR("hungarumlaut")
+HB_STR("ogonek")
+HB_STR("caron")
+HB_STR("emdash")
+HB_STR("AE")
+HB_STR("ordfeminine")
+HB_STR("Lslash")
+HB_STR("Oslash")
+HB_STR("OE")
+HB_STR("ordmasculine")
+HB_STR("ae")
+HB_STR("dotlessi")
+HB_STR("lslash")
+HB_STR("oslash")
+HB_STR("oe")
+HB_STR("germandbls")
+HB_STR("onesuperior")
+HB_STR("logicalnot")
+HB_STR("mu")
+HB_STR("trademark")
+HB_STR("Eth")
+HB_STR("onehalf")
+HB_STR("plusminus")
+HB_STR("Thorn")
+HB_STR("onequarter")
+HB_STR("divide")
+HB_STR("brokenbar")
+HB_STR("degree")
+HB_STR("thorn")
+HB_STR("threequarters")
+HB_STR("twosuperior")
+HB_STR("registered")
+HB_STR("minus")
+HB_STR("eth")
+HB_STR("multiply")
+HB_STR("threesuperior")
+HB_STR("copyright")
+HB_STR("Aacute")
+HB_STR("Acircumflex")
+HB_STR("Adieresis")
+HB_STR("Agrave")
+HB_STR("Aring")
+HB_STR("Atilde")
+HB_STR("Ccedilla")
+HB_STR("Eacute")
+HB_STR("Ecircumflex")
+HB_STR("Edieresis")
+HB_STR("Egrave")
+HB_STR("Iacute")
+HB_STR("Icircumflex")
+HB_STR("Idieresis")
+HB_STR("Igrave")
+HB_STR("Ntilde")
+HB_STR("Oacute")
+HB_STR("Ocircumflex")
+HB_STR("Odieresis")
+HB_STR("Ograve")
+HB_STR("Otilde")
+HB_STR("Scaron")
+HB_STR("Uacute")
+HB_STR("Ucircumflex")
+HB_STR("Udieresis")
+HB_STR("Ugrave")
+HB_STR("Yacute")
+HB_STR("Ydieresis")
+HB_STR("Zcaron")
+HB_STR("aacute")
+HB_STR("acircumflex")
+HB_STR("adieresis")
+HB_STR("agrave")
+HB_STR("aring")
+HB_STR("atilde")
+HB_STR("ccedilla")
+HB_STR("eacute")
+HB_STR("ecircumflex")
+HB_STR("edieresis")
+HB_STR("egrave")
+HB_STR("iacute")
+HB_STR("icircumflex")
+HB_STR("idieresis")
+HB_STR("igrave")
+HB_STR("ntilde")
+HB_STR("oacute")
+HB_STR("ocircumflex")
+HB_STR("odieresis")
+HB_STR("ograve")
+HB_STR("otilde")
+HB_STR("scaron")
+HB_STR("uacute")
+HB_STR("ucircumflex")
+HB_STR("udieresis")
+HB_STR("ugrave")
+HB_STR("yacute")
+HB_STR("ydieresis")
+HB_STR("zcaron")
+HB_STR("exclamsmall")
+HB_STR("Hungarumlautsmall")
+HB_STR("dollaroldstyle")
+HB_STR("dollarsuperior")
+HB_STR("ampersandsmall")
+HB_STR("Acutesmall")
+HB_STR("parenleftsuperior")
+HB_STR("parenrightsuperior")
+HB_STR("twodotenleader")
+HB_STR("onedotenleader")
+HB_STR("zerooldstyle")
+HB_STR("oneoldstyle")
+HB_STR("twooldstyle")
+HB_STR("threeoldstyle")
+HB_STR("fouroldstyle")
+HB_STR("fiveoldstyle")
+HB_STR("sixoldstyle")
+HB_STR("sevenoldstyle")
+HB_STR("eightoldstyle")
+HB_STR("nineoldstyle")
+HB_STR("commasuperior")
+HB_STR("threequartersemdash")
+HB_STR("periodsuperior")
+HB_STR("questionsmall")
+HB_STR("asuperior")
+HB_STR("bsuperior")
+HB_STR("centsuperior")
+HB_STR("dsuperior")
+HB_STR("esuperior")
+HB_STR("isuperior")
+HB_STR("lsuperior")
+HB_STR("msuperior")
+HB_STR("nsuperior")
+HB_STR("osuperior")
+HB_STR("rsuperior")
+HB_STR("ssuperior")
+HB_STR("tsuperior")
+HB_STR("ff")
+HB_STR("ffi")
+HB_STR("ffl")
+HB_STR("parenleftinferior")
+HB_STR("parenrightinferior")
+HB_STR("Circumflexsmall")
+HB_STR("hyphensuperior")
+HB_STR("Gravesmall")
+HB_STR("Asmall")
+HB_STR("Bsmall")
+HB_STR("Csmall")
+HB_STR("Dsmall")
+HB_STR("Esmall")
+HB_STR("Fsmall")
+HB_STR("Gsmall")
+HB_STR("Hsmall")
+HB_STR("Ismall")
+HB_STR("Jsmall")
+HB_STR("Ksmall")
+HB_STR("Lsmall")
+HB_STR("Msmall")
+HB_STR("Nsmall")
+HB_STR("Osmall")
+HB_STR("Psmall")
+HB_STR("Qsmall")
+HB_STR("Rsmall")
+HB_STR("Ssmall")
+HB_STR("Tsmall")
+HB_STR("Usmall")
+HB_STR("Vsmall")
+HB_STR("Wsmall")
+HB_STR("Xsmall")
+HB_STR("Ysmall")
+HB_STR("Zsmall")
+HB_STR("colonmonetary")
+HB_STR("onefitted")
+HB_STR("rupiah")
+HB_STR("Tildesmall")
+HB_STR("exclamdownsmall")
+HB_STR("centoldstyle")
+HB_STR("Lslashsmall")
+HB_STR("Scaronsmall")
+HB_STR("Zcaronsmall")
+HB_STR("Dieresissmall")
+HB_STR("Brevesmall")
+HB_STR("Caronsmall")
+HB_STR("Dotaccentsmall")
+HB_STR("Macronsmall")
+HB_STR("figuredash")
+HB_STR("hypheninferior")
+HB_STR("Ogoneksmall")
+HB_STR("Ringsmall")
+HB_STR("Cedillasmall")
+HB_STR("questiondownsmall")
+HB_STR("oneeighth")
+HB_STR("threeeighths")
+HB_STR("fiveeighths")
+HB_STR("seveneighths")
+HB_STR("onethird")
+HB_STR("twothirds")
+HB_STR("zerosuperior")
+HB_STR("foursuperior")
+HB_STR("fivesuperior")
+HB_STR("sixsuperior")
+HB_STR("sevensuperior")
+HB_STR("eightsuperior")
+HB_STR("ninesuperior")
+HB_STR("zeroinferior")
+HB_STR("oneinferior")
+HB_STR("twoinferior")
+HB_STR("threeinferior")
+HB_STR("fourinferior")
+HB_STR("fiveinferior")
+HB_STR("sixinferior")
+HB_STR("seveninferior")
+HB_STR("eightinferior")
+HB_STR("nineinferior")
+HB_STR("centinferior")
+HB_STR("dollarinferior")
+HB_STR("periodinferior")
+HB_STR("commainferior")
+HB_STR("Agravesmall")
+HB_STR("Aacutesmall")
+HB_STR("Acircumflexsmall")
+HB_STR("Atildesmall")
+HB_STR("Adieresissmall")
+HB_STR("Aringsmall")
+HB_STR("AEsmall")
+HB_STR("Ccedillasmall")
+HB_STR("Egravesmall")
+HB_STR("Eacutesmall")
+HB_STR("Ecircumflexsmall")
+HB_STR("Edieresissmall")
+HB_STR("Igravesmall")
+HB_STR("Iacutesmall")
+HB_STR("Icircumflexsmall")
+HB_STR("Idieresissmall")
+HB_STR("Ethsmall")
+HB_STR("Ntildesmall")
+HB_STR("Ogravesmall")
+HB_STR("Oacutesmall")
+HB_STR("Ocircumflexsmall")
+HB_STR("Otildesmall")
+HB_STR("Odieresissmall")
+HB_STR("OEsmall")
+HB_STR("Oslashsmall")
+HB_STR("Ugravesmall")
+HB_STR("Uacutesmall")
+HB_STR("Ucircumflexsmall")
+HB_STR("Udieresissmall")
+HB_STR("Yacutesmall")
+HB_STR("Thornsmall")
+HB_STR("Ydieresissmall")
+HB_STR("001.000")
+HB_STR("001.001")
+HB_STR("001.002")
+HB_STR("001.003")
+HB_STR("Black")
+HB_STR("Bold")
+HB_STR("Book")
+HB_STR("Light")
+HB_STR("Medium")
+HB_STR("Regular")
+HB_STR("Roman")
+HB_STR("Semibold")
 
 #endif /* HB_OT_CFF1_STD_STR_HH */
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 27c4d31b9ce..778167eeb23 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
@@ -326,7 +326,7 @@ struct Charset0
 
   void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const
   {
-    mapping->resize (num_glyphs, false);
+    mapping->resize_dirty  (num_glyphs);
     for (hb_codepoint_t gid = 1; gid < num_glyphs; gid++)
       mapping->arrayZ[gid] = {sids[gid - 1], gid};
   }
@@ -426,7 +426,7 @@ struct Charset1_2 {
 
   void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const
   {
-    mapping->resize (num_glyphs, false);
+    mapping->resize_dirty  (num_glyphs);
     hb_codepoint_t gid = 1;
     if (gid >= num_glyphs)
       return;
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 b2702106ecc..499bd942cde 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
@@ -202,7 +202,11 @@ struct cff2_cs_opset_path_t : cff2_cs_opset_tcoords, font->num_coords));
+  return get_path_at (font,
+                      glyph,
+                      draw_session,
+                      hb_array (font->coords,
+                                font->has_nonzero_coords ? font->num_coords : 0));
 }
 
 bool OT::cff2::accelerator_t::get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t coords) const
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 6bf37c062fc..93e9c0a2697 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
@@ -501,10 +501,6 @@ struct CmapSubtableFormat4
     this->length = c->length () - table_initpos;
     if ((long long) this->length != (long long) c->length () - table_initpos)
     {
-      // Length overflowed. Discard the current object before setting the error condition, otherwise
-      // discard is a noop which prevents the higher level code from reverting the serializer to the
-      // pre-error state in cmap4 overflow handling code.
-      c->pop_discard ();
       c->err (HB_SERIALIZE_ERROR_INT_OVERFLOW);
       return;
     }
@@ -701,16 +697,7 @@ struct CmapSubtableFormat4
     hb_barrier ();
 
     if (unlikely (!c->check_range (this, length)))
-    {
-      /* 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) hb_min ((uintptr_t) 65535,
-                                               (uintptr_t) (c->end -
-                                                            (char *) this));
-      if (!c->try_set (&length, new_length))
-        return_trace (false);
-    }
+      return_trace (false);
 
     return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
   }
@@ -1500,7 +1487,7 @@ struct CmapSubtable
   bool get_glyph (hb_codepoint_t codepoint,
                   hb_codepoint_t *glyph) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case  0: hb_barrier (); return u.format0 .get_glyph (codepoint, glyph);
     case  4: hb_barrier (); return u.format4 .get_glyph (codepoint, glyph);
     case  6: hb_barrier (); return u.format6 .get_glyph (codepoint, glyph);
@@ -1513,7 +1500,7 @@ struct CmapSubtable
   }
   void collect_unicodes (hb_set_t *out, unsigned int num_glyphs = UINT_MAX) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case  0: hb_barrier (); u.format0 .collect_unicodes (out); return;
     case  4: hb_barrier (); u.format4 .collect_unicodes (out); return;
     case  6: hb_barrier (); u.format6 .collect_unicodes (out); return;
@@ -1529,7 +1516,7 @@ struct CmapSubtable
                         hb_map_t *mapping, /* OUT */
                         unsigned num_glyphs = UINT_MAX) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case  0: hb_barrier (); u.format0 .collect_mapping (unicodes, mapping); return;
     case  4: hb_barrier (); u.format4 .collect_mapping (unicodes, mapping); return;
     case  6: hb_barrier (); u.format6 .collect_mapping (unicodes, mapping); return;
@@ -1543,7 +1530,7 @@ struct CmapSubtable
 
   unsigned get_language () const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case  0: hb_barrier (); return u.format0 .get_language ();
     case  4: hb_barrier (); return u.format4 .get_language ();
     case  6: hb_barrier (); return u.format6 .get_language ();
@@ -1574,9 +1561,9 @@ struct CmapSubtable
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return_trace (false);
+    if (!u.format.v.sanitize (c)) return_trace (false);
     hb_barrier ();
-    switch (u.format) {
+    switch (u.format.v) {
     case  0: hb_barrier (); return_trace (u.format0 .sanitize (c));
     case  4: hb_barrier (); return_trace (u.format4 .sanitize (c));
     case  6: hb_barrier (); return_trace (u.format6 .sanitize (c));
@@ -1590,7 +1577,7 @@ struct CmapSubtable
 
   public:
   union {
-  HBUINT16              format;         /* Format identifier */
+  struct { HBUINT16 v; }        format;         /* Format identifier */
   CmapSubtableFormat0   format0;
   CmapSubtableFormat4   format4;
   CmapSubtableFormat6   format6;
@@ -1600,7 +1587,7 @@ struct CmapSubtable
   CmapSubtableFormat14  format14;
   } u;
   public:
-  DEFINE_SIZE_UNION (2, format);
+  DEFINE_SIZE_UNION (2, format.v);
 };
 
 
@@ -1646,7 +1633,7 @@ struct EncodingRecord
       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 ();
+      if (c->length () - origin_length > 0 && !c->in_error()) *objidx = c->pop_pack ();
       else c->pop_discard ();
     }
 
@@ -1683,6 +1670,10 @@ struct SubtableUnicodesCache {
   {
     SubtableUnicodesCache* cache =
         (SubtableUnicodesCache*) hb_malloc (sizeof(SubtableUnicodesCache));
+
+    if (unlikely (!cache))
+      return nullptr;
+
     new (cache) SubtableUnicodesCache (source_table);
     return cache;
   }
@@ -1776,6 +1767,10 @@ struct cmap
     ;
 
     SubtableUnicodesCache* cache = SubtableUnicodesCache::create(source_table);
+
+    if (unlikely (!cache))
+      return nullptr;
+
     for (const EncodingRecord& _ : it)
       cache->set_for(&_); // populate the cache for this encoding record.
 
@@ -1810,7 +1805,7 @@ struct cmap
       if (c->in_error ())
         return false;
 
-      unsigned format = (base+_.subtable).u.format;
+      unsigned format = (base+_.subtable).u.format.v;
       if (format != 4 && format != 12 && format != 14) continue;
 
       const hb_set_t* unicodes_set = unicodes_cache->set_for (&_, local_unicodes_cache);
@@ -1912,7 +1907,7 @@ struct cmap
     + hb_iter (encodingRecord)
     | hb_map (&EncodingRecord::subtable)
     | hb_map (hb_add (this))
-    | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == 14; })
+    | hb_filter ([&] (const CmapSubtable& _) { return _.u.format.v == 14; })
     | hb_apply ([=] (const CmapSubtable& _) { _.u.format14.closure_glyphs (unicodes, glyphset); })
     ;
   }
@@ -1937,7 +1932,7 @@ struct cmap
 
     for (const EncodingRecord& _ : encodingrec_iter)
     {
-      unsigned format = (this + _.subtable).u.format;
+      unsigned format = (this + _.subtable).u.format.v;
       if (format == 12) has_format12 = true;
 
       const EncodingRecord *table = std::addressof (_);
@@ -2025,7 +2020,7 @@ struct cmap
       this->subtable_uvs = &Null (CmapSubtableFormat14);
       {
         const CmapSubtable *st = table->find_subtable (0, 5);
-        if (st && st->u.format == 14)
+        if (st && st->u.format.v == 14)
           subtable_uvs = &st->u.format14;
       }
 
@@ -2069,7 +2064,7 @@ struct cmap
       else
 #endif
       {
-        switch (subtable->u.format) {
+        switch (subtable->u.format.v) {
           /* Accelerate format 4 and format 12. */
           default:
             this->get_glyph_funcZ = get_glyph_from;
@@ -2276,7 +2271,7 @@ struct cmap
         (_.platformID == 0 && _.encodingID == 4) ||
         (_.platformID == 3 && _.encodingID == 1) ||
         (_.platformID == 3 && _.encodingID == 10) ||
-        (cmap + _.subtable).u.format == 14;
+        (cmap + _.subtable).u.format.v == 14;
   }
 
   protected:
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 0238bb346a9..8add9209f37 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc
@@ -37,6 +37,7 @@
 
 #include "hb-ot-cmap-table.hh"
 #include "hb-ot-glyf-table.hh"
+#include "hb-ot-var-gvar-table.hh"
 #include "hb-ot-cff2-table.hh"
 #include "hb-ot-cff1-table.hh"
 #include "hb-ot-hmtx-table.hh"
@@ -64,18 +65,22 @@
 using hb_ot_font_advance_cache_t = hb_cache_t<24, 16>;
 static_assert (sizeof (hb_ot_font_advance_cache_t) == 1024, "");
 
+using hb_ot_font_origin_cache_t = hb_cache_t<20, 20>;
+static_assert (sizeof (hb_ot_font_origin_cache_t) == 1024, "");
+
 struct hb_ot_font_t
 {
   const hb_ot_face_t *ot_face;
 
-  /* h_advance caching */
+  mutable hb_atomic_t cached_serial;
   mutable hb_atomic_t cached_coords_serial;
-  struct advance_cache_t
+
+  struct direction_cache_t
   {
     mutable hb_atomic_t advance_cache;
-    mutable hb_atomic_t varStore_cache;
+    mutable hb_atomic_t varStore_cache;
 
-    ~advance_cache_t ()
+    ~direction_cache_t ()
     {
       clear ();
     }
@@ -116,7 +121,7 @@ struct hb_ot_font_t
         goto retry;
     }
 
-    OT::ItemVariationStore::cache_t *acquire_varStore_cache (const OT::ItemVariationStore &varStore) const
+    OT::hb_scalar_cache_t *acquire_varStore_cache (const OT::ItemVariationStore &varStore) const
     {
     retry:
       auto *cache = varStore_cache.get_acquire ();
@@ -127,7 +132,7 @@ struct hb_ot_font_t
       else
         goto retry;
     }
-    void release_varStore_cache (OT::ItemVariationStore::cache_t *cache) const
+    void release_varStore_cache (OT::hb_scalar_cache_t *cache) const
     {
       if (!cache)
         return;
@@ -154,17 +159,157 @@ struct hb_ot_font_t
 
   } h, v;
 
+  struct origin_cache_t
+  {
+    mutable hb_atomic_t origin_cache;
+    mutable hb_atomic_t varStore_cache;
+
+    ~origin_cache_t ()
+    {
+      clear ();
+    }
+
+    hb_ot_font_origin_cache_t *acquire_origin_cache () const
+    {
+    retry:
+      auto *cache = origin_cache.get_acquire ();
+      if (!cache)
+      {
+        cache = (hb_ot_font_origin_cache_t *) hb_malloc (sizeof (hb_ot_font_origin_cache_t));
+        if (!cache)
+          return nullptr;
+        new (cache) hb_ot_font_origin_cache_t;
+        return cache;
+      }
+      if (origin_cache.cmpexch (cache, nullptr))
+        return cache;
+      else
+        goto retry;
+    }
+    void release_origin_cache (hb_ot_font_origin_cache_t *cache) const
+    {
+      if (!cache)
+        return;
+      if (!origin_cache.cmpexch (nullptr, cache))
+        hb_free (cache);
+    }
+    void clear_origin_cache () const
+    {
+    retry:
+      auto *cache = origin_cache.get_acquire ();
+      if (!cache)
+        return;
+      if (origin_cache.cmpexch (cache, nullptr))
+        hb_free (cache);
+      else
+        goto retry;
+    }
+
+    OT::hb_scalar_cache_t *acquire_varStore_cache (const OT::ItemVariationStore &varStore) const
+    {
+    retry:
+      auto *cache = varStore_cache.get_acquire ();
+      if (!cache)
+        return varStore.create_cache ();
+      if (varStore_cache.cmpexch (cache, nullptr))
+        return cache;
+      else
+        goto retry;
+    }
+    void release_varStore_cache (OT::hb_scalar_cache_t *cache) const
+    {
+      if (!cache)
+        return;
+      if (!varStore_cache.cmpexch (nullptr, cache))
+        OT::ItemVariationStore::destroy_cache (cache);
+    }
+    void clear_varStore_cache () const
+    {
+    retry:
+      auto *cache = varStore_cache.get_acquire ();
+      if (!cache)
+        return;
+      if (varStore_cache.cmpexch (cache, nullptr))
+        OT::ItemVariationStore::destroy_cache (cache);
+      else
+        goto retry;
+    }
+
+    void clear () const
+    {
+      clear_origin_cache ();
+      clear_varStore_cache ();
+    }
+  } v_origin;
+
+  struct draw_cache_t
+  {
+    mutable hb_atomic_t gvar_cache;
+
+    ~draw_cache_t ()
+    {
+      clear ();
+    }
+
+    OT::hb_scalar_cache_t *acquire_gvar_cache (const OT::gvar_accelerator_t &gvar) const
+    {
+    retry:
+      auto *cache = gvar_cache.get_acquire ();
+      if (!cache)
+        return gvar.create_cache ();
+      if (gvar_cache.cmpexch (cache, nullptr))
+        return cache;
+      else
+        goto retry;
+    }
+    void release_gvar_cache (OT::hb_scalar_cache_t *cache) const
+    {
+      if (!cache)
+        return;
+      if (!gvar_cache.cmpexch (nullptr, cache))
+        OT::gvar_accelerator_t::destroy_cache (cache);
+    }
+    void clear_gvar_cache () const
+    {
+    retry:
+      auto *cache = gvar_cache.get_acquire ();
+      if (!cache)
+        return;
+      if (gvar_cache.cmpexch (cache, nullptr))
+        OT::gvar_accelerator_t::destroy_cache (cache);
+      else
+        goto retry;
+    }
+
+    void clear () const
+    {
+      clear_gvar_cache ();
+    }
+  } draw;
+
   void check_serial (hb_font_t *font) const
   {
     int font_serial = font->serial_coords.get_acquire ();
+    if (cached_serial.get_acquire () != font_serial)
+    {
+      /* These caches are dependent on scale and synthetic settings.
+       * Any change to the font invalidates them. */
+      v_origin.clear ();
 
-    if (cached_coords_serial.get_acquire () == font_serial)
-      return;
+      cached_serial.set_release (font_serial);
+    }
 
-    h.clear ();
-    v.clear ();
+    int font_serial_coords = font->serial_coords.get_acquire ();
+    if (cached_coords_serial.get_acquire () != font_serial_coords)
+    {
+      /* These caches are independent of scale or synthetic settings.
+       * Just variation changes will invalidate them. */
+      h.clear ();
+      v.clear ();
+      draw.clear ();
 
-    cached_coords_serial.set_release (font_serial);
+      cached_coords_serial.set_release (font_serial_coords);
+    }
   }
 };
 
@@ -242,37 +387,92 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
                             unsigned advance_stride,
                             void *user_data HB_UNUSED)
 {
+  // Duplicated in v_advances. Ugly. Keep in sync'ish.
 
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   const hb_ot_face_t *ot_face = ot_font->ot_face;
   const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
 
-  ot_font->check_serial (font);
-  const OT::HVAR &HVAR = *hmtx.var_table;
-  const OT::ItemVariationStore &varStore = &HVAR + HVAR.varStore;
-  OT::ItemVariationStore::cache_t *varStore_cache = ot_font->h.acquire_varStore_cache (varStore);
+  if (unlikely (!hmtx.has_data ()))
+  {
+    hb_position_t advance = font->face->get_upem () / 2;
+    advance = font->em_scale_x (advance);
+    for (unsigned int i = 0; i < count; i++)
+    {
+      *first_advance = advance;
+      first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride);
+    }
+    return;
+  }
 
-  hb_ot_font_advance_cache_t *advance_cache = nullptr;
+#ifndef HB_NO_VAR
+  if (!font->has_nonzero_coords)
+  {
+  fallback:
+#else
+  {
+#endif
+    // Just plain htmx data. No need to cache.
+    for (unsigned int i = 0; i < count; i++)
+    {
+      *first_advance = font->em_scale_x (hmtx.get_advance_without_var_unscaled (*first_glyph));
+      first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride);
+      first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride);
+    }
+    return;
+  }
 
-  bool use_cache = font->num_coords;
-  if (use_cache)
+#ifndef HB_NO_VAR
+  /* has_nonzero_coords. */
+
+  ot_font->check_serial (font);
+  hb_ot_font_advance_cache_t *advance_cache = ot_font->h.acquire_advance_cache ();
+  if (!advance_cache)
   {
-    advance_cache = ot_font->h.acquire_advance_cache ();
-    if (!advance_cache)
-      use_cache = false;
+    // malloc failure. Just use the fallback non-variable path.
+    goto fallback;
   }
 
-  if (!use_cache)
+  /* If HVAR is present, use it.*/
+  const OT::HVAR &HVAR = *hmtx.var_table;
+  if (HVAR.has_data ())
   {
+    const OT::ItemVariationStore &varStore = &HVAR + HVAR.varStore;
+    OT::hb_scalar_cache_t *varStore_cache = ot_font->h.acquire_varStore_cache (varStore);
+
     for (unsigned int i = 0; i < count; i++)
     {
-      *first_advance = font->em_scale_x (hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache));
+      hb_position_t v;
+      unsigned cv;
+      if (advance_cache->get (*first_glyph, &cv))
+        v = cv;
+      else
+      {
+        v = hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache);
+        advance_cache->set (*first_glyph, v);
+      }
+      *first_advance = font->em_scale_x (v);
       first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride);
       first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride);
     }
+
+    ot_font->h.release_varStore_cache (varStore_cache);
+    ot_font->h.release_advance_cache (advance_cache);
+    return;
   }
-  else
-  { /* Use cache. */
+
+  const auto &gvar = *ot_face->gvar;
+  if (gvar.has_data ())
+  {
+    const auto &glyf = *ot_face->glyf;
+    auto *scratch = glyf.acquire_scratch ();
+    if (unlikely (!scratch))
+    {
+      ot_font->h.release_advance_cache (advance_cache);
+      goto fallback;
+    }
+    OT::hb_scalar_cache_t *gvar_cache = ot_font->draw.acquire_gvar_cache (gvar);
+
     for (unsigned int i = 0; i < count; i++)
     {
       hb_position_t v;
@@ -281,7 +481,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
         v = cv;
       else
       {
-        v = hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache);
+        v = glyf.get_advance_with_var_unscaled (*first_glyph, font, false, *scratch, gvar_cache);
         advance_cache->set (*first_glyph, v);
       }
       *first_advance = font->em_scale_x (v);
@@ -289,10 +489,16 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
       first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride);
     }
 
+    ot_font->draw.release_gvar_cache (gvar_cache);
+    glyf.release_scratch (scratch);
     ot_font->h.release_advance_cache (advance_cache);
+    return;
   }
 
-  ot_font->h.release_varStore_cache (varStore_cache);
+  ot_font->h.release_advance_cache (advance_cache);
+  // No HVAR or GVAR.  Just use the fallback non-variable path.
+  goto fallback;
+#endif
 }
 
 #ifndef HB_NO_VERTICAL
@@ -305,99 +511,290 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
                             unsigned advance_stride,
                             void *user_data HB_UNUSED)
 {
+  // Duplicated from h_advances. Ugly. Keep in sync'ish.
+
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   const hb_ot_face_t *ot_face = ot_font->ot_face;
   const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
 
-  if (vmtx.has_data ())
+  if (unlikely (!vmtx.has_data ()))
+  {
+    hb_font_extents_t font_extents;
+    font->get_h_extents_with_fallback (&font_extents);
+    hb_position_t advance = font_extents.descender - font_extents.ascender;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      *first_advance = advance;
+      first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride);
+    }
+    return;
+  }
+
+#ifndef HB_NO_VAR
+  if (!font->has_nonzero_coords)
+  {
+  fallback:
+#else
+  {
+#endif
+    // Just plain vtmx data. No need to cache.
+    for (unsigned int i = 0; i < count; i++)
+    {
+      *first_advance = font->em_scale_y (- (int) vmtx.get_advance_without_var_unscaled (*first_glyph));
+      first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride);
+      first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride);
+    }
+    return;
+  }
+
+#ifndef HB_NO_VAR
+  /* has_nonzero_coords. */
+
+  ot_font->check_serial (font);
+  hb_ot_font_advance_cache_t *advance_cache = ot_font->v.acquire_advance_cache ();
+  if (!advance_cache)
+  {
+    // malloc failure. Just use the fallback non-variable path.
+    goto fallback;
+  }
+
+  /* If VVAR is present, use it.*/
+  const OT::VVAR &VVAR = *vmtx.var_table;
+  if (VVAR.has_data ())
   {
-    ot_font->check_serial (font);
-    const OT::VVAR &VVAR = *vmtx.var_table;
     const OT::ItemVariationStore &varStore = &VVAR + VVAR.varStore;
-    OT::ItemVariationStore::cache_t *varStore_cache = ot_font->v.acquire_varStore_cache (varStore);
-    // TODO Use advance_cache.
+    OT::hb_scalar_cache_t *varStore_cache = ot_font->v.acquire_varStore_cache (varStore);
 
     for (unsigned int i = 0; i < count; i++)
     {
-      *first_advance = font->em_scale_y (-(int) vmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache));
+      hb_position_t v;
+      unsigned cv;
+      if (advance_cache->get (*first_glyph, &cv))
+        v = cv;
+      else
+      {
+        v = vmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache);
+        advance_cache->set (*first_glyph, v);
+      }
+      *first_advance = font->em_scale_y (- (int) v);
       first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride);
       first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride);
     }
 
     ot_font->v.release_varStore_cache (varStore_cache);
+    ot_font->v.release_advance_cache (advance_cache);
+    return;
   }
-  else
+
+  const auto &gvar = *ot_face->gvar;
+  if (gvar.has_data ())
   {
-    hb_font_extents_t font_extents;
-    font->get_h_extents_with_fallback (&font_extents);
-    hb_position_t advance = -(font_extents.ascender - font_extents.descender);
+    const auto &glyf = *ot_face->glyf;
+    auto *scratch = glyf.acquire_scratch ();
+    if (unlikely (!scratch))
+    {
+      ot_font->v.release_advance_cache (advance_cache);
+      goto fallback;
+    }
+    OT::hb_scalar_cache_t *gvar_cache = ot_font->draw.acquire_gvar_cache (gvar);
 
     for (unsigned int i = 0; i < count; i++)
     {
-      *first_advance = advance;
+      hb_position_t v;
+      unsigned cv;
+      if (advance_cache->get (*first_glyph, &cv))
+        v = cv;
+      else
+      {
+        v = glyf.get_advance_with_var_unscaled (*first_glyph, font, true, *scratch, gvar_cache);
+        advance_cache->set (*first_glyph, v);
+      }
+      *first_advance = font->em_scale_y (- (int) v);
       first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride);
       first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride);
     }
+
+    ot_font->draw.release_gvar_cache (gvar_cache);
+    glyf.release_scratch (scratch);
+    ot_font->v.release_advance_cache (advance_cache);
+    return;
   }
+
+  ot_font->v.release_advance_cache (advance_cache);
+  // No VVAR or GVAR.  Just use the fallback non-variable path.
+  goto fallback;
+#endif
 }
 #endif
 
 #ifndef HB_NO_VERTICAL
+HB_HOT
 static hb_bool_t
-hb_ot_get_glyph_v_origin (hb_font_t *font,
-                          void *font_data,
-                          hb_codepoint_t glyph,
-                          hb_position_t *x,
-                          hb_position_t *y,
-                          void *user_data HB_UNUSED)
+hb_ot_get_glyph_v_origins (hb_font_t *font,
+                           void *font_data,
+                           unsigned int count,
+                           const hb_codepoint_t *first_glyph,
+                           unsigned glyph_stride,
+                           hb_position_t *first_x,
+                           unsigned x_stride,
+                           hb_position_t *first_y,
+                           unsigned y_stride,
+                           void *user_data HB_UNUSED)
 {
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   const hb_ot_face_t *ot_face = ot_font->ot_face;
 
-  *x = font->get_glyph_h_advance (glyph) / 2;
+  /* First, set all the x values to half the advance width. */
+  font->get_glyph_h_advances (count,
+                              first_glyph, glyph_stride,
+                              first_x, x_stride);
+  for (unsigned i = 0; i < count; i++)
+  {
+    *first_x /= 2;
+    first_x = &StructAtOffsetUnaligned (first_x, x_stride);
+  }
+
+  /* The vertical origin business is messy...
+   *
+   * We allocate the cache, then have various code paths that use the cache.
+   * Each one is responsible to free it before returning.
+   */
+  hb_ot_font_origin_cache_t *origin_cache = ot_font->v_origin.acquire_origin_cache ();
 
+  /* If there is VORG, always use it. It uses VVAR for variations if necessary. */
   const OT::VORG &VORG = *ot_face->VORG;
-  if (VORG.has_data ())
+  if (origin_cache && VORG.has_data ())
   {
-    float delta = 0;
-
 #ifndef HB_NO_VAR
-    const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
-    const OT::VVAR &VVAR = *vmtx.var_table;
-    if (font->num_coords)
-      VVAR.get_vorg_delta_unscaled (glyph,
-                                    font->coords, font->num_coords,
-                                    &delta);
+    if (!font->has_nonzero_coords)
 #endif
-
-    *y = font->em_scalef_y (VORG.get_y_origin (glyph) + delta);
+    {
+      for (unsigned i = 0; i < count; i++)
+      {
+        hb_position_t origin;
+        unsigned cv;
+        if (origin_cache->get (*first_glyph, &cv))
+          origin = font->y_scale < 0 ? -static_cast(cv) : static_cast(cv);
+        else
+        {
+          origin = font->em_scalef_y (VORG.get_y_origin (*first_glyph));
+          origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin);
+        }
+
+        *first_y = origin;
+
+        first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride);
+        first_y = &StructAtOffsetUnaligned (first_y, y_stride);
+      }
+    }
+#ifndef HB_NO_VAR
+    else
+    {
+      const OT::VVAR &VVAR = *ot_face->vmtx->var_table;
+      const auto &varStore = &VVAR + VVAR.varStore;
+      auto *varStore_cache = ot_font->v_origin.acquire_varStore_cache (varStore);
+      for (unsigned i = 0; i < count; i++)
+      {
+        hb_position_t origin;
+        unsigned cv;
+        if (origin_cache->get (*first_glyph, &cv))
+          origin = font->y_scale < 0 ? -static_cast(cv) : static_cast(cv);
+        else
+        {
+          origin = font->em_scalef_y (VORG.get_y_origin (*first_glyph) +
+                                      VVAR.get_vorg_delta_unscaled (*first_glyph,
+                                                                    font->coords, font->num_coords,
+                                                                    varStore_cache));
+          origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin);
+        }
+
+        *first_y = origin;
+
+        first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride);
+        first_y = &StructAtOffsetUnaligned (first_y, y_stride);
+      }
+      ot_font->v_origin.release_varStore_cache (varStore_cache);
+    }
+#endif
+    ot_font->v_origin.release_origin_cache (origin_cache);
     return true;
   }
 
-  hb_glyph_extents_t extents = {0};
-
-  if (hb_font_get_glyph_extents (font, glyph, &extents))
+  /* If and only if `vmtx` is present and it's a `glyf` font,
+   * we use the top phantom point, deduced from vmtx,glyf[,gvar]. */
+  const auto &vmtx = *ot_face->vmtx;
+  const auto &glyf = *ot_face->glyf;
+  if (origin_cache && vmtx.has_data() && glyf.has_data ())
   {
-    const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
-    int tsb = 0;
-    if (vmtx.get_leading_bearing_with_var_unscaled (font, glyph, &tsb))
+    auto *scratch = glyf.acquire_scratch ();
+    if (unlikely (!scratch))
     {
-      *y = extents.y_bearing + font->em_scale_y (tsb);
-      return true;
+      ot_font->v_origin.release_origin_cache (origin_cache);
+      return false;
     }
+    OT::hb_scalar_cache_t *gvar_cache = font->has_nonzero_coords ?
+                                        ot_font->draw.acquire_gvar_cache (*ot_face->gvar) :
+                                        nullptr;
 
-    hb_font_extents_t font_extents;
-    font->get_h_extents_with_fallback (&font_extents);
-    hb_position_t advance = font_extents.ascender - font_extents.descender;
-    hb_position_t diff = advance - -extents.height;
-    *y = extents.y_bearing + (diff >> 1);
+    for (unsigned i = 0; i < count; i++)
+    {
+      hb_position_t origin;
+      unsigned cv;
+      if (origin_cache->get (*first_glyph, &cv))
+        origin = font->y_scale < 0 ? -static_cast(cv) : static_cast(cv);
+      else
+      {
+        origin = font->em_scalef_y (glyf.get_v_origin_with_var_unscaled (*first_glyph, font, *scratch, gvar_cache));
+        origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin);
+      }
+
+      *first_y = origin;
+
+      first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride);
+      first_y = &StructAtOffsetUnaligned (first_y, y_stride);
+    }
+
+    if (gvar_cache)
+      ot_font->draw.release_gvar_cache (gvar_cache);
+    glyf.release_scratch (scratch);
+    ot_font->v_origin.release_origin_cache (origin_cache);
     return true;
   }
 
-  hb_font_extents_t font_extents;
-  font->get_h_extents_with_fallback (&font_extents);
-  *y = font_extents.ascender;
+  /* Otherwise, use glyph extents to center the glyph vertically.
+   * If getting glyph extents failed, just use the font ascender. */
+  if (origin_cache && font->has_glyph_extents_func ())
+  {
+    hb_font_extents_t font_extents;
+    font->get_h_extents_with_fallback (&font_extents);
+    hb_position_t font_advance = font_extents.ascender - font_extents.descender;
+
+    for (unsigned i = 0; i < count; i++)
+    {
+      hb_position_t origin;
+      unsigned cv;
+
+      if (origin_cache->get (*first_glyph, &cv))
+        origin = font->y_scale < 0 ? -static_cast(cv) : static_cast(cv);
+      else
+      {
+        hb_glyph_extents_t extents = {0};
+        if (likely (font->get_glyph_extents (*first_glyph, &extents)))
+          origin = extents.y_bearing + ((font_advance - -extents.height) >> 1);
+        else
+          origin = font_extents.ascender;
+
+        origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin);
+      }
 
+      *first_y = origin;
+
+      first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride);
+      first_y = &StructAtOffsetUnaligned (first_y, y_stride);
+    }
+  }
+
+  ot_font->v_origin.release_origin_cache (origin_cache);
   return true;
 }
 #endif
@@ -498,17 +895,33 @@ hb_ot_draw_glyph_or_fail (hb_font_t *font,
                           hb_draw_funcs_t *draw_funcs, void *draw_data,
                           void *user_data)
 {
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   hb_draw_session_t draw_session {draw_funcs, draw_data};
+  bool ret = false;
+
+  OT::hb_scalar_cache_t *gvar_cache = nullptr;
+  if (font->num_coords)
+  {
+    ot_font->check_serial (font);
+    gvar_cache = ot_font->draw.acquire_gvar_cache (*ot_font->ot_face->gvar);
+  }
+
 #ifndef HB_NO_VAR_COMPOSITES
-  if (font->face->table.VARC->get_path (font, glyph, draw_session)) return true;
+  if (font->face->table.VARC->get_path (font, glyph, draw_session)) { ret = true; goto done; }
 #endif
   // Keep the following in synch with VARC::get_path_at()
-  if (font->face->table.glyf->get_path (font, glyph, draw_session)) return true;
+  if (font->face->table.glyf->get_path (font, glyph, draw_session, gvar_cache)) { ret = true; goto done; }
+
 #ifndef HB_NO_CFF
-  if (font->face->table.cff2->get_path (font, glyph, draw_session)) return true;
-  if (font->face->table.cff1->get_path (font, glyph, draw_session)) return true;
+  if (font->face->table.cff2->get_path (font, glyph, draw_session)) { ret = true; goto done; }
+  if (font->face->table.cff1->get_path (font, glyph, draw_session)) { ret = true; goto done; }
 #endif
-  return false;
+
+done:
+
+  ot_font->draw.release_gvar_cache (gvar_cache);
+
+  return ret;
 }
 #endif
 
@@ -548,12 +961,11 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_tplan->new_to_old_gid_list)
-    | hb_map ([c, &_mtx, mtx_map] (hb_codepoint_pair_t _)
+    | hb_map ([&_mtx, mtx_map] (hb_codepoint_pair_t _)
               {
                 hb_codepoint_t new_gid = _.first;
                 hb_codepoint_t old_gid = _.second;
@@ -246,8 +236,7 @@ struct hmtxvmtx
                 if (!mtx_map->has (new_gid, &v))
                 {
                   int lsb = 0;
-                  if (!_mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb))
-                    (void) _glyf_get_leading_bearing_without_var_unscaled (c->plan->source, old_gid, !T::is_horizontal, &lsb);
+                  _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb);
                   return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
                 }
                 return *v;
@@ -326,49 +315,23 @@ struct hmtxvmtx
 
     bool has_data () const { return (bool) num_bearings; }
 
-    bool get_leading_bearing_without_var_unscaled (hb_codepoint_t glyph,
+    void get_leading_bearing_without_var_unscaled (hb_codepoint_t glyph,
                                                    int *lsb) const
     {
       if (glyph < num_long_metrics)
       {
         *lsb = table->longMetricZ[glyph].sb;
-        return true;
+        return;
       }
 
       if (unlikely (glyph >= num_bearings))
-        return false;
-
-      const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
-      *lsb = bearings[glyph - num_long_metrics];
-      return true;
-    }
-
-    bool get_leading_bearing_with_var_unscaled (hb_font_t *font,
-                                                hb_codepoint_t glyph,
-                                                int *lsb) const
-    {
-      if (!font->num_coords)
-        return get_leading_bearing_without_var_unscaled (glyph, lsb);
-
-#ifndef HB_NO_VAR
-      float delta;
-      if (var_table->get_lsb_delta_unscaled (glyph, font->coords, font->num_coords, &delta) &&
-          get_leading_bearing_without_var_unscaled (glyph, lsb))
       {
-        *lsb += roundf (delta);
-        return true;
+        *lsb = 0;
+        return;
       }
 
-      // If there's no vmtx data, the phantom points from glyf table are not accurate,
-      // so we cannot take the next path.
-      bool is_vertical = T::tableTag == HB_OT_TAG_vmtx;
-      if (is_vertical && !has_data ())
-        return false;
-
-      return _glyf_get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb);
-#else
-      return false;
-#endif
+      const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
+      *lsb = bearings[glyph - num_long_metrics];
     }
 
     unsigned int get_advance_without_var_unscaled (hb_codepoint_t glyph) const
@@ -402,27 +365,17 @@ struct hmtxvmtx
       return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)];
     }
 
-    unsigned get_advance_with_var_unscaled (hb_codepoint_t  glyph,
-                                            hb_font_t      *font,
-                                            ItemVariationStore::cache_t *store_cache = nullptr) const
+#ifndef HB_NO_VAR
+    unsigned get_advance_with_var_unscaled (hb_codepoint_t     glyph,
+                                            hb_font_t         *font,
+                                            hb_scalar_cache_t *store_cache = nullptr) const
     {
       unsigned int advance = get_advance_without_var_unscaled (glyph);
-
-#ifndef HB_NO_VAR
-      if (unlikely (glyph >= num_bearings) || !font->num_coords)
-        return advance;
-
-      if (var_table.get_length ())
-        return advance + roundf (var_table->get_advance_delta_unscaled (glyph,
-                                                                        font->coords, font->num_coords,
-                                                                        store_cache));
-
-      unsigned glyf_advance = _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
-      return glyf_advance ? glyf_advance : advance;
-#else
-      return advance;
-#endif
+      return hb_max(0.0f, advance + roundf (var_table->get_advance_delta_unscaled (glyph,
+                                                                      font->coords, font->num_coords,
+                                                                      store_cache)));
     }
+#endif
 
     protected:
     // 0 <= num_long_metrics <= num_bearings <= num_advances <= num_glyphs
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 97d012e58b8..42326adcad2 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
@@ -90,11 +90,11 @@ struct KernSubTableFormat3
   template 
   void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
   {
-    set_t set;
     if (likely (glyphCount))
-      set.add_range (0, glyphCount - 1);
-    left_set.union_ (set);
-    right_set.union_ (set);
+    {
+      left_set.add_range (0, num_glyphs - 1);
+      right_set.add_range (0, num_glyphs - 1);
+    }
   }
 
   protected:
@@ -306,8 +306,8 @@ struct kern
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
 
-  bool     has_data () const { return u.version32; }
-  unsigned get_type () const { return u.major; }
+  bool     has_data () const { return u.version32.v; }
+  unsigned get_type () const { return u.major.v; }
 
   bool has_state_machine () const
   {
@@ -363,7 +363,7 @@ struct kern
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!u.version32.sanitize (c)) return_trace (false);
+    if (!u.version32.v.sanitize (c)) return_trace (false);
     hb_barrier ();
     return_trace (dispatch (c));
   }
@@ -406,15 +406,15 @@ struct kern
 
   protected:
   union {
-  HBUINT32              version32;
-  HBUINT16              major;
+  struct { HBUINT32 v; }        version32;
+  struct { HBUINT16 v; }        major;
   KernOT                ot;
 #ifndef HB_NO_AAT_SHAPE
   KernAAT               aat;
 #endif
   } u;
   public:
-  DEFINE_SIZE_UNION (4, version32);
+  DEFINE_SIZE_UNION (4, version32.v);
 };
 
 struct kern_accelerator_t : kern::accelerator_t {
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 04a79a93a89..b9baaca2a23 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
@@ -165,13 +165,13 @@ struct BaseCoordFormat3
 
 struct BaseCoord
 {
-  bool has_data () const { return u.format; }
+  bool has_data () const { return u.format.v; }
 
   hb_position_t get_coord (hb_font_t            *font,
                            const ItemVariationStore &var_store,
                            hb_direction_t        direction) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return u.format1.get_coord (font, direction);
     case 2: hb_barrier (); return u.format2.get_coord (font, direction);
     case 3: hb_barrier (); return u.format3.get_coord (font, var_store, direction);
@@ -181,7 +181,7 @@ struct BaseCoord
 
   void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 3: hb_barrier (); u.format3.collect_variation_indices (varidx_set); return;
     default:return;
     }
@@ -190,9 +190,9 @@ struct BaseCoord
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...));
     case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...));
     case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...));
@@ -203,9 +203,9 @@ struct BaseCoord
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (unlikely (!u.format.sanitize (c))) return_trace (false);
+    if (unlikely (!u.format.v.sanitize (c))) return_trace (false);
     hb_barrier ();
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return_trace (u.format1.sanitize (c));
     case 2: hb_barrier (); return_trace (u.format2.sanitize (c));
     case 3: hb_barrier (); return_trace (u.format3.sanitize (c));
@@ -215,13 +215,13 @@ struct BaseCoord
 
   protected:
   union {
-  HBUINT16              format;
+  struct { HBUINT16 v; }        format;
   BaseCoordFormat1      format1;
   BaseCoordFormat2      format2;
   BaseCoordFormat3      format3;
   } u;
   public:
-  DEFINE_SIZE_UNION (2, format);
+  DEFINE_SIZE_UNION (2, format.v);
 };
 
 struct FeatMinMaxRecord
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 7ee34185575..dcacc9cb86c 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
@@ -141,6 +141,7 @@ struct hb_subset_layout_context_t :
   const hb_map_t *lookup_index_map;
   const hb_hashmap_t> *script_langsys_map;
   const hb_map_t *feature_index_map;
+  const hb_map_t *feature_map_w_duplicates;
   const hb_hashmap_t *feature_substitutes_map;
   hb_hashmap_t> *feature_record_cond_idx_map;
   const hb_set_t *catch_all_record_feature_idxes;
@@ -165,6 +166,7 @@ struct hb_subset_layout_context_t :
       lookup_index_map = &c_->plan->gsub_lookups;
       script_langsys_map = &c_->plan->gsub_langsys;
       feature_index_map = &c_->plan->gsub_features;
+      feature_map_w_duplicates = &c_->plan->gsub_features_w_duplicates;
       feature_substitutes_map = &c_->plan->gsub_feature_substitutes_map;
       feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gsub_feature_record_cond_idx_map;
       catch_all_record_feature_idxes = &c_->plan->gsub_old_features;
@@ -175,6 +177,7 @@ struct hb_subset_layout_context_t :
       lookup_index_map = &c_->plan->gpos_lookups;
       script_langsys_map = &c_->plan->gpos_langsys;
       feature_index_map = &c_->plan->gpos_features;
+      feature_map_w_duplicates = &c_->plan->gpos_features_w_duplicates;
       feature_substitutes_map = &c_->plan->gpos_feature_substitutes_map;
       feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gpos_feature_record_cond_idx_map;
       catch_all_record_feature_idxes = &c_->plan->gpos_old_features;
@@ -825,46 +828,9 @@ struct Feature
                  const Record_sanitize_closure_t *closure = nullptr) const
   {
     TRACE_SANITIZE (this);
-    if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
-      return_trace (false);
-    hb_barrier ();
-
-    /* Some earlier versions of Adobe tools calculated the offset of the
-     * FeatureParams subtable from the beginning of the FeatureList table!
-     *
-     * If sanitizing "failed" for the FeatureParams subtable, try it with the
-     * alternative location.  We would know sanitize "failed" if old value
-     * of the offset was non-zero, but it's zeroed now.
-     *
-     * Only do this for the 'size' feature, since at the time of the faulty
-     * Adobe tools, only the 'size' feature had FeatureParams defined.
-     */
-
-    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);
-    hb_barrier ();
-
-    if (featureParams == 0 && closure &&
-        closure->tag == HB_TAG ('s','i','z','e') &&
-        closure->list_base && closure->list_base < this)
-    {
-      unsigned int new_offset_int = orig_offset -
-                                    (((char *) this) - ((char *) closure->list_base));
-
-      Offset16To new_offset;
-      /* Check that it would not overflow. */
-      new_offset = new_offset_int;
-      if (new_offset == new_offset_int &&
-          c->try_set (&featureParams, new_offset_int) &&
-          !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
-        return_trace (false);
-    }
-
-    return_trace (true);
+    return_trace (c->check_struct (this) &&
+                  featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE) &&
+                  lookupIndex.sanitize (c));
   }
 
   Offset16To
@@ -1082,15 +1048,15 @@ struct LangSys
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
 
     const uint32_t *v;
-    out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex, &v) ? *v : 0xFFFFu;
+    out->reqFeatureIndex = l->feature_map_w_duplicates->has (reqFeatureIndex, &v) ? *v : 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)
+    | hb_filter (l->feature_map_w_duplicates)
+    | hb_map (l->feature_map_w_duplicates)
     ;
 
     bool ret = bool (it);
@@ -1337,7 +1303,7 @@ struct Lookup
     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, std::forward (ds)...);
+      typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type, ds...);
       if (c->stop_sublookup_iteration (r))
         return_trace (r);
     }
@@ -1387,6 +1353,11 @@ struct Lookup
       {
         unsigned new_flag = lookupFlag;
         new_flag &= ~LookupFlag::UseMarkFilteringSet;
+        // https://github.com/harfbuzz/harfbuzz/issues/5499
+        // If we remove UseMarkFilteringSet flag because the set is now empty,
+        // we need to add IgnoreMarks flag, otherwise the lookup will not
+        // ignore any marks, which changes the behavior.
+        new_flag |= LookupFlag::IgnoreMarks;
         out->lookupFlag = new_flag;
       }
       else
@@ -1425,7 +1396,7 @@ struct Lookup
     if (unlikely (!get_subtables ().sanitize (c, this, get_type ())))
       return_trace (false);
 
-    if (unlikely (get_type () == TSubTable::Extension && !c->get_edit_count ()))
+    if (unlikely (get_type () == TSubTable::Extension))
     {
       hb_barrier ();
 
@@ -1433,11 +1404,6 @@ struct Lookup
        * 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!
-       *
-       * 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 ();
       for (unsigned int i = 1; i < subtables; i++)
@@ -2067,7 +2033,7 @@ struct ClassDef
   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) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return u.format1.get_class (glyph_id);
     case 2: hb_barrier (); return u.format2.get_class (glyph_id);
 #ifndef HB_NO_BEYOND_64K
@@ -2078,7 +2044,7 @@ struct ClassDef
     }
   }
   unsigned int get_class (hb_codepoint_t glyph_id,
-                          hb_ot_lookup_cache_t *cache) const
+                          hb_ot_layout_mapping_cache_t *cache) const
   {
     unsigned klass;
     if (cache && cache->get (glyph_id, &klass)) return klass;
@@ -2089,7 +2055,7 @@ struct ClassDef
 
   unsigned get_population () const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return u.format1.get_population ();
     case 2: hb_barrier (); return u.format2.get_population ();
 #ifndef HB_NO_BEYOND_64K
@@ -2142,7 +2108,7 @@ struct ClassDef
 
 #ifndef HB_NO_BEYOND_64K
     if (glyph_max > 0xFFFFu)
-      u.format += 2;
+      u.format.v += 2;
     if (unlikely (glyph_max > 0xFFFFFFu))
 #else
     if (unlikely (glyph_max > 0xFFFFu))
@@ -2152,9 +2118,9 @@ struct ClassDef
       return_trace (false);
     }
 
-    u.format = format;
+    u.format.v = format;
 
-    switch (u.format)
+    switch (u.format.v)
     {
     case 1: hb_barrier (); return_trace (u.format1.serialize (c, it));
     case 2: hb_barrier (); return_trace (u.format2.serialize (c, it));
@@ -2173,7 +2139,7 @@ struct ClassDef
                const Coverage* glyph_filter = nullptr) const
   {
     TRACE_SUBSET (this);
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return_trace (u.format1.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter));
     case 2: hb_barrier (); return_trace (u.format2.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter));
 #ifndef HB_NO_BEYOND_64K
@@ -2187,9 +2153,9 @@ struct ClassDef
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return_trace (false);
+    if (!u.format.v.sanitize (c)) return_trace (false);
     hb_barrier ();
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return_trace (u.format1.sanitize (c));
     case 2: hb_barrier (); return_trace (u.format2.sanitize (c));
 #ifndef HB_NO_BEYOND_64K
@@ -2202,7 +2168,7 @@ struct ClassDef
 
   unsigned cost () const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return u.format1.cost ();
     case 2: hb_barrier (); return u.format2.cost ();
 #ifndef HB_NO_BEYOND_64K
@@ -2218,7 +2184,7 @@ struct ClassDef
   template 
   bool collect_coverage (set_t *glyphs) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return u.format1.collect_coverage (glyphs);
     case 2: hb_barrier (); return u.format2.collect_coverage (glyphs);
 #ifndef HB_NO_BEYOND_64K
@@ -2234,7 +2200,7 @@ struct ClassDef
   template 
   bool collect_class (set_t *glyphs, unsigned int klass) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return u.format1.collect_class (glyphs, klass);
     case 2: hb_barrier (); return u.format2.collect_class (glyphs, klass);
 #ifndef HB_NO_BEYOND_64K
@@ -2247,7 +2213,7 @@ struct ClassDef
 
   bool intersects (const hb_set_t *glyphs) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return u.format1.intersects (glyphs);
     case 2: hb_barrier (); return u.format2.intersects (glyphs);
 #ifndef HB_NO_BEYOND_64K
@@ -2259,7 +2225,7 @@ struct ClassDef
   }
   bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return u.format1.intersects_class (glyphs, klass);
     case 2: hb_barrier (); return u.format2.intersects_class (glyphs, klass);
 #ifndef HB_NO_BEYOND_64K
@@ -2272,7 +2238,7 @@ struct ClassDef
 
   void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return u.format1.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
     case 2: hb_barrier (); return u.format2.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
 #ifndef HB_NO_BEYOND_64K
@@ -2285,7 +2251,7 @@ struct ClassDef
 
   void intersected_classes (const hb_set_t *glyphs, hb_set_t *intersect_classes) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return u.format1.intersected_classes (glyphs, intersect_classes);
     case 2: hb_barrier (); return u.format2.intersected_classes (glyphs, intersect_classes);
 #ifndef HB_NO_BEYOND_64K
@@ -2299,7 +2265,7 @@ struct ClassDef
 
   protected:
   union {
-  HBUINT16                      format;         /* Format identifier */
+  struct { HBUINT16 v; }        format;         /* Format identifier */
   ClassDefFormat1_3 format1;
   ClassDefFormat2_4 format2;
 #ifndef HB_NO_BEYOND_64K
@@ -2308,7 +2274,7 @@ struct ClassDef
 #endif
   } u;
   public:
-  DEFINE_SIZE_UNION (2, format);
+  DEFINE_SIZE_UNION (2, format.v);
 };
 
 template
@@ -2326,139 +2292,168 @@ struct delta_row_encoding_t
 {
   /* each byte represents a region, value is one of 0/1/2/4, which means bytes
    * needed for this region */
-  hb_vector_t chars;
+  struct chars_t : hb_vector_t
+  {
+    int cmp (const chars_t& other) const
+    {
+      return as_array ().cmp (other.as_array ());
+    }
+
+    hb_pair_t get_width ()
+    {
+      unsigned width = 0;
+      unsigned columns = 0;
+      for (unsigned i = 0; i < length; i++)
+      {
+        unsigned v = arrayZ[i];
+        width += v;
+        columns += (v != 0);
+      }
+      return hb_pair (width, columns);
+    }
+
+    HB_HOT
+    hb_pair_t combine_width (const chars_t& other) const
+    {
+      unsigned combined_width = 0;
+      unsigned combined_columns = 0;
+      for (unsigned i = 0; i < length; i++)
+      {
+        unsigned v = hb_max (arrayZ[i], other.arrayZ[i]);
+        combined_width += v;
+        combined_columns += (v != 0);
+      }
+      return hb_pair (combined_width, combined_columns);
+    }
+  };
+
+  hb_pair_t combine_width (const delta_row_encoding_t& other_encoding) const { return chars.combine_width (other_encoding.chars); }
+
+  // Actual data
+
+  chars_t chars;
   unsigned width = 0;
-  hb_vector_t columns;
   unsigned overhead = 0;
   hb_vector_t*> items;
 
   delta_row_encoding_t () = default;
-  delta_row_encoding_t (hb_vector_t&& chars_,
-                        const hb_vector_t* row = nullptr) :
-                        delta_row_encoding_t ()
+  delta_row_encoding_t (hb_vector_t*> &&rows, unsigned num_cols)
+  {
+    assert (rows);
+
+    items = std::move (rows);
+
+    if (unlikely (!chars.resize (num_cols)))
+      return;
+
+    calculate_chars ();
+  }
 
+  void merge (const delta_row_encoding_t& other)
   {
-    chars = std::move (chars_);
-    width = get_width ();
-    columns = get_columns ();
-    overhead = get_chars_overhead (columns);
-    if (row) items.push (row);
+    items.alloc (items.length + other.items.length);
+    for (auto &row : other.items)
+      add_row (row);
+
+    // Merge chars
+    assert (chars.length == other.chars.length);
+    for (unsigned i = 0; i < chars.length; i++)
+      chars.arrayZ[i] = hb_max (chars.arrayZ[i], other.chars.arrayZ[i]);
+    chars_changed ();
   }
 
-  bool is_empty () const
-  { return !items; }
+  void chars_changed ()
+  {
+    auto _ = chars.get_width ();
+    width = _.first;
+    overhead = get_chars_overhead (_.second);
+  }
 
-  static hb_vector_t get_row_chars (const hb_vector_t& row)
+  void calculate_chars ()
   {
-    hb_vector_t ret;
-    if (!ret.alloc (row.length)) return ret;
+    assert (items);
 
     bool long_words = false;
 
-    /* 0/1/2 byte encoding */
-    for (int i = row.length - 1; i >= 0; i--)
+    for (auto &row : items)
     {
-      int v =  row.arrayZ[i];
-      if (v == 0)
-        ret.push (0);
-      else if (v > 32767 || v < -32768)
+      assert (row->length == chars.length);
+
+      /* 0/1/2 byte encoding */
+      for (unsigned i = 0; i < row->length; i++)
       {
-        long_words = true;
-        break;
+        int v =  row->arrayZ[i];
+        if (v == 0)
+          continue;
+        else if (v > 32767 || v < -32768)
+        {
+          long_words = true;
+          chars.arrayZ[i] = hb_max (chars.arrayZ[i], 4);
+        }
+        else if (v > 127 || v < -128)
+          chars.arrayZ[i] = hb_max (chars.arrayZ[i], 2);
+        else
+          chars.arrayZ[i] = hb_max (chars.arrayZ[i], 1);
       }
-      else if (v > 127 || v < -128)
-        ret.push (2);
-      else
-        ret.push (1);
     }
 
-    if (!long_words)
-      return ret;
-
-    /* redo, 0/2/4 bytes encoding */
-    ret.reset ();
-    for (int i = row.length - 1; i >= 0; i--)
+    if (long_words)
     {
-      int v =  row.arrayZ[i];
-      if (v == 0)
-        ret.push (0);
-      else if (v > 32767 || v < -32768)
-        ret.push (4);
-      else
-        ret.push (2);
+      // Convert 1s to 2s
+      for (auto &v : chars)
+        if (v == 1)
+          v = 2;
     }
-    return ret;
-  }
 
-  inline unsigned get_width ()
-  {
-    unsigned ret = + hb_iter (chars)
-                   | hb_reduce (hb_add, 0u)
-                   ;
-    return ret;
+    chars_changed ();
   }
 
-  hb_vector_t get_columns ()
-  {
-    hb_vector_t cols;
-    cols.alloc (chars.length);
-    for (auto v : chars)
-    {
-      uint8_t flag = v ? 1 : 0;
-      cols.push (flag);
-    }
-    return cols;
-  }
+  bool is_empty () const
+  { return !items; }
 
-  static inline unsigned get_chars_overhead (const hb_vector_t& cols)
+  static inline unsigned get_chars_overhead (unsigned num_columns)
   {
     unsigned c = 4 + 6; // 4 bytes for LOffset, 6 bytes for VarData header
-    unsigned cols_bit_count = 0;
-    for (auto v : cols)
-      if (v) cols_bit_count++;
-    return c + cols_bit_count * 2;
+    return c + num_columns * 2;
   }
 
-  unsigned get_gain () const
+  unsigned get_gain (unsigned additional_bytes_per_rows = 1) const
   {
     int count = items.length;
-    return hb_max (0, (int) overhead - count);
+    return hb_max (0, (int) overhead - count * (int) additional_bytes_per_rows);
   }
 
   int gain_from_merging (const delta_row_encoding_t& other_encoding) const
   {
-    int combined_width = 0;
-    for (unsigned i = 0; i < chars.length; i++)
-      combined_width += hb_max (chars.arrayZ[i], other_encoding.chars.arrayZ[i]);
+    // Back of the envelope calculations to reject early.
+    signed additional_bytes_per_rows = other_encoding.width - width;
+    if (additional_bytes_per_rows > 0)
+    {
+      if (get_gain (additional_bytes_per_rows) == 0)
+        return 0;
+    }
+    else
+    {
+      if (other_encoding.get_gain (-additional_bytes_per_rows) == 0)
+        return 0;
+    }
 
-    hb_vector_t combined_columns;
-    combined_columns.alloc (columns.length);
-    for (unsigned i = 0; i < columns.length; i++)
-      combined_columns.push (columns.arrayZ[i] | other_encoding.columns.arrayZ[i]);
+    auto pair = combine_width (other_encoding);
+    unsigned combined_width = pair.first;
+    unsigned combined_columns = pair.second;
 
-    int combined_overhead = get_chars_overhead (combined_columns);
-    int combined_gain = (int) overhead + (int) other_encoding.overhead - combined_overhead
-                        - (combined_width - (int) width) * items.length
-                        - (combined_width - (int) other_encoding.width) * other_encoding.items.length;
+    int combined_gain = (int) overhead + (int) other_encoding.overhead;
+    combined_gain -= (combined_width - (int) width) * items.length;
+    combined_gain -= (combined_width - (int) other_encoding.width) * other_encoding.items.length;
+    combined_gain -= get_chars_overhead (combined_columns);
 
     return combined_gain;
   }
 
-  static int cmp (const void *pa, const void *pb)
-  {
-    const delta_row_encoding_t *a = (const delta_row_encoding_t *)pa;
-    const delta_row_encoding_t *b = (const delta_row_encoding_t *)pb;
-
-    int gain_a = a->get_gain ();
-    int gain_b = b->get_gain ();
-
-    if (gain_a != gain_b)
-      return gain_a - gain_b;
-
-    return (b->chars).as_array ().cmp ((a->chars).as_array ());
-  }
+  bool add_row (const hb_vector_t* row)
+  { return items.push (row); }
 
-  static int cmp_width (const void *pa, const void *pb)
+  static int cmp (const void *pa, const void *pb)
   {
     const delta_row_encoding_t *a = (const delta_row_encoding_t *)pa;
     const delta_row_encoding_t *b = (const delta_row_encoding_t *)pb;
@@ -2466,11 +2461,8 @@ struct delta_row_encoding_t
     if (a->width != b->width)
       return (int) a->width - (int) b->width;
 
-    return (b->chars).as_array ().cmp ((a->chars).as_array ());
+    return b->chars.cmp (a->chars);
   }
-
-  bool add_row (const hb_vector_t* row)
-  { return items.push (row); }
 };
 
 struct VarRegionAxis
@@ -2548,32 +2540,112 @@ struct SparseVarRegionAxis
   DEFINE_SIZE_STATIC (8);
 };
 
-#define REGION_CACHE_ITEM_CACHE_INVALID INT_MIN
-#define REGION_CACHE_ITEM_MULTIPLIER (float (1 << ((sizeof (int) * 8) - 2)))
-#define REGION_CACHE_ITEM_DIVISOR (1.f / float (1 << ((sizeof (int) * 8) - 2)))
-
-struct VarRegionList
+struct hb_scalar_cache_t
 {
-  using cache_t = hb_atomic_t;
+  private:
+  static constexpr unsigned STATIC_LENGTH = 16;
+  static constexpr int INVALID = INT_MIN;
+  static constexpr float MULTIPLIER = 1 << ((sizeof (int) * 8) - 2);
+  static constexpr float DIVISOR = 1.f / MULTIPLIER;
 
-  float evaluate (unsigned int region_index,
-                  const int *coords, unsigned int coord_len,
-                  cache_t *cache = nullptr) const
+  public:
+  hb_scalar_cache_t () : length (STATIC_LENGTH) { clear (); }
+
+  hb_scalar_cache_t (const hb_scalar_cache_t&) = delete;
+  hb_scalar_cache_t (hb_scalar_cache_t&&) = delete;
+  hb_scalar_cache_t& operator= (const hb_scalar_cache_t&) = delete;
+  hb_scalar_cache_t& operator= (hb_scalar_cache_t&&) = delete;
+
+  static hb_scalar_cache_t *create (unsigned int count,
+                                    hb_scalar_cache_t *scratch_cache = nullptr)
   {
-    if (unlikely (region_index >= regionCount))
-      return 0.;
+    if (!count) return (hb_scalar_cache_t *) &Null(hb_scalar_cache_t);
 
-    cache_t *cached_value = nullptr;
-    if (cache)
+    if (scratch_cache && count <= scratch_cache->length)
     {
-      cached_value = &(cache[region_index]);
-      if (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID)
-        return *cached_value * REGION_CACHE_ITEM_DIVISOR;
+      scratch_cache->clear ();
+      return scratch_cache;
     }
 
+    auto *cache = (hb_scalar_cache_t *) hb_malloc (sizeof (hb_scalar_cache_t) - sizeof (static_values) + sizeof (static_values[0]) * count);
+    if (unlikely (!cache)) return (hb_scalar_cache_t *) &Null(hb_scalar_cache_t);
+
+    cache->length = count;
+    cache->clear ();
+
+    return cache;
+  }
+
+  static void destroy (hb_scalar_cache_t *cache,
+                       hb_scalar_cache_t *scratch_cache = nullptr)
+  {
+    if (cache != &Null(hb_scalar_cache_t) && cache != scratch_cache)
+      hb_free (cache);
+  }
+
+  void clear ()
+  {
+    auto *values = &static_values[0];
+    unsigned i = 0;
+#ifndef HB_OPTIMIZE_SIZE
+    for (; i + 3 < length; i += 4)
+    {
+      values[i + 0] = INVALID;
+      values[i + 1] = INVALID;
+      values[i + 2] = INVALID;
+      values[i + 3] = INVALID;
+    }
+#endif
+    for (; i < length; i++)
+      values[i] = INVALID;
+  }
+
+  HB_ALWAYS_INLINE
+  bool get (unsigned i, float *value) const
+  {
+    if (unlikely (i >= length))
+    {
+      *value = 0.f;
+      return true;
+    }
+    auto *values = &static_values[0];
+    auto *cached_value = &values[i];
+    // Super hot. Most common path is that we have a cached value of 0.
+    int v = *cached_value;
+    if (likely (!v))
+    {
+      *value = 0.f;
+      return true;
+    }
+    if (v == INVALID)
+      return false;
+    *value = v * DIVISOR;
+    return true;
+  }
+
+  HB_ALWAYS_INLINE
+  void set (unsigned i, float value)
+  {
+    if (unlikely (i >= length)) return;
+    auto *values = &static_values[0];
+    auto *cached_value = &values[i];
+    *cached_value = roundf(value * MULTIPLIER);
+  }
+
+  private:
+  unsigned length;
+  mutable hb_atomic_t static_values[STATIC_LENGTH];
+};
+
+struct VarRegionList
+{
+  private:
+  float evaluate_impl (unsigned int region_index,
+                       const int *coords, unsigned int coord_len) const
+  {
     const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount);
+    float v = 1.f;
 
-    float v = 1.;
     unsigned int count = axisCount;
     for (unsigned int i = 0; i < count; i++)
     {
@@ -2581,15 +2653,32 @@ struct VarRegionList
       float factor = axes[i].evaluate (coord);
       if (factor == 0.f)
       {
-        if (cache)
-          *cached_value = 0.;
-        return 0.;
+        v = 0.f;
+        break;
       }
       v *= factor;
     }
 
+    return v;
+  }
+
+  public:
+  HB_ALWAYS_INLINE
+  float evaluate (unsigned int region_index,
+                  const int *coords, unsigned int coord_len,
+                  hb_scalar_cache_t *cache = nullptr) const
+  {
+    if (unlikely (region_index >= regionCount))
+      return 0.;
+
+    float v;
+    if (cache && cache->get (region_index, &v))
+      return v;
+
+    v = evaluate_impl (region_index, coords, coord_len);
+
     if (cache)
-      *cached_value = v * REGION_CACHE_ITEM_MULTIPLIER;
+      cache->set (region_index, v);
     return v;
   }
 
@@ -2732,29 +2821,24 @@ struct SparseVariationRegion : Array16Of
 
 struct SparseVarRegionList
 {
-  using cache_t = hb_atomic_t;
-
+  HB_ALWAYS_INLINE
   float evaluate (unsigned int region_index,
                   const int *coords, unsigned int coord_len,
-                  cache_t *cache = nullptr) const
+                  hb_scalar_cache_t *cache = nullptr) const
   {
     if (unlikely (region_index >= regions.len))
       return 0.;
 
-    cache_t *cached_value = nullptr;
-    if (cache)
-    {
-      cached_value = &(cache[region_index]);
-      if (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID)
-        return *cached_value * REGION_CACHE_ITEM_DIVISOR;
-    }
+    float v;
+    if (cache && cache->get (region_index, &v))
+      return v;
 
     const SparseVariationRegion ®ion = this+regions[region_index];
 
-    float v = region.evaluate (coords, coord_len);
-
+    v = region.evaluate (coords, coord_len);
     if (cache)
-      *cached_value = v * REGION_CACHE_ITEM_MULTIPLIER;
+      cache->set (region_index, v);
+
     return v;
   }
 
@@ -2792,46 +2876,62 @@ struct VarData
          + itemCount * get_row_size ();
   }
 
-  float get_delta (unsigned int inner,
-                   const int *coords, unsigned int coord_count,
-                   const VarRegionList ®ions,
-                   VarRegionList::cache_t *cache = nullptr) const
+  float _get_delta (unsigned int inner,
+                    const int *coords, unsigned int coord_count,
+                    const VarRegionList ®ions,
+                    hb_scalar_cache_t *cache = nullptr) const
   {
     if (unlikely (inner >= itemCount))
       return 0.;
+    bool is_long = longWords ();
+    unsigned int count = regionIndices.len;
+    unsigned word_count = wordCount ();
+    unsigned int scount = is_long ? count : word_count;
+    unsigned int lcount = is_long ? word_count : 0;
 
-   unsigned int count = regionIndices.len;
-   bool is_long = longWords ();
-   unsigned word_count = wordCount ();
-   unsigned int scount = is_long ? count : word_count;
-   unsigned int lcount = is_long ? word_count : 0;
+    const HBUINT8 *bytes = get_delta_bytes ();
+    const HBUINT8 *row = bytes + inner * get_row_size ();
 
-   const HBUINT8 *bytes = get_delta_bytes ();
-   const HBUINT8 *row = bytes + inner * get_row_size ();
+    float delta = 0.;
+    unsigned int i = 0;
 
-   float delta = 0.;
-   unsigned int i = 0;
+    const HBINT32 *lcursor = reinterpret_cast (row);
+    for (; i < lcount; i++)
+    {
+      float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
+      if (scalar)
+        delta += scalar * *lcursor;
+      lcursor++;
+    }
+    const HBINT16 *scursor = reinterpret_cast (lcursor);
+    for (; i < scount; i++)
+    {
+      float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
+      if (scalar)
+       delta += scalar * *scursor;
+      scursor++;
+    }
+    const HBINT8 *bcursor = reinterpret_cast (scursor);
+    for (; i < count; i++)
+    {
+      float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
+      if (scalar)
+        delta += scalar * *bcursor;
+      bcursor++;
+    }
 
-   const HBINT32 *lcursor = reinterpret_cast (row);
-   for (; i < lcount; i++)
-   {
-     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
-     delta += scalar * *lcursor++;
-   }
-   const HBINT16 *scursor = reinterpret_cast (lcursor);
-   for (; i < scount; i++)
-   {
-     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
-     delta += scalar * *scursor++;
-   }
-   const HBINT8 *bcursor = reinterpret_cast (scursor);
-   for (; i < count; i++)
-   {
-     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
-     delta += scalar * *bcursor++;
-   }
+    return delta;
+  }
 
-   return delta;
+  HB_ALWAYS_INLINE
+  float get_delta (unsigned int inner,
+                   const int *coords, unsigned int coord_count,
+                   const VarRegionList ®ions,
+                   hb_scalar_cache_t *cache = nullptr) const
+  {
+    unsigned int count = regionIndices.len;
+    if (!count) return 0.f; // This is quite common, so optimize it.
+    return _get_delta (inner, coords, coord_count, regions, cache);
   }
 
   void get_region_scalars (const int *coords, unsigned int coord_count,
@@ -3150,7 +3250,7 @@ struct MultiVarData
                   const int *coords, unsigned int coord_count,
                   const SparseVarRegionList ®ions,
                   hb_array_t out,
-                  SparseVarRegionList::cache_t *cache = nullptr) const
+                  hb_scalar_cache_t *cache = nullptr) const
   {
     auto &deltaSets = StructAfter (regionIndices);
 
@@ -3187,31 +3287,24 @@ struct MultiVarData
 struct ItemVariationStore
 {
   friend struct item_variations_t;
-  using cache_t = VarRegionList::cache_t;
 
-  cache_t *create_cache () const
+  hb_scalar_cache_t *create_cache () const
   {
 #ifdef HB_NO_VAR
-    return nullptr;
+    return hb_scalar_cache_t::create (0);
 #endif
-    unsigned count = (this+regions).regionCount;
-    if (!count) return nullptr;
-
-    cache_t *cache = (cache_t *) hb_malloc (sizeof (float) * count);
-    if (unlikely (!cache)) return nullptr;
-
-    for (unsigned i = 0; i < count; i++)
-      cache[i] = REGION_CACHE_ITEM_CACHE_INVALID;
-
-    return cache;
+    return hb_scalar_cache_t::create ((this+regions).regionCount);
   }
 
-  static void destroy_cache (cache_t *cache) { hb_free (cache); }
+  static void destroy_cache (hb_scalar_cache_t *cache)
+  {
+    hb_scalar_cache_t::destroy (cache);
+  }
 
   private:
   float get_delta (unsigned int outer, unsigned int inner,
                    const int *coords, unsigned int coord_count,
-                   VarRegionList::cache_t *cache = nullptr) const
+                   hb_scalar_cache_t *cache = nullptr) const
   {
 #ifdef HB_NO_VAR
     return 0.f;
@@ -3229,7 +3322,7 @@ struct ItemVariationStore
   public:
   float get_delta (unsigned int index,
                    const int *coords, unsigned int coord_count,
-                   VarRegionList::cache_t *cache = nullptr) const
+                   hb_scalar_cache_t *cache = nullptr) const
   {
     unsigned int outer = index >> 16;
     unsigned int inner = index & 0xFFFF;
@@ -3237,7 +3330,7 @@ struct ItemVariationStore
   }
   float get_delta (unsigned int index,
                    hb_array_t coords,
-                   VarRegionList::cache_t *cache = nullptr) const
+                   hb_scalar_cache_t *cache = nullptr) const
   {
     return get_delta (index,
                       coords.arrayZ, coords.length,
@@ -3356,7 +3449,7 @@ struct ItemVariationStore
     for (unsigned i = 0; i < count; i++)
     {
       hb_inc_bimap_t *map = inner_maps.push ();
-      if (!c->propagate_error(inner_maps))
+      if (unlikely (!c->propagate_error(inner_maps)))
         return_trace(nullptr);
       auto &data = this+dataSets[i];
 
@@ -3445,43 +3538,28 @@ struct ItemVariationStore
 
 struct MultiItemVariationStore
 {
-  using cache_t = SparseVarRegionList::cache_t;
-
-  cache_t *create_cache (hb_array_t static_cache = hb_array_t ()) const
+  hb_scalar_cache_t *create_cache (hb_scalar_cache_t *static_cache = nullptr) const
   {
 #ifdef HB_NO_VAR
-    return nullptr;
+    return hb_scalar_cache_t::create (0);
 #endif
     auto &r = this+regions;
     unsigned count = r.regions.len;
 
-    cache_t *cache;
-    if (count <= static_cache.length)
-      cache = static_cache.arrayZ;
-    else
-    {
-      cache = (cache_t *) hb_malloc (sizeof (float) * count);
-      if (unlikely (!cache)) return nullptr;
-    }
-
-    for (unsigned i = 0; i < count; i++)
-      cache[i] = REGION_CACHE_ITEM_CACHE_INVALID;
-
-    return cache;
+    return hb_scalar_cache_t::create (count, static_cache);
   }
 
-  static void destroy_cache (cache_t *cache,
-                             hb_array_t static_cache = hb_array_t ())
+  static void destroy_cache (hb_scalar_cache_t *cache,
+                             hb_scalar_cache_t *static_cache = nullptr)
   {
-    if (cache != static_cache.arrayZ)
-      hb_free (cache);
+    hb_scalar_cache_t::destroy (cache, static_cache);
   }
 
   private:
   void get_delta (unsigned int outer, unsigned int inner,
                   const int *coords, unsigned int coord_count,
                   hb_array_t out,
-                  VarRegionList::cache_t *cache = nullptr) const
+                  hb_scalar_cache_t *cache = nullptr) const
   {
 #ifdef HB_NO_VAR
     return;
@@ -3501,7 +3579,7 @@ struct MultiItemVariationStore
   void get_delta (unsigned int index,
                   const int *coords, unsigned int coord_count,
                   hb_array_t out,
-                  VarRegionList::cache_t *cache = nullptr) const
+                  hb_scalar_cache_t *cache = nullptr) const
   {
     unsigned int outer = index >> 16;
     unsigned int inner = index & 0xFFFF;
@@ -3510,7 +3588,7 @@ struct MultiItemVariationStore
   void get_delta (unsigned int index,
                   hb_array_t coords,
                   hb_array_t out,
-                  VarRegionList::cache_t *cache = nullptr) const
+                  hb_scalar_cache_t *cache = nullptr) const
   {
     return get_delta (index,
                       coords.arrayZ, coords.length,
@@ -3540,8 +3618,6 @@ struct MultiItemVariationStore
   DEFINE_SIZE_ARRAY_SIZED (8, dataSets);
 };
 
-#undef REGION_CACHE_ITEM_CACHE_INVALID
-
 template 
 struct DeltaSetIndexMapFormat01
 {
@@ -3592,13 +3668,19 @@ struct DeltaSetIndexMapFormat01
     return_trace (true);
   }
 
+  HB_ALWAYS_INLINE
   uint32_t map (unsigned int v) const /* Returns 16.16 outer.inner. */
   {
     /* If count is zero, pass value unchanged.  This takes
      * care of direct mapping for advance map. */
     if (!mapCount)
       return v;
+    return _map (v);
+  }
 
+  HB_HOT
+  uint32_t _map (unsigned int v) const /* Returns 16.16 outer.inner. */
+  {
     if (v >= mapCount)
       v = mapCount - 1;
 
@@ -3654,8 +3736,8 @@ struct DeltaSetIndexMap
   {
     TRACE_SERIALIZE (this);
     unsigned length = plan.get_output_map ().length;
-    u.format = length <= 0xFFFF ? 0 : 1;
-    switch (u.format) {
+    u.format.v = length <= 0xFFFF ? 0 : 1;
+    switch (u.format.v) {
     case 0: hb_barrier (); return_trace (u.format0.serialize (c, plan));
     case 1: hb_barrier (); return_trace (u.format1.serialize (c, plan));
     default:return_trace (false);
@@ -3664,7 +3746,7 @@ struct DeltaSetIndexMap
 
   uint32_t map (unsigned v) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 0: hb_barrier (); return (u.format0.map (v));
     case 1: hb_barrier (); return (u.format1.map (v));
     default:return v;
@@ -3673,7 +3755,7 @@ struct DeltaSetIndexMap
 
   unsigned get_map_count () const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 0: hb_barrier (); return u.format0.get_map_count ();
     case 1: hb_barrier (); return u.format1.get_map_count ();
     default:return 0;
@@ -3682,7 +3764,7 @@ struct DeltaSetIndexMap
 
   unsigned get_width () const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 0: hb_barrier (); return u.format0.get_width ();
     case 1: hb_barrier (); return u.format1.get_width ();
     default:return 0;
@@ -3691,7 +3773,7 @@ struct DeltaSetIndexMap
 
   unsigned get_inner_bit_count () const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 0: hb_barrier (); return u.format0.get_inner_bit_count ();
     case 1: hb_barrier (); return u.format1.get_inner_bit_count ();
     default:return 0;
@@ -3701,9 +3783,9 @@ struct DeltaSetIndexMap
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return_trace (false);
+    if (!u.format.v.sanitize (c)) return_trace (false);
     hb_barrier ();
-    switch (u.format) {
+    switch (u.format.v) {
     case 0: hb_barrier (); return_trace (u.format0.sanitize (c));
     case 1: hb_barrier (); return_trace (u.format1.sanitize (c));
     default:return_trace (true);
@@ -3713,7 +3795,7 @@ struct DeltaSetIndexMap
   DeltaSetIndexMap* copy (hb_serialize_context_t *c) const
   {
     TRACE_SERIALIZE (this);
-    switch (u.format) {
+    switch (u.format.v) {
     case 0: hb_barrier (); return_trace (reinterpret_cast (u.format0.copy (c)));
     case 1: hb_barrier (); return_trace (reinterpret_cast (u.format1.copy (c)));
     default:return_trace (nullptr);
@@ -3722,12 +3804,12 @@ struct DeltaSetIndexMap
 
   protected:
   union {
-  HBUINT8                            format;         /* Format identifier */
+  struct { HBUINT8 v; }             format;         /* Format identifier */
   DeltaSetIndexMapFormat01 format0;
   DeltaSetIndexMapFormat01 format1;
   } u;
   public:
-  DEFINE_SIZE_UNION (1, format);
+  DEFINE_SIZE_UNION (1, format.v);
 };
 
 
@@ -3736,7 +3818,7 @@ struct ItemVarStoreInstancer
   ItemVarStoreInstancer (const ItemVariationStore *varStore_,
                          const DeltaSetIndexMap *varIdxMap,
                          hb_array_t coords,
-                         VarRegionList::cache_t *cache = nullptr) :
+                         hb_scalar_cache_t *cache = nullptr) :
     varStore (varStore_), varIdxMap (varIdxMap), coords (coords), cache (cache)
   {
     if (!varStore)
@@ -3762,7 +3844,7 @@ struct ItemVarStoreInstancer
   const ItemVariationStore *varStore;
   const DeltaSetIndexMap *varIdxMap;
   hb_array_t coords;
-  VarRegionList::cache_t *cache;
+  hb_scalar_cache_t *cache;
 };
 
 struct MultiItemVarStoreInstancer
@@ -3770,7 +3852,7 @@ struct MultiItemVarStoreInstancer
   MultiItemVarStoreInstancer (const MultiItemVariationStore *varStore,
                               const DeltaSetIndexMap *varIdxMap,
                               hb_array_t coords,
-                              SparseVarRegionList::cache_t *cache = nullptr) :
+                              hb_scalar_cache_t *cache = nullptr) :
     varStore (varStore), varIdxMap (varIdxMap), coords (coords), cache (cache)
   {
     if (!varStore)
@@ -3803,7 +3885,7 @@ struct MultiItemVarStoreInstancer
   const MultiItemVariationStore *varStore;
   const DeltaSetIndexMap *varIdxMap;
   hb_array_t coords;
-  SparseVarRegionList::cache_t *cache;
+  hb_scalar_cache_t *cache;
 };
 
 
@@ -4130,7 +4212,7 @@ struct Condition
   bool evaluate (const int *coords, unsigned int coord_len,
                  Instancer *instancer) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return u.format1.evaluate (coords, coord_len, instancer);
     case 2: hb_barrier (); return u.format2.evaluate (coords, coord_len, instancer);
     case 3: hb_barrier (); return u.format3.evaluate (coords, coord_len, instancer);
@@ -4143,7 +4225,7 @@ struct Condition
   Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
                                              hb_map_t *condition_map /* OUT */) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return u.format1.keep_with_variations (c, condition_map);
     // TODO(subset)
     default: c->apply = false; return KEEP_COND_WITH_VAR;
@@ -4153,9 +4235,9 @@ struct Condition
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...));
     case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...));
     case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...));
@@ -4168,9 +4250,9 @@ struct Condition
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return_trace (false);
+    if (!u.format.v.sanitize (c)) return_trace (false);
     hb_barrier ();
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return_trace (u.format1.sanitize (c));
     case 2: hb_barrier (); return_trace (u.format2.sanitize (c));
     case 3: hb_barrier (); return_trace (u.format3.sanitize (c));
@@ -4182,7 +4264,7 @@ struct Condition
 
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
+  struct { HBUINT16 v; }        format;         /* Format identifier */
   ConditionAxisRange    format1;
   ConditionValue        format2;
   ConditionAnd          format3;
@@ -4190,7 +4272,7 @@ struct Condition
   ConditionNegate       format5;
   } u;
   public:
-  DEFINE_SIZE_UNION (2, format);
+  DEFINE_SIZE_UNION (2, format.v);
 };
 
 template 
@@ -4353,7 +4435,7 @@ struct FeatureTableSubstitutionRecord
     if (unlikely (!s->extend_min (this))) return_trace (false);
 
     uint32_t *new_feature_idx;
-    if (!c->feature_index_map->has (feature_index, &new_feature_idx))
+    if (!c->feature_map_w_duplicates->has (feature_index, &new_feature_idx))
       return_trace (false);
 
     if (!s->check_assign (featureIndex, *new_feature_idx, HB_SERIALIZE_ERROR_INT_OVERFLOW))
@@ -4371,7 +4453,7 @@ struct FeatureTableSubstitutionRecord
   {
     TRACE_SUBSET (this);
     uint32_t *new_feature_index;
-    if (!c->feature_index_map->has (featureIndex, &new_feature_index))
+    if (!c->feature_map_w_duplicates->has (featureIndex, &new_feature_index))
       return_trace (false);
 
     auto *out = c->subset_context->serializer->embed (this);
@@ -4645,7 +4727,7 @@ struct FeatureVariations
 
     int keep_up_to = -1;
     for (int i = varRecords.len - 1; i >= 0; i--) {
-      if (varRecords[i].intersects_features (this, l->feature_index_map)) {
+      if (varRecords[i].intersects_features (this, l->feature_map_w_duplicates)) {
         keep_up_to = i;
         break;
       }
@@ -4783,13 +4865,13 @@ struct VariationDevice
 
   hb_position_t get_x_delta (hb_font_t *font,
                              const ItemVariationStore &store,
-                             ItemVariationStore::cache_t *store_cache = nullptr) const
-  { return !font->num_coords ? 0 : font->em_scalef_x (get_delta (font, store, store_cache)); }
+                             hb_scalar_cache_t *store_cache = nullptr) const
+  { return !font->has_nonzero_coords ? 0 : font->em_scalef_x (get_delta (font, store, store_cache)); }
 
   hb_position_t get_y_delta (hb_font_t *font,
                              const ItemVariationStore &store,
-                             ItemVariationStore::cache_t *store_cache = nullptr) const
-  { return !font->num_coords ? 0 : font->em_scalef_y (get_delta (font, store, store_cache)); }
+                             hb_scalar_cache_t *store_cache = nullptr) const
+  { return !font->has_nonzero_coords ? 0 : font->em_scalef_y (get_delta (font, store, store_cache)); }
 
   VariationDevice* copy (hb_serialize_context_t *c,
                          const hb_hashmap_t> *layout_variation_idx_delta_map) const
@@ -4823,9 +4905,9 @@ struct VariationDevice
 
   float get_delta (hb_font_t *font,
                    const ItemVariationStore &store,
-                   ItemVariationStore::cache_t *store_cache = nullptr) const
+                   hb_scalar_cache_t *store_cache = nullptr) const
   {
-    return store.get_delta (varIdx, font->coords, font->num_coords, (ItemVariationStore::cache_t *) store_cache);
+    return store.get_delta (varIdx, font->coords, font->num_coords, store_cache);
   }
 
   protected:
@@ -4850,7 +4932,7 @@ struct Device
 {
   hb_position_t get_x_delta (hb_font_t *font,
                              const ItemVariationStore &store=Null (ItemVariationStore),
-                             ItemVariationStore::cache_t *store_cache = nullptr) const
+                             hb_scalar_cache_t *store_cache = nullptr) const
   {
     switch (u.b.format)
     {
@@ -4868,7 +4950,7 @@ struct Device
   }
   hb_position_t get_y_delta (hb_font_t *font,
                              const ItemVariationStore &store=Null (ItemVariationStore),
-                             ItemVariationStore::cache_t *store_cache = nullptr) const
+                             hb_scalar_cache_t *store_cache = nullptr) const
   {
     switch (u.b.format)
     {
@@ -4954,6 +5036,18 @@ struct Device
     }
   }
 
+  bool is_variation_device () const
+  {
+    switch (u.b.format) {
+#ifndef HB_NO_VAR
+    case 0x8000:
+      return true;
+#endif
+    default:
+      return false;
+    }
+  }
+
   protected:
   union {
   DeviceHeader          b;
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 0cfa139a260..f6aabc84ac9 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
@@ -63,12 +63,20 @@ inline bool PosLookup::dispatch_recurse_func (hb_ot_apply
   c->set_lookup_index (lookup_index);
   c->set_lookup_props (l.get_props ());
 
+  uint32_t stack_match_positions[8];
+  hb_vector_t saved_match_positions;
+  saved_match_positions.set_storage (stack_match_positions);
+  hb_swap (c->match_positions, saved_match_positions);
+
   bool ret = false;
   auto *accel = gpos->get_accel (lookup_index);
-  ret = accel && accel->apply (c, l.get_subtable_count (), false);
+  ret = accel && accel->apply (c, false);
 
   c->set_lookup_index (saved_lookup_index);
   c->set_lookup_props (saved_lookup_props);
+
+  hb_swap (c->match_positions, saved_match_positions);
+
   return ret;
 }
 #endif
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 fd8a68be02d..8d5e1f18638 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
@@ -76,12 +76,20 @@ inline bool SubstLookup::dispatch_recurse_func (hb_ot_app
   c->set_lookup_index (lookup_index);
   c->set_lookup_props (l.get_props ());
 
+  uint32_t stack_match_positions[8];
+  hb_vector_t saved_match_positions;
+  saved_match_positions.set_storage (stack_match_positions);
+  hb_swap (c->match_positions, saved_match_positions);
+
   bool ret = false;
   auto *accel = gsub->get_accel (lookup_index);
-  ret = accel && accel->apply (c, l.get_subtable_count (), false);
+  ret = accel && accel->apply (c, false);
 
   c->set_lookup_index (saved_lookup_index);
   c->set_lookup_props (saved_lookup_props);
+
+  hb_swap (c->match_positions, saved_match_positions);
+
   return ret;
 }
 #endif
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 072e5cdba26..05bbf3395bf 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
@@ -397,303 +397,311 @@ struct hb_collect_coverage_context_t :
   set_t *set;
 };
 
-struct hb_ot_apply_context_t :
-       hb_dispatch_context_t
+struct matcher_t
 {
-  struct matcher_t
-  {
-    typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
-
-    void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
-    void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
-    void set_ignore_hidden (bool ignore_hidden_) { ignore_hidden = ignore_hidden_; }
-    void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
-    void set_mask (hb_mask_t mask_) { mask = mask_; }
-    void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; }
-    void set_syllable (uint8_t syllable_)  { syllable = per_syllable ? syllable_ : 0; }
-    void set_match_func (match_func_t match_func_,
-                         const void *match_data_)
-    { match_func = match_func_; match_data = match_data_; }
-
-    enum may_match_t {
-      MATCH_NO,
-      MATCH_YES,
-      MATCH_MAYBE
-    };
+  typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
+
+  template 
+  void init (const context_t *c, bool context_match = false)
+  {
+    set_match_func (nullptr, nullptr);
+    lookup_props = c->lookup_props;
+    /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
+    ignore_zwnj = c->table_index == 1 || (context_match && c->auto_zwnj);
+    /* Ignore ZWJ if we are matching context, or asked to. */
+    ignore_zwj = context_match || c->auto_zwj;
+    /* Ignore hidden glyphs (like CGJ) during GPOS. */
+    ignore_hidden = c->table_index == 1;
+    mask = context_match ? -1 : c->lookup_mask;
+    /* Per syllable matching is only for GSUB. */
+    per_syllable = c->table_index == 0 && c->per_syllable;
+    syllable = 0;
+  }
+
+  void set_match_func (match_func_t match_func_,
+                       const void *match_data_)
+  { match_func = match_func_; match_data = match_data_; }
+
+  enum may_match_t {
+    MATCH_NO,
+    MATCH_YES,
+    MATCH_MAYBE
+  };
 
 #ifndef HB_OPTIMIZE_SIZE
-    HB_ALWAYS_INLINE
+  HB_ALWAYS_INLINE
 #endif
-    may_match_t may_match (hb_glyph_info_t &info,
-                           hb_codepoint_t glyph_data) const
-    {
-      if (!(info.mask & mask) ||
-          (syllable && syllable != info.syllable ()))
-        return MATCH_NO;
+  may_match_t may_match (hb_glyph_info_t &info,
+                         hb_codepoint_t glyph_data) const
+  {
+    if (!(info.mask & mask) ||
+        (per_syllable && syllable && syllable != info.syllable ()))
+      return MATCH_NO;
 
-      if (match_func)
-        return match_func (info, glyph_data, match_data) ? MATCH_YES : MATCH_NO;
+    if (match_func)
+      return match_func (info, glyph_data, match_data) ? MATCH_YES : MATCH_NO;
 
-      return MATCH_MAYBE;
-    }
+    return MATCH_MAYBE;
+  }
 
-    enum may_skip_t {
-      SKIP_NO,
-      SKIP_YES,
-      SKIP_MAYBE
-    };
+  enum may_skip_t {
+    SKIP_NO,
+    SKIP_YES,
+    SKIP_MAYBE
+  };
 
+  template 
 #ifndef HB_OPTIMIZE_SIZE
-    HB_ALWAYS_INLINE
+  HB_ALWAYS_INLINE
 #endif
-    may_skip_t may_skip (const hb_ot_apply_context_t *c,
-                         const hb_glyph_info_t       &info) const
-    {
-      if (!c->check_glyph_property (&info, lookup_props))
-        return SKIP_YES;
+  may_skip_t may_skip (const context_t *c,
+                       const hb_glyph_info_t &info) const
+  {
+    if (!c->check_glyph_property (&info, lookup_props))
+      return SKIP_YES;
 
-      if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
-                    (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
-                    (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
-                    (ignore_hidden || !_hb_glyph_info_is_hidden (&info))))
-        return SKIP_MAYBE;
+    if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
+                  (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
+                  (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
+                  (ignore_hidden || !_hb_glyph_info_is_hidden (&info))))
+      return SKIP_MAYBE;
 
-      return SKIP_NO;
-    }
+    return SKIP_NO;
+  }
 
-    protected:
-    unsigned int lookup_props = 0;
-    hb_mask_t mask = -1;
-    bool ignore_zwnj = false;
-    bool ignore_zwj = false;
-    bool ignore_hidden = false;
-    bool per_syllable = false;
-    uint8_t syllable = 0;
-    match_func_t match_func = nullptr;
-    const void *match_data = nullptr;
-  };
+  public:
+  unsigned int lookup_props = 0;
+  hb_mask_t mask = -1;
+  bool ignore_zwnj = false;
+  bool ignore_zwj = false;
+  bool ignore_hidden = false;
+  bool per_syllable = false;
+  uint8_t syllable = 0;
+  match_func_t match_func = nullptr;
+  const void *match_data = nullptr;
+};
 
-  struct skipping_iterator_t
+template 
+struct skipping_iterator_t
+{
+  void init (context_t *c_, bool context_match = false)
   {
-    void init (hb_ot_apply_context_t *c_, bool context_match = false)
-    {
-      c = c_;
-      end = c->buffer->len;
-      match_glyph_data16 = nullptr;
+    c = c_;
+    end = c->buffer->len;
+    match_glyph_data16 = nullptr;
 #ifndef HB_NO_BEYOND_64K
-      match_glyph_data24 = nullptr;
+    match_glyph_data24 = nullptr;
 #endif
-      matcher.set_match_func (nullptr, nullptr);
-      matcher.set_lookup_props (c->lookup_props);
-      /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
-      matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
-      /* Ignore ZWJ if we are matching context, or asked to. */
-      matcher.set_ignore_zwj  (context_match || c->auto_zwj);
-      /* Ignore hidden glyphs (like CGJ) during GPOS. */
-      matcher.set_ignore_hidden (c->table_index == 1);
-      matcher.set_mask (context_match ? -1 : c->lookup_mask);
-      /* Per syllable matching is only for GSUB. */
-      matcher.set_per_syllable (c->table_index == 0 && c->per_syllable);
-      matcher.set_syllable (0);
-    }
-    void set_lookup_props (unsigned int lookup_props)
-    {
-      matcher.set_lookup_props (lookup_props);
-    }
-    void set_match_func (matcher_t::match_func_t match_func_,
-                         const void *match_data_)
-    {
-      matcher.set_match_func (match_func_, match_data_);
-    }
-    void set_glyph_data (const HBUINT16 glyph_data[])
-    {
-      match_glyph_data16 = glyph_data;
+    matcher.init (c, context_match);
+  }
+  void set_lookup_props (unsigned int lookup_props)
+  {
+    matcher.lookup_props = lookup_props;
+  }
+  void set_match_func (matcher_t::match_func_t match_func_,
+                       const void *match_data_)
+  {
+    matcher.set_match_func (match_func_, match_data_);
+  }
+  void set_glyph_data (const HBUINT16 glyph_data[])
+  {
+    match_glyph_data16 = glyph_data;
 #ifndef HB_NO_BEYOND_64K
-      match_glyph_data24 = nullptr;
+    match_glyph_data24 = nullptr;
 #endif
-    }
+  }
 #ifndef HB_NO_BEYOND_64K
-    void set_glyph_data (const HBUINT24 glyph_data[])
-    {
-      match_glyph_data16 = nullptr;
-      match_glyph_data24 = glyph_data;
-    }
+  void set_glyph_data (const HBUINT24 glyph_data[])
+  {
+    match_glyph_data16 = nullptr;
+    match_glyph_data24 = glyph_data;
+  }
 #endif
 
 #ifndef HB_OPTIMIZE_SIZE
-    HB_ALWAYS_INLINE
+  HB_ALWAYS_INLINE
 #endif
-    void reset (unsigned int start_index_)
-    {
-      idx = start_index_;
-      end = c->buffer->len;
-      matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
-    }
+  void reset (unsigned int start_index_)
+  {
+    // For GSUB forward iterator
+    idx = start_index_;
+    end = c->buffer->len;
+    matcher.syllable = c->buffer->cur().syllable();
+  }
+  void reset_back (unsigned int start_index_, bool from_out_buffer = false)
+  {
+    // For GSUB backward iterator
+    idx = start_index_;
+    matcher.syllable = c->buffer->cur().syllable();
+  }
 
 #ifndef HB_OPTIMIZE_SIZE
-    HB_ALWAYS_INLINE
+  HB_ALWAYS_INLINE
 #endif
-    void reset_fast (unsigned int start_index_)
-    {
-      // Doesn't set end or syllable. Used by GPOS which doesn't care / change.
-      idx = start_index_;
-    }
-
-    void reject ()
-    {
-      backup_glyph_data ();
-    }
+  void reset_fast (unsigned int start_index_)
+  {
+    // Doesn't set end or syllable. Used by GPOS which doesn't care / change.
+    idx = start_index_;
+  }
 
-    matcher_t::may_skip_t
 #ifndef HB_OPTIMIZE_SIZE
-    HB_ALWAYS_INLINE
+  HB_ALWAYS_INLINE
 #endif
-    may_skip (const hb_glyph_info_t &info) const
-    { return matcher.may_skip (c, info); }
+  matcher_t::may_skip_t may_skip (const hb_glyph_info_t &info) const
+  { return matcher.may_skip (c, info); }
 
-    enum match_t {
-      MATCH,
-      NOT_MATCH,
-      SKIP
-    };
+  enum match_t {
+    MATCH,
+    NOT_MATCH,
+    SKIP
+  };
 
 #ifndef HB_OPTIMIZE_SIZE
-    HB_ALWAYS_INLINE
+  HB_ALWAYS_INLINE
 #endif
-    match_t match (hb_glyph_info_t &info)
-    {
-      matcher_t::may_skip_t skip = matcher.may_skip (c, info);
-      if (unlikely (skip == matcher_t::SKIP_YES))
-        return SKIP;
+  match_t match (hb_glyph_info_t &info)
+  {
+    matcher_t::may_skip_t skip = matcher.may_skip (c, info);
+    if (unlikely (skip == matcher_t::SKIP_YES))
+      return SKIP;
 
-      matcher_t::may_match_t match = matcher.may_match (info, get_glyph_data ());
-      if (match == matcher_t::MATCH_YES ||
-          (match == matcher_t::MATCH_MAYBE &&
-           skip == matcher_t::SKIP_NO))
-        return MATCH;
+    matcher_t::may_match_t match = matcher.may_match (info, get_glyph_data ());
+    if (match == matcher_t::MATCH_YES ||
+        (match == matcher_t::MATCH_MAYBE &&
+         skip == matcher_t::SKIP_NO))
+      return MATCH;
 
-      if (skip == matcher_t::SKIP_NO)
-        return NOT_MATCH;
+    if (skip == matcher_t::SKIP_NO)
+      return NOT_MATCH;
 
-      return SKIP;
+    return SKIP;
   }
 
 #ifndef HB_OPTIMIZE_SIZE
-    HB_ALWAYS_INLINE
+  HB_ALWAYS_INLINE
 #endif
-    bool next (unsigned *unsafe_to = nullptr)
+  bool next (unsigned *unsafe_to = nullptr)
+  {
+    auto *info = c->buffer->info;
+    const signed stop = (signed) end - 1;
+    while ((signed) idx < stop)
     {
-      const signed stop = (signed) end - 1;
-      while ((signed) idx < stop)
+      idx++;
+      switch (match (info[idx]))
       {
-        idx++;
-        switch (match (c->buffer->info[idx]))
+        case MATCH:
         {
-          case MATCH:
-          {
-            advance_glyph_data ();
-            return true;
-          }
-          case NOT_MATCH:
-          {
-            if (unsafe_to)
-              *unsafe_to = idx + 1;
-            return false;
-          }
-          case SKIP:
-            continue;
+          advance_glyph_data ();
+          return true;
         }
+        case NOT_MATCH:
+        {
+          if (unsafe_to)
+            *unsafe_to = idx + 1;
+          return false;
+        }
+        case SKIP:
+          continue;
       }
-      if (unsafe_to)
-        *unsafe_to = end;
-      return false;
     }
+    if (unsafe_to)
+      *unsafe_to = end;
+    return false;
+  }
 #ifndef HB_OPTIMIZE_SIZE
-    HB_ALWAYS_INLINE
+  HB_ALWAYS_INLINE
 #endif
-    bool prev (unsigned *unsafe_from = nullptr)
+  bool prev (unsigned *unsafe_from = nullptr)
+  {
+    auto *out_info = c->buffer->out_info;
+    const unsigned stop = 0;
+    while (idx > stop)
     {
-      const unsigned stop = 0;
-      while (idx > stop)
+      idx--;
+      switch (match (out_info[idx]))
       {
-        idx--;
-        switch (match (c->buffer->out_info[idx]))
+        case MATCH:
         {
-          case MATCH:
-          {
-            advance_glyph_data ();
-            return true;
-          }
-          case NOT_MATCH:
-          {
-            if (unsafe_from)
-              *unsafe_from = hb_max (1u, idx) - 1u;
-            return false;
-          }
-          case SKIP:
-            continue;
+          advance_glyph_data ();
+          return true;
+        }
+        case NOT_MATCH:
+        {
+          if (unsafe_from)
+            *unsafe_from = hb_max (1u, idx) - 1u;
+          return false;
         }
+        case SKIP:
+          continue;
       }
-      if (unsafe_from)
-        *unsafe_from = 0;
-      return false;
     }
+    if (unsafe_from)
+      *unsafe_from = 0;
+    return false;
+  }
 
-    HB_ALWAYS_INLINE
-    hb_codepoint_t
-    get_glyph_data ()
-    {
-      if (match_glyph_data16) return *match_glyph_data16;
-#ifndef HB_NO_BEYOND_64K
-      else
-      if (match_glyph_data24) return *match_glyph_data24;
-#endif
-      return 0;
-    }
-    HB_ALWAYS_INLINE
-    void
-    advance_glyph_data ()
-    {
-      if (match_glyph_data16) match_glyph_data16++;
+  HB_ALWAYS_INLINE
+  hb_codepoint_t
+  get_glyph_data ()
+  {
+    if (match_glyph_data16) return *match_glyph_data16;
 #ifndef HB_NO_BEYOND_64K
-      else
-      if (match_glyph_data24) match_glyph_data24++;
+    else
+    if (match_glyph_data24) return *match_glyph_data24;
 #endif
-    }
-    void
-    backup_glyph_data ()
-    {
-      if (match_glyph_data16) match_glyph_data16--;
+    return 0;
+  }
+  HB_ALWAYS_INLINE
+  void
+  advance_glyph_data ()
+  {
+    if (match_glyph_data16) match_glyph_data16++;
 #ifndef HB_NO_BEYOND_64K
-      else
-      if (match_glyph_data24) match_glyph_data24--;
+    else
+    if (match_glyph_data24) match_glyph_data24++;
 #endif
-    }
+  }
 
-    unsigned int idx;
-    protected:
-    hb_ot_apply_context_t *c;
-    matcher_t matcher;
-    const HBUINT16 *match_glyph_data16;
+  unsigned int idx;
+  protected:
+  context_t *c;
+  matcher_t matcher;
+  const HBUINT16 *match_glyph_data16;
 #ifndef HB_NO_BEYOND_64K
-    const HBUINT24 *match_glyph_data24;
+  const HBUINT24 *match_glyph_data24;
 #endif
 
-    unsigned int end;
-  };
-
+  unsigned int end;
+};
 
+struct hb_ot_apply_context_t :
+       hb_dispatch_context_t
+{
   const char *get_name () { return "APPLY"; }
   typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
+
+  template 
+  static inline auto apply_ (const T &obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (return_t, obj.apply (c, nullptr) )
+  template 
+  static inline auto apply_ (const T &obj, hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (return_t, obj.apply (c) )
   template 
-  return_t dispatch (const T &obj) { return obj.apply (this); }
+  return_t dispatch (const T &obj) { return apply_(obj, this, hb_prioritize); }
+
   static return_t default_return_value () { return false; }
   bool stop_sublookup_iteration (return_t r) const { return r; }
   return_t recurse (unsigned int sub_lookup_index)
   {
-    if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
+    assert (recurse_func);
+    if (unlikely (nesting_level_left == 0))
+    {
+      buffer->successful = false;
+      return default_return_value ();
+    }
+
+    buffer->max_ops--;
+    if (unlikely (buffer->max_ops < 0))
     {
-      buffer->shaping_failed = true;
+      buffer->successful = false;
       return default_return_value ();
     }
 
@@ -703,7 +711,7 @@ struct hb_ot_apply_context_t :
     return ret;
   }
 
-  skipping_iterator_t iter_input, iter_context;
+  skipping_iterator_t iter_input, iter_context;
 
   unsigned int table_index; /* GSUB/GPOS */
   hb_font_t *font;
@@ -715,8 +723,7 @@ struct hb_ot_apply_context_t :
   const GDEF::accelerator_t &gdef_accel;
   const hb_ot_layout_lookup_accelerator_t *lookup_accel = nullptr;
   const ItemVariationStore &var_store;
-  ItemVariationStore::cache_t *var_store_cache;
-  hb_set_digest_t digest;
+  hb_scalar_cache_t *var_store_cache;
 
   hb_direction_t direction;
   hb_mask_t lookup_mask = 1;
@@ -734,11 +741,14 @@ struct hb_ot_apply_context_t :
   signed last_base = -1; // GPOS uses
   unsigned last_base_until = 0; // GPOS uses
 
+  hb_vector_t match_positions;
+  uint32_t stack_match_positions[8];
+
   hb_ot_apply_context_t (unsigned int table_index_,
                          hb_font_t *font_,
                          hb_buffer_t *buffer_,
                          hb_blob_t *table_blob_,
-                         ItemVariationStore::cache_t *var_store_cache_ = nullptr) :
+                         hb_scalar_cache_t *var_store_cache_ = nullptr) :
                         table_index (table_index_),
                         font (font_), face (font->face), buffer (buffer_),
                         sanitizer (table_blob_),
@@ -762,7 +772,7 @@ struct hb_ot_apply_context_t :
                         has_glyph_classes (gdef.has_glyph_classes ())
   {
     init_iters ();
-    buffer->collect_codepoints (digest);
+    match_positions.set_storage (stack_match_positions);
   }
 
   void init_iters ()
@@ -778,7 +788,11 @@ struct hb_ot_apply_context_t :
   void set_random (bool random_) { random = random_; }
   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
   void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
-  void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
+  void set_lookup_props (unsigned int lookup_props_)
+  {
+    lookup_props = gdef_accel.sanitize_lookup_props (lookup_props_);
+    init_iters ();
+  }
 
   uint32_t random_number ()
   {
@@ -787,7 +801,9 @@ struct hb_ot_apply_context_t :
     return buffer->random_state;
   }
 
-  bool match_properties_mark (hb_codepoint_t  glyph,
+  HB_ALWAYS_INLINE
+  HB_HOT
+  bool match_properties_mark (const hb_glyph_info_t *info,
                               unsigned int    glyph_props,
                               unsigned int    match_props) const
   {
@@ -795,7 +811,7 @@ struct hb_ot_apply_context_t :
      * match_props has the set index.
      */
     if (match_props & LookupFlag::UseMarkFilteringSet)
-      return gdef_accel.mark_set_covers (match_props >> 16, glyph);
+      return gdef_accel.mark_set_covers (match_props >> 16, info->codepoint);
 
     /* The second byte of match_props has the meaning
      * "ignore marks of attachment type different than
@@ -811,7 +827,7 @@ struct hb_ot_apply_context_t :
   HB_ALWAYS_INLINE
 #endif
   bool check_glyph_property (const hb_glyph_info_t *info,
-                             unsigned int  match_props) const
+                             unsigned match_props) const
   {
     unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
 
@@ -821,8 +837,8 @@ struct hb_ot_apply_context_t :
     if (glyph_props & match_props & LookupFlag::IgnoreFlags)
       return false;
 
-    if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
-      return match_properties_mark (info->codepoint, glyph_props, match_props);
+    if (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK)
+      return match_properties_mark (info, glyph_props, match_props);
 
     return true;
   }
@@ -832,7 +848,7 @@ struct hb_ot_apply_context_t :
                           bool ligature = false,
                           bool component = false)
   {
-    digest.add (glyph_index);
+    buffer->digest.add (glyph_index);
 
     if (new_syllables != (unsigned) -1)
       buffer->cur().syllable() = new_syllables;
@@ -890,54 +906,58 @@ struct hb_ot_apply_context_t :
   }
 };
 
-enum class hb_ot_lookup_cache_op_t
+enum class hb_ot_subtable_cache_op_t
 {
-  CREATE,
   ENTER,
   LEAVE,
-  DESTROY,
 };
 
 struct hb_accelerate_subtables_context_t :
        hb_dispatch_context_t
 {
-  template 
-  static inline bool apply_to (const void *obj, hb_ot_apply_context_t *c)
+  template 
+  static inline auto apply_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<1>) HB_RETURN (bool, obj->apply (c, external_cache) )
+  template 
+  static inline auto apply_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<0>) HB_RETURN (bool, obj->apply (c) )
+  template 
+  static inline bool apply_to (const void *obj, hb_ot_apply_context_t *c, void *external_cache)
   {
-    const Type *typed_obj = (const Type *) obj;
-    return typed_obj->apply (c);
+    const T *typed_obj = (const T *) obj;
+    return apply_ (typed_obj, c, external_cache, hb_prioritize);
   }
 
 #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
   template 
-  static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply_cached (c) )
+  static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<2>) HB_RETURN (bool, obj->apply_cached (c, external_cache) )
   template 
-  static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (bool, obj->apply (c) )
-  template 
-  static inline bool apply_cached_to (const void *obj, hb_ot_apply_context_t *c)
+  static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<1>) HB_RETURN (bool, obj->apply (c, external_cache) )
+  template 
+  static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<0>) HB_RETURN (bool, obj->apply (c) )
+  template 
+  static inline bool apply_cached_to (const void *obj, hb_ot_apply_context_t *c, void *external_cache)
   {
-    const Type *typed_obj = (const Type *) obj;
-    return apply_cached_ (typed_obj, c, hb_prioritize);
+    const T *typed_obj = (const T *) obj;
+    return apply_cached_ (typed_obj, c, external_cache, hb_prioritize);
   }
 
   template 
-  static inline auto cache_func_ (void *p,
-                                  hb_ot_lookup_cache_op_t op,
-                                  hb_priority<1>) HB_RETURN (void *, T::cache_func (p, op) )
+  static inline auto cache_func_ (hb_ot_apply_context_t *c,
+                                  hb_ot_subtable_cache_op_t op,
+                                  hb_priority<1>) HB_RETURN (bool, T::cache_func (c, op) )
   template 
-  static inline void * cache_func_ (void *p,
-                                    hb_ot_lookup_cache_op_t op HB_UNUSED,
-                                    hb_priority<0>) { return (void *) false; }
+  static inline bool cache_func_ (hb_ot_apply_context_t *c,
+                                  hb_ot_subtable_cache_op_t op HB_UNUSED,
+                                  hb_priority<0>) { return false; }
   template 
-  static inline void * cache_func_to (void *p,
-                                      hb_ot_lookup_cache_op_t op)
+  static inline bool cache_func_to (hb_ot_apply_context_t *c,
+                                    hb_ot_subtable_cache_op_t op)
   {
-    return cache_func_ (p, op, hb_prioritize);
+    return cache_func_ (c, op, hb_prioritize);
   }
 #endif
 
-  typedef bool (*hb_apply_func_t) (const void *obj, hb_ot_apply_context_t *c);
-  typedef void * (*hb_cache_func_t) (void *p, hb_ot_lookup_cache_op_t op);
+  typedef bool (*hb_apply_func_t) (const void *obj, hb_ot_apply_context_t *c, void *external_cache);
+  typedef bool (*hb_cache_func_t) (hb_ot_apply_context_t *c, hb_ot_subtable_cache_op_t op);
 
   struct hb_applicable_t
   {
@@ -950,6 +970,7 @@ struct hb_accelerate_subtables_context_t :
 #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
                , hb_apply_func_t apply_cached_func_
                , hb_cache_func_t cache_func_
+               , void *external_cache_
 #endif
                 )
     {
@@ -958,27 +979,34 @@ struct hb_accelerate_subtables_context_t :
 #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
       apply_cached_func = apply_cached_func_;
       cache_func = cache_func_;
+      external_cache = external_cache_;
 #endif
       digest.init ();
       obj_.get_coverage ().collect_coverage (&digest);
     }
 
+#ifdef HB_NO_OT_LAYOUT_LOOKUP_CACHE
     bool apply (hb_ot_apply_context_t *c) const
     {
-      return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
+      return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c, nullptr);
+    }
+#else
+    bool apply (hb_ot_apply_context_t *c) const
+    {
+      return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c, external_cache);
     }
-#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
     bool apply_cached (hb_ot_apply_context_t *c) const
     {
-      return digest.may_have (c->buffer->cur().codepoint) &&  apply_cached_func (obj, c);
+      return digest.may_have (c->buffer->cur().codepoint) &&  apply_cached_func (obj, c, external_cache);
     }
+
     bool cache_enter (hb_ot_apply_context_t *c) const
     {
-      return (bool) cache_func (c, hb_ot_lookup_cache_op_t::ENTER);
+      return cache_func (c, hb_ot_subtable_cache_op_t::ENTER);
     }
     void cache_leave (hb_ot_apply_context_t *c) const
     {
-      cache_func (c, hb_ot_lookup_cache_op_t::LEAVE);
+      cache_func (c, hb_ot_subtable_cache_op_t::LEAVE);
     }
 #endif
 
@@ -988,6 +1016,7 @@ struct hb_accelerate_subtables_context_t :
 #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
     hb_apply_func_t apply_cached_func;
     hb_cache_func_t cache_func;
+    void *external_cache;
 #endif
     hb_set_digest_t digest;
   };
@@ -997,12 +1026,23 @@ struct hb_accelerate_subtables_context_t :
   auto cache_cost (const T &obj, hb_priority<1>) HB_AUTO_RETURN ( obj.cache_cost () )
   template 
   auto cache_cost (const T &obj, hb_priority<0>) HB_AUTO_RETURN ( 0u )
+
+  template 
+  auto external_cache_create (const T &obj, hb_priority<1>) HB_AUTO_RETURN ( obj.external_cache_create () )
+  template 
+  auto external_cache_create (const T &obj, hb_priority<0>) HB_AUTO_RETURN ( nullptr )
 #endif
 
   /* Dispatch interface. */
   template 
   return_t dispatch (const T &obj)
   {
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+    void *external_cache = nullptr;
+    if (i < 8)
+      external_cache = external_cache_create (obj, hb_prioritize);
+#endif
+
     hb_applicable_t *entry = &array[i++];
 
     entry->init (obj,
@@ -1010,6 +1050,7 @@ struct hb_accelerate_subtables_context_t :
 #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
                  , apply_cached_to
                  , cache_func_to
+                 , external_cache
 #endif
                  );
 
@@ -1023,10 +1064,10 @@ struct hb_accelerate_subtables_context_t :
      * and we allocate the cache opportunity to the costliest subtable.
      */
     unsigned cost = cache_cost (obj, hb_prioritize);
-    if (cost > cache_user_cost)
+    if (cost > subtable_cache_user_cost)
     {
-      cache_user_idx = i - 1;
-      cache_user_cost = cost;
+      subtable_cache_user_idx = i - 1;
+      subtable_cache_user_cost = cost;
     }
 #endif
 
@@ -1041,8 +1082,8 @@ struct hb_accelerate_subtables_context_t :
   unsigned i = 0;
 
 #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
-  unsigned cache_user_idx = (unsigned) -1;
-  unsigned cache_user_cost = 0;
+  unsigned subtable_cache_user_idx = (unsigned) -1;
+  unsigned subtable_cache_user_cost = 0;
 #endif
 };
 
@@ -1191,38 +1232,50 @@ static inline bool match_class (hb_glyph_info_t &info, unsigned value, const voi
   const ClassDef &class_def = *reinterpret_cast(data);
   return class_def.get_class (info.codepoint) == value;
 }
-static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, const void *data)
+static inline unsigned get_class_cached (const ClassDef &class_def, hb_glyph_info_t &info)
 {
   unsigned klass = info.syllable();
   if (klass < 255)
-    return klass == value;
-  const ClassDef &class_def = *reinterpret_cast(data);
+    return klass;
   klass = class_def.get_class (info.codepoint);
   if (likely (klass < 255))
     info.syllable() = klass;
-  return klass == value;
+  return klass;
 }
-static inline bool match_class_cached1 (hb_glyph_info_t &info, unsigned value, const void *data)
+static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, const void *data)
+{
+  const ClassDef &class_def = *reinterpret_cast(data);
+  return get_class_cached (class_def, info) == value;
+}
+static inline unsigned get_class_cached1 (const ClassDef &class_def, hb_glyph_info_t &info)
 {
   unsigned klass = info.syllable() & 0x0F;
   if (klass < 15)
-    return klass == value;
-  const ClassDef &class_def = *reinterpret_cast(data);
+    return klass;
   klass = class_def.get_class (info.codepoint);
   if (likely (klass < 15))
     info.syllable() = (info.syllable() & 0xF0) | klass;
-  return klass == value;
+  return klass;
 }
-static inline bool match_class_cached2 (hb_glyph_info_t &info, unsigned value, const void *data)
+static inline bool match_class_cached1 (hb_glyph_info_t &info, unsigned value, const void *data)
+{
+  const ClassDef &class_def = *reinterpret_cast(data);
+  return get_class_cached1 (class_def, info) == value;
+}
+static inline unsigned get_class_cached2 (const ClassDef &class_def, hb_glyph_info_t &info)
 {
   unsigned klass = (info.syllable() & 0xF0) >> 4;
   if (klass < 15)
-    return klass == value;
-  const ClassDef &class_def = *reinterpret_cast(data);
+    return klass;
   klass = class_def.get_class (info.codepoint);
   if (likely (klass < 15))
     info.syllable() = (info.syllable() & 0x0F) | (klass << 4);
-  return klass == value;
+  return klass;
+}
+static inline bool match_class_cached2 (hb_glyph_info_t &info, unsigned value, const void *data)
+{
+  const ClassDef &class_def = *reinterpret_cast(data);
+  return get_class_cached2 (class_def, info) == value;
 }
 static inline bool match_coverage (hb_glyph_info_t &info, unsigned value, const void *data)
 {
@@ -1261,16 +1314,24 @@ static bool match_input (hb_ot_apply_context_t *c,
                          match_func_t match_func,
                          const void *match_data,
                          unsigned int *end_position,
-                         unsigned int *match_positions,
                          unsigned int *p_total_component_count = nullptr)
 {
   TRACE_APPLY (nullptr);
 
-  if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
-
   hb_buffer_t *buffer = c->buffer;
 
-  hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+  if (count == 1)
+  {
+    *end_position = buffer->idx + 1;
+    c->match_positions[0] = buffer->idx;
+    if (p_total_component_count)
+      *p_total_component_count = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
+    return_trace (true);
+  }
+
+  if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
+
+  auto &skippy_iter = c->iter_input;
   skippy_iter.reset (buffer->idx);
   skippy_iter.set_match_func (match_func, match_data);
   skippy_iter.set_glyph_data (input);
@@ -1319,7 +1380,10 @@ static bool match_input (hb_ot_apply_context_t *c,
       return_trace (false);
     }
 
-    match_positions[i] = skippy_iter.idx;
+    if (unlikely (i + 1 > c->match_positions.length &&
+                  !c->match_positions.resize_dirty  (i + 1)))
+      return_trace (false);
+    c->match_positions.arrayZ[i] = skippy_iter.idx;
 
     unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
     unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
@@ -1349,7 +1413,7 @@ static bool match_input (hb_ot_apply_context_t *c,
             j--;
           }
 
-          if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
+          if (found && skippy_iter.may_skip (out[j]) == matcher_t::SKIP_YES)
             ligbase = LIGBASE_MAY_SKIP;
           else
             ligbase = LIGBASE_MAY_NOT_SKIP;
@@ -1379,13 +1443,12 @@ static bool match_input (hb_ot_apply_context_t *c,
     *p_total_component_count = total_component_count;
   }
 
-  match_positions[0] = buffer->idx;
+  c->match_positions.arrayZ[0] = buffer->idx;
 
   return_trace (true);
 }
 static inline bool ligate_input (hb_ot_apply_context_t *c,
                                  unsigned int count, /* Including the first glyph */
-                                 const unsigned int *match_positions, /* Including the first glyph */
                                  unsigned int match_end,
                                  hb_codepoint_t lig_glyph,
                                  unsigned int total_component_count)
@@ -1428,10 +1491,10 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
    *   https://bugzilla.gnome.org/show_bug.cgi?id=437633
    */
 
-  bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]);
-  bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]);
+  bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[c->match_positions.arrayZ[0]]);
+  bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[c->match_positions.arrayZ[0]]);
   for (unsigned int i = 1; i < count; i++)
-    if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
+    if (!_hb_glyph_info_is_mark (&buffer->info[c->match_positions.arrayZ[i]]))
     {
       is_base_ligature = false;
       is_mark_ligature = false;
@@ -1457,7 +1520,7 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
 
   for (unsigned int i = 1; i < count; i++)
   {
-    while (buffer->idx < match_positions[i] && buffer->successful)
+    while (buffer->idx < c->match_positions.arrayZ[i] && buffer->successful)
     {
       if (is_ligature)
       {
@@ -1512,8 +1575,14 @@ static bool match_backtrack (hb_ot_apply_context_t *c,
 {
   TRACE_APPLY (nullptr);
 
-  hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
-  skippy_iter.reset (c->buffer->backtrack_len ());
+  if (!count)
+  {
+    *match_start = c->buffer->backtrack_len ();
+    return_trace (true);
+  }
+
+  auto &skippy_iter = c->iter_context;
+  skippy_iter.reset_back (c->buffer->backtrack_len ());
   skippy_iter.set_match_func (match_func, match_data);
   skippy_iter.set_glyph_data (backtrack);
 
@@ -1545,7 +1614,13 @@ static bool match_lookahead (hb_ot_apply_context_t *c,
 {
   TRACE_APPLY (nullptr);
 
-  hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
+  if (!count)
+  {
+    *end_index = start_index;
+    return_trace (true);
+  }
+
+  auto &skippy_iter = c->iter_context;
   assert (start_index >= 1);
   skippy_iter.reset (start_index - 1);
   skippy_iter.set_match_func (match_func, match_data);
@@ -1696,7 +1771,6 @@ static inline void recurse_lookups (context_t *c,
 
 static inline void apply_lookup (hb_ot_apply_context_t *c,
                                  unsigned int count, /* Including the first glyph */
-                                 unsigned int *match_positions, /* Including the first glyph */
                                  unsigned int lookupCount,
                                  const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
                                  unsigned int match_end)
@@ -1704,9 +1778,6 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
   hb_buffer_t *buffer = c->buffer;
   int end;
 
-  unsigned int *match_positions_input = match_positions;
-  unsigned int match_positions_count = count;
-
   /* All positions are distance from beginning of *output* buffer.
    * Adjust. */
   {
@@ -1716,7 +1787,7 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
     int delta = bl - buffer->idx;
     /* Convert positions to new indexing. */
     for (unsigned int j = 0; j < count; j++)
-      match_positions[j] += delta;
+      c->match_positions.arrayZ[j] += delta;
   }
 
   for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
@@ -1728,10 +1799,10 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
     unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
 
     /* This can happen if earlier recursed lookups deleted many entries. */
-    if (unlikely (match_positions[idx] >= orig_len))
+    if (unlikely (c->match_positions.arrayZ[idx] >= orig_len))
       continue;
 
-    if (unlikely (!buffer->move_to (match_positions[idx])))
+    if (unlikely (!buffer->move_to (c->match_positions.arrayZ[idx])))
       break;
 
     if (unlikely (buffer->max_ops <= 0))
@@ -1790,9 +1861,9 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
      */
 
     end += delta;
-    if (end < int (match_positions[idx]))
+    if (end < int (c->match_positions.arrayZ[idx]))
     {
-      /* End might end up being smaller than match_positions[idx] if the recursed
+      /* End might end up being smaller than match_positions.arrayZ[idx] if the recursed
        * lookup ended up removing many items.
        * Just never rewind end beyond start of current position, since that is
        * not possible in the recursed lookup.  Also adjust delta as such.
@@ -1800,8 +1871,8 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
        * https://bugs.chromium.org/p/chromium/issues/detail?id=659496
        * https://github.com/harfbuzz/harfbuzz/issues/1611
        */
-      delta += match_positions[idx] - end;
-      end = match_positions[idx];
+      delta += c->match_positions.arrayZ[idx] - end;
+      end = c->match_positions.arrayZ[idx];
     }
 
     unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
@@ -1810,27 +1881,9 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
     {
       if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
         break;
-      if (unlikely (delta + count > match_positions_count))
-      {
-        unsigned new_match_positions_count = hb_max (delta + count, hb_max(match_positions_count, 4u) * 1.5);
-        if (match_positions == match_positions_input)
-        {
-          match_positions = (unsigned int *) hb_malloc (new_match_positions_count * sizeof (match_positions[0]));
-          if (unlikely (!match_positions))
-            break;
-          memcpy (match_positions, match_positions_input, count * sizeof (match_positions[0]));
-          match_positions_count = new_match_positions_count;
-        }
-        else
-        {
-          unsigned int *new_match_positions = (unsigned int *) hb_realloc (match_positions, new_match_positions_count * sizeof (match_positions[0]));
-          if (unlikely (!new_match_positions))
-            break;
-          match_positions = new_match_positions;
-          match_positions_count = new_match_positions_count;
-        }
-      }
-
+      if (unlikely (count + delta > c->match_positions.length &&
+                    !c->match_positions.resize_dirty  (count + delta)))
+        return;
     }
     else
     {
@@ -1840,23 +1893,20 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
     }
 
     /* Shift! */
-    memmove (match_positions + next + delta, match_positions + next,
-             (count - next) * sizeof (match_positions[0]));
+    memmove (c->match_positions + next + delta, c->match_positions + next,
+             (count - next) * sizeof (c->match_positions.arrayZ[0]));
     next += delta;
     count += delta;
 
     /* Fill in new entries. */
     for (unsigned int j = idx + 1; j < next; j++)
-      match_positions[j] = match_positions[j - 1] + 1;
+      c->match_positions.arrayZ[j] = c->match_positions.arrayZ[j - 1] + 1;
 
     /* And fixup the rest. */
     for (; next < count; next++)
-      match_positions[next] += delta;
+      c->match_positions.arrayZ[next] += delta;
   }
 
-  if (match_positions != match_positions_input)
-    hb_free (match_positions);
-
   assert (end >= 0);
   (void) buffer->move_to (end);
 }
@@ -1950,34 +2000,25 @@ static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
 }
 
 template 
-HB_ALWAYS_INLINE
-static bool context_apply_lookup (hb_ot_apply_context_t *c,
-                                  unsigned int inputCount, /* Including the first glyph (not matched) */
-                                  const HBUINT input[], /* Array of input values--start with second glyph */
-                                  unsigned int lookupCount,
-                                  const LookupRecord lookupRecord[],
-                                  const ContextApplyLookupContext &lookup_context)
+static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
+                                         unsigned int inputCount, /* Including the first glyph (not matched) */
+                                         const HBUINT input[], /* Array of input values--start with second glyph */
+                                         unsigned int lookupCount,
+                                         const LookupRecord lookupRecord[],
+                                         const ContextApplyLookupContext &lookup_context)
 {
   if (unlikely (inputCount > HB_MAX_CONTEXT_LENGTH)) return false;
-  unsigned match_positions_stack[4];
-  unsigned *match_positions = match_positions_stack;
-  if (unlikely (inputCount > ARRAY_LENGTH (match_positions_stack)))
-  {
-    match_positions = (unsigned *) hb_malloc (hb_max (inputCount, 1u) * sizeof (match_positions[0]));
-    if (unlikely (!match_positions))
-      return false;
-  }
 
   unsigned match_end = 0;
   bool ret = false;
   if (match_input (c,
                    inputCount, input,
                    lookup_context.funcs.match, lookup_context.match_data,
-                   &match_end, match_positions))
+                   &match_end))
   {
     c->buffer->unsafe_to_break (c->buffer->idx, match_end);
     apply_lookup (c,
-                  inputCount, match_positions,
+                  inputCount,
                   lookupCount, lookupRecord,
                   match_end);
     ret = true;
@@ -1988,12 +2029,34 @@ static bool context_apply_lookup (hb_ot_apply_context_t *c,
     ret = false;
   }
 
-  if (unlikely (match_positions != match_positions_stack))
-    hb_free (match_positions);
-
   return ret;
 }
 
+static inline bool context_cache_func (hb_ot_apply_context_t *c, hb_ot_subtable_cache_op_t op)
+{
+  switch (op)
+  {
+    case hb_ot_subtable_cache_op_t::ENTER:
+    {
+      if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
+        return false;
+      auto &info = c->buffer->info;
+      unsigned count = c->buffer->len;
+      for (unsigned i = 0; i < count; i++)
+        info[i].syllable() = 255;
+      c->new_syllables = 255;
+      return true;
+    }
+    case hb_ot_subtable_cache_op_t::LEAVE:
+    {
+      c->new_syllables = (unsigned) -1;
+      HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
+      break;
+    }
+  }
+  return false;
+}
+
 template 
 struct Rule
 {
@@ -2209,24 +2272,29 @@ struct RuleSet
      *
      * Replicated from LigatureSet::apply(). */
 
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    /* We use the iter_context instead of iter_input, to avoid skipping
+     * default-ignorables and such.
+     *
+     * Related: https://github.com/harfbuzz/harfbuzz/issues/4813
+     */
+    auto &skippy_iter = c->iter_context;
     skippy_iter.reset (c->buffer->idx);
     skippy_iter.set_match_func (match_always, nullptr);
     skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
-    unsigned unsafe_to = (unsigned) -1, unsafe_to1 = 0, unsafe_to2 = 0;
+    unsigned unsafe_to = (unsigned) -1, unsafe_to1, unsafe_to2 = 0;
     hb_glyph_info_t *first = nullptr, *second = nullptr;
     bool matched = skippy_iter.next ();
     if (likely (matched))
     {
-      first = &c->buffer->info[skippy_iter.idx];
-      unsafe_to = skippy_iter.idx + 1;
-
       if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
       {
         /* Can't use the fast path if eg. the next char is a default-ignorable
          * or other skippable. */
         goto slow;
       }
+
+      first = &c->buffer->info[skippy_iter.idx];
+      unsafe_to1 = skippy_iter.idx + 1;
     }
     else
     {
@@ -2242,8 +2310,15 @@ struct RuleSet
       ;
     }
     matched = skippy_iter.next ();
-    if (likely (matched && !skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])))
+    if (likely (matched))
     {
+      if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
+      {
+        /* Can't use the fast path if eg. the next char is a default-ignorable
+         * or other skippable. */
+        goto slow;
+      }
+
       second = &c->buffer->info[skippy_iter.idx];
       unsafe_to2 = skippy_iter.idx + 1;
     }
@@ -2280,6 +2355,15 @@ struct RuleSet
       {
         if (unsafe_to == (unsigned) -1)
           unsafe_to = unsafe_to1;
+
+        // Skip ahead to next possible first glyph match.
+        for (; i + 1 < num_rules; i++)
+        {
+          const auto &r2 = this+rule.arrayZ[i + 1];
+          const auto &input2 = r2.inputZ;
+          if (r2.inputCount <= 1 || input2.arrayZ[0] != input.arrayZ[0])
+            break;
+        }
       }
     }
     if (likely (unsafe_to != (unsigned) -1))
@@ -2622,46 +2706,37 @@ struct ContextFormat2_5
 
   unsigned cache_cost () const
   {
-    unsigned c = (this+classDef).cost () * ruleSet.len;
-    return c >= 4 ? c : 0;
+    return (this+classDef).cost ();
+  }
+  static bool cache_func (hb_ot_apply_context_t *c, hb_ot_subtable_cache_op_t op)
+  {
+    return context_cache_func (c, op);
   }
-  static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
+
+  struct external_cache_t
+  {
+    hb_ot_layout_binary_cache_t coverage;
+  };
+  void *external_cache_create () const
   {
-    switch (op)
+    external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t));
+    if (likely (cache))
     {
-      case hb_ot_lookup_cache_op_t::CREATE:
-        return (void *) true;
-      case hb_ot_lookup_cache_op_t::ENTER:
-      {
-        hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p;
-        if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
-          return (void *) false;
-        auto &info = c->buffer->info;
-        unsigned count = c->buffer->len;
-        for (unsigned i = 0; i < count; i++)
-          info[i].syllable() = 255;
-        c->new_syllables = 255;
-        return (void *) true;
-      }
-      case hb_ot_lookup_cache_op_t::LEAVE:
-      {
-        hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p;
-        c->new_syllables = (unsigned) -1;
-        HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
-        return nullptr;
-      }
-      case hb_ot_lookup_cache_op_t::DESTROY:
-        return nullptr;
+      cache->coverage.clear ();
     }
-    return nullptr;
+    return cache;
   }
-
-  bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
-  bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
-  bool _apply (hb_ot_apply_context_t *c, bool cached) const
+  bool apply_cached (hb_ot_apply_context_t *c, void *external_cache) const { return _apply (c, true, external_cache); }
+  bool apply (hb_ot_apply_context_t *c, void *external_cache) const { return _apply (c, false, external_cache); }
+  bool _apply (hb_ot_apply_context_t *c, bool cached, void *external_cache) const
   {
     TRACE_APPLY (this);
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+    external_cache_t *cache = (external_cache_t *) external_cache;
+    unsigned int index = (this+coverage).get_coverage_binary (c->buffer->cur().codepoint, cache ? &cache->coverage : nullptr);
+#else
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+#endif
     if (index == NOT_COVERED) return_trace (false);
 
     const ClassDef &class_def = this+classDef;
@@ -2671,10 +2746,7 @@ struct ContextFormat2_5
       &class_def
     };
 
-    if (cached && c->buffer->cur().syllable() < 255)
-      index = c->buffer->cur().syllable ();
-    else
-      index = class_def.get_class (c->buffer->cur().codepoint);
+    index = cached ? get_class_cached (class_def, c->buffer->cur()) : class_def.get_class (c->buffer->cur().codepoint);
     const RuleSet &rule_set = this+ruleSet[index];
     return_trace (rule_set.apply (c, lookup_context));
   }
@@ -2919,9 +2991,9 @@ struct Context
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...));
     case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...));
     case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...));
@@ -2935,7 +3007,7 @@ struct Context
 
   protected:
   union {
-  HBUINT16                      format;         /* Format identifier */
+  struct { HBUINT16 v; }        format;         /* Format identifier */
   ContextFormat1_4  format1;
   ContextFormat2_5  format2;
   ContextFormat3                format3;
@@ -3069,27 +3141,18 @@ static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c
 }
 
 template 
-HB_ALWAYS_INLINE
-static bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
-                                        unsigned int backtrackCount,
-                                        const HBUINT backtrack[],
-                                        unsigned int inputCount, /* Including the first glyph (not matched) */
-                                        const HBUINT input[], /* Array of input values--start with second glyph */
-                                        unsigned int lookaheadCount,
-                                        const HBUINT lookahead[],
-                                        unsigned int lookupCount,
-                                        const LookupRecord lookupRecord[],
-                                        const ChainContextApplyLookupContext &lookup_context)
+static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
+                                               unsigned int backtrackCount,
+                                               const HBUINT backtrack[],
+                                               unsigned int inputCount, /* Including the first glyph (not matched) */
+                                               const HBUINT input[], /* Array of input values--start with second glyph */
+                                               unsigned int lookaheadCount,
+                                               const HBUINT lookahead[],
+                                               unsigned int lookupCount,
+                                               const LookupRecord lookupRecord[],
+                                               const ChainContextApplyLookupContext &lookup_context)
 {
   if (unlikely (inputCount > HB_MAX_CONTEXT_LENGTH)) return false;
-  unsigned match_positions_stack[4];
-  unsigned *match_positions = match_positions_stack;
-  if (unlikely (inputCount > ARRAY_LENGTH (match_positions_stack)))
-  {
-    match_positions = (unsigned *) hb_malloc (hb_max (inputCount, 1u) * sizeof (match_positions[0]));
-    if (unlikely (!match_positions))
-      return false;
-  }
 
   unsigned start_index = c->buffer->out_len;
   unsigned end_index = c->buffer->idx;
@@ -3098,15 +3161,14 @@ static bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
   if (!(match_input (c,
                      inputCount, input,
                      lookup_context.funcs.match[1], lookup_context.match_data[1],
-                     &match_end, match_positions) && (end_index = match_end)
+                     &match_end) && (end_index = match_end)
        && match_lookahead (c,
                            lookaheadCount, lookahead,
                            lookup_context.funcs.match[2], lookup_context.match_data[2],
                            match_end, &end_index)))
   {
     c->buffer->unsafe_to_concat (c->buffer->idx, end_index);
-    ret = false;
-    goto done;
+    return false;
   }
 
   if (!match_backtrack (c,
@@ -3115,19 +3177,14 @@ static bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
                         &start_index))
   {
     c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
-    ret = false;
-    goto done;
+    return false;
   }
 
   c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
   apply_lookup (c,
-                inputCount, match_positions,
+                inputCount,
                 lookupCount, lookupRecord,
                 match_end);
-  done:
-
-  if (unlikely (match_positions != match_positions_stack))
-    hb_free (match_positions);
 
   return ret;
 }
@@ -3411,33 +3468,29 @@ struct ChainRuleSet
      *
      * Replicated from LigatureSet::apply(). */
 
-    /* If the input skippy has non-auto joiners behavior (as in Indic shapers),
-     * skip this fast path, as we don't distinguish between input & lookahead
-     * matching in the fast path.
+    /* We use the iter_context instead of iter_input, to avoid skipping
+     * default-ignorables and such.
      *
-     * https://github.com/harfbuzz/harfbuzz/issues/4813
+     * Related: https://github.com/harfbuzz/harfbuzz/issues/4813
      */
-    if (!c->auto_zwnj || !c->auto_zwj)
-      goto slow;
-
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_context;
     skippy_iter.reset (c->buffer->idx);
     skippy_iter.set_match_func (match_always, nullptr);
     skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
-    unsigned unsafe_to = (unsigned) -1, unsafe_to1 = 0, unsafe_to2 = 0;
+    unsigned unsafe_to = (unsigned) -1, unsafe_to1, unsafe_to2 = 0;
     hb_glyph_info_t *first = nullptr, *second = nullptr;
     bool matched = skippy_iter.next ();
     if (likely (matched))
     {
-      first = &c->buffer->info[skippy_iter.idx];
-      unsafe_to1 = skippy_iter.idx + 1;
-
       if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
       {
         /* Can't use the fast path if eg. the next char is a default-ignorable
          * or other skippable. */
         goto slow;
       }
+
+      first = &c->buffer->info[skippy_iter.idx];
+      unsafe_to1 = skippy_iter.idx + 1;
     }
     else
     {
@@ -3458,8 +3511,15 @@ struct ChainRuleSet
       ;
     }
     matched = skippy_iter.next ();
-    if (likely (matched && !skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])))
+    if (likely (matched))
     {
+      if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
+      {
+        /* Can't use the fast path if eg. the next char is a default-ignorable
+         * or other skippable. */
+        goto slow;
+      }
+
       second = &c->buffer->info[skippy_iter.idx];
       unsafe_to2 = skippy_iter.idx + 1;
     }
@@ -3475,7 +3535,7 @@ struct ChainRuleSet
       const auto &input = StructAfter (r.backtrack);
       const auto &lookahead = StructAfter (input);
 
-      unsigned lenP1 = hb_max ((unsigned) input.lenP1, 1u);
+      unsigned lenP1 = input.lenP1;
       if (lenP1 > 1 ?
            (!match_input ||
             match_input (*first, input.arrayZ[0], input_data))
@@ -3483,6 +3543,7 @@ struct ChainRuleSet
            (!lookahead.len || !match_lookahead ||
             match_lookahead (*first, lookahead.arrayZ[0], lookahead_data)))
       {
+        lenP1 = hb_max (lenP1, 1u);
         if (!second ||
             (lenP1 > 2 ?
              (!match_input ||
@@ -3505,6 +3566,18 @@ struct ChainRuleSet
       {
         if (unsafe_to == (unsigned) -1)
           unsafe_to = unsafe_to1;
+
+        if (lenP1 > 1)
+        {
+          // Skip ahead to next possible first glyph match.
+          for (; i + 1 < num_rules; i++)
+          {
+            const auto &r2 = this+rule.arrayZ[i + 1];
+            const auto &input2 = StructAfter (r2.backtrack);
+            if (input2.lenP1 <= 1 || input2.arrayZ[0] != input.arrayZ[0])
+              break;
+          }
+        }
       }
     }
     if (likely (unsafe_to != (unsigned) -1))
@@ -3873,45 +3946,37 @@ struct ChainContextFormat2_5
 
   unsigned cache_cost () const
   {
-    return (this+lookaheadClassDef).cost () * ruleSet.len;
+    return (this+inputClassDef).cost () + (this+lookaheadClassDef).cost ();
   }
-  static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
+  static bool cache_func (hb_ot_apply_context_t *c, hb_ot_subtable_cache_op_t op)
   {
-    switch (op)
+    return context_cache_func (c, op);
+  }
+
+  struct external_cache_t
+  {
+    hb_ot_layout_binary_cache_t coverage;
+  };
+  void *external_cache_create () const
+  {
+    external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t));
+    if (likely (cache))
     {
-      case hb_ot_lookup_cache_op_t::CREATE:
-        return (void *) true;
-      case hb_ot_lookup_cache_op_t::ENTER:
-      {
-        hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p;
-        if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
-          return (void *) false;
-        auto &info = c->buffer->info;
-        unsigned count = c->buffer->len;
-        for (unsigned i = 0; i < count; i++)
-          info[i].syllable() = 255;
-        c->new_syllables = 255;
-        return (void *) true;
-      }
-      case hb_ot_lookup_cache_op_t::LEAVE:
-      {
-        hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p;
-        c->new_syllables = (unsigned) -1;
-        HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
-        return nullptr;
-      }
-      case hb_ot_lookup_cache_op_t::DESTROY:
-        return nullptr;
+      cache->coverage.clear ();
     }
-    return nullptr;
+    return cache;
   }
-
-  bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
-  bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
-  bool _apply (hb_ot_apply_context_t *c, bool cached) const
+  bool apply_cached (hb_ot_apply_context_t *c, void *external_cache) const { return _apply (c, true, external_cache); }
+  bool apply (hb_ot_apply_context_t *c, void *external_cache) const { return _apply (c, false, external_cache); }
+  bool _apply (hb_ot_apply_context_t *c, bool cached, void *external_cache) const
   {
     TRACE_APPLY (this);
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+    external_cache_t *cache = (external_cache_t *) external_cache;
+    unsigned int index = (this+coverage).get_coverage_binary (c->buffer->cur().codepoint, cache ? &cache->coverage : nullptr);
+#else
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+#endif
     if (index == NOT_COVERED) return_trace (false);
 
     const ClassDef &backtrack_class_def = this+backtrackClassDef;
@@ -3929,11 +3994,9 @@ struct ChainContextFormat2_5
        &lookahead_class_def}
     };
 
-    // Note: Corresponds to match_class_cached2
-    if (cached && ((c->buffer->cur().syllable() & 0xF0) >> 4) < 15)
-      index = (c->buffer->cur().syllable () & 0xF0) >> 4;
-    else
-      index = input_class_def.get_class (c->buffer->cur().codepoint);
+    index = cached
+         ? get_class_cached2 (input_class_def, c->buffer->cur())
+          : input_class_def.get_class (c->buffer->cur().codepoint);
     const ChainRuleSet &rule_set = this+ruleSet[index];
     return_trace (rule_set.apply (c, lookup_context));
   }
@@ -4261,9 +4324,9 @@ struct ChainContext
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...));
     case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...));
     case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...));
@@ -4277,7 +4340,7 @@ struct ChainContext
 
   protected:
   union {
-  HBUINT16                              format; /* Format identifier */
+  struct { HBUINT16 v; }                format; /* Format identifier */
   ChainContextFormat1_4     format1;
   ChainContextFormat2_5     format2;
   ChainContextFormat3                   format3;
@@ -4352,7 +4415,7 @@ struct Extension
 {
   unsigned int get_type () const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return u.format1.get_type ();
     default:return 0;
     }
@@ -4360,7 +4423,7 @@ struct Extension
   template 
   const X& get_subtable () const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return u.format1.template get_subtable ();
     default:return Null (typename T::SubTable);
     }
@@ -4372,7 +4435,7 @@ struct Extension
   template 
   typename hb_subset_context_t::return_t dispatch (hb_subset_context_t *c, Ts&&... ds) const
   {
-    switch (u.format) {
+    switch (u.format.v) {
     case 1: hb_barrier (); return u.format1.subset (c);
     default: return c->default_return_value ();
     }
@@ -4381,9 +4444,9 @@ struct Extension
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: hb_barrier (); return_trace (u.format1.dispatch (c, std::forward (ds)...));
     default:return_trace (c->default_return_value ());
     }
@@ -4391,7 +4454,7 @@ struct Extension
 
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
+  struct { HBUINT16 v; }        format;         /* Format identifier */
   ExtensionFormat1   format1;
   } u;
 };
@@ -4428,22 +4491,14 @@ struct hb_ot_layout_lookup_accelerator_t
     for (auto& subtable : hb_iter (thiz->subtables, count))
       thiz->digest.union_ (subtable.digest);
 
-#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
-    if (c_accelerate_subtables.cache_user_cost < 4)
-      c_accelerate_subtables.cache_user_idx = (unsigned) -1;
-
-    thiz->cache_user_idx = c_accelerate_subtables.cache_user_idx;
+    thiz->count = count;
 
-    if (thiz->cache_user_idx != (unsigned) -1)
-    {
-      thiz->cache = thiz->subtables[thiz->cache_user_idx].cache_func (nullptr, hb_ot_lookup_cache_op_t::CREATE);
-      if (!thiz->cache)
-        thiz->cache_user_idx = (unsigned) -1;
-    }
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+    thiz->subtable_cache_user_idx = c_accelerate_subtables.subtable_cache_user_idx;
 
     for (unsigned i = 0; i < count; i++)
-      if (i != thiz->cache_user_idx)
-        thiz->subtables[i].apply_cached_func = thiz->subtables[i].apply_func;
+      if (i != thiz->subtable_cache_user_idx)
+       thiz->subtables[i].apply_cached_func = thiz->subtables[i].apply_func;
 #endif
 
     return thiz;
@@ -4452,11 +4507,8 @@ struct hb_ot_layout_lookup_accelerator_t
   void fini ()
   {
 #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
-    if (cache)
-    {
-      assert (cache_user_idx != (unsigned) -1);
-      subtables[cache_user_idx].cache_func (cache, hb_ot_lookup_cache_op_t::DESTROY);
-    }
+    for (unsigned i = 0; i < count; i++)
+      hb_free (subtables[i].external_cache);
 #endif
   }
 
@@ -4466,14 +4518,14 @@ struct hb_ot_layout_lookup_accelerator_t
 #ifndef HB_OPTIMIZE_SIZE
   HB_ALWAYS_INLINE
 #endif
-  bool apply (hb_ot_apply_context_t *c, unsigned subtables_count, bool use_cache) const
+  bool apply (hb_ot_apply_context_t *c, bool use_cache) const
   {
     c->lookup_accel = this;
 #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
     if (use_cache)
     {
       return
-      + hb_iter (hb_iter (subtables, subtables_count))
+      + hb_iter (hb_iter (subtables, count))
       | hb_map ([&c] (const hb_accelerate_subtables_context_t::hb_applicable_t &_) { return _.apply_cached (c); })
       | hb_any
       ;
@@ -4482,7 +4534,7 @@ struct hb_ot_layout_lookup_accelerator_t
 #endif
     {
       return
-      + hb_iter (hb_iter (subtables, subtables_count))
+      + hb_iter (hb_iter (subtables, count))
       | hb_map ([&c] (const hb_accelerate_subtables_context_t::hb_applicable_t &_) { return _.apply (c); })
       | hb_any
       ;
@@ -4493,8 +4545,8 @@ struct hb_ot_layout_lookup_accelerator_t
   bool cache_enter (hb_ot_apply_context_t *c) const
   {
 #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
-    return cache_user_idx != (unsigned) -1 &&
-           subtables[cache_user_idx].cache_enter (c);
+    return subtable_cache_user_idx != (unsigned) -1 &&
+           subtables[subtable_cache_user_idx].cache_enter (c);
 #else
     return false;
 #endif
@@ -4502,19 +4554,17 @@ struct hb_ot_layout_lookup_accelerator_t
   void cache_leave (hb_ot_apply_context_t *c) const
   {
 #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
-    subtables[cache_user_idx].cache_leave (c);
+    subtables[subtable_cache_user_idx].cache_leave (c);
 #endif
   }
 
 
   hb_set_digest_t digest;
-#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
-  public:
-  void *cache = nullptr;
   private:
-  unsigned cache_user_idx = (unsigned) -1;
+  unsigned count = 0; /* Number of subtables in the array. */
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+  unsigned subtable_cache_user_idx = (unsigned) -1;
 #endif
-  private:
   hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY];
 };
 
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 afe52963201..c73e4dc4b6d 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc
@@ -343,7 +343,7 @@ hb_ot_layout_get_glyphs_in_class (hb_face_t                  *face,
  * @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) (optional): Input = the maximum number of attachment points to return;
+ * @point_count: (inout) (nullable): 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
  *
@@ -373,7 +373,7 @@ hb_ot_layout_get_attach_points (hb_face_t      *face,
  * @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) (optional): Input = the maximum number of caret positions to return;
+ * @caret_count: (inout) (nullable): 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
  *
@@ -444,7 +444,7 @@ get_gsubgpos_table (hb_face_t *face,
  * @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) (optional): Input = the maximum number of script tags to return;
+ * @script_count: (inout) (nullable): 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
  *
@@ -541,8 +541,8 @@ hb_ot_layout_table_choose_script (hb_face_t      *face,
  * @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) (optional): The index of the requested script
- * @chosen_script: (out) (optional): #hb_tag_t of the requested script
+ * @script_index: (out) (nullable): The index of the requested script
+ * @chosen_script: (out) (nullable): #hb_tag_t of the requested script
  *
  * Selects an OpenType script for @table_tag from the @script_tags array.
  *
@@ -613,7 +613,7 @@ hb_ot_layout_table_select_script (hb_face_t      *face,
  * @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) (optional): Input = the maximum number of feature tags to return;
+ * @feature_count: (inout) (nullable): 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
  *
@@ -683,7 +683,7 @@ hb_ot_layout_table_find_feature (hb_face_t    *face,
  * @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) (optional): Input = the maximum number of language tags to return;
+ * @language_count: (inout) (nullable): 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
  *
@@ -911,7 +911,7 @@ hb_ot_layout_language_get_required_feature (hb_face_t    *face,
  * @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) (optional): Input = the maximum number of feature tags to return;
+ * @feature_count: (inout) (nullable): 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
  *
@@ -947,7 +947,7 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
  * @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) (optional): Input = the maximum number of feature tags to return;
+ * @feature_count: (inout) (nullable): 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
  *
@@ -1035,7 +1035,7 @@ hb_ot_layout_language_find_feature (hb_face_t    *face,
  * @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) (optional): Input = the maximum number of lookups to return;
+ * @lookup_count: (inout) (nullable): 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
  *
@@ -1386,10 +1386,10 @@ hb_ot_layout_collect_lookups (hb_face_t      *face,
  * @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 substituted output of the lookup
+ * @glyphs_before: (out) (nullable): Array of glyphs preceding the substitution range
+ * @glyphs_input: (out) (nullable): Array of input glyphs that would be substituted by the lookup
+ * @glyphs_after: (out) (nullable): Array of glyphs following the substitution range
+ * @glyphs_output: (out) (nullable): Array of glyphs that would be the substituted 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.
@@ -1473,7 +1473,7 @@ hb_ot_layout_table_find_feature_variations (hb_face_t    *face,
  * @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) (optional): Input = the maximum number of lookups to return;
+ * @lookup_count: (inout) (nullable): 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
  *
@@ -1777,15 +1777,15 @@ hb_ot_layout_get_size_params (hb_face_t       *face,
  * @face: #hb_face_t to work upon
  * @table_tag: table tag to query, "GSUB" or "GPOS".
  * @feature_index: index of feature to query.
- * @label_id: (out) (optional): The ‘name’ table name ID that specifies a string
- *            for a user-interface label for this feature. (May be NULL.)
- * @tooltip_id: (out) (optional): The ‘name’ table name ID that specifies a string
+ * @label_id: (out) (nullable): The ‘name’ table name ID that specifies a string
+ *            for a user-interface label for this feature.
+ * @tooltip_id: (out) (nullable): The ‘name’ table name ID that specifies a string
  *              that an application can use for tooltip text for this
- *              feature. (May be NULL.)
- * @sample_id: (out) (optional): The ‘name’ table name ID that specifies sample text
- *             that illustrates the effect of this feature. (May be NULL.)
- * @num_named_parameters: (out) (optional):  Number of named parameters. (May be zero.)
- * @first_param_id: (out) (optional): The first ‘name’ table name ID used to specify
+ *              feature.
+ * @sample_id: (out) (nullable): The ‘name’ table name ID that specifies sample text
+ *             that illustrates the effect of this feature.
+ * @num_named_parameters: (out) (nullable):  Number of named parameters.
+ * @first_param_id: (out) (nullable): The first ‘name’ table name ID used to specify
  *                  strings for user-interface labels for the feature
  *                  parameters. (Must be zero if numParameters is zero.)
  *
@@ -1852,7 +1852,7 @@ hb_ot_layout_feature_get_name_ids (hb_face_t       *face,
  * @table_tag: table tag to query, "GSUB" or "GPOS".
  * @feature_index: index of feature to query.
  * @start_offset: offset of the first character to retrieve
- * @char_count: (inout) (optional): Input = the maximum number of characters to return;
+ * @char_count: (inout) (nullable): 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
@@ -1915,31 +1915,33 @@ struct GPOSProxy
 
 static inline bool
 apply_forward (OT::hb_ot_apply_context_t *c,
-               const OT::hb_ot_layout_lookup_accelerator_t &accel,
-               unsigned subtable_count)
+               const OT::hb_ot_layout_lookup_accelerator_t &accel)
 {
-  bool use_cache = accel.cache_enter (c);
+  bool use_hot_subtable_cache = accel.cache_enter (c);
 
   bool ret = false;
   hb_buffer_t *buffer = c->buffer;
-  while (buffer->idx < buffer->len && buffer->successful)
+  while (buffer->successful)
   {
-    bool applied = false;
-    auto &cur = buffer->cur();
-    if (accel.digest.may_have (cur.codepoint) &&
-        (cur.mask & c->lookup_mask) &&
-        c->check_glyph_property (&cur, c->lookup_props))
-     {
-       applied = accel.apply (c, subtable_count, use_cache);
-     }
+    hb_glyph_info_t *info = buffer->info;
+    unsigned j = buffer->idx;
+    while (j < buffer->len &&
+           !(accel.digest.may_have (info[j].codepoint) &&
+             (info[j].mask & c->lookup_mask) &&
+             c->check_glyph_property (&info[j], c->lookup_props)))
+      j++;
+    if (unlikely (j > buffer->idx && !buffer->next_glyphs (j - buffer->idx)))
+      break;
+    if (buffer->idx >= buffer->len)
+      break;
 
-    if (applied)
+    if (accel.apply (c, use_hot_subtable_cache))
       ret = true;
     else
       (void) buffer->next_glyph ();
   }
 
-  if (use_cache)
+  if (use_hot_subtable_cache)
     accel.cache_leave (c);
 
   return ret;
@@ -1947,8 +1949,7 @@ apply_forward (OT::hb_ot_apply_context_t *c,
 
 static inline bool
 apply_backward (OT::hb_ot_apply_context_t *c,
-               const OT::hb_ot_layout_lookup_accelerator_t &accel,
-               unsigned subtable_count)
+               const OT::hb_ot_layout_lookup_accelerator_t &accel)
 {
   bool ret = false;
   hb_buffer_t *buffer = c->buffer;
@@ -1958,11 +1959,10 @@ apply_backward (OT::hb_ot_apply_context_t *c,
     if (accel.digest.may_have (cur.codepoint) &&
         (cur.mask & c->lookup_mask) &&
         c->check_glyph_property (&cur, c->lookup_props))
-      ret |= accel.apply (c, subtable_count, false);
+      ret |= accel.apply (c, false);
 
     /* The reverse lookup doesn't "advance" cursor (for good reason). */
     buffer->idx--;
-
   }
   while ((int) buffer->idx >= 0);
   return ret;
@@ -1975,7 +1975,6 @@ apply_string (OT::hb_ot_apply_context_t *c,
               const OT::hb_ot_layout_lookup_accelerator_t &accel)
 {
   hb_buffer_t *buffer = c->buffer;
-  unsigned subtable_count = lookup.get_subtable_count ();
 
   if (unlikely (!buffer->len || !c->lookup_mask))
     return false;
@@ -1991,7 +1990,7 @@ apply_string (OT::hb_ot_apply_context_t *c,
       buffer->clear_output ();
 
     buffer->idx = 0;
-    ret = apply_forward (c, accel, subtable_count);
+    ret = apply_forward (c, accel);
 
     if (!Proxy::always_inplace)
       buffer->sync ();
@@ -2001,7 +2000,7 @@ apply_string (OT::hb_ot_apply_context_t *c,
     /* in-place backward substitution/positioning */
     assert (!buffer->have_output);
     buffer->idx = buffer->len - 1;
-    ret = apply_backward (c, accel, subtable_count);
+    ret = apply_backward (c, accel);
   }
 
   return ret;
@@ -2017,7 +2016,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
   unsigned int i = 0;
 
   auto *font_data = font->data.ot.get ();
-  auto *var_store_cache = font_data == HB_SHAPER_DATA_SUCCEEDED ? nullptr : (OT::ItemVariationStore::cache_t *) font_data;
+  auto *var_store_cache = (OT::hb_scalar_cache_t *) font_data;
 
   OT::hb_ot_apply_context_t c (table_index, font, buffer, proxy.accel.get_blob (), var_store_cache);
   c.set_recurse_func (Proxy::Lookup::template dispatch_recurse_func);
@@ -2037,11 +2036,8 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
       if (buffer->messaging () &&
           !buffer->message (font, "start lookup %u feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag))) continue;
 
-      /* c.digest is a digest of all the current glyphs in the buffer
-       * (plus some past glyphs).
-       *
-       * Only try applying the lookup if there is any overlap. */
-      if (accel->digest.may_intersect (c.digest))
+      /* Only try applying the lookup if there is any overlap. */
+      if (accel->digest.may_intersect (buffer->digest))
       {
         c.set_lookup_index (lookup_index);
         c.set_lookup_mask (lookup.mask, false);
@@ -2067,7 +2063,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
       if (stage->pause_func (plan, font, buffer))
       {
         /* Refresh working buffer digest since buffer changed. */
-        buffer->collect_codepoints (c.digest);
+        buffer->update_digest ();
       }
     }
   }
@@ -2601,6 +2597,7 @@ hb_ot_layout_get_baseline_with_fallback2 (hb_font_t                   *font,
 #endif
 
 
+#ifndef HB_NO_LAYOUT_RARELY_USED
 struct hb_get_glyph_alternates_dispatch_t :
        hb_dispatch_context_t
 {
@@ -2620,14 +2617,13 @@ struct hb_get_glyph_alternates_dispatch_t :
   ( _dispatch (obj, hb_prioritize, std::forward (ds)...) )
 };
 
-#ifndef HB_NO_LAYOUT_RARELY_USED
 /**
  * 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) (optional): Input = the maximum number of alternate glyphs to return;
+ * @alternate_count: (inout) (nullable): 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.
@@ -2654,6 +2650,64 @@ hb_ot_layout_lookup_get_glyph_alternates (hb_face_t      *face,
   return ret;
 }
 
+struct hb_collect_glyph_alternates_dispatch_t :
+       hb_dispatch_context_t
+{
+  static return_t default_return_value () { return false; }
+  bool stop_sublookup_iteration (return_t r) const { return false; }
+
+  private:
+  template  auto
+  _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
+  ( (obj.collect_glyph_alternates (std::forward (ds)...), true) )
+  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, std::forward (ds)...) )
+};
+
+/**
+ * hb_ot_layout_lookup_collect_glyph_alternates:
+ * @face: a face.
+ * @lookup_index: index of the feature lookup to query.
+ * @alternate_count: (inout): mapping from glyph index to number of alternates for that glyph.
+ * @alternate_glyphs: (inout): mapping from encoded glyph index and alternate index, to alternate glyph ids.
+ *
+ * Collects alternates of glyphs from a given GSUB lookup index.
+ *
+ * For one-to-one GSUB glyph substitutions, this function collects the
+ * substituted glyph.
+ *
+ * For lookups that assign multiple alternates to a glyph, all alternate glyphs are collected.
+ *
+ * For other lookup types, nothing is performed and `false` is returned.
+ *
+ * The `alternate_count` mapping will contain the number of alternates for each glyph id.
+ * Upon entry, this mapping should contain the glyph ids as keys, and the number of alternates
+ * currently known for each glyph id as values.
+ *
+ * The `alternate_glyphs` mapping will contain the alternate glyph ids for each glyph id.
+ * The mapping is encoded in the following way, upon entry and after processing:
+ * If G is the glyph id, and A0, A1, ..., A(n-1) are the alternate glyph ids,
+ * the mapping will contain the following entries: (G + (i << 24)) -> A(i)
+ * for i = 0, 1, ..., n-1 where n is the number of alternates for G as per `alternate_count`.
+ *
+ * Return value: `true` if alternates were collected, `false` otherwise.
+ * Since: 12.1.0
+ */
+HB_EXTERN hb_bool_t
+hb_ot_layout_lookup_collect_glyph_alternates (hb_face_t *face,
+                                              unsigned   lookup_index,
+                                              hb_map_t  *alternate_count /* IN/OUT */,
+                                              hb_map_t  *alternate_glyphs /* IN/OUT */)
+{
+  hb_collect_glyph_alternates_dispatch_t c;
+  const OT::SubstLookup &lookup = face->table.GSUB->table->get_lookup (lookup_index);
+  return lookup.dispatch (&c, alternate_count, alternate_glyphs);
+}
 
 struct hb_position_single_dispatch_t :
        hb_dispatch_context_t
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 1d9db1105bd..b814c2acda3 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.h
@@ -383,6 +383,12 @@ hb_ot_layout_lookup_get_glyph_alternates (hb_face_t      *face,
                                           unsigned       *alternate_count /* IN/OUT */,
                                           hb_codepoint_t *alternate_glyphs /* OUT */);
 
+HB_EXTERN hb_bool_t
+hb_ot_layout_lookup_collect_glyph_alternates (hb_face_t *face,
+                                              unsigned   lookup_index,
+                                              hb_map_t  *alternate_count /* IN/OUT */,
+                                              hb_map_t  *alternate_glyphs /* IN/OUT */);
+
 HB_EXTERN hb_bool_t
 hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
                                       unsigned int          lookup_index,
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 a68c8421e4c..f669ac7c46d 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh
@@ -217,8 +217,6 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
 
   if (u >= 0x80u)
   {
-    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
-
     if (unlikely (unicode->is_default_ignorable (u)))
     {
       buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
@@ -247,6 +245,7 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
 
     if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (gen_cat)))
     {
+      buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_CONTINUATIONS;
       props |= UPROPS_MASK_CONTINUATION;
       props |= unicode->modified_combining_class (u)<<8;
     }
@@ -361,8 +360,9 @@ _hb_glyph_info_unhide (hb_glyph_info_t *info)
 }
 
 static inline void
-_hb_glyph_info_set_continuation (hb_glyph_info_t *info)
+_hb_glyph_info_set_continuation (hb_glyph_info_t *info, hb_buffer_t *buffer)
 {
+  buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_CONTINUATIONS;
   info->unicode_props() |= UPROPS_MASK_CONTINUATION;
 }
 static inline void
@@ -410,18 +410,6 @@ _hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
   return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWJ);
 }
 static inline bool
-_hb_glyph_info_is_joiner (const hb_glyph_info_t *info)
-{
-  return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & (UPROPS_MASK_Cf_ZWNJ|UPROPS_MASK_Cf_ZWJ));
-}
-static inline void
-_hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
-{
-  if (!_hb_glyph_info_is_unicode_format (info))
-    return;
-  info->unicode_props() ^= UPROPS_MASK_Cf_ZWNJ | UPROPS_MASK_Cf_ZWJ;
-}
-static inline bool
 _hb_glyph_info_is_aat_deleted (const hb_glyph_info_t *info)
 {
   return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_AAT_DELETED);
@@ -657,4 +645,18 @@ _hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer)
 #undef lig_props
 #undef glyph_props
 
+static inline void
+_hb_collect_glyph_alternates_add (hb_codepoint_t from,
+                                  hb_codepoint_t to,
+                                  hb_map_t *alternate_count,
+                                  hb_map_t *alternate_glyphs)
+{
+  hb_codepoint_t zero = 0;
+  hb_codepoint_t *i = &zero;
+  alternate_count->has (from, &i);
+  alternate_glyphs->set (from | (*i << 24), to);
+  alternate_count->set (from, *i + 1);
+}
+
+
 #endif /* HB_OT_LAYOUT_HH */
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 b33e01fd6c9..ad9d7cb03e8 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
@@ -69,6 +69,8 @@ struct MathValueRecord
 
 struct MathConstants
 {
+  friend struct MATH;
+
   MathConstants* copy (hb_serialize_context_t *c) const
   {
     TRACE_SERIALIZE (this);
@@ -1109,8 +1111,8 @@ struct MATH
   {
 #ifndef HB_NO_MATH
     switch HB_CODEPOINT_ENCODE3 (font->face->table.MATH.get_blob ()->length,
-                                 get_constant (HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT, font),
-                                 get_constant (HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT, font))
+                                 (this+mathConstants).minHeight[1], // displayOperatorMinHeight
+                                 (this+mathConstants).minHeight[0]) // delimitedSubFormulaMinHeight
     {
       /* sha1sum:ab4a4fe054d23061f3c039493d6f665cfda2ecf5  cambria.ttc
        * sha1sum:086855301bff644f9d8827b88491fcf73a6d4cb9  cambria.ttc
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-post-macroman.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-post-macroman.hh
index b4df8aaeeab..269b4d3fe45 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-post-macroman.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-post-macroman.hh
@@ -31,264 +31,264 @@
 #endif
 
 
-_S(".notdef")
-_S(".null")
-_S("nonmarkingreturn")
-_S("space")
-_S("exclam")
-_S("quotedbl")
-_S("numbersign")
-_S("dollar")
-_S("percent")
-_S("ampersand")
-_S("quotesingle")
-_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("grave")
-_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("Adieresis")
-_S("Aring")
-_S("Ccedilla")
-_S("Eacute")
-_S("Ntilde")
-_S("Odieresis")
-_S("Udieresis")
-_S("aacute")
-_S("agrave")
-_S("acircumflex")
-_S("adieresis")
-_S("atilde")
-_S("aring")
-_S("ccedilla")
-_S("eacute")
-_S("egrave")
-_S("ecircumflex")
-_S("edieresis")
-_S("iacute")
-_S("igrave")
-_S("icircumflex")
-_S("idieresis")
-_S("ntilde")
-_S("oacute")
-_S("ograve")
-_S("ocircumflex")
-_S("odieresis")
-_S("otilde")
-_S("uacute")
-_S("ugrave")
-_S("ucircumflex")
-_S("udieresis")
-_S("dagger")
-_S("degree")
-_S("cent")
-_S("sterling")
-_S("section")
-_S("bullet")
-_S("paragraph")
-_S("germandbls")
-_S("registered")
-_S("copyright")
-_S("trademark")
-_S("acute")
-_S("dieresis")
-_S("notequal")
-_S("AE")
-_S("Oslash")
-_S("infinity")
-_S("plusminus")
-_S("lessequal")
-_S("greaterequal")
-_S("yen")
-_S("mu")
-_S("partialdiff")
-_S("summation")
-_S("product")
-_S("pi")
-_S("integral")
-_S("ordfeminine")
-_S("ordmasculine")
-_S("Omega")
-_S("ae")
-_S("oslash")
-_S("questiondown")
-_S("exclamdown")
-_S("logicalnot")
-_S("radical")
-_S("florin")
-_S("approxequal")
-_S("Delta")
-_S("guillemotleft")
-_S("guillemotright")
-_S("ellipsis")
-_S("nonbreakingspace")
-_S("Agrave")
-_S("Atilde")
-_S("Otilde")
-_S("OE")
-_S("oe")
-_S("endash")
-_S("emdash")
-_S("quotedblleft")
-_S("quotedblright")
-_S("quoteleft")
-_S("quoteright")
-_S("divide")
-_S("lozenge")
-_S("ydieresis")
-_S("Ydieresis")
-_S("fraction")
-_S("currency")
-_S("guilsinglleft")
-_S("guilsinglright")
-_S("fi")
-_S("fl")
-_S("daggerdbl")
-_S("periodcentered")
-_S("quotesinglbase")
-_S("quotedblbase")
-_S("perthousand")
-_S("Acircumflex")
-_S("Ecircumflex")
-_S("Aacute")
-_S("Edieresis")
-_S("Egrave")
-_S("Iacute")
-_S("Icircumflex")
-_S("Idieresis")
-_S("Igrave")
-_S("Oacute")
-_S("Ocircumflex")
-_S("apple")
-_S("Ograve")
-_S("Uacute")
-_S("Ucircumflex")
-_S("Ugrave")
-_S("dotlessi")
-_S("circumflex")
-_S("tilde")
-_S("macron")
-_S("breve")
-_S("dotaccent")
-_S("ring")
-_S("cedilla")
-_S("hungarumlaut")
-_S("ogonek")
-_S("caron")
-_S("Lslash")
-_S("lslash")
-_S("Scaron")
-_S("scaron")
-_S("Zcaron")
-_S("zcaron")
-_S("brokenbar")
-_S("Eth")
-_S("eth")
-_S("Yacute")
-_S("yacute")
-_S("Thorn")
-_S("thorn")
-_S("minus")
-_S("multiply")
-_S("onesuperior")
-_S("twosuperior")
-_S("threesuperior")
-_S("onehalf")
-_S("onequarter")
-_S("threequarters")
-_S("franc")
-_S("Gbreve")
-_S("gbreve")
-_S("Idotaccent")
-_S("Scedilla")
-_S("scedilla")
-_S("Cacute")
-_S("cacute")
-_S("Ccaron")
-_S("ccaron")
-_S("dcroat")
+HB_STR(".notdef")
+HB_STR(".null")
+HB_STR("nonmarkingreturn")
+HB_STR("space")
+HB_STR("exclam")
+HB_STR("quotedbl")
+HB_STR("numbersign")
+HB_STR("dollar")
+HB_STR("percent")
+HB_STR("ampersand")
+HB_STR("quotesingle")
+HB_STR("parenleft")
+HB_STR("parenright")
+HB_STR("asterisk")
+HB_STR("plus")
+HB_STR("comma")
+HB_STR("hyphen")
+HB_STR("period")
+HB_STR("slash")
+HB_STR("zero")
+HB_STR("one")
+HB_STR("two")
+HB_STR("three")
+HB_STR("four")
+HB_STR("five")
+HB_STR("six")
+HB_STR("seven")
+HB_STR("eight")
+HB_STR("nine")
+HB_STR("colon")
+HB_STR("semicolon")
+HB_STR("less")
+HB_STR("equal")
+HB_STR("greater")
+HB_STR("question")
+HB_STR("at")
+HB_STR("A")
+HB_STR("B")
+HB_STR("C")
+HB_STR("D")
+HB_STR("E")
+HB_STR("F")
+HB_STR("G")
+HB_STR("H")
+HB_STR("I")
+HB_STR("J")
+HB_STR("K")
+HB_STR("L")
+HB_STR("M")
+HB_STR("N")
+HB_STR("O")
+HB_STR("P")
+HB_STR("Q")
+HB_STR("R")
+HB_STR("S")
+HB_STR("T")
+HB_STR("U")
+HB_STR("V")
+HB_STR("W")
+HB_STR("X")
+HB_STR("Y")
+HB_STR("Z")
+HB_STR("bracketleft")
+HB_STR("backslash")
+HB_STR("bracketright")
+HB_STR("asciicircum")
+HB_STR("underscore")
+HB_STR("grave")
+HB_STR("a")
+HB_STR("b")
+HB_STR("c")
+HB_STR("d")
+HB_STR("e")
+HB_STR("f")
+HB_STR("g")
+HB_STR("h")
+HB_STR("i")
+HB_STR("j")
+HB_STR("k")
+HB_STR("l")
+HB_STR("m")
+HB_STR("n")
+HB_STR("o")
+HB_STR("p")
+HB_STR("q")
+HB_STR("r")
+HB_STR("s")
+HB_STR("t")
+HB_STR("u")
+HB_STR("v")
+HB_STR("w")
+HB_STR("x")
+HB_STR("y")
+HB_STR("z")
+HB_STR("braceleft")
+HB_STR("bar")
+HB_STR("braceright")
+HB_STR("asciitilde")
+HB_STR("Adieresis")
+HB_STR("Aring")
+HB_STR("Ccedilla")
+HB_STR("Eacute")
+HB_STR("Ntilde")
+HB_STR("Odieresis")
+HB_STR("Udieresis")
+HB_STR("aacute")
+HB_STR("agrave")
+HB_STR("acircumflex")
+HB_STR("adieresis")
+HB_STR("atilde")
+HB_STR("aring")
+HB_STR("ccedilla")
+HB_STR("eacute")
+HB_STR("egrave")
+HB_STR("ecircumflex")
+HB_STR("edieresis")
+HB_STR("iacute")
+HB_STR("igrave")
+HB_STR("icircumflex")
+HB_STR("idieresis")
+HB_STR("ntilde")
+HB_STR("oacute")
+HB_STR("ograve")
+HB_STR("ocircumflex")
+HB_STR("odieresis")
+HB_STR("otilde")
+HB_STR("uacute")
+HB_STR("ugrave")
+HB_STR("ucircumflex")
+HB_STR("udieresis")
+HB_STR("dagger")
+HB_STR("degree")
+HB_STR("cent")
+HB_STR("sterling")
+HB_STR("section")
+HB_STR("bullet")
+HB_STR("paragraph")
+HB_STR("germandbls")
+HB_STR("registered")
+HB_STR("copyright")
+HB_STR("trademark")
+HB_STR("acute")
+HB_STR("dieresis")
+HB_STR("notequal")
+HB_STR("AE")
+HB_STR("Oslash")
+HB_STR("infinity")
+HB_STR("plusminus")
+HB_STR("lessequal")
+HB_STR("greaterequal")
+HB_STR("yen")
+HB_STR("mu")
+HB_STR("partialdiff")
+HB_STR("summation")
+HB_STR("product")
+HB_STR("pi")
+HB_STR("integral")
+HB_STR("ordfeminine")
+HB_STR("ordmasculine")
+HB_STR("Omega")
+HB_STR("ae")
+HB_STR("oslash")
+HB_STR("questiondown")
+HB_STR("exclamdown")
+HB_STR("logicalnot")
+HB_STR("radical")
+HB_STR("florin")
+HB_STR("approxequal")
+HB_STR("Delta")
+HB_STR("guillemotleft")
+HB_STR("guillemotright")
+HB_STR("ellipsis")
+HB_STR("nonbreakingspace")
+HB_STR("Agrave")
+HB_STR("Atilde")
+HB_STR("Otilde")
+HB_STR("OE")
+HB_STR("oe")
+HB_STR("endash")
+HB_STR("emdash")
+HB_STR("quotedblleft")
+HB_STR("quotedblright")
+HB_STR("quoteleft")
+HB_STR("quoteright")
+HB_STR("divide")
+HB_STR("lozenge")
+HB_STR("ydieresis")
+HB_STR("Ydieresis")
+HB_STR("fraction")
+HB_STR("currency")
+HB_STR("guilsinglleft")
+HB_STR("guilsinglright")
+HB_STR("fi")
+HB_STR("fl")
+HB_STR("daggerdbl")
+HB_STR("periodcentered")
+HB_STR("quotesinglbase")
+HB_STR("quotedblbase")
+HB_STR("perthousand")
+HB_STR("Acircumflex")
+HB_STR("Ecircumflex")
+HB_STR("Aacute")
+HB_STR("Edieresis")
+HB_STR("Egrave")
+HB_STR("Iacute")
+HB_STR("Icircumflex")
+HB_STR("Idieresis")
+HB_STR("Igrave")
+HB_STR("Oacute")
+HB_STR("Ocircumflex")
+HB_STR("apple")
+HB_STR("Ograve")
+HB_STR("Uacute")
+HB_STR("Ucircumflex")
+HB_STR("Ugrave")
+HB_STR("dotlessi")
+HB_STR("circumflex")
+HB_STR("tilde")
+HB_STR("macron")
+HB_STR("breve")
+HB_STR("dotaccent")
+HB_STR("ring")
+HB_STR("cedilla")
+HB_STR("hungarumlaut")
+HB_STR("ogonek")
+HB_STR("caron")
+HB_STR("Lslash")
+HB_STR("lslash")
+HB_STR("Scaron")
+HB_STR("scaron")
+HB_STR("Zcaron")
+HB_STR("zcaron")
+HB_STR("brokenbar")
+HB_STR("Eth")
+HB_STR("eth")
+HB_STR("Yacute")
+HB_STR("yacute")
+HB_STR("Thorn")
+HB_STR("thorn")
+HB_STR("minus")
+HB_STR("multiply")
+HB_STR("onesuperior")
+HB_STR("twosuperior")
+HB_STR("threesuperior")
+HB_STR("onehalf")
+HB_STR("onequarter")
+HB_STR("threequarters")
+HB_STR("franc")
+HB_STR("Gbreve")
+HB_STR("gbreve")
+HB_STR("Idotaccent")
+HB_STR("Scedilla")
+HB_STR("scedilla")
+HB_STR("Cacute")
+HB_STR("cacute")
+HB_STR("Ccaron")
+HB_STR("ccaron")
+HB_STR("dcroat")
 
 
 #endif /* HB_OT_POST_MACROMAN_HH */
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 2401e18f0e6..c17e7628975 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
@@ -409,16 +409,13 @@ position_around_base (const hb_ot_shape_plan_t *plan,
 }
 
 static inline void
-position_cluster (const hb_ot_shape_plan_t *plan,
-                  hb_font_t *font,
-                  hb_buffer_t  *buffer,
-                  unsigned int start,
-                  unsigned int end,
-                  bool adjust_offsets_when_zeroing)
+position_cluster_impl (const hb_ot_shape_plan_t *plan,
+                       hb_font_t *font,
+                       hb_buffer_t  *buffer,
+                       unsigned int start,
+                       unsigned int end,
+                       bool adjust_offsets_when_zeroing)
 {
-  if (end - start < 2)
-    return;
-
   /* Find the base glyph */
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = start; i < end; i++)
@@ -441,6 +438,20 @@ position_cluster (const hb_ot_shape_plan_t *plan,
     }
 }
 
+static HB_ALWAYS_INLINE void
+position_cluster (const hb_ot_shape_plan_t *plan,
+                  hb_font_t *font,
+                  hb_buffer_t  *buffer,
+                  unsigned int start,
+                  unsigned int end,
+                  bool adjust_offsets_when_zeroing)
+{
+  if (end - start < 2)
+    return;
+
+  position_cluster_impl (plan, font, buffer, start, end, adjust_offsets_when_zeroing);
+}
+
 void
 _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan,
                                      hb_font_t *font,
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 cb941bc7fbd..508ed6a5076 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
@@ -78,14 +78,14 @@
 static inline void
 set_glyph (hb_glyph_info_t &info, hb_font_t *font)
 {
-  (void) font->get_nominal_glyph (info.codepoint, &info.glyph_index());
+  (void) font->get_nominal_glyph (info.codepoint, &info.normalizer_glyph_index());
 }
 
 static inline void
 output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
 {
   /* This is very confusing indeed. */
-  buffer->cur().glyph_index() = glyph;
+  buffer->cur().normalizer_glyph_index() = glyph;
   (void) buffer->output_glyph (unichar);
   _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer);
 }
@@ -93,7 +93,7 @@ output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
 static inline void
 next_char (hb_buffer_t *buffer, hb_codepoint_t glyph)
 {
-  buffer->cur().glyph_index() = glyph;
+  buffer->cur().normalizer_glyph_index() = glyph;
   (void) buffer->next_glyph ();
 }
 
@@ -210,7 +210,7 @@ handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c,
   hb_font_t * const font = c->font;
   for (; buffer->idx < end - 1 && buffer->successful;) {
     if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
-      if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
+      if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().normalizer_glyph_index()))
       {
         hb_codepoint_t unicode = buffer->cur().codepoint;
         (void) buffer->replace_glyphs (2, 1, &unicode);
@@ -342,7 +342,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
         unsigned int done = font->get_nominal_glyphs (end - buffer->idx,
                                                       &buffer->cur().codepoint,
                                                       sizeof (buffer->info[0]),
-                                                      &buffer->cur().glyph_index(),
+                                                      &buffer->cur().normalizer_glyph_index(),
                                                       sizeof (buffer->info[0]));
         if (unlikely (!buffer->next_glyphs (done))) break;
       }
@@ -456,7 +456,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
           buffer->out_len--; /* Remove the second composable. */
           /* Modify starter and carry on. */
           buffer->out_info[starter].codepoint = composed;
-          buffer->out_info[starter].glyph_index() = glyph;
+          buffer->out_info[starter].normalizer_glyph_index() = glyph;
           _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer);
 
           continue;
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.hh
index 9f17bdbb243..138e895e8e1 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.hh
@@ -32,7 +32,7 @@
 
 
 /* buffer var allocations, used during the normalization process */
-#define glyph_index()   var1.u32
+#define normalizer_glyph_index()        var1.u32
 
 struct hb_ot_shape_plan_t;
 
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 477a7c7fc72..69b188f7aa3 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc
@@ -44,6 +44,7 @@
 #include "hb-ot-face.hh"
 
 #include "hb-set.hh"
+#include "hb-unicode.hh"
 
 #include "hb-aat-layout.hh"
 #include "hb-ot-layout-gdef-table.hh"
@@ -92,7 +93,7 @@ hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t                     *fac
   shaper = hb_ot_shaper_categorize (props.script, props.direction, map.chosen_script[0]);
 
   script_zero_marks = shaper->zero_width_marks != HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE;
-  script_fallback_mark_positioning = shaper->fallback_position;
+  script_fallback_position = shaper->fallback_position;
 
 #ifndef HB_NO_AAT_SHAPE
   /* https://github.com/harfbuzz/harfbuzz/issues/1528 */
@@ -178,12 +179,12 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t           &plan,
 #endif
 #ifndef HB_NO_OT_KERN
     else if (hb_ot_layout_has_kerning (face))
-      plan.apply_kern = true;
+      plan.apply_kern = script_fallback_position; // Not all shapers apply legacy `kern`
 #endif
     else {}
   }
 
-  plan.apply_fallback_kern = !(plan.apply_gpos || plan.apply_kerx || plan.apply_kern);
+  plan.apply_fallback_kern = script_fallback_position && !(plan.apply_gpos || plan.apply_kerx || plan.apply_kern);
 
   plan.zero_marks = script_zero_marks &&
                     !plan.apply_kerx &&
@@ -203,7 +204,7 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t           &plan,
                                               );
 
   plan.fallback_mark_positioning = plan.adjust_mark_positioning_when_zeroing &&
-                                   script_fallback_mark_positioning;
+                                   script_fallback_position;
 
 #ifndef HB_NO_AAT_SHAPE
   /* If we're using morx shaping, we cancel mark position adjustment because
@@ -425,25 +426,20 @@ _hb_ot_shaper_face_data_destroy (hb_ot_face_data_t *data)
  */
 
 struct hb_ot_font_data_t {
-  OT::ItemVariationStore::cache_t unused; // Just for alignment
+  OT::hb_scalar_cache_t unused; // Just for alignment
 };
 
 hb_ot_font_data_t *
 _hb_ot_shaper_font_data_create (hb_font_t *font)
 {
-  if (!font->num_coords)
-    return (hb_ot_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
-
   const OT::ItemVariationStore &var_store = font->face->table.GDEF->table->get_var_store ();
-  auto *cache = (hb_ot_font_data_t *) var_store.create_cache ();
-  return cache ? cache : (hb_ot_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+  return (hb_ot_font_data_t *) var_store.create_cache ();
 }
 
 void
 _hb_ot_shaper_font_data_destroy (hb_ot_font_data_t *data)
 {
-  if (data == HB_SHAPER_DATA_SUCCEEDED) return;
-  OT::ItemVariationStore::destroy_cache ((OT::ItemVariationStore::cache_t *) data);
+  OT::ItemVariationStore::destroy_cache ((OT::hb_scalar_cache_t *) data);
 }
 
 
@@ -488,6 +484,9 @@ hb_set_unicode_props (hb_buffer_t *buffer)
   {
     _hb_glyph_info_set_unicode_props (&info[i], buffer);
 
+    if (info[i].codepoint < 0x80)
+      continue;
+
     unsigned gen_cat = _hb_glyph_info_get_general_category (&info[i]);
     if (FLAG_UNSAFE (gen_cat) &
         (FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |
@@ -502,7 +501,7 @@ hb_set_unicode_props (hb_buffer_t *buffer)
     if (unlikely (gen_cat == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL &&
                   hb_in_range (info[i].codepoint, 0x1F3FBu, 0x1F3FFu)))
     {
-      _hb_glyph_info_set_continuation (&info[i]);
+      _hb_glyph_info_set_continuation (&info[i], buffer);
     }
     /* Regional_Indicators are hairy as hell...
      * https://github.com/harfbuzz/harfbuzz/issues/2265 */
@@ -510,18 +509,18 @@ hb_set_unicode_props (hb_buffer_t *buffer)
     {
       if (_hb_codepoint_is_regional_indicator (info[i - 1].codepoint) &&
           !_hb_glyph_info_is_continuation (&info[i - 1]))
-        _hb_glyph_info_set_continuation (&info[i]);
+        _hb_glyph_info_set_continuation (&info[i], buffer);
     }
 #ifndef HB_NO_EMOJI_SEQUENCES
     else if (unlikely (_hb_glyph_info_is_zwj (&info[i])))
     {
-      _hb_glyph_info_set_continuation (&info[i]);
+      _hb_glyph_info_set_continuation (&info[i], buffer);
       if (i + 1 < count &&
           _hb_unicode_is_emoji_Extended_Pictographic (info[i + 1].codepoint))
       {
         i++;
         _hb_glyph_info_set_unicode_props (&info[i], buffer);
-        _hb_glyph_info_set_continuation (&info[i]);
+        _hb_glyph_info_set_continuation (&info[i], buffer);
       }
     }
 #endif
@@ -540,7 +539,9 @@ hb_set_unicode_props (hb_buffer_t *buffer)
      * https://github.com/harfbuzz/harfbuzz/issues/3844
      */
     else if (unlikely (hb_in_ranges (info[i].codepoint, 0xFF9Eu, 0xFF9Fu, 0xE0020u, 0xE007Fu)))
-      _hb_glyph_info_set_continuation (&info[i]);
+      _hb_glyph_info_set_continuation (&info[i], buffer);
+    else if (unlikely (info[i].codepoint == 0x2044u /* FRACTION SLASH */))
+      buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_FRACTION_SLASH;
   }
 }
 
@@ -576,7 +577,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
 static void
 hb_form_clusters (hb_buffer_t *buffer)
 {
-  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
+  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_CONTINUATIONS))
     return;
 
   if (HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES (buffer->cluster_level))
@@ -618,14 +619,14 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
     for (unsigned i = 0; i < count; i++)
     {
       auto gc = _hb_glyph_info_get_general_category (&info[i]);
-      if (gc == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
-        found_number = true;
-      else if (HB_UNICODE_GENERAL_CATEGORY_IS_LETTER (gc))
+      if (HB_UNICODE_GENERAL_CATEGORY_IS_LETTER (gc))
       {
         found_letter = true;
         break;
       }
-      else if (_hb_codepoint_is_regional_indicator (info[i].codepoint))
+      else if (gc == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
+        found_number = true;
+      else if (unlikely (_hb_codepoint_is_regional_indicator (info[i].codepoint)))
         found_ri = true;
     }
     if ((found_number || found_ri) && !found_letter)
@@ -651,59 +652,6 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
  * Substitute
  */
 
-#ifndef HB_NO_VERTICAL
-static hb_codepoint_t
-hb_vert_char_for (hb_codepoint_t u)
-{
-  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;
-  }
-
-  return u;
-}
-#endif
-
 static inline void
 hb_ot_rotate_chars (const hb_ot_shape_context_t *c)
 {
@@ -729,7 +677,7 @@ hb_ot_rotate_chars (const hb_ot_shape_context_t *c)
   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);
+      hb_codepoint_t codepoint = hb_unicode_funcs_t::vertical_char_for (info[i].codepoint);
       if (unlikely (codepoint != info[i].codepoint && c->font->has_glyph (codepoint)))
         info[i].codepoint = codepoint;
     }
@@ -744,7 +692,7 @@ hb_ot_shape_setup_masks_fraction (const hb_ot_shape_context_t *c)
   return;
 #endif
 
-  if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
+  if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_FRACTION_SLASH) ||
       !c->plan->has_frac)
     return;
 
@@ -845,7 +793,13 @@ hb_ot_zero_width_default_ignorables (const hb_buffer_t *buffer)
   unsigned int i = 0;
   for (i = 0; i < count; i++)
     if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
-      pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
+    {
+      pos[i].x_advance = pos[i].y_advance = 0;
+      if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+        pos[i].x_offset = 0;
+      else
+        pos[i].y_offset = 0;
+    }
 }
 
 static void
@@ -900,11 +854,11 @@ hb_ot_hide_default_ignorables (hb_buffer_t *buffer,
 static inline void
 hb_ot_map_glyphs_fast (hb_buffer_t  *buffer)
 {
-  /* Normalization process sets up glyph_index(), we just copy it. */
+  /* Normalization process sets up normalizer_glyph_index(), we just copy it. */
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
-    info[i].codepoint = info[i].glyph_index();
+    info[i].codepoint = info[i].normalizer_glyph_index();
 
   buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
 }
@@ -942,7 +896,7 @@ hb_ot_substitute_default (const hb_ot_shape_context_t *c)
 
   hb_ot_rotate_chars (c);
 
-  HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
+  HB_BUFFER_ALLOCATE_VAR (buffer, normalizer_glyph_index);
 
   _hb_ot_shape_normalize (c->plan, buffer, c->font);
 
@@ -954,7 +908,7 @@ hb_ot_substitute_default (const hb_ot_shape_context_t *c)
 
   hb_ot_map_glyphs_fast (buffer);
 
-  HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
+  HB_BUFFER_DEALLOCATE_VAR (buffer, normalizer_glyph_index);
 }
 
 static inline void
@@ -969,11 +923,17 @@ hb_ot_substitute_plan (const hb_ot_shape_context_t *c)
 
 #ifndef HB_NO_AAT_SHAPE
   if (unlikely (c->plan->apply_morx))
+  {
     hb_aat_layout_substitute (c->plan, c->font, c->buffer,
                               c->user_features, c->num_user_features);
+    c->buffer->update_digest ();
+  }
   else
 #endif
+  {
+    c->buffer->update_digest ();
     c->plan->substitute (c->font, buffer);
+  }
 }
 
 static inline void
@@ -1054,23 +1014,16 @@ hb_ot_position_default (const hb_ot_shape_context_t *c)
   {
     c->font->get_glyph_h_advances (count, &info[0].codepoint, sizeof(info[0]),
                                    &pos[0].x_advance, sizeof(pos[0]));
-    /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
-    if (c->font->has_glyph_h_origin_func ())
-      for (unsigned int i = 0; i < count; i++)
-        c->font->subtract_glyph_h_origin (info[i].codepoint,
-                                          &pos[i].x_offset,
-                                          &pos[i].y_offset);
+    // h_origin defaults to zero; only apply it if the font has it.
+    if (c->font->has_glyph_h_origin_func () || c->font->has_glyph_h_origins_func ())
+      c->font->subtract_glyph_h_origins (c->buffer);
   }
   else
   {
     c->font->get_glyph_v_advances (count, &info[0].codepoint, sizeof(info[0]),
                                    &pos[0].y_advance, sizeof(pos[0]));
-    for (unsigned int i = 0; i < count; i++)
-    {
-      c->font->subtract_glyph_v_origin (info[i].codepoint,
-                                        &pos[i].x_offset,
-                                        &pos[i].y_offset);
-    }
+    // v_origin defaults to non-zero; apply even if only fallback is there.
+    c->font->subtract_glyph_v_origins (c->buffer);
   }
   if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK)
     _hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer);
@@ -1079,10 +1032,6 @@ hb_ot_position_default (const hb_ot_shape_context_t *c)
 static inline void
 hb_ot_position_plan (const hb_ot_shape_context_t *c)
 {
-  unsigned int count = c->buffer->len;
-  hb_glyph_info_t *info = c->buffer->info;
-  hb_glyph_position_t *pos = c->buffer->pos;
-
   /* If the font has no GPOS and direction is forward, then when
    * zeroing mark widths, we shift the mark with it, such that the
    * mark is positioned hanging over the previous glyph.  When
@@ -1097,12 +1046,9 @@ hb_ot_position_plan (const hb_ot_shape_context_t *c)
 
   /* We change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */
 
-  /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
-  if (c->font->has_glyph_h_origin_func ())
-    for (unsigned int i = 0; i < count; i++)
-      c->font->add_glyph_h_origin (info[i].codepoint,
-                                   &pos[i].x_offset,
-                                   &pos[i].y_offset);
+  // h_origin defaults to zero; only apply it if the font has it.
+  if (c->font->has_glyph_h_origin_func () || c->font->has_glyph_h_origins_func ())
+    c->font->add_glyph_h_origins (c->buffer);
 
   hb_ot_layout_position_start (c->font, c->buffer);
 
@@ -1139,12 +1085,9 @@ hb_ot_position_plan (const hb_ot_shape_context_t *c)
   hb_ot_zero_width_default_ignorables (c->buffer);
   hb_ot_layout_position_finish_offsets (c->font, c->buffer);
 
-  /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
-  if (c->font->has_glyph_h_origin_func ())
-    for (unsigned int i = 0; i < count; i++)
-      c->font->subtract_glyph_h_origin (info[i].codepoint,
-                                        &pos[i].x_offset,
-                                        &pos[i].y_offset);
+  // h_origin defaults to zero; only apply it if the font has it.
+  if (c->font->has_glyph_h_origin_func () || c->font->has_glyph_h_origins_func ())
+    c->font->subtract_glyph_h_origins (c->buffer);
 
   if (c->plan->fallback_mark_positioning)
     _hb_ot_shape_fallback_mark_position (c->plan, c->font, c->buffer,
@@ -1172,8 +1115,33 @@ hb_propagate_flags (hb_buffer_t *buffer)
   /* Propagate cluster-level glyph flags to be the same on all cluster glyphs.
    * Simplifies using them. */
 
-  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS))
+  hb_mask_t and_mask = HB_GLYPH_FLAG_DEFINED;
+  if ((buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0)
+    and_mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
+
+  hb_glyph_info_t *info = buffer->info;
+
+  if ((buffer->flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL) == 0)
+  {
+    foreach_cluster (buffer, start, end)
+    {
+      if (end - start == 1)
+      {
+        info[start].mask &= and_mask;
+        continue;
+      }
+
+      unsigned int mask = 0;
+      for (unsigned int i = start; i < end; i++)
+        mask |= info[i].mask;
+
+      mask &= and_mask;
+
+      for (unsigned int i = start; i < end; i++)
+        info[i].mask = mask;
+    }
     return;
+  }
 
   /* If we are producing SAFE_TO_INSERT_TATWEEL, then do two things:
    *
@@ -1181,30 +1149,20 @@ hb_propagate_flags (hb_buffer_t *buffer)
    *   are UNSAFE_TO_BREAK, then clear the SAFE_TO_INSERT_TATWEEL,
    * - Any place that is SAFE_TO_INSERT_TATWEEL, is also now UNSAFE_TO_BREAK.
    *
-   * We couldn't make this interaction earlier. It has to be done here.
+   * We couldn't make this interaction earlier. It has to be done this way.
    */
-  bool flip_tatweel = buffer->flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL;
-
-  bool clear_concat = (buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0;
-
-  hb_glyph_info_t *info = buffer->info;
-
   foreach_cluster (buffer, start, end)
   {
     unsigned int mask = 0;
     for (unsigned int i = start; i < end; i++)
-      mask |= info[i].mask & HB_GLYPH_FLAG_DEFINED;
+      mask |= info[i].mask;
 
-    if (flip_tatweel)
-    {
-      if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
-        mask &= ~HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL;
-      if (mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL)
-        mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
-    }
+    if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
+      mask &= ~HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL;
+    if (mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL)
+      mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
 
-    if (clear_concat)
-        mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
+    mask &= and_mask;
 
     for (unsigned int i = start; i < end; i++)
       info[i].mask = mask;
@@ -1245,8 +1203,6 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
   _hb_buffer_deallocate_unicode_vars (c->buffer);
 
   c->buffer->props.direction = c->target_direction;
-
-  c->buffer->leave ();
 }
 
 
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 068d7192d0d..649acddb414 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh
@@ -150,7 +150,7 @@ struct hb_ot_shape_planner_t
   static constexpr bool apply_morx = false;
 #endif
   bool script_zero_marks : 1;
-  bool script_fallback_mark_positioning : 1;
+  bool script_fallback_position : 1;
   const struct hb_ot_shaper_t *shaper;
 
   HB_INTERNAL hb_ot_shape_planner_t (hb_face_t                     *face,
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-joining-list.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-joining-list.hh
index e38686e3ebb..79d3014d3e1 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-joining-list.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-joining-list.hh
@@ -6,10 +6,10 @@
  *
  * on files with these headers:
  *
- * # ArabicShaping-16.0.0.txt
- * # Date: 2024-07-30
- * # Scripts-16.0.0.txt
- * # Date: 2024-04-30, 21:48:40 GMT
+ * # ArabicShaping-17.0.0.txt
+ * # Date: 2025-08-14
+ * # Scripts-17.0.0.txt
+ * # Date: 2025-07-24, 13:28:55 GMT
  */
 
 #ifndef HB_OT_SHAPER_ARABIC_JOINING_LIST_HH
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-table.hh
index 19bd72d4218..5f87995ea9c 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-table.hh
@@ -6,10 +6,10 @@
  *
  * on files with these headers:
  *
- * # ArabicShaping-16.0.0.txt
- * # Date: 2024-07-30
- * # Blocks-16.0.0.txt
- * # Date: 2024-02-02
+ * # ArabicShaping-17.0.0.txt
+ * # Date: 2025-08-14
+ * # Blocks-17.0.0.txt
+ * # Date: 2025-08-01
  * UnicodeData.txt does not have a header.
  */
 
@@ -80,7 +80,7 @@ static const uint8_t joining_table[] =
   /* Arabic Extended-B */
 
   /* 0860 */                                 R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,
-  /* 0880 */ R,R,R,C,C,C,D,U,U,D,D,D,D,D,R,X,U,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 0880 */ R,R,R,C,C,C,D,U,U,D,D,D,D,D,R,D,U,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
 
   /* Arabic Extended-A */
 
@@ -140,9 +140,9 @@ static const uint8_t joining_table[] =
 
   /* Arabic Extended-C */
 
-  /* 10EC0 */     R,D,D,
+  /* 10EC0 */     R,D,D,X,D,D,
 
-#define joining_offset_0x10f30u 1185
+#define joining_offset_0x10f30u 1188
 
   /* Sogdian */
 
@@ -161,14 +161,14 @@ static const uint8_t joining_table[] =
   /* 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 1341
+#define joining_offset_0x110bdu 1344
 
   /* Kaithi */
 
   /* 110A0 */                                                           U,X,X,
   /* 110C0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,U,
 
-#define joining_offset_0x1e900u 1358
+#define joining_offset_0x1e900u 1361
 
   /* Adlam */
 
@@ -176,7 +176,7 @@ static const uint8_t joining_table[] =
   /* 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,X,X,X,X,X,X,X,T,
 
-}; /* Table items: 1434; occupancy: 57% */
+}; /* Table items: 1437; occupancy: 58% */
 
 
 static unsigned int
@@ -204,7 +204,7 @@ joining_type (hb_codepoint_t u)
       if (hb_in_range (u, 0x10AC0u, 0x10AEFu)) return joining_table[u - 0x10AC0u + joining_offset_0x10ac0u];
       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, 0x10EC2u, 0x10EC4u)) return joining_table[u - 0x10EC2u + joining_offset_0x10ec2u];
+      if (hb_in_range (u, 0x10EC2u, 0x10EC7u)) return joining_table[u - 0x10EC2u + joining_offset_0x10ec2u];
       if (hb_in_range (u, 0x10F30u, 0x10FCBu)) return joining_table[u - 0x10F30u + joining_offset_0x10f30u];
       break;
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc
index 7379bb7f15b..981c0f9224b 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc
@@ -654,7 +654,7 @@ postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan,
 
 /* https://www.unicode.org/reports/tr53/ */
 
-static hb_codepoint_t
+static const hb_codepoint_t
 modifier_combining_marks[] =
 {
   0x0654u, /* ARABIC HAMZA ABOVE */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc
index 5c46ebbc281..5f15aff8b7c 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc
@@ -427,7 +427,7 @@ const hb_ot_shaper_t _hb_ot_shaper_hangul =
   HB_TAG_NONE, /* gpos_tag */
   HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
-  false, /* fallback_position */
+  true, /* fallback_position */
 };
 
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-machine.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-machine.hh
index 25e6d85ef80..76c5e83e30f 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-machine.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-machine.hh
@@ -53,7 +53,7 @@ enum indic_syllable_type_t {
 };
 
 
-#line 57 "hb-ot-shaper-indic-machine.hh"
+#line 54 "hb-ot-shaper-indic-machine.hh"
 #define indic_syllable_machine_ex_A 9u
 #define indic_syllable_machine_ex_C 1u
 #define indic_syllable_machine_ex_CM 16u
@@ -77,7 +77,7 @@ enum indic_syllable_type_t {
 #define indic_syllable_machine_ex_ZWNJ 5u
 
 
-#line 81 "hb-ot-shaper-indic-machine.hh"
+#line 76 "hb-ot-shaper-indic-machine.hh"
 static const unsigned char _indic_syllable_machine_trans_keys[] = {
         8u, 57u, 4u, 57u, 5u, 57u, 5u, 57u, 13u, 13u, 4u, 57u, 4u, 57u, 4u, 57u,
         8u, 57u, 5u, 57u, 5u, 57u, 13u, 13u, 4u, 57u, 4u, 57u, 4u, 57u, 4u, 57u,
@@ -1126,7 +1126,7 @@ find_syllables_indic (hb_buffer_t *buffer)
   int cs;
   hb_glyph_info_t *info = buffer->info;
 
-#line 1130 "hb-ot-shaper-indic-machine.hh"
+#line 1119 "hb-ot-shaper-indic-machine.hh"
         {
         cs = indic_syllable_machine_start;
         ts = 0;
@@ -1142,7 +1142,7 @@ find_syllables_indic (hb_buffer_t *buffer)
 
   unsigned int syllable_serial = 1;
 
-#line 1146 "hb-ot-shaper-indic-machine.hh"
+#line 1131 "hb-ot-shaper-indic-machine.hh"
         {
         int _slen;
         int _trans;
@@ -1156,7 +1156,7 @@ _resume:
 #line 1 "NONE"
         {ts = p;}
         break;
-#line 1160 "hb-ot-shaper-indic-machine.hh"
+#line 1143 "hb-ot-shaper-indic-machine.hh"
         }
 
         _keys = _indic_syllable_machine_trans_keys + (cs<<1);
@@ -1268,7 +1268,7 @@ _eof_trans:
 #line 117 "hb-ot-shaper-indic-machine.rl"
         {act = 7;}
         break;
-#line 1272 "hb-ot-shaper-indic-machine.hh"
+#line 1232 "hb-ot-shaper-indic-machine.hh"
         }
 
 _again:
@@ -1277,7 +1277,7 @@ _again:
 #line 1 "NONE"
         {ts = 0;}
         break;
-#line 1281 "hb-ot-shaper-indic-machine.hh"
+#line 1239 "hb-ot-shaper-indic-machine.hh"
         }
 
         if ( ++p != pe )
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-table.cc
index b87c530853b..bf27efee21b 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-table.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-table.cc
@@ -6,12 +6,12 @@
  *
  * on files with these headers:
  *
- * # IndicSyllabicCategory-16.0.0.txt
- * # Date: 2024-04-30, 21:48:21 GMT
- * # IndicPositionalCategory-16.0.0.txt
- * # Date: 2024-04-30, 21:48:21 GMT
- * # Blocks-16.0.0.txt
- * # Date: 2024-02-02
+ * # IndicSyllabicCategory-17.0.0.txt
+ * # Date: 2025-08-01, 04:02:23 GMT
+ * # IndicPositionalCategory-17.0.0.txt
+ * # Date: 2025-07-29, 13:35:52 GMT
+ * # Blocks-17.0.0.txt
+ * # Date: 2025-08-01
  */
 
 #include "hb.hh"
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic.cc
index d78b5670f61..bec802429ab 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic.cc
@@ -296,11 +296,6 @@ 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_t virama_glyph;
 
   hb_indic_would_substitute_feature_t rphf;
@@ -327,9 +322,6 @@ 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 = -1;
 
   /* Use zero-context would_substitute() matching for new-spec of the main
@@ -943,17 +935,7 @@ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
                                        unsigned int start, unsigned int end)
 {
   /* 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:
-     * If dotted-circle is the last glyph, it just does nothing.
-     * Ie. It doesn't form Reph. */
-    if (buffer->info[end - 1].indic_category() == I_Cat(DOTTEDCIRCLE))
-      return;
-  }
+   * should just chain... */
 
   initial_reordering_consonant_syllable (plan, face, buffer, start, end);
 }
@@ -1347,8 +1329,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
        * Uniscribe doesn't do this.
        * TEST: U+0930,U+094D,U+0915,U+094B,U+094D
        */
-      if (!indic_plan->uniscribe_bug_compatible &&
-          unlikely (is_halant (info[new_reph_pos])))
+      if (unlikely (is_halant (info[new_reph_pos])))
       {
         for (unsigned int i = base + 1; i < new_reph_pos; i++)
           if (FLAG_UNSAFE (info[i].indic_category()) & (FLAG (I_Cat(M)) | FLAG (I_Cat(MPst))))
@@ -1451,27 +1432,6 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
     else
       buffer->unsafe_to_break (start - 1, start + 1);
   }
-
-
-  /*
-   * Finish off the clusters and go home!
-   */
-  if (indic_plan->uniscribe_bug_compatible)
-  {
-    switch ((hb_tag_t) plan->props.script)
-    {
-      case HB_SCRIPT_TAMIL:
-        break;
-
-      default:
-        /* Uniscribe merges the entire syllable into a single cluster... Except for Tamil.
-         * This means, half forms are submerged into the main consonant's cluster.
-         * This is unnecessary, and makes cursor positioning harder, but that's what
-         * Uniscribe does. */
-        buffer->merge_clusters (start, end);
-        break;
-    }
-  }
 }
 
 
@@ -1501,9 +1461,7 @@ preprocess_text_indic (const hb_ot_shape_plan_t *plan,
                        hb_buffer_t              *buffer,
                        hb_font_t                *font)
 {
-  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
-  if (!indic_plan->uniscribe_bug_compatible)
-    _hb_preprocess_text_vowel_constraints (plan, buffer, font);
+  _hb_preprocess_text_vowel_constraints (plan, buffer, font);
 }
 
 static bool
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-khmer-machine.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-khmer-machine.hh
index e1f657c758a..2442f0341ef 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-khmer-machine.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-khmer-machine.hh
@@ -48,7 +48,7 @@ enum khmer_syllable_type_t {
 };
 
 
-#line 52 "hb-ot-shaper-khmer-machine.hh"
+#line 49 "hb-ot-shaper-khmer-machine.hh"
 #define khmer_syllable_machine_ex_C 1u
 #define khmer_syllable_machine_ex_DOTTEDCIRCLE 11u
 #define khmer_syllable_machine_ex_H 4u
@@ -66,7 +66,7 @@ enum khmer_syllable_type_t {
 #define khmer_syllable_machine_ex_ZWNJ 5u
 
 
-#line 70 "hb-ot-shaper-khmer-machine.hh"
+#line 65 "hb-ot-shaper-khmer-machine.hh"
 static const unsigned char _khmer_syllable_machine_trans_keys[] = {
         5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u,
         5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u,
@@ -294,7 +294,7 @@ find_syllables_khmer (hb_buffer_t *buffer)
   int cs;
   hb_glyph_info_t *info = buffer->info;
 
-#line 298 "hb-ot-shaper-khmer-machine.hh"
+#line 287 "hb-ot-shaper-khmer-machine.hh"
         {
         cs = khmer_syllable_machine_start;
         ts = 0;
@@ -310,7 +310,7 @@ find_syllables_khmer (hb_buffer_t *buffer)
 
   unsigned int syllable_serial = 1;
 
-#line 314 "hb-ot-shaper-khmer-machine.hh"
+#line 299 "hb-ot-shaper-khmer-machine.hh"
         {
         int _slen;
         int _trans;
@@ -324,7 +324,7 @@ _resume:
 #line 1 "NONE"
         {ts = p;}
         break;
-#line 328 "hb-ot-shaper-khmer-machine.hh"
+#line 311 "hb-ot-shaper-khmer-machine.hh"
         }
 
         _keys = _khmer_syllable_machine_trans_keys + (cs<<1);
@@ -394,7 +394,7 @@ _eof_trans:
 #line 98 "hb-ot-shaper-khmer-machine.rl"
         {act = 3;}
         break;
-#line 398 "hb-ot-shaper-khmer-machine.hh"
+#line 368 "hb-ot-shaper-khmer-machine.hh"
         }
 
 _again:
@@ -403,7 +403,7 @@ _again:
 #line 1 "NONE"
         {ts = 0;}
         break;
-#line 407 "hb-ot-shaper-khmer-machine.hh"
+#line 375 "hb-ot-shaper-khmer-machine.hh"
         }
 
         if ( ++p != pe )
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-khmer.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-khmer.cc
index 2a4aed2ab1b..1f5028aa3ee 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-khmer.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-khmer.cc
@@ -141,12 +141,6 @@ override_features_khmer (hb_ot_shape_planner_t *plan)
    * typographical correctness.", hence in overrides... */
   map->enable_feature (HB_TAG('c','l','i','g'));
 
-  /* Uniscribe does not apply 'kern' in Khmer. */
-  if (hb_options ().uniscribe_bug_compatible)
-  {
-    map->disable_feature (HB_TAG('k','e','r','n'));
-  }
-
   map->disable_feature (HB_TAG('l','i','g','a'));
 }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-myanmar-machine.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-myanmar-machine.hh
index 64eb761b4ea..6e5fce609bc 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-myanmar-machine.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-myanmar-machine.hh
@@ -50,7 +50,7 @@ enum myanmar_syllable_type_t {
 };
 
 
-#line 54 "hb-ot-shaper-myanmar-machine.hh"
+#line 51 "hb-ot-shaper-myanmar-machine.hh"
 #define myanmar_syllable_machine_ex_A 9u
 #define myanmar_syllable_machine_ex_As 32u
 #define myanmar_syllable_machine_ex_C 1u
@@ -78,7 +78,7 @@ enum myanmar_syllable_type_t {
 #define myanmar_syllable_machine_ex_ZWNJ 5u
 
 
-#line 82 "hb-ot-shaper-myanmar-machine.hh"
+#line 77 "hb-ot-shaper-myanmar-machine.hh"
 static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
         1u, 57u, 3u, 57u, 5u, 57u, 5u, 57u, 3u, 57u, 5u, 57u, 3u, 57u, 3u, 57u,
         3u, 57u, 3u, 57u, 3u, 57u, 5u, 57u, 1u, 15u, 3u, 57u, 3u, 57u, 3u, 57u,
@@ -549,7 +549,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
   int cs;
   hb_glyph_info_t *info = buffer->info;
 
-#line 553 "hb-ot-shaper-myanmar-machine.hh"
+#line 542 "hb-ot-shaper-myanmar-machine.hh"
         {
         cs = myanmar_syllable_machine_start;
         ts = 0;
@@ -565,7 +565,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
 
   unsigned int syllable_serial = 1;
 
-#line 569 "hb-ot-shaper-myanmar-machine.hh"
+#line 554 "hb-ot-shaper-myanmar-machine.hh"
         {
         int _slen;
         int _trans;
@@ -579,7 +579,7 @@ _resume:
 #line 1 "NONE"
         {ts = p;}
         break;
-#line 583 "hb-ot-shaper-myanmar-machine.hh"
+#line 566 "hb-ot-shaper-myanmar-machine.hh"
         }
 
         _keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
@@ -649,7 +649,7 @@ _eof_trans:
 #line 113 "hb-ot-shaper-myanmar-machine.rl"
         {act = 3;}
         break;
-#line 653 "hb-ot-shaper-myanmar-machine.hh"
+#line 623 "hb-ot-shaper-myanmar-machine.hh"
         }
 
 _again:
@@ -658,7 +658,7 @@ _again:
 #line 1 "NONE"
         {ts = 0;}
         break;
-#line 662 "hb-ot-shaper-myanmar-machine.hh"
+#line 630 "hb-ot-shaper-myanmar-machine.hh"
         }
 
         if ( ++p != pe )
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc
index a0ea464e775..42fc4bbcc44 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc
@@ -163,7 +163,7 @@ thai_pua_shape (hb_codepoint_t u, thai_action_t action, hb_font_t *font)
 }
 
 
-static enum thai_above_state_t
+static const enum thai_above_state_t
 {     /* Cluster above looks like: */
   T0, /*  ⣤                      */
   T1, /*     ⣼                   */
@@ -191,7 +191,7 @@ static const struct thai_above_state_machine_edge_t {
 };
 
 
-static enum thai_below_state_t
+static const enum thai_below_state_t
 {
   B0, /* No descender */
   B1, /* Removable descender */
@@ -334,7 +334,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
 
     /* Is SARA AM. Decompose and reorder. */
     (void) buffer->output_glyph (NIKHAHIT_FROM_SARA_AM (u));
-    _hb_glyph_info_set_continuation (&buffer->prev());
+    _hb_glyph_info_set_continuation (&buffer->prev(), buffer);
     if (unlikely (!buffer->replace_glyph (SARA_AA_FROM_SARA_AM (u)))) break;
 
     /* Make Nikhahit be recognized as a ccc=0 mark when zeroing widths. */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-machine.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-machine.hh
index 46f66f7d285..22a5356a877 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-machine.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-machine.hh
@@ -53,7 +53,7 @@ enum use_syllable_type_t {
 };
 
 
-#line 57 "hb-ot-shaper-use-machine.hh"
+#line 54 "hb-ot-shaper-use-machine.hh"
 #define use_syllable_machine_ex_B 1u
 #define use_syllable_machine_ex_CGJ 6u
 #define use_syllable_machine_ex_CMAbv 31u
@@ -100,7 +100,7 @@ enum use_syllable_type_t {
 #define use_syllable_machine_ex_ZWNJ 14u
 
 
-#line 104 "hb-ot-shaper-use-machine.hh"
+#line 99 "hb-ot-shaper-use-machine.hh"
 static const unsigned char _use_syllable_machine_trans_keys[] = {
         49u, 51u, 0u, 56u, 11u, 56u, 11u, 56u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u,
         14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u,
@@ -929,7 +929,7 @@ find_syllables_use (hb_buffer_t *buffer)
   unsigned int act HB_UNUSED;
   int cs;
 
-#line 933 "hb-ot-shaper-use-machine.hh"
+#line 922 "hb-ot-shaper-use-machine.hh"
         {
         cs = use_syllable_machine_start;
         ts = 0;
@@ -942,7 +942,7 @@ find_syllables_use (hb_buffer_t *buffer)
 
   unsigned int syllable_serial = 1;
 
-#line 946 "hb-ot-shaper-use-machine.hh"
+#line 931 "hb-ot-shaper-use-machine.hh"
         {
         int _slen;
         int _trans;
@@ -956,7 +956,7 @@ _resume:
 #line 1 "NONE"
         {ts = p;}
         break;
-#line 960 "hb-ot-shaper-use-machine.hh"
+#line 943 "hb-ot-shaper-use-machine.hh"
         }
 
         _keys = _use_syllable_machine_trans_keys + (cs<<1);
@@ -1078,7 +1078,7 @@ _eof_trans:
 #line 181 "hb-ot-shaper-use-machine.rl"
         {act = 9;}
         break;
-#line 1082 "hb-ot-shaper-use-machine.hh"
+#line 1039 "hb-ot-shaper-use-machine.hh"
         }
 
 _again:
@@ -1087,7 +1087,7 @@ _again:
 #line 1 "NONE"
         {ts = 0;}
         break;
-#line 1091 "hb-ot-shaper-use-machine.hh"
+#line 1046 "hb-ot-shaper-use-machine.hh"
         }
 
         if ( ++p != pe )
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-table.hh
index d3c49949aa8..a69abefdd01 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-table.hh
@@ -6,18 +6,18 @@
  *
  * on files with these headers:
  *
- * # IndicSyllabicCategory-16.0.0.txt
- * # Date: 2024-04-30, 21:48:21 GMT
- * # IndicPositionalCategory-16.0.0.txt
- * # Date: 2024-04-30, 21:48:21 GMT
- * # ArabicShaping-16.0.0.txt
- * # Date: 2024-07-30
- * # DerivedCoreProperties-16.0.0.txt
- * # Date: 2024-05-31, 18:09:32 GMT
- * # Blocks-16.0.0.txt
- * # Date: 2024-02-02
- * # Scripts-16.0.0.txt
- * # Date: 2024-04-30, 21:48:40 GMT
+ * # IndicSyllabicCategory-17.0.0.txt
+ * # Date: 2025-08-01, 04:02:23 GMT
+ * # IndicPositionalCategory-17.0.0.txt
+ * # Date: 2025-07-29, 13:35:52 GMT
+ * # ArabicShaping-17.0.0.txt
+ * # Date: 2025-08-14
+ * # DerivedCoreProperties-17.0.0.txt
+ * # Date: 2025-07-30, 23:55:08 GMT
+ * # Blocks-17.0.0.txt
+ * # Date: 2025-08-01
+ * # Scripts-17.0.0.txt
+ * # Date: 2025-07-24, 13:28:55 GMT
  * # Override values For Indic_Syllabic_Category
  * # Not derivable
  * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
@@ -101,8 +101,9 @@
 
 #ifndef HB_OPTIMIZE_SIZE
 
-static const uint8_t
-hb_use_u8[3345] =
+#include 
+
+static const uint8_t hb_use_u8[3343]=
 {
      16,   50,   51,   51,   51,   52,   51,   83,  118,  131,   57,   58,   59,  195,  211,   62,
      51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
@@ -126,24 +127,24 @@ hb_use_u8[3345] =
      49,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   50,   51,    2,    2,    2,
       2,    2,    2,    2,    2,   52,   53,    2,   54,    2,    2,   55,   56,    2,   57,   58,
      59,   60,   61,   62,   63,   64,   65,   66,   67,   68,   69,    2,   70,   71,   72,   73,
-      2,   74,    2,   75,   76,   77,   78,    2,    2,   79,   80,   81,   82,    2,   83,   84,
-      2,   85,   85,   85,   85,   85,   85,   85,   85,   86,   85,   85,   85,   85,   85,   85,
-     85,   85,   85,   85,   85,   85,   85,   85,   85,   85,   85,   85,   85,   85,   85,   85,
-     85,   85,   85,   85,   85,   85,   85,   85,   87,    2,    2,    2,    2,    2,    2,    2,
+      2,   74,    2,   75,   76,   77,   78,   79,    2,   80,   81,   82,   83,    2,   84,   85,
+      2,   86,   86,   86,   86,   86,   86,   86,   86,   87,   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,   88,    2,    2,    2,    2,    2,    2,    2,
       2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,   88,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,    2,    2,    2,   89,   90,    2,    2,    2,   91,    2,    2,    2,   92,
-     93,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,    2,    2,    2,    2,   94,   94,   94,   95,    2,    2,    2,    2,    2,
+      2,    2,    2,   89,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,   90,   91,    2,    2,    2,   92,    2,    2,    2,   93,
+     94,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,   95,   95,   95,   96,    2,    2,    2,    2,    2,
       2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,    2,    2,    2,    2,    2,    2,   96,   97,    2,    2,    2,    2,    2,
-      2,    2,    2,   98,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,   97,   98,    2,    2,    2,    2,    2,
+      2,    2,    2,   99,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
       2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,   99,    2,    2,  100,    2,    2,    2,  101,    2,  102,    2,    2,    2,
-      2,    2,    2,  103,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      2,  104,  104,  105,  106,  104,  104,  104,  104,  104,  104,  104,  104,  104,  104,  104,
-    104,  104,  104,  104,  104,  104,  104,  104,  104,  104,  104,  104,  104,  104,  104,  104,
-    104,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,
+      2,    2,    2,  100,    2,    2,  101,    2,    2,    2,  102,    2,  103,    2,    2,    2,
+      2,    2,    2,  104,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,  105,  105,  106,  107,  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,
+    105,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,
       0,    2,    2,    2,    2,    2,    0,    0,    0,    0,    0,    0,    0,    0,    3,    4,
       0,    5,    0,    0,    0,    0,    0,    6,    0,    0,    7,    0,    0,    0,    0,    0,
       0,    0,    0,    0,    1,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
@@ -192,99 +193,99 @@ hb_use_u8[3345] =
      48,   48,   48,   48,   15,   82,   83,   84,   85,   86,   87,    0,    0,    0,    0,   88,
       0,    9,    0,    0,   30,    0,   89,   81,   90,    2,    2,    2,    2,    9,    0,    0,
       0,   42,   42,   91,   92,    2,    2,    2,    2,    2,    2,    2,    2,   13,    9,    0,
-      0,   93,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      9,   22,   80,   45,   22,   94,   61,    0,    0,   95,   96,   95,   95,   97,   98,    0,
-      0,    2,    2,    2,    2,    2,    2,    2,    0,    2,    2,    9,    0,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,    2,    0,    0,    2,    2,    2,    2,   29,    0,    0,
-      0,    2,    2,    2,    2,    2,    9,    0,    0,    2,    2,    2,   52,   99,   45,    0,
-      0,    2,    2,  100,  101,  102,  103,   61,   63,  104,   16,   45,   22,   59,   21,   80,
-     48,   48,   76,   11,   11,   11,  105,   46,   40,   11,  106,   74,    2,    2,    2,    2,
-      2,    2,    2,  107,   22,   20,   20,   22,   48,   48,   22,  108,    2,    2,    2,    9,
-      0,    0,    0,    0,    0,    0,  109,  110,  110,  110,  110,    0,    0,    0,    0,    0,
-      0,  106,   74,    2,    2,    2,    2,    2,    2,   60,   61,   59,   25,   22,  111,   61,
-      2,    2,    2,    2,  107,   22,   23,   45,   45,  102,  112,    0,    0,    0,    0,    0,
-      0,    2,    2,   61,   18,   48,   23,  113,  102,  102,  102,  114,  115,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,    0,   30,    2,   11,   46,  116,  116,  116,   11,  116,
-    116,   15,  116,  116,  116,   26,    0,   40,    0,    0,    0,  117,   51,   11,    5,    0,
-      0,    0,    0,    0,    0,    0,  118,    0,    0,    0,    0,    0,    0,    0,    6,  119,
-    120,   42,   42,    5,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,  120,  120,
-    121,  120,  120,  120,  120,  120,  120,  120,  120,    0,    0,  122,    0,    0,    0,    0,
-      0,    0,    7,  122,    0,    0,    0,    0,    0,   46,    0,    0,    0,    0,    0,    0,
-      0,    0,    0,    0,    0,    0,    0,    9,    0,    0,    0,    0,  123,  123,    0,    0,
-      0,    2,    2,    2,    2,    0,    0,    0,   30,    0,    0,    0,    0,    0,    0,    0,
-    124,    0,  123,  123,    0,    0,    0,    0,    0,    2,   53,    2,  108,    2,   10,    2,
-      2,    2,   65,   19,   16,    0,    0,   31,    0,    2,    2,    0,    0,    0,    0,    0,
-      0,   29,    2,    2,    2,    2,    2,    2,    2,    2,    2,  125,   23,   23,   23,   23,
-     23,   23,   23,  126,    0,    0,    0,    0,    0,   11,   11,   11,   11,   11,   11,   11,
-     11,   11,    2,    0,    0,    0,    0,    0,   52,    2,    2,    2,   22,   22,  127,  116,
-      0,    2,    2,    2,  128,   20,   59,   20,  113,  102,  129,    0,    0,    0,    0,    0,
-      0,   11,  130,    2,    2,    2,    2,    2,    2,    2,  131,   23,   22,   20,   48,  132,
-    133,  134,    0,    0,    0,    0,    0,    0,    0,    2,    2,   52,   30,    2,    2,    2,
-      2,    2,    2,    2,    2,   10,   22,   59,   99,   76,  135,  136,  137,    0,    0,    0,
-      0,    2,  138,    2,    2,    2,    2,  139,    0,   30,    2,   42,    5,    0,   79,   15,
-      2,   53,   22,  140,   52,   53,    2,    2,  105,   10,    9,    0,    0,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,  141,   21,   25,    0,    0,  142,  143,    0,    0,    0,
-      0,    2,   65,   45,   23,   80,   47,  144,    0,   81,   81,   81,   81,   81,   81,   81,
-     81,    0,    0,    0,    0,    0,    0,    0,    6,  120,  120,  120,  120,  121,    0,    0,
-      0,    2,    2,    2,    2,    2,    9,    2,    2,    2,    9,    2,   30,    2,    2,    2,
-      2,    2,   30,    2,    2,    2,   30,    9,    0,  128,   20,   27,   31,    0,    0,  145,
-    146,    2,    2,   30,    2,   30,    2,    2,    2,    2,    2,    2,    0,   14,   37,    0,
-    147,    2,    2,   13,   37,    0,   30,    2,    2,    2,    0,    0,    0,    0,    0,    0,
-      0,    0,    0,    0,    0,   30,    2,    2,    9,    2,    2,   11,   41,    0,    0,    0,
-      0,    2,    2,    2,    0,   27,   22,   22,   30,    2,    2,    2,    0,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,   27,   38,    0,    2,    2,    2,  116,  116,  116,  116,
-    116,  148,    2,    9,    0,    0,    0,    0,    0,    2,   14,   14,    0,    0,    0,    0,
-      0,    9,    2,    2,    9,    2,    2,    2,    2,   30,    2,    9,    0,   30,    2,    0,
-      0,  149,  150,  151,    2,    2,    2,    2,    2,    2,    2,    2,    2,   22,   22,   20,
-     20,   20,   22,   22,  134,    0,    0,    0,    0,    0,  152,  152,  152,  152,  152,  152,
-    152,  152,  152,  152,    2,    2,    2,    2,    2,   53,   52,   53,    0,    0,    0,    0,
-    153,   11,   74,    2,    2,    2,    2,    2,    2,   18,   19,   21,   16,   24,   37,    0,
-      0,    0,   31,    0,    0,    0,    0,    0,    0,   11,   49,    2,    2,    2,    2,    2,
-      2,    2,    2,    2,  128,   20,   22,  154,   22,   21,  155,  156,    2,    2,    2,    2,
-      2,    0,    0,   65,  157,    0,    0,    0,    0,    2,   13,    0,    0,    0,    0,    0,
-      0,    2,   65,   25,   20,   20,   20,   22,   22,  108,  158,    0,    0,   56,  159,   31,
-    160,   30,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   23,
-     19,   22,   22,  161,   44,    0,    0,    0,   49,  128,    0,    0,    0,    0,    0,    0,
-      0,    2,    2,    2,    9,    9,    2,    2,   30,    2,    2,    2,    2,    2,    2,    2,
-     30,    2,    2,    2,    2,    2,    2,    2,   10,   18,   19,   21,   22,  162,   31,    0,
-      0,   11,   11,   30,    2,    2,    2,    9,   30,    9,    2,   30,    2,    2,   58,   17,
-     23,   16,   23,   47,   32,   33,   32,   34,    0,    0,    0,    0,   35,    0,    0,    0,
-      2,    2,   23,    0,   11,   11,   11,   46,    0,   11,   11,   46,    0,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,   30,    0,    9,    2,    2,    2,   30,   45,   59,   20,
-     20,   31,   33,   32,   32,   25,  163,   29,  164,  165,   37,    0,    0,    0,    0,    0,
-      0,   12,   26,    0,    0,    0,    0,    0,    0,    2,    2,   65,   25,   20,   20,   20,
-     22,   23,  126,   15,   17,    0,    0,    0,    0,    2,    2,    2,    2,    2,    0,    0,
-    166,  167,    0,    0,    0,    0,    0,    0,    0,   18,   19,   20,   20,   66,   99,   25,
-    160,   11,  168,    9,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,    2,
-     65,   25,   20,   20,    0,   48,   48,   11,  169,   37,    0,    0,    0,    0,    0,    0,
-      0,    0,    0,    0,    0,    2,    2,   20,    0,   23,   19,   20,   20,   21,   16,   82,
-    169,   38,    0,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,   10,  170,
-     25,   20,   22,   22,  168,    9,    0,    0,    0,    2,    2,    2,    2,    2,    9,   43,
-    136,   23,   22,   20,   76,   21,   22,    0,    0,    2,    2,    2,    9,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,    2,   18,   19,   20,   21,   22,  105,  169,   37,    0,
-      0,    2,    2,    2,    9,   30,    0,    2,    2,    2,    2,   30,    9,    2,    2,    2,
-      2,   23,   23,   18,   32,   33,   12,  171,  165,  172,  173,    0,    0,    0,    0,    0,
-      0,    2,    2,    2,    2,    0,    2,    2,    2,   65,   25,   20,   20,    0,   22,   23,
-     29,  108,    0,   33,    0,    0,    0,    0,    0,   52,   20,   22,   22,   22,  140,    2,
-      2,    2,  174,  175,   11,   15,  176,   61,  177,    0,    0,    1,  147,    0,    0,    0,
-      0,   52,   20,   22,   16,   19,   20,    2,    2,    2,    2,  158,  158,  158,  178,  178,
-    178,  178,  178,  178,   15,  179,    0,   30,    0,   22,   20,   20,   31,   22,   22,   11,
+      0,    2,    2,    2,    2,    2,    2,    2,    9,   22,   80,   45,   22,   93,   61,    0,
+      0,   94,   95,   94,   94,   96,   97,    0,    0,    2,    2,    2,    2,    2,    2,    2,
+      0,    2,    2,    9,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,    0,
+      0,    2,    2,    2,    2,   29,    0,    0,    0,    2,    2,    2,    2,    2,    9,    0,
+      0,    2,    2,    2,   52,   98,   45,    0,    0,    2,    2,   99,  100,  101,  102,   61,
+     63,  103,   16,   45,   22,   59,   21,   80,   48,   48,   76,   11,   11,   11,  104,   46,
+     40,   11,  105,   74,    2,    2,    2,    2,    2,    2,    2,  106,   22,   20,   20,   22,
+     48,   48,   22,  107,    2,    2,    2,    9,    0,    0,    0,    0,    0,    0,  108,  109,
+    109,  109,  109,    0,    0,    0,    0,    0,    0,  105,   74,    2,    2,    2,    2,    2,
+      2,   60,   61,   59,   25,   22,  110,   61,    2,    2,    2,    2,  106,   22,   23,   45,
+     45,  101,  111,    0,    0,    0,    0,    0,    0,    2,    2,   61,   18,   48,   23,  112,
+    101,  101,  101,  113,  114,    0,    0,    0,    0,    2,    2,    2,    2,    2,    0,   30,
+      2,   11,   46,  115,  115,  115,   11,  115,  115,   15,  115,  115,  115,   26,    0,   40,
+      0,    0,    0,  116,   51,   11,    5,    0,    0,    0,    0,    0,    0,    0,  117,    0,
+      0,    0,    0,    0,    0,    0,    6,  118,  119,   42,   42,    5,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,  119,  119,  120,  119,  119,  119,  119,  119,  119,  119,
+    119,    0,    0,  121,    0,    0,    0,    0,    0,    0,    7,  121,    0,    0,    0,    0,
+      0,   46,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    9,
+      0,    0,    0,    0,  122,  122,    0,    0,    0,    2,    2,    2,    2,    0,    0,    0,
+     30,    0,    0,    0,    0,    0,    0,    0,  123,    0,  122,  122,    0,    0,    0,    0,
+      0,    2,   53,    2,  107,    2,   10,    2,    2,    2,   65,   19,   16,    0,    0,   31,
+      0,    2,    2,    0,    0,    0,    0,    0,    0,   29,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,  124,   23,   23,   23,   23,   23,   23,   23,  125,    0,    0,    0,    0,
+      0,   11,   11,   11,   11,   11,   11,   11,   11,   11,    2,    0,    0,    0,    0,    0,
+     52,    2,    2,    2,   22,   22,  126,  115,    0,    2,    2,    2,  127,   20,   59,   20,
+    112,  101,  128,    0,    0,    0,    0,    0,    0,   11,  129,    2,    2,    2,    2,    2,
+      2,    2,  130,   23,   22,   20,   48,  131,  132,  133,    0,    0,    0,    0,    0,    0,
+      0,    2,    2,   52,   30,    2,    2,    2,    2,    2,    2,    2,    2,   10,   22,   59,
+     98,   76,  134,  135,  136,    0,    0,    0,    0,    2,  137,    2,    2,    2,    2,  138,
+      0,   30,    2,   42,    5,    0,   79,   15,    2,  139,   20,   53,  127,  139,    2,    2,
+    140,   10,    9,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,  141,   21,
+     25,    0,    0,  142,  143,    0,    0,    0,    0,    2,   65,   45,   23,   80,   47,  144,
+      0,   81,   81,   81,   81,   81,   81,   81,   81,    0,    0,    0,    0,    0,    0,    0,
+      6,  119,  119,  119,  119,  120,    0,    0,    0,    2,    2,    2,    2,    2,    9,    2,
+      2,    2,    9,    2,   30,    2,    2,    2,    2,    2,   30,    2,    2,    2,   30,    9,
+      0,  127,   20,   27,   31,    0,    0,  145,  146,    2,    2,   30,    2,   30,    2,    2,
+      2,    2,    2,    2,    0,   14,   37,    0,  147,    2,    2,   13,   37,    0,   30,    2,
+      2,    2,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   30,    2,    2,
+      9,    2,    2,   11,   41,    0,    0,    0,    0,    2,    2,    2,    0,   27,   22,   22,
+     30,    2,    2,    2,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,   27,   38,
+      0,    2,    2,    2,  115,  115,  115,  115,  115,  148,    2,    9,    0,    0,    0,    0,
+      0,    2,   14,   14,    0,    0,    0,    0,    0,    9,    2,    2,    9,    2,    2,    2,
+      2,   30,    2,    9,    0,   30,    2,    0,    0,  149,  150,  151,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,   22,   22,   20,   20,   20,   22,   22,  133,    0,    0,    0,
+      0,    0,  152,  152,  152,  152,  152,  152,  152,  152,  152,  152,    2,    2,    2,    2,
+      2,   53,   52,   53,    0,    0,    0,    0,  153,   11,   74,    2,    2,    2,    2,    2,
+      2,   18,   19,   21,   16,   24,   37,    0,    0,    0,   31,    0,    0,    0,    0,    0,
+      0,   11,   49,    2,    2,    2,    2,    2,    2,    2,    2,    2,  127,   20,   22,  154,
+     22,   21,  155,  156,    2,    2,    2,    2,    2,    0,    0,   65,  157,    0,    0,    0,
+      0,    2,   13,    0,    0,    0,    0,    0,    0,    2,   65,   25,   20,   20,   20,   22,
+     22,  107,  158,    0,    0,   56,  159,   31,  160,   30,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,   23,   19,   22,   22,  161,   44,    0,    0,    0,
+     49,  127,    0,    0,    0,    0,    0,    0,    0,    2,    2,    2,    9,    9,    2,    2,
+     30,    2,    2,    2,    2,    2,    2,    2,   30,    2,    2,    2,    2,    2,    2,    2,
+     10,   18,   19,   21,   22,  162,   31,    0,    0,   11,   11,   30,    2,    2,    2,    9,
+     30,    9,    2,   30,    2,    2,   58,   17,   23,   16,   23,   47,   32,   33,   32,   34,
+      0,    0,    0,    0,   35,    0,    0,    0,    2,    2,   23,    0,   11,   11,   11,   46,
+      0,   11,   11,   46,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,   30,    0,
+      9,    2,    2,    2,   30,   45,   59,   20,   20,   31,   33,   32,   32,   25,  163,   29,
+    164,  165,   37,    0,    0,    0,    0,    0,    0,   12,   26,    0,    0,    0,    0,    0,
+      0,    2,    2,   65,   25,   20,   20,   20,   22,   23,  125,   15,   17,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    0,    0,  166,  167,    0,    0,    0,    0,    0,    0,
+      0,   18,   19,   20,   20,   66,   98,   25,  160,   11,  168,    9,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    2,    2,   65,   25,   20,   20,    0,   48,   48,   11,
+    169,   37,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    2,    2,   20,
+      0,   23,   19,   20,   20,   21,   16,   82,  169,   38,    0,    0,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,   10,  170,   25,   20,   22,   22,  168,    9,    0,    0,
+      0,    2,    2,    2,    2,    2,    9,   43,  135,   23,   22,   20,   76,   21,   22,    0,
+      0,    2,    2,    2,    9,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,   18,
+     19,   20,   21,   22,  104,  169,   37,    0,    0,    2,    2,    2,    9,   30,    0,    2,
+      2,    2,    2,   30,    9,    2,    2,    2,    2,   23,   23,   18,   32,   33,   12,  171,
+    165,  172,  173,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    0,    2,    2,
+      2,   65,   25,   20,   20,    0,   22,   23,   29,  107,    0,   33,    0,    0,    0,    0,
+      0,   52,   20,   22,   22,   22,  139,    2,    2,    2,  174,  140,   11,   15,  175,   61,
+    176,    0,    0,    1,  147,    0,    0,    0,    0,   52,   20,   22,   16,   19,   20,    2,
+      2,    2,    2,  158,  158,  158,  177,  177,  177,  177,  177,  177,   15,  178,    0,   30,
+      0,   16,   20,   16,   16,    0,    0,    0,    0,   22,   20,   20,   31,   22,   22,   11,
     169,    0,   61,   61,   61,   61,   61,   61,   61,   66,   21,   82,   46,    0,    0,    0,
       0,    2,    2,    2,    9,    2,   30,    2,    2,   52,   22,   22,   31,    0,   38,   22,
-     27,   11,  159,  180,  181,    0,    0,    0,    0,    2,    2,    2,   30,    9,    2,    2,
+     27,   11,  159,  179,  180,    0,    0,    0,    0,    2,    2,    2,   30,    9,    2,    2,
       2,    2,    2,    2,    2,    2,   23,   23,   47,   22,   35,   82,   68,    0,    0,    0,
-      0,    2,  182,   66,   47,    0,    0,    0,    0,   11,  183,    2,    2,    2,    2,    2,
+      0,    2,  181,   66,   47,    0,    0,    0,    0,   11,  182,    2,    2,    2,    2,    2,
       2,    2,    2,   23,   22,   20,   31,    0,   48,   16,  143,    0,    0,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,  156,    0,    0,  184,  184,  184,  184,  184,  184,  184,
-    184,  185,  185,  185,  186,  187,  185,  184,  184,  188,  184,  184,  189,  190,  190,  190,
-    190,  190,  190,  190,    0,    0,    0,    0,    0,  184,  184,  184,  184,  184,  191,    0,
-      0,    2,    2,    2,    2,    2,    2,    2,   22,   22,   22,   22,   22,   22,  192,  193,
-    194,   11,   11,   11,   46,    0,    0,    0,    0,   29,   74,    2,    2,    2,    2,    2,
+      0,    2,    2,    2,    2,    2,  156,    0,    0,  183,  183,  183,  183,  183,  183,  183,
+    183,  184,  184,  184,  185,  186,  184,  183,  183,  187,  183,  183,  188,  189,  189,  189,
+    189,  189,  189,  189,    0,    0,    0,    0,    0,  183,  183,  183,  183,  183,  190,    0,
+      0,    2,    2,    2,    2,    2,    2,    2,   22,   22,   22,   22,   22,   22,  191,  192,
+    193,   11,   11,   11,   46,    0,    0,    0,    0,   29,   74,    2,    2,    2,    2,    2,
       2,    2,    2,    2,    2,    2,   65,   47,    0,    2,    2,    2,    2,    2,    9,    0,
-     58,  195,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,
-     20,   20,   20,   20,   20,    0,    0,    0,   40,  116,   26,    0,    0,    0,    0,    0,
+     58,  194,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,
+     20,   20,   20,   20,   20,    0,    0,    0,   40,  115,   26,    0,    0,    0,    0,    0,
       0,    0,    0,    9,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-     30,    2,    2,    2,    2,    2,    0,   58,   37,    0,    6,  120,  120,  120,  121,    0,
+     30,    2,    2,    2,    2,    2,    0,   58,   37,    0,    6,  119,  119,  119,  120,    0,
       0,   11,   11,   11,   49,    2,    2,    2,    0,    2,    2,    2,    2,    2,    0,    0,
       2,    2,    2,    2,    2,    2,    2,    2,   46,    2,    2,    2,    2,    2,    2,   11,
      11,    2,    2,    2,    2,    2,    2,   22,   22,    2,    2,    2,    2,    2,    2,    2,
@@ -300,23 +301,21 @@ hb_use_u8[3345] =
   VMBlw,VMPst,   IS, VAbv, MPst, MPre, MBlw, MBlw,    B, MBlw, MBlw, VPst,VMPst,VMPst,    B, MBlw,
    VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw,    B,VMPst, VBlw, VPst,  CGJ,  CGJ, VPst,VMAbv,VMAbv,
   FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv,   IS,FMAbv,    B,FMAbv,    B,  CGJ,   WJ,  CGJ,   GB,
-  CMAbv,CMAbv,    B,   GB,    B, VAbv,  SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv,
-   VPre,    B, MPre, MBlw,  SUB, FAbv, FAbv, MAbv,  SUB,   Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv,
-   VPst,    H,    B,    O,SMAbv,SMAbv,SMAbv, VPst,   IS,   RK,   RK, VBlw, FAbv,VMPre,VMPre,FMAbv,
-  CMBlw,VMBlw,VMBlw,VMAbv,   CS,    O,FMAbv, ZWNJ,  CGJ,   WJ,   WJ,   WJ,    O,FMPst,    O,   SB,
-     SE,    O,    H, MPst, VPst,    H,VMAbv, VAbv,VMBlw,    B, VBlw, FPst, VPst, FAbv,VMPst,    B,
-  CMAbv, VAbv, MBlw, MPst, MBlw,    H,    O, VBlw, MPst, MPre, MAbv, MBlw,    O,    B, FAbv, FAbv,
-   FPst, VBlw,    B,    B, VPre,    O,VMPst,   IS,    O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv,    O,
+  CMAbv,CMAbv,    B, VAbv,  SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre,    B,
+   MPre, MBlw,  SUB, FAbv, FAbv, MAbv,  SUB,   Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst,    H,
+      B,    O,SMAbv,SMAbv,SMAbv, VPst,   IS,   RK,   RK, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,
+  VMBlw,VMAbv,   CS,    O,FMAbv, ZWNJ,  CGJ,   WJ,   WJ,   WJ,    O,FMPst,    O,   SB,   SE,    O,
+      H, MPst, VPst,    H,VMAbv, VAbv,VMBlw,    B, VBlw, FPst, VPst, FAbv,VMPst,    B,CMAbv, VAbv,
+   MBlw, MPst, MBlw,    H,    O, VBlw, MPst, MPre, MAbv, MBlw,    O,    B, FAbv, FAbv, FPst, VBlw,
+      B, VBlw,VMAbv,    B, VPre,    O,VMPst,   IS,    O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv,    O,
      IS,VMBlw,    B,VMPst,VMAbv,VMPst,   CS,   CS,    B,    N,    N,    O,   HN, VPre, VBlw, VAbv,
      IS,CMAbv,    O, VPst,    B,    R,    R,CMBlw, VAbv, VPre,VMAbv,VMAbv,    H, VAbv,CMBlw,VMPst,
       O,VMAbv,CMBlw,   IS,    R,FMAbv,    B,   CS,   CS,    H,CMBlw,VMPst,    H,VMPst, VAbv,VMAbv,
-   VPst, MPst,    R, MPst,CMBlw,    B,FMBlw, VBlw,VMAbv,   CS,  SUB,  SUB,   GB, FBlw, FBlw,CMAbv,
-     IS, VBlw,   IS,    R, MBlw,   GB, VAbv,    R,VMPst,    G,    G,    J,    J,    J,   SB,   SE,
-      J,   HR,    G,    G,   HM,   HM,   HM,    G,    O, MPre, MPre, MPst,VMAbv, MBlw, VBlw,    O,
-   VBlw,
+   VPst, MPst,    R, MPst,CMBlw,    B,FMBlw,   CS,  SUB,  SUB,   GB, FBlw, FBlw,CMAbv,   IS, VBlw,
+     IS,    R, MBlw,   GB, VAbv,    R,VMPst,    G,    G,    J,    J,    J,   SB,   SE,    J,   HR,
+      G,    G,   HM,   HM,   HM,    G,    O, MPre, MPre, MPst,VMAbv, MBlw, VBlw,    O, VBlw,
 };
-static const uint16_t
-hb_use_u16[856] =
+static const uint16_t hb_use_u16[864]=
 {
     0,  0,  1,  2,  0,  3,  0,  3,  0,  0,  4,  5,  0,  6,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  7,  0,  0,  0,
@@ -330,66 +329,65 @@ hb_use_u16[856] =
    73, 74, 75, 76, 77,  0,  0,  0, 10, 10, 78, 79, 80, 81, 82, 83,
    84, 85,  0,  0,  0,  0,  0,  0, 10, 86, 10, 87, 10, 88, 89, 90,
    10, 10, 10, 91, 92, 93,  2,  0, 94,  0, 10, 10, 10, 10, 10, 95,
-   96, 10, 97,  0,  0,  0,  0,  0, 98, 99,100,101, 31, 10,102,103,
-   10, 10,104, 10,105,106,  0,  0, 10,107, 10, 10, 10,108,109,110,
-    2,  2,  0,  0,  0,  0,  0,  0,111, 10, 10,112,113,  2,114,115,
-  116, 10,117, 10, 10, 10,118,119, 10, 10,120,121,122,  0,  0,  0,
-    0,  0,  0,  0,  0,123,124,125,  0,  0,  0,  0,  0,  0,  0,126,
-  127,128,129,  0,  0,  0,130,131,132,  0,  0,  0,  0,  0,  0,133,
-    0,  0,  0,  0,134,  0,  0,  0,  0,  0,  0,  0,  0,  0,135,  0,
-    0,  0,  0, 10, 10, 10,136,137,  0,  0,138,  0,  0,  0,  0,  0,
-  139, 10,140,  0, 10, 10, 10,141,142, 10, 10,143,144,  2,145,146,
-   10, 10,147, 10,148,149,  0,  0,150, 10, 10,151,152,  2,153, 99,
-   10, 10,154,155,156,  2, 10,157, 10, 10, 10,158,159,  0,160,161,
-    0,  0,  0,  0, 10, 10,162,  2,163,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,164,  0,  0,  0,  0,  0,  0,  0,165,
-    0,  0,  0,  0,  0,  0,  0,166,166,167, 34,168,  0,  0,  0,  0,
-  169,170, 10,171, 95,  0,  0,  0,  0,  0,  0,  0, 70, 10,172,  0,
-   10,173,174,  0,  0,  0,  0,  0, 10, 10,175,  2,  9, 10,176, 10,
-  177,  0,  0,  0,  0,  0,  0,  0, 10, 10,178,173,  0,  0,  0,  0,
-    0,  0,  0, 10,179,180,  0, 10,181,  0,  0,182,183,  0,  0,  0,
-  184, 10, 10,185,186,187,188,189,190, 10, 10,191,192,  0,  0,  0,
-  193, 10,194,195,196, 10, 10,197,190, 10, 10,198,199,106,200,103,
-   10, 34,201,202,203,  0,  0,  0,204,205, 95, 10, 10,206,207,  2,
-  208, 21, 22,209,210,211,212,213,214, 10, 10,215,216,217,218,  0,
-   10, 10, 10,219,220,221,222,  0,200, 10, 10,223,224,  2,  0,  0,
-   10, 10,225,226,227,228,  0,  0, 10, 10, 10,229,230,  2,  0,  0,
-   10, 10,231,232,  2, 10,141,  0, 10,233,234,104,235,  0,  0,  0,
-   10, 10,236,237,  0,  0,  0,  0,238,239, 10,240,241,  2,  0,  0,
-    0,  0,242, 10, 10,243,244,  0,245, 10, 10,246,247,248, 10, 10,
-  249,250,  0,  0,  0,  0,  0,  0, 22, 10,225,251,  8, 10, 71, 19,
-   10,252, 74,253,  0,  0,  0,  0,254, 10, 10,255,256,  2,257, 10,
-  258,259,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 10,260,
-  261, 49, 10,262,263,264,  0,  0,265,265,265,265,265,265,265,265,
-  265,265,265,266,267,268,265,265,265,265,265,265,265,265,265,269,
-   10,270,271,  2,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,
-   10, 10, 10,272,  0,  0,  0,  0,  0,  0,  0,  0,273, 10,274,  2,
-   10, 10, 10, 10,275,276,277,277,278,279,  0,  0,  0,  0,280,  0,
-   10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,177,  0,281,
-   10, 10, 10, 10, 10, 10,106, 71, 95,282,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,283, 10, 10, 71,284,285,  0,  0,  0,
-    0, 10,286,  0, 10, 10,287,  2,  0,  0,  0,  0,  0, 10,288,  2,
-    0,  0,  0,  0,  0, 10,289,106, 10, 10, 10, 10,290,  2,  0,  0,
-  130,130,130,130,130,130,130,130,163,163,163,163,163,163,163,163,
-  163,163,163,163,163,163,163,130,
+   96, 10, 97,  0,  0,  0,  0,  0, 10, 98, 99,100, 31, 10,101,102,
+   10, 10,103, 10,104,105,  0,  0, 10,106, 10, 10, 10,107,108,109,
+    2,  2,  0,  0,  0,  0,  0,  0,110, 10, 10,111,112,  2,113,114,
+  115, 10,116, 10, 10, 10,117,118, 10, 10,119,120,121,  0,  0,  0,
+    0,  0,  0,  0,  0,122,123,124,  0,  0,  0,  0,  0,  0,  0,125,
+  126,127,128,  0,  0,  0,129,130,131,  0,  0,  0,  0,  0,  0,132,
+    0,  0,  0,  0,133,  0,  0,  0,  0,  0,  0,  0,  0,  0,134,  0,
+    0,  0,  0, 10, 10, 10,135,136,  0,  0,137,  0,  0,  0,  0,  0,
+  138, 10,139,  0, 10, 10, 10,140,141, 10, 10,142,143,  2,144,145,
+   10, 10,146, 10,147,148,  0,  0,149, 10, 10,150,151,  2,152, 98,
+   10, 10,153,154,155,  2, 10,156, 10, 10, 10,157,158,  0,159,160,
+    0,  0,  0,  0, 10, 10,161,  2,162,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,163,  0,  0,  0,  0,  0,  0,  0,164,
+    0,  0,  0,  0,  0,  0,  0,165,165,166, 34,167,  0,  0,  0,  0,
+  168,169, 10,170, 95,  0,  0,  0,  0,  0,  0,  0, 70, 10,171,  0,
+   10,172,173,  0,  0,  0,  0,  0, 10, 10,174,  2,  9, 10,175, 10,
+  176,  0,  0,  0,  0,  0,  0,  0, 10, 10,177,172,  0,  0,  0,  0,
+    0,  0,  0, 10,178,179,  0, 10,180,  0,  0,181,182,  0,  0,  0,
+  183, 10, 10,184,185,186,187,188,189, 10, 10,190,191,  0,  0,  0,
+  192, 10,193,194,195, 10, 10,196,189, 10, 10,197,198,105,199,102,
+   10, 34,200,201,202,  0,  0,  0,203,204, 95, 10, 10,205,206,  2,
+  207, 21, 22,208,209,210,211,212,213, 10, 10,214,215,216,217,  0,
+   10, 10, 10,218,219,220,221,  0,199, 10, 10,222,223,  2,  0,  0,
+   10, 10,224,225,226,227,  0,  0, 10, 10, 10,228,229,  2,  0,  0,
+   10, 10,230,231,  2, 10,140,  0, 10,232,233,103,234,  0,  0,  0,
+   10, 10,235,236,  0,  0,  0,  0,237,238, 10,239,240,  2,  0,  0,
+    0,  0,241, 10, 10,242,243,  0,244, 10, 10,245,246,247, 10, 10,
+  248,249,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,250,  0,
+   22, 10,224,251,  8, 10, 71, 19, 10,252, 74,253,  0,  0,  0,  0,
+  254, 10, 10,255,256,  2,257, 10,258,259,  2,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 10,260,261, 49, 10,262,263,264,  0,  0,
+  265,265,265,265,265,265,265,265,265,265,265,266,267,268,265,265,
+  265,265,265,265,265,265,265,269, 10,270,271,  2,  0,  0,  0,  0,
+    0,  0,  0,  0,  2,  0,  0,  0, 10, 10, 10,272,  0,  0,  0,  0,
+    0,  0,  0,  0,273, 10,274,  2, 10, 10, 10, 10,275,276,277,277,
+  278,279,  0,  0,  0,  0,280,  0, 10, 10, 10, 10, 10, 10, 10, 10,
+   10, 10, 10, 10, 10,176,  0,281, 10, 10, 10, 10, 10, 10,105, 71,
+   95,282,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,283,
+   10, 10, 71,284,285,  0,  0,  0,  0, 10,286,  0, 10, 10,287,  2,
+    0,  0,  0,  0,  0, 10,288,  2,  0,  0,  0,  0,  0, 10,289,105,
+   10, 10, 10, 10,290,  2,  0,  0,129,129,129,129,129,129,129,129,
+  162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,129,
 };
 
-static inline unsigned
-hb_use_b4 (const uint8_t* a, unsigned i)
+static inline uint8_t hb_use_b4 (const uint8_t* a, unsigned i)
 {
-  return (a[i>>1]>>((i&1u)<<2))&15u;
+  return (a[i>>1]>>((i&1)<<2))&15;
 }
-static inline uint_fast8_t
-hb_use_get_category (unsigned u)
+static inline uint8_t hb_use_get_category (unsigned u)
 {
-  return u<921600u?hb_use_u8[2953+(((hb_use_u8[625+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
+  return u<921600 ? hb_use_u8[2953u+((hb_use_u8[625u+((hb_use_u16[((hb_use_u8[113u+((hb_use_b4(hb_use_u8,((((((((u)>>1))>>3))>>3))>>5)))<<5)+((((((((u)>>1))>>3))>>3))&31)])<<3)+((((((u)>>1))>>3))&7)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : O;
 }
 
 
 #else
 
-static const uint8_t
-hb_use_u8[3657] =
+#include 
+
+static const uint8_t hb_use_u8[3663]=
 {
      16,   50,   51,   51,   51,   52,   51,   83,  118,  131,   57,   58,   59,  195,  211,   62,
      51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
@@ -405,16 +403,16 @@ hb_use_u8[3657] =
       1,    1,    1,    1,    1,    1,    1,    1,    1,   25,   26,   27,   28,    1,    1,    1,
       1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   29,
      30,    1,    1,    1,    1,    1,   31,    1,    1,    1,    1,   32,   33,    1,   34,   35,
-     36,   37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,    1,   48,   49,   50,
-     51,   52,   52,   52,   52,   53,   52,   52,   52,   52,   52,   52,   52,   52,   52,   52,
-     52,   52,   52,   52,   54,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-      1,    1,   55,    1,    1,    1,    1,    1,    1,    1,    1,   56,   57,    1,   58,    1,
-     59,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   60,   61,    1,    1,
-      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   62,    1,    1,
-      1,    1,   63,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-      1,    1,   64,   65,    1,   66,   67,    1,    1,    1,   68,    1,    1,    1,    1,    1,
-      1,   69,   70,   69,   69,   69,   69,   69,   69,   69,   69,   69,   69,   69,   69,   69,
-     69,    0,    1,    2,    2,    0,    3,    4,    0,    0,    0,    0,    0,    0,    0,    0,
+     36,   37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,   48,   49,   50,   51,
+     52,   53,   53,   53,   53,   54,   53,   53,   53,   53,   53,   53,   53,   53,   53,   53,
+     53,   53,   53,   53,   55,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+      1,    1,   56,    1,    1,    1,    1,    1,    1,    1,    1,   57,   58,    1,   59,    1,
+     60,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   61,   62,    1,    1,
+      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   63,    1,    1,
+      1,    1,   64,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+      1,    1,   65,   66,    1,   67,   68,    1,    1,    1,   69,    1,    1,    1,    1,    1,
+      1,   70,   71,   70,   70,   70,   70,   70,   70,   70,   70,   70,   70,   70,   70,   70,
+     70,    0,    1,    2,    2,    0,    3,    4,    0,    0,    0,    0,    0,    0,    0,    0,
       0,    0,    0,    5,    0,    0,    0,    0,    0,    0,    0,    6,    0,    0,    0,    0,
       0,    0,    0,    0,    0,    0,    0,    7,    8,    0,    0,    9,    0,    0,    0,    0,
       0,   10,   11,   12,   13,   14,   15,   16,   17,   18,   19,   20,   21,   22,   23,   24,
@@ -438,120 +436,120 @@ hb_use_u8[3657] =
       0,    0,    0,    0,    0,   56,  179,  180,    0,   56,  181,  182,    0,   56,  183,  184,
     185,  186,  187,  188,    0,    0,    0,    0,    0,   56,  189,    0,    0,    0,    0,    0,
       0,  190,  191,  192,    0,    0,  193,  194,  195,  196,  197,  198,   56,  199,    0,    0,
-      0,  200,  201,  202,  203,  204,  205,    0,    0,  206,  207,  208,  209,  210,   67,    0,
-      0,    0,    0,    0,    0,    0,    0,    0,  211,  212,  213,  214,    0,    0,    0,    0,
-      0,  215,  215,  215,  215,  215,  215,  215,  215,  215,  216,  217,  215,  215,  215,  215,
-    215,  215,  215,  215,  215,  215,  215,  215,  218,  219,  220,    0,    0,    0,    0,    0,
-      0,    0,    0,    0,    0,    0,    0,   67,    0,   56,  221,    0,    0,    0,    0,    0,
-      0,    0,    0,  222,  223,    0,    0,    0,    0,   56,   56,  224,  225,  226,    0,    0,
-    227,   56,   56,   56,   56,   56,   56,   56,   56,   56,   56,   56,   56,   56,   56,  228,
-    229,   56,   56,   56,  230,  231,    0,    0,    0,    0,    0,    0,  232,    0,    0,    0,
-      0,   56,  233,  234,    0,    0,    0,    0,    0,    0,    0,    0,    0,  101,  235,   56,
-    236,    0,    0,    0,    0,    0,    0,  101,  237,    0,    0,    0,    0,    0,    0,  101,
-    238,   56,   56,  239,    0,    0,    0,    0,    0,  240,  240,  240,  240,  240,  240,  240,
-    240,  241,  241,  241,  241,  241,  241,  241,  242,    0,    0,    0,    0,    0,    0,    0,
-      0,    0,    0,    0,    0,    0,    0,    1,    0,    2,    2,    2,    2,    2,    0,    0,
-      0,    0,    0,    0,    0,    0,    3,    4,    0,    5,    0,    0,    0,    0,    0,    6,
-      0,    0,    7,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,    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,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,    2,    2,    2,   10,   11,   11,   11,   11,    0,    0,    0,    9,   12,
-      0,    2,    2,    2,    2,   13,   14,    0,    0,   11,   15,    2,    2,    2,    2,    2,
-      2,    2,    2,    2,    2,    2,   16,   17,   18,   19,   20,   21,   22,   16,   23,   24,
-     25,   12,   26,   27,   20,    2,    2,    2,    2,    2,   20,    0,    2,    2,    2,    2,
-      2,    0,    2,    2,    2,    2,    2,    2,    2,   28,   29,   30,    2,    2,    2,    9,
-     30,    9,   30,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    9,    2,    2,
-      2,    9,    9,    0,    2,    2,    0,   17,   18,   19,   20,   31,   32,   33,   32,   34,
-      0,    0,    0,    0,   35,    0,    0,    2,   30,    2,    0,    0,    0,    0,    0,    9,
-     36,   12,   15,   30,    2,    2,    9,    0,   30,    9,    2,   30,    9,    2,    0,   37,
-     18,   19,   31,    0,   27,   38,   27,   39,    0,   40,    0,    0,    0,   30,    2,    9,
-      9,    0,    0,    0,    2,    2,    2,    2,    2,   41,   42,   43,    0,    0,    0,    0,
-      0,   12,   15,   30,    2,    2,    2,    2,   30,    2,   30,    2,    2,    2,    2,    2,
-      2,    9,    2,   30,    2,    2,    0,   17,   18,   19,   20,   21,   27,   22,   35,   24,
-      0,    0,    0,    0,    0,   30,   41,   41,   44,   12,   29,   30,    2,    2,    2,    9,
-     30,    9,    2,   30,    2,    2,    0,   17,   45,    0,    0,   27,   22,    0,    0,    2,
-     30,   30,    0,    0,    0,    0,    0,    0,    0,    0,   46,   30,    2,    2,    9,    0,
-      2,    9,    2,    2,    0,   30,    9,    9,    2,    0,   30,    9,    0,    2,    9,    0,
-      2,    2,    2,    2,    2,    2,    0,    0,   23,   16,   47,    0,   48,   33,   48,   34,
-      0,    0,    0,    0,   35,    0,    0,    0,    0,   15,   29,   49,    2,    2,    2,    9,
-      2,    9,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    0,   17,
-     22,   16,   23,   47,   22,   38,   22,   39,    0,    0,    0,   27,   31,    2,    9,    0,
-      0,   10,   29,   30,    2,    2,    2,    9,    2,    2,    2,   30,    2,    2,    0,   17,
-     45,    0,    0,   35,   47,    0,    0,    0,    9,   50,   51,    0,    0,    0,    0,    0,
-      0,   11,   29,    2,    2,    2,    2,    9,    2,    2,    2,    2,    2,    2,   52,   53,
-     23,   19,   20,   31,   48,   33,   48,   34,   54,    0,    0,    0,   35,    0,    0,    0,
-     30,   12,   29,   30,    2,    2,    2,    2,    2,    2,    2,    2,    9,    0,    2,    2,
-      2,    2,   30,    2,    2,    2,    2,   30,    0,    2,    2,    2,    9,    0,   55,    0,
-     35,   23,   22,   31,   31,   18,   48,   48,   25,    0,   23,    0,    0,    0,    0,    0,
-      0,    2,    0,    2,    9,    0,    0,    0,    0,    0,    0,    0,    0,   20,    0,    0,
-      0,    2,    2,   56,   56,   57,    0,    0,   18,    2,    2,    2,    2,   30,    2,    2,
-      2,    2,    2,    2,    2,    2,    2,    9,    0,   58,   21,   59,   22,   22,   20,   20,
-     46,   21,   11,   31,   11,    2,    2,   60,   61,   61,   61,   61,   61,   62,   61,   61,
-     61,   61,   61,   61,   61,   61,   61,   61,   61,   61,   61,   61,   61,   61,   61,   63,
-      0,    0,    0,    0,   64,    0,    0,    0,    0,    2,    2,    2,    2,    2,   65,   45,
-     59,   66,   22,   22,   67,   68,   69,   70,   71,    2,    2,    2,    2,    2,    1,    0,
-      5,    2,    2,    2,   23,   20,    2,    2,   72,   71,   73,   74,   65,   73,   29,   29,
-      2,   52,   22,   53,    2,    2,    2,    2,    2,    2,   75,   76,   77,   29,   29,   78,
-     79,    2,    2,    2,    2,    2,   29,   45,    0,    2,   59,   80,    0,    0,    0,    0,
-     30,    2,   59,   47,    0,    0,    0,    0,    0,    2,   59,    0,    0,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,    2,    9,    2,    9,   59,    0,    0,    0,    0,    0,
-      0,    2,    2,   81,   45,   22,   59,   20,   48,   48,   48,   48,   15,   82,   83,   84,
-     85,   86,   87,    0,    0,    0,    0,   88,    0,    9,    0,    0,   30,    0,   89,   81,
-     90,    2,    2,    2,    2,    9,    0,    0,    0,   42,   42,   91,   92,    2,    2,    2,
-      2,    2,    2,    2,    2,   13,    9,    0,    0,   93,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,    2,    2,    2,    2,    2,    9,   22,   80,   45,   22,   94,   61,    0,
-      0,   95,   96,   95,   95,   97,   98,    0,    0,    2,    2,    2,    2,    2,    2,    2,
+      0,    0,    0,    0,  200,    0,    0,    0,    0,  201,  202,  203,  204,  205,  206,    0,
+      0,  207,  208,  209,  210,  211,   67,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    212,  213,  214,  215,    0,    0,    0,    0,    0,  216,  216,  216,  216,  216,  216,  216,
+    216,  216,  217,  218,  216,  216,  216,  216,  216,  216,  216,  216,  216,  216,  216,  216,
+    219,  220,  221,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   67,
+      0,   56,  222,    0,    0,    0,    0,    0,    0,    0,    0,  223,  224,    0,    0,    0,
+      0,   56,   56,  225,  226,  227,    0,    0,  228,   56,   56,   56,   56,   56,   56,   56,
+     56,   56,   56,   56,   56,   56,   56,  229,  230,   56,   56,   56,  231,  232,    0,    0,
+      0,    0,    0,    0,  233,    0,    0,    0,    0,   56,  234,  235,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,  101,  236,   56,  237,    0,    0,    0,    0,    0,    0,  101,
+    238,    0,    0,    0,    0,    0,    0,  101,  239,   56,   56,  240,    0,    0,    0,    0,
+      0,  241,  241,  241,  241,  241,  241,  241,  241,  242,  242,  242,  242,  242,  242,  242,
+    243,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,
+      0,    2,    2,    2,    2,    2,    0,    0,    0,    0,    0,    0,    0,    0,    3,    4,
+      0,    5,    0,    0,    0,    0,    0,    6,    0,    0,    7,    0,    0,    0,    0,    0,
+      0,    0,    0,    0,    1,    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,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   10,   11,
+     11,   11,   11,    0,    0,    0,    9,   12,    0,    2,    2,    2,    2,   13,   14,    0,
+      0,   11,   15,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   16,   17,
+     18,   19,   20,   21,   22,   16,   23,   24,   25,   12,   26,   27,   20,    2,    2,    2,
+      2,    2,   20,    0,    2,    2,    2,    2,    2,    0,    2,    2,    2,    2,    2,    2,
+      2,   28,   29,   30,    2,    2,    2,    9,   30,    9,   30,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    9,    2,    2,    2,    9,    9,    0,    2,    2,    0,   17,
+     18,   19,   20,   31,   32,   33,   32,   34,    0,    0,    0,    0,   35,    0,    0,    2,
+     30,    2,    0,    0,    0,    0,    0,    9,   36,   12,   15,   30,    2,    2,    9,    0,
+     30,    9,    2,   30,    9,    2,    0,   37,   18,   19,   31,    0,   27,   38,   27,   39,
+      0,   40,    0,    0,    0,   30,    2,    9,    9,    0,    0,    0,    2,    2,    2,    2,
+      2,   41,   42,   43,    0,    0,    0,    0,    0,   12,   15,   30,    2,    2,    2,    2,
+     30,    2,   30,    2,    2,    2,    2,    2,    2,    9,    2,   30,    2,    2,    0,   17,
+     18,   19,   20,   21,   27,   22,   35,   24,    0,    0,    0,    0,    0,   30,   41,   41,
+     44,   12,   29,   30,    2,    2,    2,    9,   30,    9,    2,   30,    2,    2,    0,   17,
+     45,    0,    0,   27,   22,    0,    0,    2,   30,   30,    0,    0,    0,    0,    0,    0,
+      0,    0,   46,   30,    2,    2,    9,    0,    2,    9,    2,    2,    0,   30,    9,    9,
+      2,    0,   30,    9,    0,    2,    9,    0,    2,    2,    2,    2,    2,    2,    0,    0,
+     23,   16,   47,    0,   48,   33,   48,   34,    0,    0,    0,    0,   35,    0,    0,    0,
+      0,   15,   29,   49,    2,    2,    2,    9,    2,    9,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    0,   17,   22,   16,   23,   47,   22,   38,   22,   39,
+      0,    0,    0,   27,   31,    2,    9,    0,    0,   10,   29,   30,    2,    2,    2,    9,
+      2,    2,    2,   30,    2,    2,    0,   17,   45,    0,    0,   35,   47,    0,    0,    0,
+      9,   50,   51,    0,    0,    0,    0,    0,    0,   11,   29,    2,    2,    2,    2,    9,
+      2,    2,    2,    2,    2,    2,   52,   53,   23,   19,   20,   31,   48,   33,   48,   34,
+     54,    0,    0,    0,   35,    0,    0,    0,   30,   12,   29,   30,    2,    2,    2,    2,
+      2,    2,    2,    2,    9,    0,    2,    2,    2,    2,   30,    2,    2,    2,    2,   30,
+      0,    2,    2,    2,    9,    0,   55,    0,   35,   23,   22,   31,   31,   18,   48,   48,
+     25,    0,   23,    0,    0,    0,    0,    0,    0,    2,    0,    2,    9,    0,    0,    0,
+      0,    0,    0,    0,    0,   20,    0,    0,    0,    2,    2,   56,   56,   57,    0,    0,
+     18,    2,    2,    2,    2,   30,    2,    2,    2,    2,    2,    2,    2,    2,    2,    9,
+      0,   58,   21,   59,   22,   22,   20,   20,   46,   21,   11,   31,   11,    2,    2,   60,
+     61,   61,   61,   61,   61,   62,   61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+     61,   61,   61,   61,   61,   61,   61,   63,    0,    0,    0,    0,   64,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,   65,   45,   59,   66,   22,   22,   67,   68,   69,   70,
+     71,    2,    2,    2,    2,    2,    1,    0,    5,    2,    2,    2,   23,   20,    2,    2,
+     72,   71,   73,   74,   65,   73,   29,   29,    2,   52,   22,   53,    2,    2,    2,    2,
+      2,    2,   75,   76,   77,   29,   29,   78,   79,    2,    2,    2,    2,    2,   29,   45,
+      0,    2,   59,   80,    0,    0,    0,    0,   30,    2,   59,   47,    0,    0,    0,    0,
+      0,    2,   59,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,    9,
+      2,    9,   59,    0,    0,    0,    0,    0,    0,    2,    2,   81,   45,   22,   59,   20,
+     48,   48,   48,   48,   15,   82,   83,   84,   85,   86,   87,    0,    0,    0,    0,   88,
+      0,    9,    0,    0,   30,    0,   89,   81,   90,    2,    2,    2,    2,    9,    0,    0,
+      0,   42,   42,   91,   92,    2,    2,    2,    2,    2,    2,    2,    2,   13,    9,    0,
+      0,    2,    2,    2,    2,    2,    2,    2,    9,   22,   80,   45,   22,   93,   61,    0,
+      0,   94,   95,   94,   94,   96,   97,    0,    0,    2,    2,    2,    2,    2,    2,    2,
       0,    2,    2,    9,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,    0,
       0,    2,    2,    2,    2,   29,    0,    0,    0,    2,    2,    2,    2,    2,    9,    0,
-      0,    2,    2,    2,   52,   99,   45,    0,    0,    2,    2,  100,  101,  102,  103,   61,
-     63,  104,   16,   45,   22,   59,   21,   80,   48,   48,   76,   11,   11,   11,  105,   46,
-     40,   11,  106,   74,    2,    2,    2,    2,    2,    2,    2,  107,   22,   20,   20,   22,
-     48,   48,   22,  108,    2,    2,    2,    9,    0,    0,    0,    0,    0,    0,  109,  110,
-    110,  110,  110,    0,    0,    0,    0,    0,    0,  106,   74,    2,    2,    2,    2,    2,
-      2,   60,   61,   59,   25,   22,  111,   61,    2,    2,    2,    2,  107,   22,   23,   45,
-     45,  102,  112,    0,    0,    0,    0,    0,    0,    2,    2,   61,   18,   48,   23,  113,
-    102,  102,  102,  114,  115,    0,    0,    0,    0,    2,    2,    2,    2,    2,    0,   30,
-      2,   11,   46,  116,  116,  116,   11,  116,  116,   15,  116,  116,  116,   26,    0,   40,
-      0,    0,    0,  117,   51,   11,    5,    0,    0,    0,    0,    0,    0,    0,  118,    0,
-      0,    0,    0,    0,    0,    0,    6,  119,  120,   42,   42,    5,    0,    0,    0,    0,
-      0,    0,    0,    0,    0,    0,  120,  120,  121,  120,  120,  120,  120,  120,  120,  120,
-    120,    0,    0,  122,    0,    0,    0,    0,    0,    0,    7,  122,    0,    0,    0,    0,
+      0,    2,    2,    2,   52,   98,   45,    0,    0,    2,    2,   99,  100,  101,  102,   61,
+     63,  103,   16,   45,   22,   59,   21,   80,   48,   48,   76,   11,   11,   11,  104,   46,
+     40,   11,  105,   74,    2,    2,    2,    2,    2,    2,    2,  106,   22,   20,   20,   22,
+     48,   48,   22,  107,    2,    2,    2,    9,    0,    0,    0,    0,    0,    0,  108,  109,
+    109,  109,  109,    0,    0,    0,    0,    0,    0,  105,   74,    2,    2,    2,    2,    2,
+      2,   60,   61,   59,   25,   22,  110,   61,    2,    2,    2,    2,  106,   22,   23,   45,
+     45,  101,  111,    0,    0,    0,    0,    0,    0,    2,    2,   61,   18,   48,   23,  112,
+    101,  101,  101,  113,  114,    0,    0,    0,    0,    2,    2,    2,    2,    2,    0,   30,
+      2,   11,   46,  115,  115,  115,   11,  115,  115,   15,  115,  115,  115,   26,    0,   40,
+      0,    0,    0,  116,   51,   11,    5,    0,    0,    0,    0,    0,    0,    0,  117,    0,
+      0,    0,    0,    0,    0,    0,    6,  118,  119,   42,   42,    5,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,  119,  119,  120,  119,  119,  119,  119,  119,  119,  119,
+    119,    0,    0,  121,    0,    0,    0,    0,    0,    0,    7,  121,    0,    0,    0,    0,
       0,   46,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    9,
-      0,    0,    0,    0,  123,  123,    0,    0,    0,    2,    2,    2,    2,    0,    0,    0,
-     30,    0,    0,    0,    0,    0,    0,    0,  124,    0,  123,  123,    0,    0,    0,    0,
-      0,    2,   53,    2,  108,    2,   10,    2,    2,    2,   65,   19,   16,    0,    0,   31,
+      0,    0,    0,    0,  122,  122,    0,    0,    0,    2,    2,    2,    2,    0,    0,    0,
+     30,    0,    0,    0,    0,    0,    0,    0,  123,    0,  122,  122,    0,    0,    0,    0,
+      0,    2,   53,    2,  107,    2,   10,    2,    2,    2,   65,   19,   16,    0,    0,   31,
       0,    2,    2,    0,    0,    0,    0,    0,    0,   29,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,  125,   23,   23,   23,   23,   23,   23,   23,  126,    0,    0,    0,    0,
+      2,    2,    2,  124,   23,   23,   23,   23,   23,   23,   23,  125,    0,    0,    0,    0,
       0,   11,   11,   11,   11,   11,   11,   11,   11,   11,    2,    0,    0,    0,    0,    0,
-     52,    2,    2,    2,   22,   22,  127,  116,    0,    2,    2,    2,  128,   20,   59,   20,
-    113,  102,  129,    0,    0,    0,    0,    0,    0,   11,  130,    2,    2,    2,    2,    2,
-      2,    2,  131,   23,   22,   20,   48,  132,  133,  134,    0,    0,    0,    0,    0,    0,
+     52,    2,    2,    2,   22,   22,  126,  115,    0,    2,    2,    2,  127,   20,   59,   20,
+    112,  101,  128,    0,    0,    0,    0,    0,    0,   11,  129,    2,    2,    2,    2,    2,
+      2,    2,  130,   23,   22,   20,   48,  131,  132,  133,    0,    0,    0,    0,    0,    0,
       0,    2,    2,   52,   30,    2,    2,    2,    2,    2,    2,    2,    2,   10,   22,   59,
-     99,   76,  135,  136,  137,    0,    0,    0,    0,    2,  138,    2,    2,    2,    2,  139,
-      0,   30,    2,   42,    5,    0,   79,   15,    2,   53,   22,  140,   52,   53,    2,    2,
-    105,   10,    9,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,  141,   21,
+     98,   76,  134,  135,  136,    0,    0,    0,    0,    2,  137,    2,    2,    2,    2,  138,
+      0,   30,    2,   42,    5,    0,   79,   15,    2,  139,   20,   53,  127,  139,    2,    2,
+    140,   10,    9,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,  141,   21,
      25,    0,    0,  142,  143,    0,    0,    0,    0,    2,   65,   45,   23,   80,   47,  144,
       0,   81,   81,   81,   81,   81,   81,   81,   81,    0,    0,    0,    0,    0,    0,    0,
-      6,  120,  120,  120,  120,  121,    0,    0,    0,    2,    2,    2,    2,    2,    9,    2,
+      6,  119,  119,  119,  119,  120,    0,    0,    0,    2,    2,    2,    2,    2,    9,    2,
       2,    2,    9,    2,   30,    2,    2,    2,    2,    2,   30,    2,    2,    2,   30,    9,
-      0,  128,   20,   27,   31,    0,    0,  145,  146,    2,    2,   30,    2,   30,    2,    2,
+      0,  127,   20,   27,   31,    0,    0,  145,  146,    2,    2,   30,    2,   30,    2,    2,
       2,    2,    2,    2,    0,   14,   37,    0,  147,    2,    2,   13,   37,    0,   30,    2,
       2,    2,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   30,    2,    2,
       9,    2,    2,   11,   41,    0,    0,    0,    0,    2,    2,    2,    0,   27,   22,   22,
      30,    2,    2,    2,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,   27,   38,
-      0,    2,    2,    2,  116,  116,  116,  116,  116,  148,    2,    9,    0,    0,    0,    0,
+      0,    2,    2,    2,  115,  115,  115,  115,  115,  148,    2,    9,    0,    0,    0,    0,
       0,    2,   14,   14,    0,    0,    0,    0,    0,    9,    2,    2,    9,    2,    2,    2,
       2,   30,    2,    9,    0,   30,    2,    0,    0,  149,  150,  151,    2,    2,    2,    2,
-      2,    2,    2,    2,    2,   22,   22,   20,   20,   20,   22,   22,  134,    0,    0,    0,
+      2,    2,    2,    2,    2,   22,   22,   20,   20,   20,   22,   22,  133,    0,    0,    0,
       0,    0,  152,  152,  152,  152,  152,  152,  152,  152,  152,  152,    2,    2,    2,    2,
       2,   53,   52,   53,    0,    0,    0,    0,  153,   11,   74,    2,    2,    2,    2,    2,
       2,   18,   19,   21,   16,   24,   37,    0,    0,    0,   31,    0,    0,    0,    0,    0,
-      0,   11,   49,    2,    2,    2,    2,    2,    2,    2,    2,    2,  128,   20,   22,  154,
+      0,   11,   49,    2,    2,    2,    2,    2,    2,    2,    2,    2,  127,   20,   22,  154,
      22,   21,  155,  156,    2,    2,    2,    2,    2,    0,    0,   65,  157,    0,    0,    0,
       0,    2,   13,    0,    0,    0,    0,    0,    0,    2,   65,   25,   20,   20,   20,   22,
-     22,  108,  158,    0,    0,   56,  159,   31,  160,   30,    2,    2,    2,    2,    2,    2,
+     22,  107,  158,    0,    0,   56,  159,   31,  160,   30,    2,    2,    2,    2,    2,    2,
       2,    2,    2,    2,    2,    2,    2,   23,   19,   22,   22,  161,   44,    0,    0,    0,
-     49,  128,    0,    0,    0,    0,    0,    0,    0,    2,    2,    2,    9,    9,    2,    2,
+     49,  127,    0,    0,    0,    0,    0,    0,    0,    2,    2,    2,    9,    9,    2,    2,
      30,    2,    2,    2,    2,    2,    2,    2,   30,    2,    2,    2,    2,    2,    2,    2,
      10,   18,   19,   21,   22,  162,   31,    0,    0,   11,   11,   30,    2,    2,    2,    9,
      30,    9,    2,   30,    2,    2,   58,   17,   23,   16,   23,   47,   32,   33,   32,   34,
@@ -559,70 +557,69 @@ hb_use_u8[3657] =
       0,   11,   11,   46,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,   30,    0,
       9,    2,    2,    2,   30,   45,   59,   20,   20,   31,   33,   32,   32,   25,  163,   29,
     164,  165,   37,    0,    0,    0,    0,    0,    0,   12,   26,    0,    0,    0,    0,    0,
-      0,    2,    2,   65,   25,   20,   20,   20,   22,   23,  126,   15,   17,    0,    0,    0,
+      0,    2,    2,   65,   25,   20,   20,   20,   22,   23,  125,   15,   17,    0,    0,    0,
       0,    2,    2,    2,    2,    2,    0,    0,  166,  167,    0,    0,    0,    0,    0,    0,
-      0,   18,   19,   20,   20,   66,   99,   25,  160,   11,  168,    9,    0,    0,    0,    0,
+      0,   18,   19,   20,   20,   66,   98,   25,  160,   11,  168,    9,    0,    0,    0,    0,
       0,    2,    2,    2,    2,    2,    2,    2,   65,   25,   20,   20,    0,   48,   48,   11,
     169,   37,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    2,    2,   20,
       0,   23,   19,   20,   20,   21,   16,   82,  169,   38,    0,    0,    0,    0,    0,    0,
       0,    2,    2,    2,    2,    2,   10,  170,   25,   20,   22,   22,  168,    9,    0,    0,
-      0,    2,    2,    2,    2,    2,    9,   43,  136,   23,   22,   20,   76,   21,   22,    0,
+      0,    2,    2,    2,    2,    2,    9,   43,  135,   23,   22,   20,   76,   21,   22,    0,
       0,    2,    2,    2,    9,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,   18,
-     19,   20,   21,   22,  105,  169,   37,    0,    0,    2,    2,    2,    9,   30,    0,    2,
+     19,   20,   21,   22,  104,  169,   37,    0,    0,    2,    2,    2,    9,   30,    0,    2,
       2,    2,    2,   30,    9,    2,    2,    2,    2,   23,   23,   18,   32,   33,   12,  171,
     165,  172,  173,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    0,    2,    2,
-      2,   65,   25,   20,   20,    0,   22,   23,   29,  108,    0,   33,    0,    0,    0,    0,
-      0,   52,   20,   22,   22,   22,  140,    2,    2,    2,  174,  175,   11,   15,  176,   61,
-    177,    0,    0,    1,  147,    0,    0,    0,    0,   52,   20,   22,   16,   19,   20,    2,
-      2,    2,    2,  158,  158,  158,  178,  178,  178,  178,  178,  178,   15,  179,    0,   30,
-      0,   22,   20,   20,   31,   22,   22,   11,  169,    0,   61,   61,   61,   61,   61,   61,
-     61,   66,   21,   82,   46,    0,    0,    0,    0,    2,    2,    2,    9,    2,   30,    2,
-      2,   52,   22,   22,   31,    0,   38,   22,   27,   11,  159,  180,  181,    0,    0,    0,
-      0,    2,    2,    2,   30,    9,    2,    2,    2,    2,    2,    2,    2,    2,   23,   23,
-     47,   22,   35,   82,   68,    0,    0,    0,    0,    2,  182,   66,   47,    0,    0,    0,
-      0,   11,  183,    2,    2,    2,    2,    2,    2,    2,    2,   23,   22,   20,   31,    0,
-     48,   16,  143,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,  156,    0,
-      0,  184,  184,  184,  184,  184,  184,  184,  184,  185,  185,  185,  186,  187,  185,  184,
-    184,  188,  184,  184,  189,  190,  190,  190,  190,  190,  190,  190,    0,    0,    0,    0,
-      0,  184,  184,  184,  184,  184,  191,    0,    0,    2,    2,    2,    2,    2,    2,    2,
-     22,   22,   22,   22,   22,   22,  192,  193,  194,   11,   11,   11,   46,    0,    0,    0,
-      0,   29,   74,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   65,   47,
-      0,    2,    2,    2,    2,    2,    9,    0,   58,  195,   20,   20,   20,   20,   20,   20,
-     20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,    0,    0,    0,
-     40,  116,   26,    0,    0,    0,    0,    0,    0,    0,    0,    9,    0,    0,    0,    0,
-      0,    0,    0,    0,    0,    0,    0,    0,   30,    2,    2,    2,    2,    2,    0,   58,
-     37,    0,    6,  120,  120,  120,  121,    0,    0,   11,   11,   11,   49,    2,    2,    2,
-      0,    2,    2,    2,    2,    2,    0,    0,    2,    2,    2,    2,    2,    2,    2,    2,
-     46,    2,    2,    2,    2,    2,    2,   11,   11,    2,    2,    2,    2,    2,    2,   22,
-     22,    2,    2,    2,    2,    2,    2,    2,   20,    2,    2,   44,   44,   44,   92,    0,
-      0,    O,    O,    O,   GB,    B,    B,    O,   SB,    O,   SE,   GB,    O,    O,   WJ,FMPst,
-  FMPst,    O,  CGJ,    B,    O,    B,VMAbv,VMAbv,VMAbv,    O,VMAbv,    B,CMBlw,CMBlw,CMBlw,VMAbv,
-  VMPst, VAbv, VPst,CMBlw,    B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst,
-   VPst, VPst,    H, VPre, VPst,VMBlw,    O,    O, VAbv,   GB,VMAbv,VMPst,VMPst,    O,    B, VBlw,
-      O,    O, VPre, VPre,    O, VPre,    H,    O, VPst,FMAbv,    O,CMBlw,    O, VAbv,    O, VAbv,
-      H,    O,VMBlw,VMAbv,CMAbv,   GB,   GB,    O, MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv,    O, VPst,
-      O, VPre, VPre,VMAbv,    B,    O,   CS,   CS,VMPst,    B, VAbv, VAbv,    B,    R,    O,  HVM,
-      O,    O,FMBlw,    O,CMAbv,    O,CMBlw, VAbv, VBlw,    B,  SUB,  SUB,  SUB,    O,  SUB,  SUB,
-      O,FMBlw,    O,    B, VPst, VBlw, VPre,VMAbv,VMBlw,VMPst,   IS, VAbv, MPst, MPre, MBlw, MBlw,
-      B, MBlw, MBlw, VPst,VMPst,VMPst,    B, MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw,    B,
-  VMPst, VBlw, VPst,  CGJ,  CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv,   IS,
-  FMAbv,    B,FMAbv,    B,  CGJ,   WJ,  CGJ,   GB,CMAbv,CMAbv,    B,   GB,    B, VAbv,  SUB, FPst,
-   FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre,    B, MPre, MBlw,  SUB, FAbv, FAbv, MAbv,
-    SUB,   Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst,    H,    B,    O,SMAbv,SMAbv,SMAbv, VPst,
-     IS,   RK,   RK, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv,   CS,    O,FMAbv, ZWNJ,
-    CGJ,   WJ,   WJ,   WJ,    O,FMPst,    O,   SB,   SE,    O,    H, MPst, VPst,    H,VMAbv, VAbv,
-  VMBlw,    B, VBlw, FPst, VPst, FAbv,VMPst,    B,CMAbv, VAbv, MBlw, MPst, MBlw,    H,    O, VBlw,
-   MPst, MPre, MAbv, MBlw,    O,    B, FAbv, FAbv, FPst, VBlw,    B,    B, VPre,    O,VMPst,   IS,
-      O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv,    O,   IS,VMBlw,    B,VMPst,VMAbv,VMPst,   CS,   CS,
-      B,    N,    N,    O,   HN, VPre, VBlw, VAbv,   IS,CMAbv,    O, VPst,    B,    R,    R,CMBlw,
-   VAbv, VPre,VMAbv,VMAbv,    H, VAbv,CMBlw,VMPst,    O,VMAbv,CMBlw,   IS,    R,FMAbv,    B,   CS,
-     CS,    H,CMBlw,VMPst,    H,VMPst, VAbv,VMAbv, VPst, MPst,    R, MPst,CMBlw,    B,FMBlw, VBlw,
-  VMAbv,   CS,  SUB,  SUB,   GB, FBlw, FBlw,CMAbv,   IS, VBlw,   IS,    R, MBlw,   GB, VAbv,    R,
-  VMPst,    G,    G,    J,    J,    J,   SB,   SE,    J,   HR,    G,    G,   HM,   HM,   HM,    G,
-      O, MPre, MPre, MPst,VMAbv, MBlw, VBlw,    O, VBlw,
+      2,   65,   25,   20,   20,    0,   22,   23,   29,  107,    0,   33,    0,    0,    0,    0,
+      0,   52,   20,   22,   22,   22,  139,    2,    2,    2,  174,  140,   11,   15,  175,   61,
+    176,    0,    0,    1,  147,    0,    0,    0,    0,   52,   20,   22,   16,   19,   20,    2,
+      2,    2,    2,  158,  158,  158,  177,  177,  177,  177,  177,  177,   15,  178,    0,   30,
+      0,   16,   20,   16,   16,    0,    0,    0,    0,   22,   20,   20,   31,   22,   22,   11,
+    169,    0,   61,   61,   61,   61,   61,   61,   61,   66,   21,   82,   46,    0,    0,    0,
+      0,    2,    2,    2,    9,    2,   30,    2,    2,   52,   22,   22,   31,    0,   38,   22,
+     27,   11,  159,  179,  180,    0,    0,    0,    0,    2,    2,    2,   30,    9,    2,    2,
+      2,    2,    2,    2,    2,    2,   23,   23,   47,   22,   35,   82,   68,    0,    0,    0,
+      0,    2,  181,   66,   47,    0,    0,    0,    0,   11,  182,    2,    2,    2,    2,    2,
+      2,    2,    2,   23,   22,   20,   31,    0,   48,   16,  143,    0,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,  156,    0,    0,  183,  183,  183,  183,  183,  183,  183,
+    183,  184,  184,  184,  185,  186,  184,  183,  183,  187,  183,  183,  188,  189,  189,  189,
+    189,  189,  189,  189,    0,    0,    0,    0,    0,  183,  183,  183,  183,  183,  190,    0,
+      0,    2,    2,    2,    2,    2,    2,    2,   22,   22,   22,   22,   22,   22,  191,  192,
+    193,   11,   11,   11,   46,    0,    0,    0,    0,   29,   74,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,   65,   47,    0,    2,    2,    2,    2,    2,    9,    0,
+     58,  194,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,
+     20,   20,   20,   20,   20,    0,    0,    0,   40,  115,   26,    0,    0,    0,    0,    0,
+      0,    0,    0,    9,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+     30,    2,    2,    2,    2,    2,    0,   58,   37,    0,    6,  119,  119,  119,  120,    0,
+      0,   11,   11,   11,   49,    2,    2,    2,    0,    2,    2,    2,    2,    2,    0,    0,
+      2,    2,    2,    2,    2,    2,    2,    2,   46,    2,    2,    2,    2,    2,    2,   11,
+     11,    2,    2,    2,    2,    2,    2,   22,   22,    2,    2,    2,    2,    2,    2,    2,
+     20,    2,    2,   44,   44,   44,   92,    0,    0,    O,    O,    O,   GB,    B,    B,    O,
+     SB,    O,   SE,   GB,    O,    O,   WJ,FMPst,FMPst,    O,  CGJ,    B,    O,    B,VMAbv,VMAbv,
+  VMAbv,    O,VMAbv,    B,CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw,    B, VPst, VPre, VPst,
+   VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VPst,    H, VPre, VPst,VMBlw,    O,    O,
+   VAbv,   GB,VMAbv,VMPst,VMPst,    O,    B, VBlw,    O,    O, VPre, VPre,    O, VPre,    H,    O,
+   VPst,FMAbv,    O,CMBlw,    O, VAbv,    O, VAbv,    H,    O,VMBlw,VMAbv,CMAbv,   GB,   GB,    O,
+   MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv,    O, VPst,    O, VPre, VPre,VMAbv,    B,    O,   CS,   CS,
+  VMPst,    B, VAbv, VAbv,    B,    R,    O,  HVM,    O,    O,FMBlw,    O,CMAbv,    O,CMBlw, VAbv,
+   VBlw,    B,  SUB,  SUB,  SUB,    O,  SUB,  SUB,    O,FMBlw,    O,    B, VPst, VBlw, VPre,VMAbv,
+  VMBlw,VMPst,   IS, VAbv, MPst, MPre, MBlw, MBlw,    B, MBlw, MBlw, VPst,VMPst,VMPst,    B, MBlw,
+   VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw,    B,VMPst, VBlw, VPst,  CGJ,  CGJ, VPst,VMAbv,VMAbv,
+  FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv,   IS,FMAbv,    B,FMAbv,    B,  CGJ,   WJ,  CGJ,   GB,
+  CMAbv,CMAbv,    B, VAbv,  SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre,    B,
+   MPre, MBlw,  SUB, FAbv, FAbv, MAbv,  SUB,   Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst,    H,
+      B,    O,SMAbv,SMAbv,SMAbv, VPst,   IS,   RK,   RK, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,
+  VMBlw,VMAbv,   CS,    O,FMAbv, ZWNJ,  CGJ,   WJ,   WJ,   WJ,    O,FMPst,    O,   SB,   SE,    O,
+      H, MPst, VPst,    H,VMAbv, VAbv,VMBlw,    B, VBlw, FPst, VPst, FAbv,VMPst,    B,CMAbv, VAbv,
+   MBlw, MPst, MBlw,    H,    O, VBlw, MPst, MPre, MAbv, MBlw,    O,    B, FAbv, FAbv, FPst, VBlw,
+      B, VBlw,VMAbv,    B, VPre,    O,VMPst,   IS,    O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv,    O,
+     IS,VMBlw,    B,VMPst,VMAbv,VMPst,   CS,   CS,    B,    N,    N,    O,   HN, VPre, VBlw, VAbv,
+     IS,CMAbv,    O, VPst,    B,    R,    R,CMBlw, VAbv, VPre,VMAbv,VMAbv,    H, VAbv,CMBlw,VMPst,
+      O,VMAbv,CMBlw,   IS,    R,FMAbv,    B,   CS,   CS,    H,CMBlw,VMPst,    H,VMPst, VAbv,VMAbv,
+   VPst, MPst,    R, MPst,CMBlw,    B,FMBlw,   CS,  SUB,  SUB,   GB, FBlw, FBlw,CMAbv,   IS, VBlw,
+     IS,    R, MBlw,   GB, VAbv,    R,VMPst,    G,    G,    J,    J,    J,   SB,   SE,    J,   HR,
+      G,    G,   HM,   HM,   HM,    G,    O, MPre, MPre, MPst,VMAbv, MBlw, VBlw,    O, VBlw,
 };
-static const uint16_t
-hb_use_u16[486] =
+static const uint16_t hb_use_u16[488]=
 {
     0,  0,  1,  2,  0,  3,  4,  5,  0,  6,  7,  0,  8,  0,  9, 10,
    11, 12, 10, 13, 14, 10, 10, 15, 16, 17, 18, 19, 20, 21, 22, 23,
@@ -633,43 +630,43 @@ hb_use_u16[486] =
    31, 66, 67, 68, 10, 69, 70, 10, 71, 72, 73, 74, 75, 76, 77,  0,
    10, 10, 78, 79, 80, 81, 82, 83, 84, 85, 10, 86, 10, 87, 10, 88,
    89, 90, 10, 91, 92, 93,  2,  0, 94,  0, 10, 95, 96, 10, 97,  0,
-   98, 99,100,101, 31, 10,102,103,104, 10,105,106, 10,107, 10,108,
-  109,110,  2,  2,111, 10, 10,112,113,  2,114,115,116, 10,117, 10,
-  118,119,120,121,122,  0,  0,123,124,125,  0,126,127,128,129,  0,
-  130,131,132,  0,  0,133,134,  0,135,  0,  0, 10,136,137,138,  0,
-  139, 10,140,  0, 10,141,142, 10, 10,143,144,  2,145,146,147, 10,
-  148,149,150, 10, 10,151,152,  2,153, 99,154,155,156,  2, 10,157,
-   10,158,159,  0,160,161,162,  2,163,  0,  0,164,  0,165,  0,166,
-  166,167, 34,168,169,170, 10,171, 95,  0,172,  0, 10,173,174,  0,
-  175,  2,176, 10,177,  0,178,173,179,180,181,  0,  0,182,183,  0,
-  184, 10, 10,185,186,187,188,189,190, 10, 10,191,192,  0,193, 10,
-  194,195,196, 10, 10,197, 10,198,199,106,200,103, 10, 34,201,202,
-  203,  0,204,205, 95, 10, 10,206,207,  2,208, 21, 22,209,210,211,
-  212,213,214, 10, 10,215,216,217,218,  0, 10,219,220,221,222,  0,
-  200, 10, 10,223,224,  2,225,226,227,228, 10,229,230,  2,231,232,
-    2, 10,141,  0, 10,233,234,104,235,  0,236,237,238,239, 10,240,
-  241,  2,242, 10, 10,243,244,  0,245, 10, 10,246,247,248,249,250,
-   22, 10,225,251,  8, 10, 71, 19, 10,252, 74,253,254, 10, 10,255,
-  256,  2,257, 10,258,259, 10,260,261, 49, 10,262,263,264,265,265,
-  265,266,267,268,265,269, 10,270,271,  2, 10,272,273, 10,274,  2,
-  275,276,277,277,278,279,280,  0, 10,177,  0,281,106, 71, 95,282,
-    0,283, 71,284,285,  0,286,  0,287,  2,288,  2,289,106,290,  2,
-  130,130,163,163,163,130,
+   10, 98, 99,100, 31, 10,101,102,103, 10,104,105, 10,106, 10,107,
+  108,109,  2,  2,110, 10, 10,111,112,  2,113,114,115, 10,116, 10,
+  117,118,119,120,121,  0,  0,122,123,124,  0,125,126,127,128,  0,
+  129,130,131,  0,  0,132,133,  0,134,  0,  0, 10,135,136,137,  0,
+  138, 10,139,  0, 10,140,141, 10, 10,142,143,  2,144,145,146, 10,
+  147,148,149, 10, 10,150,151,  2,152, 98,153,154,155,  2, 10,156,
+   10,157,158,  0,159,160,161,  2,162,  0,  0,163,  0,164,  0,165,
+  165,166, 34,167,168,169, 10,170, 95,  0,171,  0, 10,172,173,  0,
+  174,  2,175, 10,176,  0,177,172,178,179,180,  0,  0,181,182,  0,
+  183, 10, 10,184,185,186,187,188,189, 10, 10,190,191,  0,192, 10,
+  193,194,195, 10, 10,196, 10,197,198,105,199,102, 10, 34,200,201,
+  202,  0,203,204, 95, 10, 10,205,206,  2,207, 21, 22,208,209,210,
+  211,212,213, 10, 10,214,215,216,217,  0, 10,218,219,220,221,  0,
+  199, 10, 10,222,223,  2,224,225,226,227, 10,228,229,  2,230,231,
+    2, 10,140,  0, 10,232,233,103,234,  0,235,236,237,238, 10,239,
+  240,  2,241, 10, 10,242,243,  0,244, 10, 10,245,246,247,248,249,
+  250,  0, 22, 10,224,251,  8, 10, 71, 19, 10,252, 74,253,254, 10,
+   10,255,256,  2,257, 10,258,259, 10,260,261, 49, 10,262,263,264,
+  265,265,265,266,267,268,265,269, 10,270,271,  2, 10,272,273, 10,
+  274,  2,275,276,277,277,278,279,280,  0, 10,176,  0,281,105, 71,
+   95,282,  0,283, 71,284,285,  0,286,  0,287,  2,288,  2,289,105,
+  290,  2,129,129,162,162,162,129,
 };
 
-static inline unsigned
-hb_use_b4 (const uint8_t* a, unsigned i)
+static inline uint8_t hb_use_b4 (const uint8_t* a, unsigned i)
 {
-  return (a[i>>1]>>((i&1u)<<2))&15u;
+  return (a[i>>1]>>((i&1)<<2))&15;
 }
-static inline uint_fast8_t
-hb_use_get_category (unsigned u)
+static inline uint8_t hb_use_get_category (unsigned u)
 {
-  return u<921600u?hb_use_u8[3265+(((hb_use_u8[937+(((hb_use_u16[((hb_use_u8[369+(((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>1>>3>>4))<<4)+((u>>1>>3>>1>>3)&15u))])<<3)+((u>>1>>3>>1)&7u))])<<1)+((u>>1>>3)&1u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
+  return u<921600 ? hb_use_u8[3273u+((hb_use_u8[945u+((hb_use_u16[((hb_use_u8[369u+((hb_use_u8[113u+((hb_use_b4(hb_use_u8,((((((((((u)>>1))>>3))>>1))>>3))>>4)))<<4)+((((((((((u)>>1))>>3))>>1))>>3))&15)])<<3)+((((((((u)>>1))>>3))>>1))&7)])<<1)+((((((u)>>1))>>3))&1)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : O;
 }
 
+
 #endif
 
+
 #undef B
 #undef CGJ
 #undef CS
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-vowel-constraints.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-vowel-constraints.cc
index 4a112e1c289..bb586a68ce5 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-vowel-constraints.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-vowel-constraints.cc
@@ -10,8 +10,8 @@
  * # Date: 2015-03-12, 21:17:00 GMT [AG]
  * # Date: 2019-11-08, 23:22:00 GMT [AG]
  *
- * # Scripts-16.0.0.txt
- * # Date: 2024-04-30, 21:48:40 GMT
+ * # Scripts-17.0.0.txt
+ * # Date: 2025-07-24, 13:28:55 GMT
  */
 
 #include "hb.hh"
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper.hh
index 48cd5296ffd..9993507e360 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper.hh
@@ -396,6 +396,12 @@ hb_ot_shaper_categorize (hb_script_t script,
     case HB_SCRIPT_TODHRI:
     case HB_SCRIPT_TULU_TIGALARI:
 
+    /* Unicode-17.0 additions */
+    case HB_SCRIPT_BERIA_ERFE:
+    case HB_SCRIPT_SIDETIC:
+    case HB_SCRIPT_TAI_YO:
+    case HB_SCRIPT_TOLONG_SIKI:
+
       /* 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-stat-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh
index 10165f57b75..28bc23d8f01 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
@@ -352,7 +352,7 @@ struct AxisValue
 {
   float get_value (unsigned int axis_index) const
   {
-    switch (u.format)
+    switch (u.format.v)
     {
     case 1: hb_barrier (); return u.format1.get_value ();
     case 2: hb_barrier (); return u.format2.get_value ();
@@ -364,7 +364,7 @@ struct AxisValue
 
   unsigned int get_axis_index () const
   {
-    switch (u.format)
+    switch (u.format.v)
     {
     case 1: hb_barrier (); return u.format1.get_axis_index ();
     case 2: hb_barrier (); return u.format2.get_axis_index ();
@@ -376,7 +376,7 @@ struct AxisValue
 
   hb_ot_name_id_t get_value_name_id () const
   {
-    switch (u.format)
+    switch (u.format.v)
     {
     case 1: hb_barrier (); return u.format1.get_value_name_id ();
     case 2: hb_barrier (); return u.format2.get_value_name_id ();
@@ -389,9 +389,9 @@ struct AxisValue
   template 
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
-    TRACE_DISPATCH (this, u.format);
-    switch (u.format) {
+    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format.v);
+    switch (u.format.v) {
     case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...));
     case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...));
     case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...));
@@ -403,7 +403,7 @@ struct AxisValue
   bool keep_axis_value (const hb_array_t axis_records,
                         hb_hashmap_t *user_axes_location) const
   {
-    switch (u.format)
+    switch (u.format.v)
     {
     case 1: hb_barrier (); return u.format1.keep_axis_value (axis_records, user_axes_location);
     case 2: hb_barrier (); return u.format2.keep_axis_value (axis_records, user_axes_location);
@@ -420,7 +420,7 @@ struct AxisValue
       return_trace (false);
     hb_barrier ();
 
-    switch (u.format)
+    switch (u.format.v)
     {
     case 1: hb_barrier (); return_trace (u.format1.sanitize (c));
     case 2: hb_barrier (); return_trace (u.format2.sanitize (c));
@@ -433,14 +433,14 @@ struct AxisValue
   protected:
   union
   {
-  HBUINT16              format;
+  struct { HBUINT16 v; }        format;
   AxisValueFormat1      format1;
   AxisValueFormat2      format2;
   AxisValueFormat3      format3;
   AxisValueFormat4      format4;
   } u;
   public:
-  DEFINE_SIZE_UNION (2, format);
+  DEFINE_SIZE_UNION (2, format.v);
 };
 
 struct AxisValueOffsetArray: UnsizedArrayOf>
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 50ddf5f6967..4933e661371 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,8 +6,8 @@
  *
  * on files with these headers:
  *
- * 
- * File-Date: 2025-01-21
+ * 
+ * File-Date: 2025-08-25
  */
 
 #ifndef HB_OT_TAG_TABLE_HH
@@ -704,7 +704,7 @@ static const LangTag ot_languages3[] = {
 /*{HB_TAG('g','u','z',' '),     HB_TAG('G','U','Z',' ')},*/     /* Gusii */
   {HB_TAG('g','w','i',' '),     HB_TAG('A','T','H',' ')},       /* Gwichʼin -> Athapaskan */
   {HB_TAG('g','y','n',' '),     HB_TAG('C','P','P',' ')},       /* Guyanese Creole English -> Creoles */
-  {HB_TAG('h','a','a',' '),     HB_TAG('A','T','H',' ')},       /* Han -> Athapaskan */
+  {HB_TAG('h','a','a',' '),     HB_TAG('A','T','H',' ')},       /* Hän -> Athapaskan */
   {HB_TAG('h','a','e',' '),     HB_TAG('O','R','O',' ')},       /* Eastern Oromo -> Oromo */
   {HB_TAG('h','a','i',' '),     HB_TAG('H','A','I','0')},       /* Haida [macrolanguage] */
   {HB_TAG('h','a','k',' '),     HB_TAG('Z','H','S',' ')},       /* Hakka Chinese -> Chinese, Simplified */
@@ -921,7 +921,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('k','v','t',' '),     HB_TAG('K','R','N',' ')},       /* Lahta Karen -> Karen */
   {HB_TAG('k','v','u',' '),     HB_TAG('K','R','N',' ')},       /* Yinbaw Karen -> Karen */
   {HB_TAG('k','v','y',' '),     HB_TAG('K','R','N',' ')},       /* Yintale Karen -> Karen */
-/*{HB_TAG('k','w','k',' '),     HB_TAG('K','W','K',' ')},*/     /* Kwakiutl -> Kwakʼwala */
+/*{HB_TAG('k','w','k',' '),     HB_TAG('K','W','K',' ')},*/     /* Kwakʼwala */
   {HB_TAG('k','w','w',' '),     HB_TAG('C','P','P',' ')},       /* Kwinti -> Creoles */
   {HB_TAG('k','w','y',' '),     HB_TAG('K','O','N','0')},       /* San Salvador Kongo -> Kongo */
   {HB_TAG('k','x','c',' '),     HB_TAG('K','M','S',' ')},       /* Konso -> Komso */
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 e26687c34ed..8a9307d6933 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
@@ -143,10 +143,13 @@ struct AxisValueMap
 
 struct SegmentMaps : Array16Of
 {
-  int map (int value, unsigned int from_offset = 0, unsigned int to_offset = 1) const
+  float map_float (float value, unsigned int from_offset = 0, unsigned int to_offset = 1) const
   {
-#define fromCoord coords[from_offset].to_int ()
-#define toCoord coords[to_offset].to_int ()
+#define fromCoord coords[from_offset].to_float ()
+#define toCoord coords[to_offset].to_float ()
+
+    const auto *map = arrayZ;
+
     /* 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. */
@@ -155,47 +158,98 @@ struct SegmentMaps : Array16Of
       if (!len)
         return value;
       else /* len == 1*/
-        return value - arrayZ[0].fromCoord + arrayZ[0].toCoord;
+        return value - map[0].fromCoord + map[0].toCoord;
     }
 
-    if (value <= arrayZ[0].fromCoord)
-      return value - arrayZ[0].fromCoord + arrayZ[0].toCoord;
+    // At least two mappings now.
+
+    /* CoreText is wild...
+     * PingFangUI avar needs all this special-casing...
+     * So we implement an extended version of the spec here,
+     * which is more robust and more likely to be compatible with
+     * the wild. */
+
+    unsigned start = 0;
+    unsigned end = len;
+    if (map[start].fromCoord == -1 && map[start].toCoord == -1 && map[start+1].fromCoord == -1)
+      start++;
+    if (map[end-1].fromCoord == +1 && map[end-1].toCoord == +1 && map[end-2].fromCoord == +1)
+      end--;
+
+    /* Look for exact match first, and do lots of special-casing. */
+    unsigned i;
+    for (i = start; i < end; i++)
+      if (value == map[i].fromCoord)
+        break;
+    if (i < end)
+    {
+      // There's at least one exact match. See if there are more.
+      unsigned j = i;
+      for (; j + 1 < end; j++)
+        if (value != map[j + 1].fromCoord)
+          break;
+
+      // [i,j] inclusive are all exact matches:
+
+      // If there's only one, return it. This is the only spec-compliant case.
+      if (i == j)
+        return map[i].toCoord;
+      // If there's exactly three, return the middle one.
+      if (i + 2 == j)
+        return map[i + 1].toCoord;
+
+      // Ignore the middle ones. Return the one mapping closer to 0.
+      if (value < 0) return map[j].toCoord;
+      if (value > 0) return map[i].toCoord;
+
+      // Mapping 0? CoreText seems confused. It seems to prefer 0 here...
+      // So we'll just return the smallest one. lol
+      return fabsf (map[i].toCoord) < fabsf (map[j].toCoord) ? map[i].toCoord : map[j].toCoord;
+
+      // Mapping 0? Return one not mapping to 0.
+      if (map[i].toCoord == 0)
+        return map[j].toCoord;
+      else
+        return map[i].toCoord;
+    }
 
-    unsigned int i;
-    unsigned int count = len - 1;
-    for (i = 1; i < count && value > arrayZ[i].fromCoord; i++)
-      ;
+    /* There's at least two and we're not an exact match. Prepare to lerp. */
 
-    if (value >= arrayZ[i].fromCoord)
-      return value - arrayZ[i].fromCoord + arrayZ[i].toCoord;
+    // Find the segment we're in.
+    for (i = start; i < end; i++)
+      if (value < map[i].fromCoord)
+        break;
 
-    if (unlikely (arrayZ[i-1].fromCoord == arrayZ[i].fromCoord))
-      return arrayZ[i-1].toCoord;
+    if (i == 0)
+    {
+      // Value before all segments; Shift.
+      return value - map[0].fromCoord + map[0].toCoord;
+    }
+    if (i == end)
+    {
+      // Value after all segments; Shift.
+      return value - map[end - 1].fromCoord + map[end - 1].toCoord;
+    }
+
+    // Actually interpolate.
+    auto &before = map[i-1];
+    auto &after = map[i];
+    float denom = after.fromCoord - before.fromCoord; // Can't be zero by now.
+    return before.toCoord + ((after.toCoord - before.toCoord) * (value - before.fromCoord)) / denom;
 
-    int denom = arrayZ[i].fromCoord - arrayZ[i-1].fromCoord;
-    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); }
+  float unmap_float (float value) const { return map_float (value, 1, 0); }
 
+
+  // TODO Kill this.
   Triple unmap_axis_range (const Triple& axis_range) const
   {
-    F2DOT14 val, unmapped_val;
-
-    val.set_float (axis_range.minimum);
-    unmapped_val.set_int (unmap (val.to_int ()));
-    float unmapped_min = unmapped_val.to_float ();
-
-    val.set_float (axis_range.middle);
-    unmapped_val.set_int (unmap (val.to_int ()));
-    float unmapped_middle = unmapped_val.to_float ();
-
-    val.set_float (axis_range.maximum);
-    unmapped_val.set_int (unmap (val.to_int ()));
-    float unmapped_max = unmapped_val.to_float ();
+    float unmapped_min = unmap_float (axis_range.minimum);
+    float unmapped_middle = unmap_float (axis_range.middle);
+    float unmapped_max = unmap_float (axis_range.maximum);
 
     return Triple{(double) unmapped_min, (double) unmapped_middle, (double) unmapped_max};
   }
@@ -203,6 +257,11 @@ struct SegmentMaps : Array16Of
   bool subset (hb_subset_context_t *c, hb_tag_t axis_tag) const
   {
     TRACE_SUBSET (this);
+
+    /* This function cannot work on avar2 table (and currently doesn't).
+     * We should instead keep the design coords in the shape plan and use
+     * those. unmap_axis_range needs to be killed. */
+
     /* avar mapped normalized axis range*/
     Triple *axis_range;
     if (!c->plan->axes_location.has (axis_tag, &axis_range))
@@ -304,14 +363,14 @@ struct avar
     return_trace (true);
   }
 
-  void map_coords (int *coords, unsigned int coords_length) const
+  void map_coords_16_16 (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->map (coords[i]);
+      coords[i] = roundf (map->map_float (coords[i] / 65536.f) * 65536.f);
       map = &StructAfter (*map);
     }
 
@@ -329,15 +388,20 @@ struct avar
     const auto &var_store = this+v2.varStore;
     auto *var_store_cache = var_store.create_cache ();
 
+    hb_vector_t coords_2_14;
+    coords_2_14.resize (coords_length);
+    for (unsigned i = 0; i < coords_length; i++)
+      coords_2_14[i] = roundf (coords[i] / 4.f); // 16.16 -> 2.14
+
     hb_vector_t out;
     out.alloc (coords_length);
     for (unsigned i = 0; i < coords_length; i++)
     {
       int v = coords[i];
       uint32_t varidx = varidx_map.map (i);
-      float delta = var_store.get_delta (varidx, coords, coords_length, var_store_cache);
-      v += roundf (delta);
-      v = hb_clamp (v, -(1<<14), +(1<<14));
+      float delta = var_store.get_delta (varidx, coords_2_14.arrayZ, coords_2_14.length, var_store_cache);
+      v += roundf (delta * 4); // 2.14 -> 16.16
+      v = hb_clamp (v, -(1<<16), +(1<<16));
       out.push (v);
     }
     for (unsigned i = 0; i < coords_length; i++)
@@ -347,16 +411,54 @@ struct avar
 #endif
   }
 
-  void unmap_coords (int *coords, unsigned int coords_length) const
+  bool has_v2_data () const { return version.major > 1; }
+
+  // axis normalization is done in 2.14 here
+  // TODO: deprecate this API once fonttools is updated to use 16.16 normalization
+  bool map_coords_2_14 (float *coords, unsigned int coords_length) const
   {
+    hb_vector_t coords_2_14;
+    if (!coords_2_14.resize (coords_length)) return false;
     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]);
+      int v = roundf (map->map_float (coords[i]) * 16384.f);
+      coords_2_14[i] = v;
+      coords[i] = v / 16384.f;
       map = &StructAfter (*map);
     }
+
+#ifndef HB_NO_AVAR2
+    if (version.major < 2)
+      return true;
+    hb_barrier ();
+
+    for (; count < axisCount; count++)
+      map = &StructAfter (*map);
+
+    const auto &v2 = * (const avarV2Tail *) map;
+
+    const auto &varidx_map = this+v2.varIdxMap;
+    const auto &var_store = this+v2.varStore;
+    auto *var_store_cache = var_store.create_cache ();
+
+    for (unsigned i = 0; i < coords_length; i++)
+    {
+      int v = coords_2_14[i];
+      uint32_t varidx = varidx_map.map (i);
+      float delta = var_store.get_delta (varidx, coords_2_14.arrayZ, coords_2_14.length, var_store_cache);
+      v += roundf (delta);
+      v = hb_clamp (v, -(1<<16), +(1<<16));
+      coords[i] = v / 16384.f;
+    }
+
+    OT::ItemVariationStore::destroy_cache (var_store_cache);
+    return true;
+#else
+    return version.major < 2;
+#endif
   }
 
   bool subset (hb_subset_context_t *c) const
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-common.hh
index 72deddef213..d0a4224c9b0 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-common.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-common.hh
@@ -27,24 +27,35 @@
 #define HB_OT_VAR_COMMON_HH
 
 #include "hb-ot-layout-common.hh"
+#include "hb-alloc-pool.hh"
 #include "hb-priority-queue.hh"
 #include "hb-subset-instancer-iup.hh"
 
 
 namespace OT {
 
+using rebase_tent_result_scratch_t = hb_pair_t;
 
 /* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */
 struct TupleVariationHeader
 {
   friend struct tuple_delta_t;
-  unsigned get_size (unsigned axis_count) const
-  { return min_size + get_all_tuples (axis_count).get_size (); }
+  unsigned get_size (unsigned axis_count_times_2) const
+  {
+    // This function is super hot in mega-var-fonts with hundreds of masters.
+    unsigned ti = tupleIndex;
+    if (unlikely ((ti & (TupleIndex::EmbeddedPeakTuple | TupleIndex::IntermediateRegion))))
+    {
+      unsigned count = ((ti & TupleIndex::EmbeddedPeakTuple) != 0) + ((ti & TupleIndex::IntermediateRegion) != 0) * 2;
+      return min_size + count * axis_count_times_2;
+    }
+    return min_size;
+  }
 
   unsigned get_data_size () const { return varDataSize; }
 
-  const TupleVariationHeader &get_next (unsigned axis_count) const
-  { return StructAtOffset (this, get_size (axis_count)); }
+  const TupleVariationHeader &get_next (unsigned axis_count_times_2) const
+  { return StructAtOffset (this, get_size (axis_count_times_2)); }
 
   bool unpack_axis_tuples (unsigned axis_count,
                            const hb_array_t shared_tuples,
@@ -53,7 +64,7 @@ struct TupleVariationHeader
   {
     const F2DOT14 *peak_tuple = nullptr;
     if (has_peak ())
-      peak_tuple = get_peak_tuple (axis_count).arrayZ;
+      peak_tuple = get_peak_tuple (axis_count);
     else
     {
       unsigned int index = get_index ();
@@ -68,8 +79,8 @@ struct TupleVariationHeader
 
     if (has_interm)
     {
-      start_tuple = get_start_tuple (axis_count).arrayZ;
-      end_tuple = get_end_tuple (axis_count).arrayZ;
+      start_tuple = get_start_tuple (axis_count);
+      end_tuple = get_end_tuple (axis_count);
     }
 
     for (unsigned i = 0; i < axis_count; i++)
@@ -98,88 +109,109 @@ struct TupleVariationHeader
     return true;
   }
 
+  HB_ALWAYS_INLINE
   double calculate_scalar (hb_array_t coords, unsigned int coord_count,
                            const hb_array_t shared_tuples,
-                           const hb_vector_t> *shared_tuple_active_idx = nullptr) const
+                           hb_scalar_cache_t *shared_tuple_scalar_cache = nullptr) const
   {
+    unsigned tuple_index = tupleIndex;
+
     const F2DOT14 *peak_tuple;
 
-    unsigned start_idx = 0;
-    unsigned end_idx = coord_count;
-    unsigned step = 1;
+    bool has_interm = tuple_index & TupleIndex::IntermediateRegion; // Inlined for performance
 
-    if (has_peak ())
-      peak_tuple = get_peak_tuple (coord_count).arrayZ;
+    if (unlikely (tuple_index & TupleIndex::EmbeddedPeakTuple)) // Inlined for performance
+    {
+      peak_tuple = get_peak_tuple (coord_count);
+      shared_tuple_scalar_cache = nullptr;
+    }
     else
     {
-      unsigned int index = get_index ();
-      if (unlikely ((index + 1) * coord_count > shared_tuples.length))
-        return 0.0;
-      peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count).arrayZ;
+      unsigned int index = tuple_index & TupleIndex::TupleIndexMask; // Inlined for performance
 
-      if (shared_tuple_active_idx)
+      float scalar;
+      if (shared_tuple_scalar_cache &&
+          shared_tuple_scalar_cache->get (index, &scalar))
       {
-        if (unlikely (index >= shared_tuple_active_idx->length))
-          return 0.0;
-        auto _ = (*shared_tuple_active_idx).arrayZ[index];
-        if (_.second != -1)
-        {
-          start_idx = _.first;
-          end_idx = _.second + 1;
-          step = _.second - _.first;
-        }
-        else if (_.first != -1)
-        {
-          start_idx = _.first;
-          end_idx = start_idx + 1;
-        }
+        if (has_interm && (scalar != 0 && scalar != 1.f))
+          shared_tuple_scalar_cache = nullptr;
+        else
+          return (double) scalar;
       }
+
+      if (unlikely ((index + 1) * coord_count > shared_tuples.length))
+        return 0.0;
+      peak_tuple = shared_tuples.arrayZ + (coord_count * index);
+
     }
 
     const F2DOT14 *start_tuple = nullptr;
     const F2DOT14 *end_tuple = nullptr;
-    bool has_interm = has_intermediate ();
+
     if (has_interm)
     {
-      start_tuple = get_start_tuple (coord_count).arrayZ;
-      end_tuple = get_end_tuple (coord_count).arrayZ;
+      start_tuple = get_start_tuple (coord_count);
+      end_tuple = get_end_tuple (coord_count);
     }
 
     double scalar = 1.0;
-    for (unsigned int i = start_idx; i < end_idx; i += step)
+#ifndef HB_OPTIMIZE_SIZE
+#if HB_FAST_NUM_ACCESS
+    bool skip = coord_count >= 16;
+#endif
+#endif
+    for (unsigned int i = 0; i < coord_count; i++)
     {
+#ifndef HB_OPTIMIZE_SIZE
+#if HB_FAST_NUM_ACCESS
+      if (skip)
+      {
+        while (i + 4 <= coord_count && * (HBUINT64LE *) &peak_tuple[i] == 0)
+          i += 4;
+        while (i < coord_count && peak_tuple[i].to_int () == 0)
+          i += 1;
+        if (i >= coord_count)
+          break;
+      }
+#endif
+#endif
+
       int peak = peak_tuple[i].to_int ();
       if (!peak) continue;
 
       int v = coords[i];
+      if (!v) { scalar = 0.0; break; }
       if (v == peak) continue;
 
       if (has_interm)
       {
+        shared_tuple_scalar_cache = nullptr;
         int start = start_tuple[i].to_int ();
         int end = end_tuple[i].to_int ();
         if (unlikely (start > peak || peak > end ||
                       (start < 0 && end > 0 && peak))) continue;
-        if (v < start || v > end) return 0.0;
+        if (v < start || v > end) { scalar = 0.0; break; }
         if (v < peak)
         { if (peak != start) scalar *= (double) (v - start) / (peak - start); }
         else
         { if (peak != end) scalar *= (double) (end - v) / (end - peak); }
       }
-      else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.0;
+      else if (v < hb_min (0, peak) || v > hb_max (0, peak)) { scalar = 0.0; break; }
       else
         scalar *= (double) v / peak;
     }
+    if (shared_tuple_scalar_cache)
+      shared_tuple_scalar_cache->set (get_index (), scalar);
     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; }
+  bool           has_peak () const { return tupleIndex & TupleIndex::EmbeddedPeakTuple; }
+  bool   has_intermediate () const { return tupleIndex & TupleIndex::IntermediateRegion; }
+  bool has_private_points () const { return tupleIndex & TupleIndex::PrivatePointNumbers; }
+  unsigned      get_index () const { return tupleIndex & TupleIndex::TupleIndexMask; }
 
   protected:
-  struct TuppleIndex : HBUINT16
+  struct TupleIndex : HBUINT16
   {
     enum Flags {
       EmbeddedPeakTuple   = 0x8000u,
@@ -188,22 +220,24 @@ struct TupleVariationHeader
       TupleIndexMask      = 0x0FFFu
     };
 
-    TuppleIndex& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
+    TupleIndex& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
     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); }
+  const F2DOT14* get_all_tuples_base (unsigned axis_count) const
+  { return StructAfter> (tupleIndex).arrayZ; }
+  const F2DOT14* get_peak_tuple (unsigned axis_count) const
+  { return get_all_tuples_base (axis_count); }
+  const F2DOT14* get_start_tuple (unsigned axis_count) const
+  { return get_all_tuples_base (axis_count) + has_peak () * axis_count; }
+  const F2DOT14* get_end_tuple (unsigned axis_count) const
+  { return get_all_tuples_base (axis_count) + has_peak () * 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).
+  TupleIndex    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 */
@@ -221,6 +255,21 @@ struct TupleVariationHeader
   DEFINE_SIZE_MIN (4);
 };
 
+struct optimize_scratch_t
+{
+  iup_scratch_t iup;
+  hb_vector_t opt_indices;
+  hb_vector_t rounded_x_deltas;
+  hb_vector_t rounded_y_deltas;
+  hb_vector_t opt_deltas_x;
+  hb_vector_t opt_deltas_y;
+  hb_vector_t opt_point_data;
+  hb_vector_t opt_deltas_data;
+  hb_vector_t point_data;
+  hb_vector_t deltas_data;
+  hb_vector_t rounded_deltas;
+};
+
 struct tuple_delta_t
 {
   static constexpr bool realloc_move = true;  // Watch out when adding new members!
@@ -241,11 +290,12 @@ struct tuple_delta_t
   hb_vector_t compiled_tuple_header;
   hb_vector_t compiled_deltas;
 
-  /* compiled peak coords, empty for non-gvar tuples */
-  hb_vector_t compiled_peak_coords;
+  hb_vector_t compiled_peak_coords;
+  hb_vector_t compiled_interm_coords;
 
-  tuple_delta_t () = default;
+  tuple_delta_t (hb_alloc_pool_t *pool = nullptr) {}
   tuple_delta_t (const tuple_delta_t& o) = default;
+  tuple_delta_t& operator = (const tuple_delta_t& o) = default;
 
   friend void swap (tuple_delta_t& a, tuple_delta_t& b) noexcept
   {
@@ -267,6 +317,18 @@ struct tuple_delta_t
     return *this;
   }
 
+  void copy_from (const tuple_delta_t& o, hb_alloc_pool_t *pool = nullptr)
+  {
+    axis_tuples = o.axis_tuples;
+    indices.duplicate_vector_from_pool (pool, o.indices);
+    deltas_x.duplicate_vector_from_pool (pool, o.deltas_x);
+    deltas_y.duplicate_vector_from_pool (pool, o.deltas_y);
+    compiled_tuple_header.duplicate_vector_from_pool (pool, o.compiled_tuple_header);
+    compiled_deltas.duplicate_vector_from_pool (pool, o.compiled_deltas);
+    compiled_peak_coords.duplicate_vector_from_pool (pool, o.compiled_peak_coords);
+    compiled_interm_coords.duplicate_vector_from_pool (pool, o.compiled_interm_coords);
+  }
+
   void remove_axis (hb_tag_t axis_tag)
   { axis_tuples.del (axis_tag); }
 
@@ -321,31 +383,44 @@ struct tuple_delta_t
     return *this;
   }
 
-  hb_vector_t change_tuple_var_axis_limit (hb_tag_t axis_tag, Triple axis_limit,
-                                                          TripleDistances axis_triple_distances) const
+  void change_tuple_var_axis_limit (hb_tag_t axis_tag, Triple axis_limit,
+                                    TripleDistances axis_triple_distances,
+                                    hb_vector_t& out,
+                                    rebase_tent_result_scratch_t &scratch,
+                                    hb_alloc_pool_t *pool = nullptr)
   {
-    hb_vector_t out;
+    // May move *this out.
+
+    out.reset ();
     Triple *tent;
     if (!axis_tuples.has (axis_tag, &tent))
     {
-      out.push (*this);
-      return out;
+      out.push (std::move (*this));
+      return;
     }
 
     if ((tent->minimum < 0.0 && tent->maximum > 0.0) ||
         !(tent->minimum <= tent->middle && tent->middle <= tent->maximum))
-      return out;
+      return;
 
     if (tent->middle == 0.0)
     {
-      out.push (*this);
-      return out;
+      out.push (std::move (*this));
+      return;
     }
 
-    rebase_tent_result_t solutions = rebase_tent (*tent, axis_limit, axis_triple_distances);
-    for (auto &t : solutions)
+    rebase_tent_result_t &solutions = scratch.first;
+    rebase_tent (*tent, axis_limit, axis_triple_distances, solutions, scratch.second);
+    for (unsigned i = 0; i < solutions.length; i++)
     {
-      tuple_delta_t new_var = *this;
+      auto &t = solutions.arrayZ[i];
+
+      tuple_delta_t new_var;
+      if (i < solutions.length - 1)
+        new_var.copy_from (*this, pool);
+      else
+        new_var = std::move (*this);
+
       if (t.second == Triple ())
         new_var.remove_axis (axis_tag);
       else
@@ -354,38 +429,76 @@ struct tuple_delta_t
       new_var *= t.first;
       out.push (std::move (new_var));
     }
-
-    return out;
   }
 
-  bool compile_peak_coords (const hb_map_t& axes_index_map,
-                            const hb_map_t& axes_old_index_tag_map)
+  bool compile_coords (const hb_map_t& axes_index_map,
+                       const hb_map_t& axes_old_index_tag_map,
+                       hb_alloc_pool_t *pool= nullptr)
   {
-    unsigned axis_count = axes_index_map.get_population ();
-    if (unlikely (!compiled_peak_coords.alloc (axis_count * F2DOT14::static_size)))
+    unsigned cur_axis_count = axes_index_map.get_population ();
+    if (pool)
+    {
+      if (unlikely (!compiled_peak_coords.allocate_from_pool (pool, cur_axis_count)))
+        return false;
+    }
+    else if (unlikely (!compiled_peak_coords.resize (cur_axis_count)))
       return false;
 
+    hb_array_t start_coords, end_coords;
+
     unsigned orig_axis_count = axes_old_index_tag_map.get_population ();
+    unsigned j = 0;
     for (unsigned i = 0; i < orig_axis_count; i++)
     {
       if (!axes_index_map.has (i))
         continue;
 
       hb_tag_t axis_tag = axes_old_index_tag_map.get (i);
-      Triple *coords;
-      F2DOT14 peak_coord;
+      Triple *coords = nullptr;
       if (axis_tuples.has (axis_tag, &coords))
-        peak_coord.set_float (coords->middle);
-      else
-        peak_coord.set_int (0);
+      {
+        float min_val = coords->minimum;
+        float val = coords->middle;
+        float max_val = coords->maximum;
+
+        compiled_peak_coords.arrayZ[j].set_float (val);
+
+        if (min_val != hb_min (val, 0.f) || max_val != hb_max (val, 0.f))
+        {
+          if (!compiled_interm_coords)
+          {
+            if (pool)
+            {
+              if (unlikely (!compiled_interm_coords.allocate_from_pool (pool, 2 * cur_axis_count)))
+                return false;
+            }
+            else if (unlikely (!compiled_interm_coords.resize (2 * cur_axis_count)))
+              return false;
+            start_coords = compiled_interm_coords.as_array ().sub_array (0, cur_axis_count);
+            end_coords = compiled_interm_coords.as_array ().sub_array (cur_axis_count);
+
+            for (unsigned k = 0; k < j; k++)
+            {
+              signed peak = compiled_peak_coords.arrayZ[k].to_int ();
+              if (!peak) continue;
+              start_coords.arrayZ[k].set_int (hb_min (peak, 0));
+              end_coords.arrayZ[k].set_int (hb_max (peak, 0));
+            }
+          }
+
+        }
+
+        if (compiled_interm_coords)
+        {
+          start_coords.arrayZ[j].set_float (min_val);
+          end_coords.arrayZ[j].set_float (max_val);
+        }
+      }
 
-      /* push F2DOT14 value into char vector */
-      int16_t val = peak_coord.to_int ();
-      compiled_peak_coords.push (static_cast (val >> 8));
-      compiled_peak_coords.push (static_cast (val & 0xFF));
+      j++;
     }
 
-    return !compiled_peak_coords.in_error ();
+    return !compiled_peak_coords.in_error () && !compiled_interm_coords.in_error ();
   }
 
   /* deltas should be compiled already before we compile tuple
@@ -394,7 +507,8 @@ struct tuple_delta_t
   bool compile_tuple_var_header (const hb_map_t& axes_index_map,
                                  unsigned points_data_length,
                                  const hb_map_t& axes_old_index_tag_map,
-                                 const hb_hashmap_t*, unsigned>* shared_tuples_idx_map)
+                                 const hb_hashmap_t*, unsigned>* shared_tuples_idx_map,
+                                 hb_alloc_pool_t *pool = nullptr)
   {
     /* compiled_deltas could be empty after iup delta optimization, we can skip
      * compiling this tuple and return true */
@@ -403,7 +517,7 @@ struct tuple_delta_t
     unsigned cur_axis_count = axes_index_map.get_population ();
     /* allocate enough memory: 1 peak + 2 intermediate coords + fixed header size */
     unsigned alloc_len = 3 * cur_axis_count * (F2DOT14::static_size) + 4;
-    if (unlikely (!compiled_tuple_header.resize (alloc_len))) return false;
+    if (unlikely (!compiled_tuple_header.allocate_from_pool (pool, alloc_len, false))) return false;
 
     unsigned flag = 0;
     /* skip the first 4 header bytes: variationDataSize+tupleIndex */
@@ -411,6 +525,9 @@ struct tuple_delta_t
     F2DOT14* end = reinterpret_cast (compiled_tuple_header.end ());
     hb_array_t coords (p, end - p);
 
+    if (!shared_tuples_idx_map)
+      compile_coords (axes_index_map, axes_old_index_tag_map); // non-gvar tuples do not have compiled coords yet
+
     /* encode peak coords */
     unsigned peak_count = 0;
     unsigned *shared_tuple_idx;
@@ -421,16 +538,16 @@ struct tuple_delta_t
     }
     else
     {
-      peak_count = encode_peak_coords(coords, flag, axes_index_map, axes_old_index_tag_map);
+      peak_count = encode_peak_coords(coords, flag);
       if (!peak_count) return false;
     }
 
     /* encode interim coords, it's optional so returned num could be 0 */
-    unsigned interim_count = encode_interm_coords (coords.sub_array (peak_count), flag, axes_index_map, axes_old_index_tag_map);
+    unsigned interim_count = encode_interm_coords (coords.sub_array (peak_count), flag);
 
     /* pointdata length = 0 implies "use shared points" */
     if (points_data_length)
-      flag |= TupleVariationHeader::TuppleIndex::PrivatePointNumbers;
+      flag |= TupleVariationHeader::TupleIndex::PrivatePointNumbers;
 
     unsigned serialized_data_size = points_data_length + compiled_deltas.length;
     TupleVariationHeader *o = reinterpret_cast (compiled_tuple_header.begin ());
@@ -438,105 +555,63 @@ struct tuple_delta_t
     o->tupleIndex = flag;
 
     unsigned total_header_len = 4 + (peak_count + interim_count) * (F2DOT14::static_size);
-    return compiled_tuple_header.resize (total_header_len);
+    compiled_tuple_header.shrink_back_to_pool (pool, total_header_len);
+    return true;
   }
 
   unsigned encode_peak_coords (hb_array_t peak_coords,
-                               unsigned& flag,
-                               const hb_map_t& axes_index_map,
-                               const hb_map_t& axes_old_index_tag_map) const
+                               unsigned& flag) const
   {
-    unsigned orig_axis_count = axes_old_index_tag_map.get_population ();
-    auto it = peak_coords.iter ();
-    unsigned count = 0;
-    for (unsigned i = 0; i < orig_axis_count; i++)
-    {
-      if (!axes_index_map.has (i)) /* axis pinned */
-        continue;
-      hb_tag_t axis_tag = axes_old_index_tag_map.get (i);
-      Triple *coords;
-      if (!axis_tuples.has (axis_tag, &coords))
-        (*it).set_int (0);
-      else
-        (*it).set_float (coords->middle);
-      it++;
-      count++;
-    }
-    flag |= TupleVariationHeader::TuppleIndex::EmbeddedPeakTuple;
-    return count;
+    hb_memcpy (&peak_coords[0], &compiled_peak_coords[0], compiled_peak_coords.length * sizeof (compiled_peak_coords[0]));
+    flag |= TupleVariationHeader::TupleIndex::EmbeddedPeakTuple;
+    return compiled_peak_coords.length;
   }
 
   /* if no need to encode intermediate coords, then just return p */
   unsigned encode_interm_coords (hb_array_t coords,
-                                 unsigned& flag,
-                                 const hb_map_t& axes_index_map,
-                                 const hb_map_t& axes_old_index_tag_map) const
+                                 unsigned& flag) const
   {
-    unsigned orig_axis_count = axes_old_index_tag_map.get_population ();
-    unsigned cur_axis_count = axes_index_map.get_population ();
-
-    auto start_coords_iter = coords.sub_array (0, cur_axis_count).iter ();
-    auto end_coords_iter = coords.sub_array (cur_axis_count).iter ();
-    bool encode_needed = false;
-    unsigned count = 0;
-    for (unsigned i = 0; i < orig_axis_count; i++)
+    if (compiled_interm_coords)
     {
-      if (!axes_index_map.has (i)) /* axis pinned */
-        continue;
-      hb_tag_t axis_tag = axes_old_index_tag_map.get (i);
-      Triple *coords;
-      float min_val = 0.f, val = 0.f, max_val = 0.f;
-      if (axis_tuples.has (axis_tag, &coords))
-      {
-        min_val = coords->minimum;
-        val = coords->middle;
-        max_val = coords->maximum;
-      }
-
-      (*start_coords_iter).set_float (min_val);
-      (*end_coords_iter).set_float (max_val);
-
-      start_coords_iter++;
-      end_coords_iter++;
-      count += 2;
-      if (min_val != hb_min (val, 0.f) || max_val != hb_max (val, 0.f))
-        encode_needed = true;
-    }
-
-    if (encode_needed)
-    {
-      flag |= TupleVariationHeader::TuppleIndex::IntermediateRegion;
-      return count;
+      hb_memcpy (&coords[0], &compiled_interm_coords[0], compiled_interm_coords.length * sizeof (compiled_interm_coords[0]));
+      flag |= TupleVariationHeader::TupleIndex::IntermediateRegion;
     }
-    return 0;
+    return compiled_interm_coords.length;
   }
 
-  bool compile_deltas ()
-  { return compile_deltas (indices, deltas_x, deltas_y, compiled_deltas); }
+  bool compile_deltas (hb_vector_t &rounded_deltas_scratch,
+                       hb_alloc_pool_t *pool = nullptr)
+  { return compile_deltas (indices, deltas_x, deltas_y, compiled_deltas, rounded_deltas_scratch, pool); }
 
   static bool compile_deltas (hb_array_t point_indices,
                               hb_array_t x_deltas,
                               hb_array_t y_deltas,
-                              hb_vector_t &compiled_deltas /* OUT */)
+                              hb_vector_t &compiled_deltas, /* OUT */
+                              hb_vector_t &rounded_deltas, /* scratch */
+                              hb_alloc_pool_t *pool = nullptr)
   {
-    hb_vector_t rounded_deltas;
-    if (unlikely (!rounded_deltas.alloc (point_indices.length)))
+    if (unlikely (!rounded_deltas.resize_dirty  (point_indices.length)))
       return false;
 
+    unsigned j = 0;
     for (unsigned i = 0; i < point_indices.length; i++)
     {
       if (!point_indices[i]) continue;
-      int rounded_delta = (int) roundf (x_deltas.arrayZ[i]);
-      rounded_deltas.push (rounded_delta);
+      rounded_deltas.arrayZ[j++] = (int) roundf (x_deltas.arrayZ[i]);
     }
+    rounded_deltas.resize (j);
 
     if (!rounded_deltas) return true;
-    /* allocate enough memories 5 * num_deltas */
-    unsigned alloc_len = 5 * rounded_deltas.length;
+    /* Allocate enough memory: this is the correct bound:
+     * Worst case scenario is that each delta has to be encoded in 4 bytes, and there
+     * are runs of 64 items each. Any delta encoded in less than 4 bytes (2, 1, or 0)
+     * is still smaller than the 4-byte encoding even with their control byte.
+     * The initial 2 is to handle length==0, for both x and y deltas. */
+    unsigned alloc_len = 2 + 4 * rounded_deltas.length + (rounded_deltas.length + 63) / 64;
     if (y_deltas)
       alloc_len *= 2;
 
-    if (unlikely (!compiled_deltas.resize (alloc_len))) return false;
+    if (unlikely (!compiled_deltas.allocate_from_pool (pool, alloc_len, false))) return false;
 
     unsigned encoded_len = compile_deltas (compiled_deltas, rounded_deltas);
 
@@ -557,28 +632,30 @@ struct tuple_delta_t
       if (j != rounded_deltas.length) return false;
       encoded_len += compile_deltas (compiled_deltas.as_array ().sub_array (encoded_len), rounded_deltas);
     }
-    return compiled_deltas.resize (encoded_len);
+    compiled_deltas.shrink_back_to_pool (pool, encoded_len);
+    return true;
   }
 
   static unsigned compile_deltas (hb_array_t encoded_bytes,
                                   hb_array_t deltas)
   {
-    return TupleValues::compile (deltas, encoded_bytes);
+    return TupleValues::compile_unsafe (deltas, encoded_bytes);
   }
 
-  bool calc_inferred_deltas (const contour_point_vector_t& orig_points)
+  bool calc_inferred_deltas (const contour_point_vector_t& orig_points,
+                             hb_vector_t &scratch)
   {
     unsigned point_count = orig_points.length;
     if (point_count != indices.length)
       return false;
 
     unsigned ref_count = 0;
-    hb_vector_t end_points;
+
+    hb_vector_t &end_points = scratch.reset ();
 
     for (unsigned i = 0; i < point_count; i++)
     {
-      if (indices.arrayZ[i])
-        ref_count++;
+      ref_count += indices.arrayZ[i];
       if (orig_points.arrayZ[i].is_end_point)
         end_points.push (i);
     }
@@ -587,7 +664,7 @@ struct tuple_delta_t
       return true;
     if (unlikely (end_points.in_error ())) return false;
 
-    hb_set_t inferred_idxes;
+    hb_bit_set_t inferred_idxes;
     unsigned start_point = 0;
     for (unsigned end_point : end_points)
     {
@@ -661,6 +738,7 @@ struct tuple_delta_t
 
   bool optimize (const contour_point_vector_t& contour_points,
                  bool is_composite,
+                 optimize_scratch_t &scratch,
                  double tolerance = 0.5 + 1e-10)
   {
     unsigned count = contour_points.length;
@@ -668,22 +746,21 @@ struct tuple_delta_t
         deltas_y.length != count)
       return false;
 
-    hb_vector_t opt_indices;
-    hb_vector_t rounded_x_deltas, rounded_y_deltas;
+    hb_vector_t &opt_indices = scratch.opt_indices.reset ();
+    hb_vector_t &rounded_x_deltas = scratch.rounded_x_deltas;
+    hb_vector_t &rounded_y_deltas = scratch.rounded_y_deltas;
 
-    if (unlikely (!rounded_x_deltas.alloc (count) ||
-                  !rounded_y_deltas.alloc (count)))
+    if (unlikely (!rounded_x_deltas.resize_dirty  (count) ||
+                  !rounded_y_deltas.resize_dirty  (count)))
       return false;
 
     for (unsigned i = 0; i < count; i++)
     {
-      int rounded_x_delta = (int) roundf (deltas_x.arrayZ[i]);
-      int rounded_y_delta = (int) roundf (deltas_y.arrayZ[i]);
-      rounded_x_deltas.push (rounded_x_delta);
-      rounded_y_deltas.push (rounded_y_delta);
+      rounded_x_deltas.arrayZ[i] = (int) roundf (deltas_x.arrayZ[i]);
+      rounded_y_deltas.arrayZ[i] = (int) roundf (deltas_y.arrayZ[i]);
     }
 
-    if (!iup_delta_optimize (contour_points, rounded_x_deltas, rounded_y_deltas, opt_indices, tolerance))
+    if (!iup_delta_optimize (contour_points, rounded_x_deltas, rounded_y_deltas, opt_indices, scratch.iup, tolerance))
       return false;
 
     unsigned ref_count = 0;
@@ -692,7 +769,8 @@ struct tuple_delta_t
 
     if (ref_count == count) return true;
 
-    hb_vector_t opt_deltas_x, opt_deltas_y;
+    hb_vector_t &opt_deltas_x = scratch.opt_deltas_x.reset ();
+    hb_vector_t &opt_deltas_y = scratch.opt_deltas_y.reset ();
     bool is_comp_glyph_wo_deltas = (is_composite && ref_count == 0);
     if (is_comp_glyph_wo_deltas)
     {
@@ -705,34 +783,31 @@ struct tuple_delta_t
         opt_indices.arrayZ[i] = false;
     }
 
-    hb_vector_t opt_point_data;
+    hb_vector_t &opt_point_data = scratch.opt_point_data.reset ();
     if (!compile_point_set (opt_indices, opt_point_data))
       return false;
-    hb_vector_t opt_deltas_data;
+    hb_vector_t &opt_deltas_data = scratch.opt_deltas_data.reset ();
     if (!compile_deltas (opt_indices,
                          is_comp_glyph_wo_deltas ? opt_deltas_x : deltas_x,
                          is_comp_glyph_wo_deltas ? opt_deltas_y : deltas_y,
-                         opt_deltas_data))
+                         opt_deltas_data,
+                         scratch.rounded_deltas))
       return false;
 
-    hb_vector_t point_data;
+    hb_vector_t &point_data = scratch.point_data.reset ();
     if (!compile_point_set (indices, point_data))
       return false;
-    hb_vector_t deltas_data;
-    if (!compile_deltas (indices, deltas_x, deltas_y, deltas_data))
+    hb_vector_t &deltas_data = scratch.deltas_data.reset ();
+    if (!compile_deltas (indices, deltas_x, deltas_y, deltas_data, scratch.rounded_deltas))
       return false;
 
     if (opt_point_data.length + opt_deltas_data.length < point_data.length + deltas_data.length)
     {
-      indices.fini ();
       indices = std::move (opt_indices);
 
       if (is_comp_glyph_wo_deltas)
       {
-        deltas_x.fini ();
         deltas_x = std::move (opt_deltas_x);
-
-        deltas_y.fini ();
         deltas_y = std::move (opt_deltas_y);
       }
     }
@@ -757,7 +832,7 @@ struct tuple_delta_t
 
     /* allocate enough memories: 2 bytes for count + 3 bytes for each point */
     unsigned num_bytes = 2 + 3 *num_points;
-    if (unlikely (!compiled_points.resize (num_bytes, false)))
+    if (unlikely (!compiled_points.resize_dirty  (num_bytes)))
       return false;
 
     unsigned pos = 0;
@@ -821,7 +896,7 @@ struct tuple_delta_t
       else
         compiled_points.arrayZ[header_pos] = (run_length - 1) | 0x80;
     }
-    return compiled_points.resize (pos, false);
+    return compiled_points.resize_dirty  (pos);
   }
 
   static double infer_delta (double target_val, double prev_val, double next_val, double prev_delta, double next_delta)
@@ -852,15 +927,15 @@ struct TupleVariationData
     return_trace (c->check_struct (this));
   }
 
-  unsigned get_size (unsigned axis_count) const
+  unsigned get_size (unsigned axis_count_times_2) const
   {
     unsigned total_size = min_size;
     unsigned count = tupleVarCount.get_count ();
     const TupleVariationHeader *tuple_var_header = &(get_tuple_var_header());
     for (unsigned i = 0; i < count; i++)
     {
-      total_size += tuple_var_header->get_size (axis_count) + tuple_var_header->get_data_size ();
-      tuple_var_header = &tuple_var_header->get_next (axis_count);
+      total_size += tuple_var_header->get_size (axis_count_times_2) + tuple_var_header->get_data_size ();
+      tuple_var_header = &tuple_var_header->get_next (axis_count_times_2);
     }
 
     return total_size;
@@ -925,8 +1000,12 @@ struct TupleVariationData
                                      const hb_map_t *axes_old_index_tag_map,
                                      const hb_vector_t &shared_indices,
                                      const hb_array_t shared_tuples,
-                                     bool is_composite_glyph)
+                                     hb_alloc_pool_t *pool = nullptr,
+                                     bool is_composite_glyph = false)
     {
+      hb_vector_t private_indices;
+      hb_vector_t deltas_x;
+      hb_vector_t deltas_y;
       do
       {
         const HBUINT8 *p = iterator.get_serialized_data ();
@@ -939,7 +1018,7 @@ struct TupleVariationData
             || axis_tuples.is_empty ())
           return false;
 
-        hb_vector_t private_indices;
+        private_indices.reset ();
         bool has_private_points = iterator.current_tuple->has_private_points ();
         const HBUINT8 *end = p + length;
         if (has_private_points &&
@@ -950,27 +1029,24 @@ struct TupleVariationData
         bool apply_to_all = (indices.length == 0);
         unsigned num_deltas = apply_to_all ? point_count : indices.length;
 
-        hb_vector_t deltas_x;
-
-        if (unlikely (!deltas_x.resize (num_deltas, false) ||
+        if (unlikely (!deltas_x.resize_dirty  (num_deltas) ||
                       !TupleVariationData::decompile_deltas (p, deltas_x, end)))
           return false;
 
-        hb_vector_t deltas_y;
         if (is_gvar)
         {
-          if (unlikely (!deltas_y.resize (num_deltas, false) ||
+          if (unlikely (!deltas_y.resize_dirty  (num_deltas) ||
                         !TupleVariationData::decompile_deltas (p, deltas_y, end)))
             return false;
         }
 
         tuple_delta_t var;
         var.axis_tuples = std::move (axis_tuples);
-        if (unlikely (!var.indices.resize (point_count) ||
-                      !var.deltas_x.resize (point_count, false)))
+        if (unlikely (!var.indices.allocate_from_pool (pool, point_count) ||
+                      !var.deltas_x.allocate_from_pool (pool, point_count, false)))
           return false;
 
-        if (is_gvar && unlikely (!var.deltas_y.resize (point_count, false)))
+        if (is_gvar && unlikely (!var.deltas_y.allocate_from_pool (pool, point_count, false)))
           return false;
 
         for (unsigned i = 0; i < num_deltas; i++)
@@ -1012,8 +1088,8 @@ struct TupleVariationData
         /* In VarData, deltas are organized in rows, convert them into
          * column(region) based tuples, resize deltas_x first */
         tuple_delta_t tuple;
-        if (!tuple.deltas_x.resize (item_count, false) ||
-            !tuple.indices.resize (item_count, false))
+        if (!tuple.deltas_x.resize_dirty  (item_count) ||
+            !tuple.indices.resize_dirty  (item_count))
           return false;
 
         for (unsigned i = 0; i < item_count; i++)
@@ -1041,7 +1117,8 @@ struct TupleVariationData
     }
 
     bool change_tuple_variations_axis_limits (const hb_hashmap_t& normalized_axes_location,
-                                              const hb_hashmap_t& axes_triple_distances)
+                                              const hb_hashmap_t& axes_triple_distances,
+                                              hb_alloc_pool_t *pool = nullptr)
     {
       /* sort axis_tag/axis_limits, make result deterministic */
       hb_vector_t axis_tags;
@@ -1050,6 +1127,10 @@ struct TupleVariationData
       for (auto t : normalized_axes_location.keys ())
         axis_tags.push (t);
 
+      // Reused vectors for reduced malloc pressure.
+      rebase_tent_result_scratch_t scratch;
+      hb_vector_t out;
+
       axis_tags.qsort (_cmp_axis_tag);
       for (auto axis_tag : axis_tags)
       {
@@ -1061,9 +1142,10 @@ struct TupleVariationData
           axis_triple_distances = axes_triple_distances.get (axis_tag);
 
         hb_vector_t new_vars;
-        for (const tuple_delta_t& var : tuple_vars)
+        for (tuple_delta_t& var : tuple_vars)
         {
-          hb_vector_t out = var.change_tuple_var_axis_limit (axis_tag, *axis_limit, axis_triple_distances);
+          // This may move var out.
+          var.change_tuple_var_axis_limit (axis_tag, *axis_limit, axis_triple_distances, out, scratch, pool);
           if (!out) continue;
 
           unsigned new_len = new_vars.length + out.length;
@@ -1074,7 +1156,6 @@ struct TupleVariationData
           for (unsigned i = 0; i < out.length; i++)
             new_vars.push (std::move (out[i]));
         }
-        tuple_vars.fini ();
         tuple_vars = std::move (new_vars);
       }
       return true;
@@ -1085,9 +1166,12 @@ struct TupleVariationData
     bool merge_tuple_variations (contour_point_vector_t* contour_points = nullptr)
     {
       hb_vector_t new_vars;
+      // The pre-allocation is essential for address stability of pointers
+      // we store in the hashmap.
+      if (unlikely (!new_vars.alloc (tuple_vars.length)))
+        return false;
       hb_hashmap_t*, unsigned> m;
-      unsigned i = 0;
-      for (const tuple_delta_t& var : tuple_vars)
+      for (tuple_delta_t& var : tuple_vars)
       {
         /* if all axes are pinned, drop the tuple variation */
         if (var.axis_tuples.is_empty ())
@@ -1107,13 +1191,17 @@ struct TupleVariationData
         }
         else
         {
-          new_vars.push (var);
-          if (!m.set (&(var.axis_tuples), i))
+          auto *new_var = new_vars.push ();
+          if (unlikely (new_vars.in_error ()))
+            return false;
+          hb_swap (*new_var, var);
+          if (unlikely (!m.set (&(new_var->axis_tuples), new_vars.length - 1)))
             return false;
-          i++;
         }
       }
-      tuple_vars.fini ();
+      m.fini (); // Just in case, since it points into new_vars data.
+                 // Shouldn't be necessary though, since we only move new_vars, not its
+                 // contents.
       tuple_vars = std::move (new_vars);
       return true;
     }
@@ -1173,20 +1261,22 @@ struct TupleVariationData
       }
     }
 
-    bool calc_inferred_deltas (const contour_point_vector_t& contour_points)
+    bool calc_inferred_deltas (const contour_point_vector_t& contour_points,
+                               hb_vector_t &scratch)
     {
       for (tuple_delta_t& var : tuple_vars)
-        if (!var.calc_inferred_deltas (contour_points))
+        if (!var.calc_inferred_deltas (contour_points, scratch))
           return false;
 
       return true;
     }
 
-    bool iup_optimize (const contour_point_vector_t& contour_points)
+    bool iup_optimize (const contour_point_vector_t& contour_points,
+                       optimize_scratch_t &scratch)
     {
       for (tuple_delta_t& var : tuple_vars)
       {
-        if (!var.optimize (contour_points, is_composite))
+        if (!var.optimize (contour_points, is_composite, scratch))
           return false;
       }
       return true;
@@ -1195,16 +1285,21 @@ struct TupleVariationData
     public:
     bool instantiate (const hb_hashmap_t& normalized_axes_location,
                       const hb_hashmap_t& axes_triple_distances,
+                      optimize_scratch_t &scratch,
+                      hb_alloc_pool_t *pool = nullptr,
                       contour_point_vector_t* contour_points = nullptr,
                       bool optimize = false)
     {
       if (!tuple_vars) return true;
-      if (!change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances))
+      if (!change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances, pool))
         return false;
       /* compute inferred deltas only for gvar */
       if (contour_points)
-        if (!calc_inferred_deltas (*contour_points))
+      {
+        hb_vector_t scratch;
+        if (!calc_inferred_deltas (*contour_points, scratch))
           return false;
+      }
 
       /* if iup delta opt is on, contour_points can't be null */
       if (optimize && !contour_points)
@@ -1213,7 +1308,7 @@ struct TupleVariationData
       if (!merge_tuple_variations (optimize ? contour_points : nullptr))
         return false;
 
-      if (optimize && !iup_optimize (*contour_points)) return false;
+      if (optimize && !iup_optimize (*contour_points, scratch)) return false;
       return !tuple_vars.in_error ();
     }
 
@@ -1221,7 +1316,8 @@ struct TupleVariationData
                         const hb_map_t& axes_old_index_tag_map,
                         bool use_shared_points,
                         bool is_gvar = false,
-                        const hb_hashmap_t*, unsigned>* shared_tuples_idx_map = nullptr)
+                        const hb_hashmap_t*, unsigned>* shared_tuples_idx_map = nullptr,
+                        hb_alloc_pool_t *pool = nullptr)
     {
       // return true for empty glyph
       if (!tuple_vars)
@@ -1241,6 +1337,7 @@ struct TupleVariationData
         if (shared_points_bytes)
           compiled_byte_size += shared_points_bytes->length;
       }
+      hb_vector_t rounded_deltas_scratch;
       // compile delta and tuple var header for each tuple variation
       for (auto& tuple: tuple_vars)
       {
@@ -1254,12 +1351,13 @@ struct TupleVariationData
          * this tuple */
         if (!points_data->length)
           continue;
-        if (!tuple.compile_deltas ())
+        if (!tuple.compile_deltas (rounded_deltas_scratch, pool))
           return false;
 
         unsigned points_data_length = (points_data != shared_points_bytes) ? points_data->length : 0;
         if (!tuple.compile_tuple_var_header (axes_index_map, points_data_length, axes_old_index_tag_map,
-                                             shared_tuples_idx_map))
+                                             shared_tuples_idx_map,
+                                             pool))
           return false;
         compiled_byte_size += tuple.compiled_tuple_header.length + points_data_length + tuple.compiled_deltas.length;
       }
@@ -1330,8 +1428,9 @@ struct TupleVariationData
     {
       var_data_bytes = var_data_bytes_;
       var_data = var_data_bytes_.as ();
-      index = 0;
+      tuples_left = var_data->tupleVarCount.get_count ();
       axis_count = axis_count_;
+      axis_count_times_2 = axis_count_ * 2;
       current_tuple = &var_data->get_tuple_var_header ();
       data_offset = 0;
       table_base = table_base_;
@@ -1349,30 +1448,42 @@ struct TupleVariationData
       return true;
     }
 
-    bool is_valid () const
+    bool is_valid ()
     {
-      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)));
+      if (unlikely (tuples_left <= 0))
+        return false;
+
+      current_tuple_size = TupleVariationHeader::min_size;
+      if (unlikely (!var_data_bytes.check_end ((const char *) current_tuple + current_tuple_size)))
+        return false;
+
+      current_tuple_size = current_tuple->get_size (axis_count_times_2);
+      if (unlikely (!var_data_bytes.check_end ((const char *) current_tuple + current_tuple_size)))
+        return false;
+
+      return true;
     }
 
+    HB_ALWAYS_INLINE
     bool move_to_next ()
     {
       data_offset += current_tuple->get_data_size ();
-      current_tuple = ¤t_tuple->get_next (axis_count);
-      index++;
+      current_tuple = &StructAtOffset (current_tuple, current_tuple_size);
+      tuples_left--;
       return is_valid ();
     }
 
+    // TODO: Make it return (sanitized) hb_bytes_t
     const HBUINT8 *get_serialized_data () const
     { return &(table_base+var_data->data) + data_offset; }
 
     private:
+    signed tuples_left;
     const TupleVariationData *var_data;
-    unsigned int index;
     unsigned int axis_count;
+    unsigned int axis_count_times_2;
     unsigned int data_offset;
+    unsigned int current_tuple_size;
     const void *table_base;
 
     public:
@@ -1411,7 +1522,7 @@ struct TupleVariationData
       if (unlikely (p + 1 > end)) return false;
       count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++;
     }
-    if (unlikely (!points.resize (count, false))) return false;
+    if (unlikely (!points.resize_dirty  (count))) return false;
 
     unsigned n = 0;
     unsigned i = 0;
@@ -1446,12 +1557,14 @@ struct TupleVariationData
   }
 
   template 
+  HB_ALWAYS_INLINE
   static bool decompile_deltas (const HBUINT8 *&p /* IN/OUT */,
                                 hb_vector_t &deltas /* IN/OUT */,
                                 const HBUINT8 *end,
-                                bool consume_all = false)
+                                bool consume_all = false,
+                                unsigned start = 0)
   {
-    return TupleValues::decompile (p, deltas, end, consume_all);
+    return TupleValues::decompile (p, deltas, end, consume_all, start);
   }
 
   bool has_data () const { return tupleVarCount; }
@@ -1463,6 +1576,7 @@ struct TupleVariationData
                                    const hb_vector_t &shared_indices,
                                    const hb_array_t shared_tuples,
                                    tuple_variations_t& tuple_variations, /* OUT */
+                                   hb_alloc_pool_t *pool = nullptr,
                                    bool is_composite_glyph = false) const
   {
     return tuple_variations.create_from_tuple_var_data (iterator, tupleVarCount,
@@ -1470,6 +1584,7 @@ struct TupleVariationData
                                                         axes_old_index_tag_map,
                                                         shared_indices,
                                                         shared_tuples,
+                                                        pool,
                                                         is_composite_glyph);
   }
 
@@ -1634,8 +1749,9 @@ struct item_variations_t
   bool instantiate_tuple_vars (const hb_hashmap_t& normalized_axes_location,
                                const hb_hashmap_t& axes_triple_distances)
   {
+    optimize_scratch_t scratch;
     for (tuple_variations_t& tuple_vars : vars)
-      if (!tuple_vars.instantiate (normalized_axes_location, axes_triple_distances))
+      if (!tuple_vars.instantiate (normalized_axes_location, axes_triple_distances, scratch))
         return false;
 
     if (!build_region_list ()) return false;
@@ -1720,30 +1836,28 @@ struct item_variations_t
 
   struct combined_gain_idx_tuple_t
   {
-    int gain;
-    unsigned idx_1;
-    unsigned idx_2;
+    uint64_t encoded;
 
     combined_gain_idx_tuple_t () = default;
-    combined_gain_idx_tuple_t (int gain_, unsigned i, unsigned j)
-        :gain (gain_), idx_1 (i), idx_2 (j) {}
+    combined_gain_idx_tuple_t (unsigned gain, unsigned i, unsigned j)
+        : encoded ((uint64_t (0xFFFFFF - gain) << 40) | (uint64_t (i) << 20) | uint64_t (j))
+    {
+      assert (gain < 0xFFFFFF);
+      assert (i < 0xFFFFFFF && j < 0xFFFFFFF);
+    }
 
     bool operator < (const combined_gain_idx_tuple_t& o)
     {
-      if (gain != o.gain)
-        return gain < o.gain;
-
-      if (idx_1 != o.idx_1)
-        return idx_1 < o.idx_1;
-
-      return idx_2 < o.idx_2;
+      return encoded < o.encoded;
     }
 
     bool operator <= (const combined_gain_idx_tuple_t& o)
     {
-      if (*this < o) return true;
-      return gain == o.gain && idx_1 == o.idx_1 && idx_2 == o.idx_2;
+      return encoded <= o.encoded;
     }
+
+    unsigned idx_1 () const { return (encoded >> 20) & 0xFFFFF; };
+    unsigned idx_2 () const { return encoded & 0xFFFFF; };
   };
 
   bool as_item_varstore (bool optimize=true, bool use_no_variation_idx=true)
@@ -1765,9 +1879,9 @@ struct item_variations_t
     hb_hashmap_t*> front_mapping;
     unsigned start_row = 0;
     hb_vector_t encoding_objs;
-    hb_hashmap_t, unsigned> chars_idx_map;
 
     /* delta_rows map, used for filtering out duplicate rows */
+    hb_vector_t *> major_rows;
     hb_hashmap_t*, unsigned> delta_rows_map;
     for (unsigned major = 0; major < vars.length; major++)
     {
@@ -1775,6 +1889,9 @@ struct item_variations_t
        * (row based) delta */
       const tuple_variations_t& tuples = vars[major];
       unsigned num_rows = var_data_num_rows[major];
+
+      if (!num_rows) continue;
+
       for (const tuple_delta_t& tuple: tuples.tuple_vars)
       {
         if (tuple.deltas_x.length != num_rows)
@@ -1789,24 +1906,11 @@ struct item_variations_t
         {
           int rounded_delta = roundf (tuple.deltas_x[i]);
           delta_rows[start_row + i][*col_idx] += rounded_delta;
-          if ((!has_long) && (rounded_delta < -65536 || rounded_delta > 65535))
-            has_long = true;
+          has_long |= rounded_delta < -65536 || rounded_delta > 65535;
         }
       }
 
-      if (!optimize)
-      {
-        /* assemble a delta_row_encoding_t for this subtable, skip optimization so
-         * chars is not initialized, we only need delta rows for serialization */
-        delta_row_encoding_t obj;
-        for (unsigned r = start_row; r < start_row + num_rows; r++)
-          obj.add_row (&(delta_rows.arrayZ[r]));
-
-        encodings.push (std::move (obj));
-        start_row += num_rows;
-        continue;
-      }
-
+      major_rows.reset ();
       for (unsigned minor = 0; minor < num_rows; minor++)
       {
         const hb_vector_t& row = delta_rows[start_row + minor];
@@ -1828,42 +1932,40 @@ struct item_variations_t
         if (!front_mapping.set ((major<<16) + minor, &row))
           return false;
 
-        hb_vector_t chars = delta_row_encoding_t::get_row_chars (row);
-        if (!chars) return false;
-
         if (delta_rows_map.has (&row))
           continue;
 
         delta_rows_map.set (&row, 1);
-        unsigned *obj_idx;
-        if (chars_idx_map.has (chars, &obj_idx))
-        {
-          delta_row_encoding_t& obj = encoding_objs[*obj_idx];
-          if (!obj.add_row (&row))
-            return false;
-        }
-        else
-        {
-          if (!chars_idx_map.set (chars, encoding_objs.length))
-            return false;
-          delta_row_encoding_t obj (std::move (chars), &row);
-          encoding_objs.push (std::move (obj));
-        }
+
+        major_rows.push (&row);
       }
 
+      if (major_rows)
+        encoding_objs.push (delta_row_encoding_t (std::move (major_rows), num_cols));
+
       start_row += num_rows;
     }
 
     /* return directly if no optimization, maintain original VariationIndex so
      * varidx_map would be empty */
-    if (!optimize) return !encodings.in_error ();
+    if (!optimize)
+    {
+      encodings = std::move (encoding_objs);
+      return !encodings.in_error ();
+    }
+
+    /* NOTE: Fonttools instancer always optimizes VarStore from scratch. This
+     * is too costly for large fonts. So, instead, we retain the encodings of
+     * the original VarStore, and just try to combine them if possible. This
+     * is a compromise between optimization and performance and practically
+     * works very well. */
 
-    /* sort encoding_objs */
+    // This produces slightly smaller results in some cases.
     encoding_objs.qsort ();
 
-    /* main algorithm: repeatedly pick 2 best encodings to combine, and combine
-     * them */
-    hb_priority_queue_t queue;
+    /* main algorithm: repeatedly pick 2 best encodings to combine, and combine them */
+    using item_t = hb_priority_queue_t::item_t;
+    hb_vector_t queue_items;
     unsigned num_todos = encoding_objs.length;
     for (unsigned i = 0; i < num_todos; i++)
     {
@@ -1871,16 +1973,18 @@ struct item_variations_t
       {
         int combining_gain = encoding_objs.arrayZ[i].gain_from_merging (encoding_objs.arrayZ[j]);
         if (combining_gain > 0)
-          queue.insert (combined_gain_idx_tuple_t (-combining_gain, i, j), 0);
+          queue_items.push (item_t (combined_gain_idx_tuple_t (combining_gain, i, j), 0));
       }
     }
 
-    hb_set_t removed_todo_idxes;
+    hb_priority_queue_t queue (std::move (queue_items));
+
+    hb_bit_set_t removed_todo_idxes;
     while (queue)
     {
       auto t = queue.pop_minimum ().first;
-      unsigned i = t.idx_1;
-      unsigned j = t.idx_2;
+      unsigned i = t.idx_1 ();
+      unsigned j = t.idx_2 ();
 
       if (removed_todo_idxes.has (i) || removed_todo_idxes.has (j))
         continue;
@@ -1891,40 +1995,36 @@ struct item_variations_t
       removed_todo_idxes.add (i);
       removed_todo_idxes.add (j);
 
-      hb_vector_t combined_chars;
-      if (!combined_chars.alloc (encoding.chars.length))
-        return false;
-
-      for (unsigned idx = 0; idx < encoding.chars.length; idx++)
-      {
-        uint8_t v = hb_max (encoding.chars.arrayZ[idx], other_encoding.chars.arrayZ[idx]);
-        combined_chars.push (v);
-      }
-
-      delta_row_encoding_t combined_encoding_obj (std::move (combined_chars));
-      for (const auto& row : hb_concat (encoding.items, other_encoding.items))
-        combined_encoding_obj.add_row (row);
+      encoding.merge (other_encoding);
 
       for (unsigned idx = 0; idx < encoding_objs.length; idx++)
       {
         if (removed_todo_idxes.has (idx)) continue;
 
         const delta_row_encoding_t& obj = encoding_objs.arrayZ[idx];
-        if (obj.chars == combined_chars)
+        // In the unlikely event that the same encoding exists already, combine it.
+        if (obj.width == encoding.width && obj.chars == encoding.chars)
         {
+          // This is straight port from fonttools algorithm. I added this branch there
+          // because I thought it can happen. But looks like we never get in here in
+          // practice. I'm not confident enough to remove it though; in theory it can
+          // happen. I think it's just that our tests are not extensive enough to hit
+          // this path.
+
           for (const auto& row : obj.items)
-            combined_encoding_obj.add_row (row);
+            encoding.add_row (row);
 
           removed_todo_idxes.add (idx);
           continue;
         }
 
-        int combined_gain = combined_encoding_obj.gain_from_merging (obj);
+        int combined_gain = encoding.gain_from_merging (obj);
         if (combined_gain > 0)
-          queue.insert (combined_gain_idx_tuple_t (-combined_gain, idx, encoding_objs.length), 0);
+          queue.insert (combined_gain_idx_tuple_t (combined_gain, idx, encoding_objs.length), 0);
       }
 
-      encoding_objs.push (std::move (combined_encoding_obj));
+      auto moved_encoding = std::move (encoding);
+      encoding_objs.push (moved_encoding);
     }
 
     int num_final_encodings = (int) encoding_objs.length - (int) removed_todo_idxes.get_population ();
@@ -1937,9 +2037,6 @@ struct item_variations_t
       encodings.push (std::move (encoding_objs.arrayZ[i]));
     }
 
-    /* sort again based on width, make result deterministic */
-    encodings.qsort (delta_row_encoding_t::cmp_width);
-
     return compile_varidx_map (front_mapping);
   }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-cvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-cvar-table.hh
index 3dc4ebaebd8..d8f497d5346 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-cvar-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-cvar-table.hh
@@ -84,7 +84,7 @@ struct cvar
     if (!coords) return true;
     hb_vector_t shared_indices;
     TupleVariationData<>::tuple_iterator_t iterator;
-    unsigned var_data_length = tuple_var_data->get_size (axis_count);
+    unsigned var_data_length = tuple_var_data->get_size (axis_count * 2);
     hb_bytes_t var_data_bytes = hb_bytes_t (reinterpret_cast (tuple_var_data), var_data_length);
     if (!TupleVariationData<>::get_tuple_iterator (var_data_bytes, axis_count, base,
                                                  shared_indices, &iterator))
@@ -113,7 +113,7 @@ struct cvar
 
       bool apply_to_all = (indices.length == 0);
       unsigned num_deltas = apply_to_all ? num_cvt_item : indices.length;
-      if (unlikely (!unpacked_deltas.resize (num_deltas, false))) return false;
+      if (unlikely (!unpacked_deltas.resize_dirty  (num_deltas))) return false;
       if (unlikely (!TupleVariationData<>::decompile_deltas (p, unpacked_deltas, end))) return false;
 
       for (unsigned int i = 0; i < num_deltas; i++)
@@ -158,7 +158,8 @@ struct cvar
                                      tuple_variations))
       return_trace (false);
 
-    if (!tuple_variations.instantiate (c->plan->axes_location, c->plan->axes_triple_distances))
+    optimize_scratch_t scratch;
+    if (!tuple_variations.instantiate (c->plan->axes_location, c->plan->axes_triple_distances, scratch))
       return_trace (false);
 
     if (!tuple_variations.compile_bytes (c->plan->axes_index_map, c->plan->axes_old_index_tag_map,
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 f2725eaa282..74d392de9b7 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
@@ -179,7 +179,7 @@ struct AxisRecord
 
   hb_tag_t get_axis_tag () const { return axisTag; }
 
-  int normalize_axis_value (float v) const
+  float normalize_axis_value (float v) const
   {
     float min_value, default_value, max_value;
     get_coordinates (min_value, default_value, max_value);
@@ -189,23 +189,9 @@ struct AxisRecord
     if (v == default_value)
       return 0;
     else if (v < default_value)
-      v = (v - default_value) / (default_value - min_value);
+      return (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;
+      return (v - default_value) / (max_value - default_value);
   }
 
   hb_ot_name_id_t get_name_id () const { return axisNameID; }
@@ -341,12 +327,9 @@ struct fvar
     return axes.lfind (tag, &i) && ((void) axes[i].get_axis_info (i, info), true);
   }
 
-  int normalize_axis_value (unsigned int axis_index, float v) const
+  float normalize_axis_value (unsigned int axis_index, float v) const
   { return get_axes ()[axis_index].normalize_axis_value (v); }
 
-  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; }
 
   hb_ot_name_id_t get_instance_subfamily_name_id (unsigned int instance_index) const
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
index 9f9b5be3cbe..7c42f548456 100644
--- 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
@@ -66,12 +66,14 @@ struct glyph_variations_t
 
   hb_vector_t glyph_variations;
 
-  hb_vector_t compiled_shared_tuples;
+  hb_vector_t compiled_shared_tuples;
   private:
   unsigned shared_tuples_count = 0;
 
   /* shared coords-> index map after instantiation */
-  hb_hashmap_t*, unsigned> shared_tuples_idx_map;
+  hb_hashmap_t*, unsigned> shared_tuples_idx_map;
+
+  hb_alloc_pool_t pool;
 
   public:
   unsigned compiled_shared_tuples_count () const
@@ -128,6 +130,7 @@ struct glyph_variations_t
                                           iterator, &(plan->axes_old_index_tag_map),
                                           shared_indices, shared_tuples,
                                           tuple_vars, /* OUT */
+                                          &pool,
                                           is_composite_glyph))
         return false;
       glyph_variations.push (std::move (tuple_vars));
@@ -139,6 +142,7 @@ struct glyph_variations_t
   {
     unsigned count = plan->new_to_old_gid_list.length;
     bool iup_optimize = false;
+    optimize_scratch_t scratch;
     iup_optimize = plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS;
     for (unsigned i = 0; i < count; i++)
     {
@@ -146,7 +150,7 @@ struct glyph_variations_t
       contour_point_vector_t *all_points;
       if (!plan->new_gid_contour_points_map.has (new_gid, &all_points))
         return false;
-      if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, all_points, iup_optimize))
+      if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, scratch, &pool, all_points, iup_optimize))
         return false;
     }
     return true;
@@ -161,7 +165,8 @@ struct glyph_variations_t
       if (!vars.compile_bytes (axes_index_map, axes_old_index_tag_map,
                                true, /* use shared points*/
                                true,
-                               &shared_tuples_idx_map))
+                               &shared_tuples_idx_map,
+                               &pool))
         return false;
 
     return true;
@@ -172,20 +177,21 @@ struct glyph_variations_t
   {
     /* key is pointer to compiled_peak_coords inside each tuple, hashing
      * function will always deref pointers first */
-    hb_hashmap_t*, unsigned> coords_count_map;
+    hb_hashmap_t*, unsigned> coords_count_map;
 
     /* count the num of shared coords */
     for (tuple_variations_t& vars: glyph_variations)
     {
       for (tuple_delta_t& var : vars.tuple_vars)
       {
-        if (!var.compile_peak_coords (axes_index_map, axes_old_index_tag_map))
+        if (!var.compile_coords (axes_index_map, axes_old_index_tag_map, &pool))
           return false;
-        unsigned* count;
-        if (coords_count_map.has (&(var.compiled_peak_coords), &count))
-          coords_count_map.set (&(var.compiled_peak_coords), *count + 1);
+        unsigned *count;
+        unsigned hash = hb_hash (&var.compiled_peak_coords);
+        if (coords_count_map.has_with_hash (&(var.compiled_peak_coords), hash, &count))
+          (*count)++;
         else
-          coords_count_map.set (&(var.compiled_peak_coords), 1);
+          coords_count_map.set_with_hash (&(var.compiled_peak_coords), hash, 1);
       }
     }
 
@@ -193,66 +199,45 @@ struct glyph_variations_t
       return false;
 
     /* add only those coords that are used more than once into the vector and sort */
-    hb_vector_t*> shared_coords;
-    if (unlikely (!shared_coords.alloc (coords_count_map.get_population ())))
-      return false;
-
-    for (const auto _ : coords_count_map.iter ())
-    {
-      if (_.second == 1) continue;
-      shared_coords.push (_.first);
-    }
+    hb_vector_t*, unsigned>> shared_coords {
+      + hb_iter (coords_count_map)
+      | hb_filter ([] (const hb_pair_t*, unsigned>& p) { return p.second > 1; })
+    };
+    if (unlikely (shared_coords.in_error ())) return false;
 
     /* no shared tuples: no coords are used more than once */
     if (!shared_coords) return true;
     /* sorting based on the coords frequency first (high to low), then compare
      * the coords bytes */
-    hb_qsort (shared_coords.arrayZ, shared_coords.length, sizeof (hb_vector_t*), _cmp_coords, (void *) (&coords_count_map));
+    shared_coords.qsort (_cmp_coords);
 
     /* build shared_coords->idx map and shared tuples byte array */
 
     shared_tuples_count = hb_min (0xFFFu + 1, shared_coords.length);
-    unsigned len = shared_tuples_count * (shared_coords[0]->length);
+    unsigned len = shared_tuples_count * (shared_coords[0].first->length);
     if (unlikely (!compiled_shared_tuples.alloc (len)))
       return false;
 
     for (unsigned i = 0; i < shared_tuples_count; i++)
     {
-      shared_tuples_idx_map.set (shared_coords[i], i);
+      shared_tuples_idx_map.set (shared_coords[i].first, i);
       /* add a concat() in hb_vector_t? */
-      for (char c : shared_coords[i]->iter ())
+      for (auto c : shared_coords[i].first->iter ())
         compiled_shared_tuples.push (c);
     }
 
     return true;
   }
 
-  static int _cmp_coords (const void *pa, const void *pb, void *arg)
+  static int _cmp_coords (const void *pa, const void *pb)
   {
-    const hb_hashmap_t*, unsigned>* coords_count_map =
-        reinterpret_cast*, unsigned>*> (arg);
-
-    /* shared_coords is hb_vector_t*> so casting pa/pb
-     * to be a pointer to a pointer */
-    const hb_vector_t** a = reinterpret_cast**> (const_cast(pa));
-    const hb_vector_t** b = reinterpret_cast**> (const_cast(pb));
-
-    bool has_a = coords_count_map->has (*a);
-    bool has_b = coords_count_map->has (*b);
-
-    if (has_a && has_b)
-    {
-      unsigned a_num = coords_count_map->get (*a);
-      unsigned b_num = coords_count_map->get (*b);
+    const hb_pair_t *, unsigned> *a = (const hb_pair_t *, unsigned> *) pa;
+    const hb_pair_t *, unsigned> *b = (const hb_pair_t *, unsigned> *) pb;
 
-      if (a_num != b_num)
-        return b_num - a_num;
+    if (a->second != b->second)
+      return b->second - a->second; // high to low
 
-      return (*b)->as_array().cmp ((*a)->as_array ());
-    }
-    else if (has_a) return -1;
-    else if (has_b) return 1;
-    else return 0;
+    return b->first->as_array().cmp (a->first->as_array ());
   }
 
   templatesharedTuples = 0;
     else
     {
-      hb_array_t shared_tuples = glyph_vars.compiled_shared_tuples.as_array ().copy (c);
+      hb_array_t shared_tuples = glyph_vars.compiled_shared_tuples.as_array ().copy (c);
       if (!shared_tuples.arrayZ) return_trace (false);
-      out->sharedTuples = shared_tuples.arrayZ - (char *) out;
+      out->sharedTuples = (const char *) shared_tuples.arrayZ - (char *) out;
     }
 
     char *glyph_var_data = c->start_embed ();
@@ -463,10 +448,18 @@ struct gvar_GVAR
     if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
       it++;
     unsigned int subset_data_size = 0;
+    unsigned padding_size = 0;
     for (auto &_ : it)
     {
       hb_codepoint_t old_gid = _.second;
-      subset_data_size += get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length;
+      unsigned glyph_data_size = get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length;
+      if (glyph_data_size % 2)
+      {
+        glyph_data_size++;
+        padding_size++;
+      }
+
+      subset_data_size += glyph_data_size;
     }
 
     /* According to the spec: If the short format (Offset16) is used for offsets,
@@ -495,6 +488,8 @@ struct gvar_GVAR
 
     /* This ordering relative to the shared tuples array, which puts the glyphVariationData
        last in the table, is required when HB_SUBSET_FLAGS_IFTB_REQUIREMENTS is set */
+    if (long_offset)
+      subset_data_size -= padding_size;
     char *subset_data = c->serializer->allocate_size (subset_data_size, false);
     if (!subset_data) return_trace (false);
     out->dataZ = subset_data - (char *) out;
@@ -533,8 +528,16 @@ struct gvar_GVAR
                                                             old_gid);
 
       hb_memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length);
-      subset_data += var_data_bytes.length;
-      glyph_offset += var_data_bytes.length;
+      unsigned glyph_data_size = var_data_bytes.length;
+      subset_data += glyph_data_size;
+      glyph_offset += glyph_data_size;
+
+      if (!long_offset && (glyph_data_size % 2))
+      {
+        *subset_data = 0;
+        subset_data++;
+        glyph_offset++;
+      }
 
       if (long_offset)
         ((HBUINT32 *) subset_offsets)[gid] = glyph_offset;
@@ -582,6 +585,17 @@ struct gvar_GVAR
   public:
   struct accelerator_t
   {
+
+    hb_scalar_cache_t *create_cache () const
+    {
+      return hb_scalar_cache_t::create (table->sharedTupleCount);
+    }
+
+    static void destroy_cache (hb_scalar_cache_t *cache)
+    {
+      hb_scalar_cache_t::destroy (cache);
+    }
+
     bool has_data () const { return table->has_data (); }
 
     accelerator_t (hb_face_t *face)
@@ -589,36 +603,6 @@ struct gvar_GVAR
       table = hb_sanitize_context_t ().reference_table (face);
       /* If sanitize failed, set glyphCount to 0. */
       glyphCount = table->version.to_int () ? face->get_num_glyphs () : 0;
-
-      /* For shared tuples that only have one or two axes active, shared the index
-       * of that axis as a cache. This will speed up caclulate_scalar() a lot
-       * for fonts with lots of axes and many "monovar" or "duovar" tuples. */
-      hb_array_t shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount);
-      unsigned count = table->sharedTupleCount;
-      if (unlikely (!shared_tuple_active_idx.resize (count, false))) return;
-      unsigned axis_count = table->axisCount;
-      for (unsigned i = 0; i < count; i++)
-      {
-        hb_array_t tuple = shared_tuples.sub_array (axis_count * i, axis_count);
-        int idx1 = -1, idx2 = -1;
-        for (unsigned j = 0; j < axis_count; j++)
-        {
-          const F2DOT14 &peak = tuple.arrayZ[j];
-          if (peak.to_int () != 0)
-          {
-            if (idx1 == -1)
-              idx1 = j;
-            else if (idx2 == -1)
-              idx2 = j;
-            else
-            {
-              idx1 = idx2 = -1;
-              break;
-            }
-          }
-        }
-        shared_tuple_active_idx.arrayZ[i] = {idx1, idx2};
-      }
     }
     ~accelerator_t () { table.destroy (); }
 
@@ -655,6 +639,7 @@ struct gvar_GVAR
                                  hb_array_t coords,
                                  const hb_array_t points,
                                  hb_glyf_scratch_t &scratch,
+                                 hb_scalar_cache_t *gvar_cache = nullptr,
                                  bool phantom_only = false) const
     {
       if (unlikely (glyph >= glyphCount)) return true;
@@ -690,10 +675,12 @@ struct gvar_GVAR
 
       unsigned count = points.length;
       bool flush = false;
+
       do
       {
         float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples,
-                                                                 &shared_tuple_active_idx);
+                                                                 gvar_cache);
+
         if (scalar == 0.f) continue;
         const HBUINT8 *p = iterator.get_serialized_data ();
         unsigned int length = iterator.current_tuple->get_data_size ();
@@ -702,7 +689,7 @@ struct gvar_GVAR
 
         if (!deltas)
         {
-          if (unlikely (!deltas_vec.resize (count, false))) return false;
+          if (unlikely (!deltas_vec.resize_dirty  (count))) return false;
           deltas = deltas_vec.as_array ();
           hb_memset (deltas.arrayZ + (phantom_only ? count - 4 : 0), 0,
                      (phantom_only ? 4 : count) * sizeof (deltas[0]));
@@ -717,11 +704,12 @@ struct gvar_GVAR
         const hb_array_t &indices = has_private_points ? private_indices : shared_indices;
 
         bool apply_to_all = (indices.length == 0);
-        unsigned int num_deltas = apply_to_all ? points.length : indices.length;
-        if (unlikely (!x_deltas.resize (num_deltas, false))) return false;
-        if (unlikely (!GlyphVariationData::decompile_deltas (p, x_deltas, end))) return false;
-        if (unlikely (!y_deltas.resize (num_deltas, false))) return false;
-        if (unlikely (!GlyphVariationData::decompile_deltas (p, y_deltas, end))) return false;
+        unsigned num_deltas = apply_to_all ? points.length : indices.length;
+        unsigned start_deltas = (apply_to_all && phantom_only && num_deltas >= 4 ? num_deltas - 4 : 0);
+        if (unlikely (!x_deltas.resize_dirty  (num_deltas))) return false;
+        if (unlikely (!GlyphVariationData::decompile_deltas (p, x_deltas, end, false, start_deltas))) return false;
+        if (unlikely (!y_deltas.resize_dirty  (num_deltas))) return false;
+        if (unlikely (!GlyphVariationData::decompile_deltas (p, y_deltas, end, false, start_deltas))) return false;
 
         if (!apply_to_all)
         {
@@ -884,7 +872,6 @@ struct gvar_GVAR
     private:
     hb_blob_ptr_t table;
     unsigned glyphCount;
-    hb_vector_t> shared_tuple_active_idx;
   };
 
   protected:
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 40a85a62b78..652d738e7b5 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
@@ -42,57 +42,62 @@ struct index_map_subset_plan_t
     VORG_INDEX
   };
 
-  void init (const DeltaSetIndexMap  &index_map,
+  void init (const DeltaSetIndexMap  *index_map,
              hb_inc_bimap_t          &outer_map,
              hb_vector_t &inner_sets,
              const hb_subset_plan_t  *plan,
              bool bypass_empty = true)
   {
     map_count = 0;
-    outer_bit_count = 0;
-    inner_bit_count = 1;
     max_inners.init ();
     output_map.init ();
 
-    if (bypass_empty && !index_map.get_map_count ()) return;
+    if (bypass_empty && (!index_map || !index_map->get_map_count ())) return;
 
     unsigned int        last_val = (unsigned int)-1;
     hb_codepoint_t      last_gid = HB_CODEPOINT_INVALID;
 
-    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 */
     auto &new_to_old_gid_list = plan->new_to_old_gid_list;
     unsigned count = new_to_old_gid_list.length;
-    for (unsigned j = count; j; j--)
+    if (!index_map)
     {
-      hb_codepoint_t gid = new_to_old_gid_list.arrayZ[j - 1].first;
-      hb_codepoint_t old_gid = new_to_old_gid_list.arrayZ[j - 1].second;
-
-      unsigned int v = index_map.map (old_gid);
-      if (last_gid == HB_CODEPOINT_INVALID)
+      map_count = new_to_old_gid_list.tail ().first + 1;
+    }
+    else
+    {
+      for (unsigned j = count; j; j--)
       {
+        hb_codepoint_t gid = new_to_old_gid_list.arrayZ[j - 1].first;
+        hb_codepoint_t old_gid = new_to_old_gid_list.arrayZ[j - 1].second;
+
+        unsigned int v = index_map->map (old_gid);
+        if (last_gid == HB_CODEPOINT_INVALID)
+        {
         last_val = v;
         last_gid = gid;
         continue;
-      }
-      if (v != last_val)
+        }
+        if (v != last_val)
         break;
 
-      last_gid = gid;
+        last_gid = gid;
+      }
+
+      if (unlikely (last_gid == (hb_codepoint_t)-1)) return;
+      map_count = last_gid + 1;
     }
 
-    if (unlikely (last_gid == (hb_codepoint_t)-1)) return;
-    map_count = last_gid + 1;
     for (auto _ : plan->new_to_old_gid_list)
     {
       hb_codepoint_t gid = _.first;
       if (gid >= map_count) break;
 
       hb_codepoint_t old_gid = _.second;
-      unsigned int v = index_map.map (old_gid);
+      unsigned int v = index_map ? index_map->map (old_gid): old_gid;
       unsigned int outer = v >> 16;
       unsigned int inner = v & 0xFFFF;
       outer_map.add (outer);
@@ -113,6 +118,9 @@ struct index_map_subset_plan_t
               const hb_vector_t &inner_maps,
               const hb_subset_plan_t *plan)
   {
+    outer_bit_count = 1;
+    inner_bit_count = 1;
+
     for (unsigned int i = 0; i < max_inners.length; i++)
     {
       if (inner_maps[i].get_population () == 0) continue;
@@ -128,9 +136,13 @@ struct index_map_subset_plan_t
 
       if (unlikely (new_gid >= map_count)) break;
 
-      uint32_t v = input_map->map (old_gid);
-      unsigned int outer = v >> 16;
-      output_map.arrayZ[new_gid] = (outer_map[outer] << 16) | (inner_maps[outer][v & 0xFFFF]);
+      uint32_t v = input_map? input_map->map (old_gid) : old_gid;
+      unsigned outer = v >> 16;
+      unsigned new_outer = outer_map[outer];
+      unsigned bit_count = (new_outer == 0) ? 1 : hb_bit_storage (new_outer);
+      outer_bit_count = hb_max (bit_count, outer_bit_count);
+
+      output_map.arrayZ[new_gid] = (new_outer << 16) | (inner_maps[outer][v & 0xFFFF]);
     }
   }
 
@@ -204,8 +216,8 @@ struct hvarvvar_subset_plan_t
     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, false);
-    if (index_maps[0] == &Null (DeltaSetIndexMap))
+    index_map_plans[0].init (index_maps[0], outer_map, inner_sets, plan, false);
+    if (!index_maps[0])
     {
       retain_adv_map = plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS;
       outer_map.add (0);
@@ -215,7 +227,7 @@ struct hvarvvar_subset_plan_t
     }
 
     for (unsigned int i = 1; i < index_maps.length; i++)
-      index_map_plans[i].init (*index_maps[i], outer_map, inner_sets, plan);
+      index_map_plans[i].init (index_maps[i], outer_map, inner_sets, plan);
 
     outer_map.sort ();
 
@@ -284,6 +296,8 @@ struct HVARVVAR
   static constexpr hb_tag_t HVARTag = HB_OT_TAG_HVAR;
   static constexpr hb_tag_t VVARTag = HB_OT_TAG_VVAR;
 
+  bool has_data () const { return version.major != 0; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -301,9 +315,14 @@ struct HVARVVAR
 
   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));
+    if (advMap) index_maps.push (&(this+advMap));
+    else index_maps.push (nullptr);
+
+    if (lsbMap) index_maps.push (&(this+lsbMap));
+    else index_maps.push (nullptr);
+
+    if (rsbMap) index_maps.push (&(this+rsbMap));
+    else index_maps.push (nullptr);
   }
 
   bool serialize_index_maps (hb_serialize_context_t *c,
@@ -382,9 +401,10 @@ struct HVARVVAR
                                                 hvar_plan.index_map_plans.as_array ()));
   }
 
+  HB_ALWAYS_INLINE
   float get_advance_delta_unscaled (hb_codepoint_t  glyph,
                                     const int *coords, unsigned int coord_count,
-                                    ItemVariationStore::cache_t *store_cache = nullptr) const
+                                    hb_scalar_cache_t *store_cache = nullptr) const
   {
     uint32_t varidx = (this+advMap).map (glyph);
     return (this+varStore).get_delta (varidx,
@@ -392,16 +412,6 @@ struct HVARVVAR
                                       store_cache);
   }
 
-  bool get_lsb_delta_unscaled (hb_codepoint_t glyph,
-                               const int *coords, unsigned int coord_count,
-                               float *lsb) const
-  {
-    if (!lsbMap) return false;
-    uint32_t varidx = (this+lsbMap).map (glyph);
-    *lsb = (this+varStore).get_delta (varidx, coords, coord_count);
-    return true;
-  }
-
   public:
   FixedVersion<>version;        /* Version of the metrics variation table
                                  * initially set to 0x00010000u */
@@ -435,7 +445,8 @@ struct VVAR : HVARVVAR {
   void listup_index_maps (hb_vector_t &index_maps) const
   {
     HVARVVAR::listup_index_maps (index_maps);
-    index_maps.push (&(this+vorgMap));
+    if (vorgMap) index_maps.push (&(this+vorgMap));
+    else index_maps.push (nullptr);
   }
 
   bool serialize_index_maps (hb_serialize_context_t *c,
@@ -454,14 +465,16 @@ struct VVAR : HVARVVAR {
 
   bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset (c); }
 
-  bool get_vorg_delta_unscaled (hb_codepoint_t glyph,
-                                const int *coords, unsigned int coord_count,
-                                float *delta) const
+  HB_ALWAYS_INLINE
+  float get_vorg_delta_unscaled (hb_codepoint_t glyph,
+                                 const int *coords, unsigned int coord_count,
+                                 hb_scalar_cache_t *store_cache = nullptr) const
   {
-    if (!vorgMap) return false;
+    if (!vorgMap) return 0.f;
     uint32_t varidx = (this+vorgMap).map (glyph);
-    *delta = (this+varStore).get_delta (varidx, coords, coord_count);
-    return true;
+    return (this+varStore).get_delta (varidx,
+                                      coords, coord_count,
+                                      store_cache);
   }
 
   protected:
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 8c695c41e24..4d594d587d8 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc
@@ -286,10 +286,14 @@ hb_ot_var_normalize_variations (hb_face_t            *face,
     hb_ot_var_axis_info_t info;
     if (hb_ot_var_find_axis_info (face, variations[i].tag, &info) &&
         info.axis_index < coords_length)
-      coords[info.axis_index] = fvar.normalize_axis_value (info.axis_index, variations[i].value);
+      coords[info.axis_index] = roundf (fvar.normalize_axis_value (info.axis_index, variations[i].value) * 65536.0f);
   }
 
-  face->table.avar->map_coords (coords, coords_length);
+  face->table.avar->map_coords_16_16 (coords, coords_length);
+
+  // Round to 2.14
+  for (unsigned i = 0; i < coords_length; i++)
+    coords[i] = (coords[i] + 2) >> 2;
 }
 
 /**
@@ -309,6 +313,10 @@ hb_ot_var_normalize_variations (hb_face_t            *face,
  * Any additional scaling defined in the face's `avar` table is also
  * applied, as described at https://docs.microsoft.com/en-us/typography/opentype/spec/avar
  *
+ * Note: @coords_length must be the same as the number of axes in the face, as
+ * for example returned by hb_ot_var_get_axis_count().
+ * Otherwise, the behavior is undefined.
+ *
  * Since: 1.4.2
  **/
 void
@@ -319,9 +327,13 @@ hb_ot_var_normalize_coords (hb_face_t    *face,
 {
   const OT::fvar &fvar = *face->table.fvar;
   for (unsigned int i = 0; i < coords_length; i++)
-    normalized_coords[i] = fvar.normalize_axis_value (i, design_coords[i]);
+    normalized_coords[i] = roundf (fvar.normalize_axis_value (i, design_coords[i]) * 65536.0f);
+
+  face->table.avar->map_coords_16_16 (normalized_coords, coords_length);
 
-  face->table.avar->map_coords (normalized_coords, coords_length);
+  // Round to 2.14
+  for (unsigned i = 0; i < coords_length; i++)
+    normalized_coords[i] = (normalized_coords[i] + 2) >> 2;
 }
 
 
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 b2300a327da..ff7ce678e4e 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
@@ -61,6 +61,7 @@ struct VORG
 
   bool has_data () const { return version.to_int (); }
 
+  HB_ALWAYS_INLINE
   int get_y_origin (hb_codepoint_t glyph) const
   {
     unsigned int i;
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-outline.cc b/src/java.desktop/share/native/libharfbuzz/hb-outline.cc
index 85ffc793678..12963fe46e3 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-outline.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-outline.cc
@@ -84,6 +84,15 @@ void hb_outline_t::replay (hb_draw_funcs_t *pen, void *pen_data) const
   }
 }
 
+void hb_outline_t::translate (float dx, float dy)
+{
+  for (auto &p : points)
+  {
+    p.x += dx;
+    p.y += dy;
+  }
+}
+
 void hb_outline_t::slant (float slant_xy)
 {
   for (auto &p : points)
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-outline.hh b/src/java.desktop/share/native/libharfbuzz/hb-outline.hh
index c5b68c05dd7..9e394a68d9c 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-outline.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-outline.hh
@@ -69,6 +69,7 @@ struct hb_outline_t
 
   HB_INTERNAL void replay (hb_draw_funcs_t *pen, void *pen_data) const;
   HB_INTERNAL float control_area () const;
+  HB_INTERNAL void translate (float dx, float dy);
   HB_INTERNAL void slant (float slant_xy);
   HB_INTERNAL void embolden (float x_strength, float y_strength,
                              float x_shift, float y_shift);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc b/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc
index bc08c5a9e14..e867f37f3c5 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc
@@ -49,7 +49,7 @@ hb_paint_extents_push_transform (hb_paint_funcs_t *funcs HB_UNUSED,
 {
   hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
 
-  c->push_transform (hb_transform_t {xx, yx, xy, yy, dx, dy});
+  c->push_transform (hb_transform_t<> {xx, yx, xy, yy, dx, dy});
 }
 
 static void
@@ -71,7 +71,7 @@ hb_paint_extents_push_clip_glyph (hb_paint_funcs_t *funcs HB_UNUSED,
 {
   hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
 
-  hb_extents_t extents;
+  hb_extents_t<> extents;
   hb_draw_funcs_t *draw_extent_funcs = hb_draw_extents_get_funcs ();
   hb_font_draw_glyph (font, glyph, draw_extent_funcs, &extents);
   c->push_clip (extents);
@@ -85,7 +85,7 @@ hb_paint_extents_push_clip_rectangle (hb_paint_funcs_t *funcs HB_UNUSED,
 {
   hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
 
-  hb_extents_t extents = {xmin, ymin, xmax, ymax};
+  hb_extents_t<> extents = {xmin, ymin, xmax, ymax};
   c->push_clip (extents);
 }
 
@@ -136,10 +136,10 @@ hb_paint_extents_paint_image (hb_paint_funcs_t *funcs HB_UNUSED,
   if (!glyph_extents)
     return false; // Happens with SVG images.
 
-  hb_extents_t extents = {(float) glyph_extents->x_bearing,
-                          (float) glyph_extents->y_bearing + glyph_extents->height,
-                          (float) glyph_extents->x_bearing + glyph_extents->width,
-                          (float) glyph_extents->y_bearing};
+  hb_extents_t<> extents = {(float) glyph_extents->x_bearing,
+                            (float) glyph_extents->y_bearing + glyph_extents->height,
+                            (float) glyph_extents->x_bearing + glyph_extents->width,
+                            (float) glyph_extents->y_bearing};
   c->push_clip (extents);
   c->paint ();
   c->pop_clip ();
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh b/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh
index 60374eaa2d2..531eb3c7c52 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh
@@ -41,9 +41,9 @@ struct hb_paint_extents_context_t
     clips.clear ();
     groups.clear ();
 
-    transforms.push (hb_transform_t{});
-    clips.push (hb_bounds_t{hb_bounds_t::UNBOUNDED});
-    groups.push (hb_bounds_t{hb_bounds_t::EMPTY});
+    transforms.push (hb_transform_t<>{});
+    clips.push (hb_bounds_t<>{hb_bounds_t<>::UNBOUNDED});
+    groups.push (hb_bounds_t<>{hb_bounds_t<>::EMPTY});
   }
 
   hb_paint_extents_context_t ()
@@ -51,19 +51,19 @@ struct hb_paint_extents_context_t
     clear ();
   }
 
-  hb_extents_t get_extents ()
+  hb_extents_t<> get_extents ()
   {
     return groups.tail().extents;
   }
 
   bool is_bounded ()
   {
-    return groups.tail().status != hb_bounds_t::UNBOUNDED;
+    return groups.tail().status != hb_bounds_t<>::UNBOUNDED;
   }
 
-  void push_transform (const hb_transform_t &trans)
+  void push_transform (const hb_transform_t<> &trans)
   {
-    hb_transform_t t = transforms.tail ();
+    hb_transform_t<> t = transforms.tail ();
     t.multiply (trans);
     transforms.push (t);
   }
@@ -73,13 +73,13 @@ struct hb_paint_extents_context_t
     transforms.pop ();
   }
 
-  void push_clip (hb_extents_t extents)
+  void push_clip (hb_extents_t<> extents)
   {
     /* Transform extents and push a new clip. */
-    const hb_transform_t &t = transforms.tail ();
+    const hb_transform_t<> &t = transforms.tail ();
     t.transform_extents (extents);
 
-    auto bounds = hb_bounds_t {extents};
+    auto bounds = hb_bounds_t<> {extents};
     bounds.intersect (clips.tail ());
 
     clips.push (bounds);
@@ -92,19 +92,19 @@ struct hb_paint_extents_context_t
 
   void push_group ()
   {
-    groups.push (hb_bounds_t {hb_bounds_t::EMPTY});
+    groups.push (hb_bounds_t<> {hb_bounds_t<>::EMPTY});
   }
 
   void pop_group (hb_paint_composite_mode_t mode)
   {
-    const hb_bounds_t src_bounds = groups.pop ();
-    hb_bounds_t &backdrop_bounds = groups.tail ();
+    const hb_bounds_t<> src_bounds = groups.pop ();
+    hb_bounds_t<> &backdrop_bounds = groups.tail ();
 
     // https://learn.microsoft.com/en-us/typography/opentype/spec/colr#format-32-paintcomposite
     switch ((int) mode)
     {
       case HB_PAINT_COMPOSITE_MODE_CLEAR:
-        backdrop_bounds.status = hb_bounds_t::EMPTY;
+        backdrop_bounds.status = hb_bounds_t<>::EMPTY;
         break;
       case HB_PAINT_COMPOSITE_MODE_SRC:
       case HB_PAINT_COMPOSITE_MODE_SRC_OUT:
@@ -125,16 +125,16 @@ struct hb_paint_extents_context_t
 
   void paint ()
   {
-    const hb_bounds_t &clip = clips.tail ();
-    hb_bounds_t &group = groups.tail ();
+    const hb_bounds_t<> &clip = clips.tail ();
+    hb_bounds_t<> &group = groups.tail ();
 
     group.union_ (clip);
   }
 
   protected:
-  hb_vector_t transforms;
-  hb_vector_t clips;
-  hb_vector_t groups;
+  hb_vector_t> transforms;
+  hb_vector_t> clips;
+  hb_vector_t> groups;
 };
 
 HB_INTERNAL hb_paint_funcs_t *
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-paint.hh b/src/java.desktop/share/native/libharfbuzz/hb-paint.hh
index 2abadebab3c..aedbcbdcbe2 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-paint.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-paint.hh
@@ -28,6 +28,7 @@
 #include "hb.hh"
 #include "hb-face.hh"
 #include "hb-font.hh"
+#include "hb-geometry.hh"
 
 #define HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS \
   HB_PAINT_FUNC_IMPLEMENT (push_transform) \
@@ -72,7 +73,11 @@ struct hb_paint_funcs_t
                        float xx, float yx,
                        float xy, float yy,
                        float dx, float dy)
-  { func.push_transform (this, paint_data,
+  {
+    // Handle -0.f to avoid -0.f == 0.f in the transform matrix.
+    if (dx == -0.f) dx = 0.f;
+    if (dy == -0.f) dy = 0.f;
+    func.push_transform (this, paint_data,
                          xx, yx, xy, yy, dx, dy,
                          !user_data ? nullptr : user_data->push_transform); }
   void pop_transform (void *paint_data)
@@ -182,54 +187,59 @@ struct hb_paint_funcs_t
                     0, 0);
   }
 
-  HB_NODISCARD
-  bool push_translate (void *paint_data,
-                       float dx, float dy)
+  void push_transform (void *paint_data, hb_transform_t t)
   {
-    if (!dx && !dy)
-      return false;
+    push_transform (paint_data, t.xx, t.yx, t.xy, t.yy, t.x0, t.y0);
+  }
 
+  void push_translate (void *paint_data,
+                       float dx, float dy)
+  {
     push_transform (paint_data,
-                    1.f, 0.f, 0.f, 1.f, dx, dy);
-    return true;
+                    hb_transform_t::translation (dx, dy));
   }
 
-  HB_NODISCARD
-  bool push_scale (void *paint_data,
+  void push_scale (void *paint_data,
                    float sx, float sy)
   {
-    if (sx == 1.f && sy == 1.f)
-      return false;
-
     push_transform (paint_data,
-                    sx, 0.f, 0.f, sy, 0.f, 0.f);
-    return true;
+                    hb_transform_t::scaling (sx, sy));
+  }
+  void push_scale_around_center (void *paint_data,
+                                 float sx, float sy,
+                                 float cx, float cy)
+  {
+    push_transform (paint_data,
+                    hb_transform_t::scaling_around_center (sx, sy, cx, cy));
   }
 
-  HB_NODISCARD
-  bool push_rotate (void *paint_data,
+  void push_rotate (void *paint_data,
                     float a)
   {
-    if (!a)
-      return false;
+    push_transform (paint_data,
+                    hb_transform_t::rotation (a * HB_PI));
+  }
 
-    float cc = cosf (a * HB_PI);
-    float ss = sinf (a * HB_PI);
-    push_transform (paint_data, cc, ss, -ss, cc, 0.f, 0.f);
-    return true;
+  void push_rotate_around_center (void *paint_data,
+                                  float a,
+                                  float cx, float cy)
+  {
+    push_transform (paint_data,
+                    hb_transform_t::rotation_around_center (a * HB_PI, cx, cy));
   }
 
-  HB_NODISCARD
-  bool push_skew (void *paint_data,
+  void push_skew (void *paint_data,
                   float sx, float sy)
   {
-    if (!sx && !sy)
-      return false;
-
-    float x = tanf (-sx * HB_PI);
-    float y = tanf (+sy * HB_PI);
-    push_transform (paint_data, 1.f, y, x, 1.f, 0.f, 0.f);
-    return true;
+    push_transform (paint_data,
+                    hb_transform_t::skewing (-sx * HB_PI, sy * HB_PI));
+  }
+  void push_skew_around_center (void *paint_data,
+                                float sx, float sy,
+                                float cx, float cy)
+  {
+    push_transform (paint_data,
+                    hb_transform_t::skewing_around_center (-sx * HB_PI, sy * HB_PI, cx, cy));
   }
 };
 DECLARE_NULL_INSTANCE (hb_paint_funcs_t);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-priority-queue.hh b/src/java.desktop/share/native/libharfbuzz/hb-priority-queue.hh
index 274d5df4c54..753e86b8ca6 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-priority-queue.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-priority-queue.hh
@@ -45,12 +45,22 @@
 template 
 struct hb_priority_queue_t
 {
- private:
+ public:
   typedef hb_pair_t item_t;
+
+ private:
   hb_vector_t heap;
 
  public:
 
+  hb_priority_queue_t () = default;
+  hb_priority_queue_t (hb_vector_t&& other) : heap (std::move (other))
+  {
+    // Heapify the vector.
+    for (int i = (heap.length / 2) - 1; i >= 0; i--)
+      bubble_down (i);
+  }
+
   void reset () { heap.resize (0); }
 
   bool in_error () const { return heap.in_error (); }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-repacker.hh b/src/java.desktop/share/native/libharfbuzz/hb-repacker.hh
index cb4fdeead2e..7d118b52169 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-repacker.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-repacker.hh
@@ -217,11 +217,17 @@ bool _try_isolating_subgraphs (const hb_vector_t& over
   unsigned maximum_to_move = hb_max ((sorted_graph.num_roots_for_space (space) / 2u), 1u);
   if (roots_to_isolate.get_population () > maximum_to_move) {
     // Only move at most half of the roots in a space at a time.
-    unsigned extra = roots_to_isolate.get_population () - maximum_to_move;
-    while (extra--) {
-      uint32_t root = HB_SET_VALUE_INVALID;
-      roots_to_isolate.previous (&root);
-      roots_to_isolate.del (root);
+    //
+    // Note: this was ported from non-stable ids to stable ids. So to retain the same behaviour
+    // with regards to which roots are removed from the set we need to remove them in the topological
+    // order, not the object id order.
+    int extra = roots_to_isolate.get_population () - maximum_to_move;
+    for (unsigned id : sorted_graph.ordering_) {
+      if (!extra) break;
+      if (roots_to_isolate.has(id)) {
+        roots_to_isolate.del(id);
+        extra--;
+      }
     }
   }
 
@@ -266,7 +272,7 @@ bool _resolve_shared_overflow(const hb_vector_t& overf
     result = sorted_graph.duplicate(&parents, r.child);
   }
 
-  if (result == (unsigned) -1) return result;
+  if (result == (unsigned) -1) return false;
 
   if (parents.get_population() > 1) {
     // If the duplicated node has more than one parent pre-emptively raise it's priority to the maximum.
@@ -283,7 +289,7 @@ bool _resolve_shared_overflow(const hb_vector_t& overf
     sorted_graph.vertices_[result].give_max_priority();
   }
 
-  return result;
+  return true;
 }
 
 static inline
@@ -302,8 +308,11 @@ bool _process_overflows (const hb_vector_t& overflows,
     {
       // The child object is shared, we may be able to eliminate the overflow
       // by duplicating it.
-      if (!_resolve_shared_overflow(overflows, i, sorted_graph)) continue;
-      return true;
+      if (_resolve_shared_overflow(overflows, i, sorted_graph))
+        return true;
+
+      // Sometimes we can't duplicate a node which looks shared because it's not actually shared
+      // (eg. all links from the same parent) in this case continue on to other resolution options.
     }
 
     if (child.is_leaf () && !priority_bumped_parents.has (r.parent))
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-sanitize.hh b/src/java.desktop/share/native/libharfbuzz/hb-sanitize.hh
index 1f8ba32bae2..1e9ee9ba960 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-sanitize.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-sanitize.hh
@@ -64,9 +64,6 @@
  *
  *   - 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.
  *
  *
@@ -98,6 +95,12 @@
  * 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.
+ *
+ * Note:
+ * Sanitize was named so because it used to try to recover from errors by
+ * modifying the data to make it valid.  This is no longer the case, as it
+ * could make HarfBuzz hallucinate new rules if there was aliasing in the
+ * data.  However, the name stuck.  See: https://behdad.github.io/harfbust/
  */
 
 /* This limits sanitizing time on really broken fonts. */
@@ -120,12 +123,12 @@
 struct hb_sanitize_context_t :
        hb_dispatch_context_t
 {
-  hb_sanitize_context_t () :
-        start (nullptr), end (nullptr),
+  hb_sanitize_context_t (const char *start_ = nullptr, const char *end_ = nullptr) :
+        start (start_), end (end_),
         length (0),
         max_ops (0), max_subtables (0),
         recursion_depth (0),
-        writable (false), edit_count (0),
+        writable (false),
         blob (nullptr),
         num_glyphs (65536),
         num_glyphs_set (false),
@@ -212,14 +215,22 @@ struct hb_sanitize_context_t :
 
   void reset_object ()
   {
-    this->start = this->blob->data;
-    this->end = this->start + this->blob->length;
+    if (this->blob)
+    {
+      this->start = this->blob->data;
+      this->end = this->start + this->blob->length;
+    }
     this->length = this->end - this->start;
     assert (this->start <= this->end); /* Must not overflow. */
   }
 
-  void start_processing ()
+  void start_processing (const char *start_ = nullptr, const char *end_ = nullptr)
   {
+    if (start_)
+    {
+      this->start = start_;
+      this->end = end_;
+    }
     reset_object ();
     unsigned m;
     if (unlikely (hb_unsigned_mul_overflows (this->end - this->start, HB_SANITIZE_MAX_OPS_FACTOR, &m)))
@@ -228,7 +239,6 @@ struct hb_sanitize_context_t :
       this->max_ops = hb_clamp (m,
                                 (unsigned) HB_SANITIZE_MAX_OPS_MIN,
                                 (unsigned) HB_SANITIZE_MAX_OPS_MAX);
-    this->edit_count = 0;
     this->debug_depth = 0;
     this->recursion_depth = 0;
 
@@ -241,8 +251,8 @@ struct hb_sanitize_context_t :
   void end_processing ()
   {
     DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1,
-                     "end [%p..%p] %u edit requests",
-                     this->start, this->end, this->edit_count);
+                     "end [%p..%p]",
+                     this->start, this->end);
 
     hb_blob_destroy (this->blob);
     this->blob = nullptr;
@@ -250,9 +260,6 @@ struct hb_sanitize_context_t :
     this->length = 0;
   }
 
-  unsigned get_edit_count () { return edit_count; }
-
-
   bool check_ops(unsigned count)
   {
     /* Avoid underflow */
@@ -396,35 +403,6 @@ struct hb_sanitize_context_t :
       return likely (this->check_point ((const char *) 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] (%u 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)
   {
@@ -432,7 +410,6 @@ struct hb_sanitize_context_t :
 
     init (blob);
 
-  retry:
     DEBUG_MSG_FUNC (SANITIZE, start, "start");
 
     start_processing ();
@@ -446,36 +423,6 @@ struct hb_sanitize_context_t :
     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 %u 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 %u edits in second round; FAILING", 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 ();
 
@@ -506,7 +453,6 @@ struct hb_sanitize_context_t :
   private:
   int recursion_depth;
   bool writable;
-  unsigned int edit_count;
   hb_blob_t *blob;
   unsigned int num_glyphs;
   bool  num_glyphs_set;
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-script-list.h b/src/java.desktop/share/native/libharfbuzz/hb-script-list.h
index f811dbc3408..16347b9d84e 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-script-list.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-script-list.h
@@ -223,6 +223,10 @@ HB_END_DECLS
  * @HB_SCRIPT_SUNUWAR: `Sunu`, Since: 10.0.0
  * @HB_SCRIPT_TODHRI: `Todr`, Since: 10.0.0
  * @HB_SCRIPT_TULU_TIGALARI: `Tutg`, Since: 10.0.0
+ * @HB_SCRIPT_BERIA_ERFE: `Berf`, Since: 11.5.0
+ * @HB_SCRIPT_SIDETIC: `Sidt`, Since: 11.5.0
+ * @HB_SCRIPT_TAI_YO: `Tayo`, Since: 11.5.0
+ * @HB_SCRIPT_TOLONG_SIKI: `Tols`, Since: 11.5.0
  * @HB_SCRIPT_INVALID: No script set
  *
  * Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
@@ -461,6 +465,14 @@ typedef enum
   HB_SCRIPT_TODHRI                      = HB_TAG ('T','o','d','r'), /*16.0*/
   HB_SCRIPT_TULU_TIGALARI               = HB_TAG ('T','u','t','g'), /*16.0*/
 
+  /*
+   * Since 11.5.0
+   */
+  HB_SCRIPT_BERIA_ERFE                  = HB_TAG ('B','e','r','f'), /*17.0*/
+  HB_SCRIPT_SIDETIC                     = HB_TAG ('S','i','d','t'), /*17.0*/
+  HB_SCRIPT_TAI_YO                      = HB_TAG ('T','a','y','o'), /*17.0*/
+  HB_SCRIPT_TOLONG_SIKI                 = HB_TAG ('T','o','l','s'), /*17.0*/
+
   /* No script set. */
   HB_SCRIPT_INVALID                     = HB_TAG_NONE,
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh b/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh
index 704d0ffd12b..9fe99c85ea7 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh
@@ -34,7 +34,7 @@
 #include "hb.hh"
 #include "hb-blob.hh"
 #include "hb-map.hh"
-#include "hb-pool.hh"
+#include "hb-free-pool.hh"
 
 #include "hb-subset-serialize.h"
 
@@ -724,7 +724,7 @@ struct hb_serialize_context_t
            hb_requires (hb_is_iterator (Iterator)),
            typename ...Ts>
   void copy_all (Iterator it, Ts&&... ds)
-  { for (decltype (*it) _ : it) copy (_, std::forward (ds)...); }
+  { for (decltype (*it) _ : it) copy (_, ds...); }
 
   template 
   hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; }
@@ -794,7 +794,8 @@ struct hb_serialize_context_t
   template 
   void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset)
   {
-    auto &off = * ((BEInt *) (parent->head + link.position));
+    // XXX We should stop assuming big-endian!
+    auto &off = * ((HBInt *) (parent->head + link.position));
     assert (0 == off);
     check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW);
   }
@@ -814,7 +815,7 @@ struct hb_serialize_context_t
   }
 
   /* Object memory pool. */
-  hb_pool_t object_pool;
+  hb_free_pool_t object_pool;
 
   /* Stack of currently under construction objects. */
   object_t *current;
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-set-digest.hh b/src/java.desktop/share/native/libharfbuzz/hb-set-digest.hh
index f0416d5fa1d..f8cb0998260 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-set-digest.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-set-digest.hh
@@ -55,11 +55,11 @@
  *   - For each glyph, if it doesn't match the subtable digest,
  *     skip it.
  *
- * The main filter we use is a combination of four bits-pattern
+ * The filter we use is a combination of three bits-pattern
  * filters. A bits-pattern filter checks a number of bits (5 or 6)
- * of the input number (glyph-id in this case) and checks whether
+ * of the input number (glyph-id in most cases) and checks whether
  * its pattern is amongst the patterns of any of the accepted values.
- * The accepted patterns are represented as a "long" integer. The
+ * The accepted patterns are represented as a "long" integer. Each
  * check is done using four bitwise operations only.
  */
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shape.cc b/src/java.desktop/share/native/libharfbuzz/hb-shape.cc
index d14f577be00..a36fa14fb28 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-shape.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-shape.cc
@@ -149,14 +149,11 @@ hb_shape_full (hb_font_t          *font,
 
   hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
 
-  if (buffer->max_ops <= 0)
-    buffer->shaping_failed = true;
-
   hb_shape_plan_destroy (shape_plan);
 
   if (text_buffer)
   {
-    if (res && buffer->successful && !buffer->shaping_failed
+    if (res && buffer->successful
             && text_buffer->successful
             && !buffer->verify (text_buffer,
                                 font,
@@ -199,6 +196,7 @@ hb_shape (hb_font_t           *font,
 
 
 #ifdef HB_EXPERIMENTAL_API
+#ifndef HB_NO_VAR
 
 static float
 buffer_advance (hb_buffer_t *buffer)
@@ -440,7 +438,7 @@ hb_shape_justify (hb_font_t          *font,
 
   return true;
 }
-
+#endif
 #endif
 
 
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 f079caf4d35..cb386f26827 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-shaper-list.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-shaper-list.hh
@@ -57,6 +57,14 @@ HB_SHAPER_IMPLEMENT (directwrite)
 HB_SHAPER_IMPLEMENT (coretext)
 #endif
 
+#ifdef HAVE_HARFRUST
+HB_SHAPER_IMPLEMENT (harfrust)
+#endif
+
+#ifdef HAVE_KBTS
+HB_SHAPER_IMPLEMENT (kbts)
+#endif
+
 #ifndef HB_NO_FALLBACK_SHAPE
 HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */
 #endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-static.cc b/src/java.desktop/share/native/libharfbuzz/hb-static.cc
index 4e70e413651..06cc80b5f38 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-static.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-static.cc
@@ -113,27 +113,4 @@ hb_face_t::load_upem () const
   return ret;
 }
 
-
-#ifndef HB_NO_VAR
-bool
-_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical,
-                                             int *lsb)
-{
-  return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb);
-}
-
-unsigned
-_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
-{
-  return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical);
-}
-#endif
-
-bool
-_glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb)
-{
-  return face->table.glyf->get_leading_bearing_without_var_unscaled (gid, is_vertical, lsb);
-}
-
-
 #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 9d00cae6c32..51413b6da44 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-string-array.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-string-array.hh
@@ -45,25 +45,25 @@ static const union HB_STRING_ARRAY_TYPE_NAME {
  * but C++ does not allow that.
  * https://stackoverflow.com/q/28433862
  */
-#define _S(s) char HB_PASTE (str, __LINE__)[sizeof (s)];
+#define HB_STR(s) char HB_PASTE (str, __LINE__)[sizeof (s)];
 #include HB_STRING_ARRAY_LIST
-#undef _S
+#undef HB_STR
   } st;
   char str[HB_VAR_ARRAY];
 }
 HB_STRING_ARRAY_POOL_NAME =
 {
   {
-#define _S(s) s,
+#define HB_STR(s) s,
 #include HB_STRING_ARRAY_LIST
-#undef _S
+#undef HB_STR
   }
 };
 static const unsigned int HB_STRING_ARRAY_OFFS_NAME[] =
 {
-#define _S(s) offsetof (union HB_STRING_ARRAY_TYPE_NAME, st.HB_PASTE(str, __LINE__)),
+#define HB_STR(s) offsetof (union HB_STRING_ARRAY_TYPE_NAME, st.HB_PASTE(str, __LINE__)),
 #include HB_STRING_ARRAY_LIST
-#undef _S
+#undef HB_STR
   sizeof (HB_STRING_ARRAY_TYPE_NAME)
 };
 
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 e7bddaef723..843ad69f2f9 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
@@ -861,8 +861,7 @@ struct subr_subsetter_t
         {
           // Hack to point vector to static string.
           auto &b = buffArray.arrayZ[last];
-          b.length = 1;
-          b.arrayZ = const_cast(endchar_str);
+          b.set_storage (const_cast(endchar_str), 1);
         }
 
       last++; // Skip over gid
@@ -877,8 +876,7 @@ struct subr_subsetter_t
       {
         // Hack to point vector to static string.
         auto &b = buffArray.arrayZ[last];
-        b.length = 1;
-        b.arrayZ = const_cast(endchar_str);
+        b.set_storage (const_cast(endchar_str), 1);
       }
 
     return true;
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-iup.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-iup.hh
index 01987bd258d..8ee02c07dbe 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-iup.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-iup.hh
@@ -26,12 +26,27 @@
 #define HB_SUBSET_INSTANCER_IUP_HH
 
 #include "hb-subset-plan.hh"
+
+struct iup_scratch_t
+{
+  hb_vector_t end_points;
+  hb_vector_t interp_x_deltas;
+  hb_vector_t interp_y_deltas;
+  hb_vector_t costs;
+  hb_vector_t chain;
+  hb_vector_t rot_indices;
+  hb_vector_t rot_x_deltas;
+  hb_vector_t rot_y_deltas;
+  contour_point_vector_t rot_points;
+};
+
 /* given contour points and deltas, optimize a set of referenced points within error
  * tolerance. Returns optimized referenced point indices */
 HB_INTERNAL bool iup_delta_optimize (const contour_point_vector_t& contour_points,
                                      const hb_vector_t& x_deltas,
                                      const hb_vector_t& y_deltas,
                                      hb_vector_t& opt_indices, /* OUT */
+                                     iup_scratch_t &scratch,
                                      double tolerance = 0.0);
 
 #endif /* HB_SUBSET_INSTANCER_IUP_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.cc
index c67fee421c2..15227bdab48 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.cc
@@ -62,9 +62,10 @@ static inline double supportScalar (double coord, const Triple &tent)
     return  (end - coord) / (end - peak);
 }
 
-static inline rebase_tent_result_t
-_solve (Triple tent, Triple axisLimit, bool negative = false)
+static inline void
+_solve (Triple tent, Triple axisLimit, rebase_tent_result_t &out, bool negative = false)
 {
+  out.reset();
   double axisMin = axisLimit.minimum;
   double axisDef = axisLimit.middle;
   double axisMax = axisLimit.maximum;
@@ -75,14 +76,12 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
   // Mirror the problem such that axisDef <= peak
   if (axisDef > peak)
   {
-    rebase_tent_result_t vec = _solve (_reverse_negate (tent),
-                           _reverse_negate (axisLimit),
-                           !negative);
+    _solve (_reverse_negate (tent), _reverse_negate (axisLimit), out, !negative);
 
-    for (auto &p : vec)
+    for (auto &p : out)
       p = hb_pair (p.first, _reverse_negate (p.second));
 
-    return vec;
+    return;
   }
   // axisDef <= peak
 
@@ -98,7 +97,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
    *    axisMin     axisDef    axisMax   lower     upper
    */
   if (axisMax <= lower && axisMax < peak)
-      return rebase_tent_result_t{};  // No overlap
+      return;  // No overlap
 
   /* case 2: Only the peak and outermost bound fall outside the new limit;
    * we keep the deltaset, update peak and outermost bound and scale deltas
@@ -133,18 +132,18 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
     double mult = supportScalar (axisMax, tent);
     tent = Triple{lower, axisMax, axisMax};
 
-    rebase_tent_result_t vec = _solve (tent, axisLimit);
+    _solve (tent, axisLimit, out);
 
-    for (auto &p : vec)
+    for (auto &p : out)
       p = hb_pair (p.first * mult, p.second);
 
-    return vec;
+    return;
   }
 
   // lower <= axisDef <= peak <= axisMax
 
   double gain = supportScalar (axisDef, tent);
-  rebase_tent_result_t out {hb_pair (gain, Triple{})};
+  out.push(hb_pair (gain, Triple{}));
 
   // First, the positive side
 
@@ -362,8 +361,6 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
     out.push (hb_pair (scalar1 - gain, loc1));
     out.push (hb_pair (scalar2 - gain, loc2));
   }
-
-  return out;
 }
 
 static inline TripleDistances _reverse_triple_distances (const TripleDistances &v)
@@ -405,18 +402,21 @@ double renormalizeValue (double v, const Triple &triple,
   return (-v_distance) /total_distance;
 }
 
-rebase_tent_result_t
-rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances)
+void
+rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances,
+             rebase_tent_result_t &out,
+             rebase_tent_result_t &scratch)
 {
   assert (-1.0 <= axisLimit.minimum && axisLimit.minimum <= axisLimit.middle && axisLimit.middle <= axisLimit.maximum && axisLimit.maximum <= +1.0);
   assert (-2.0 <= tent.minimum && tent.minimum <= tent.middle && tent.middle <= tent.maximum && tent.maximum <= +2.0);
   assert (tent.middle != 0.0);
 
-  rebase_tent_result_t sols = _solve (tent, axisLimit);
+  rebase_tent_result_t &sols = scratch;
+  _solve (tent, axisLimit, sols);
 
   auto n = [&axisLimit, &axis_triple_distances] (double v) { return renormalizeValue (v, axisLimit, axis_triple_distances); };
 
-  rebase_tent_result_t out;
+  out.reset();
   for (auto &p : sols)
   {
     if (!p.first) continue;
@@ -429,6 +429,4 @@ rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distance
     out.push (hb_pair (p.first,
                        Triple{n (t.minimum), n (t.middle), n (t.maximum)}));
   }
-
-  return out;
 }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.hh
index 9764dcc1725..574d58d53d8 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.hh
@@ -42,10 +42,9 @@ struct TripleDistances
   double positive;
 };
 
-struct Triple {
-
-  Triple () :
-    minimum (0.0), middle (0.0), maximum (0.0) {}
+struct Triple
+{
+  Triple () = default;
 
   Triple (double minimum_, double middle_, double maximum_) :
     minimum (minimum_), middle (middle_), maximum (maximum_) {}
@@ -81,10 +80,9 @@ struct Triple {
     return current;
   }
 
-
-  double minimum;
-  double middle;
-  double maximum;
+  double minimum = 0;
+  double middle = 0;
+  double maximum = 0;
 };
 
 using rebase_tent_result_item_t = hb_pair_t;
@@ -107,8 +105,10 @@ HB_INTERNAL double renormalizeValue (double v, const Triple &triple,
  * If tent value is Triple{}, that is a special deltaset that should
  * be always-enabled (called "gain").
  */
-HB_INTERNAL rebase_tent_result_t rebase_tent (Triple tent,
-                                              Triple axisLimit,
-                                              TripleDistances axis_triple_distances);
+HB_INTERNAL void rebase_tent (Triple tent,
+                              Triple axisLimit,
+                              TripleDistances axis_triple_distances,
+                              rebase_tent_result_t &out,
+                              rebase_tent_result_t &scratch);
 
 #endif /* HB_SUBSET_INSTANCER_SOLVER_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan-member-list.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan-member-list.hh
index ade8278c40f..398fe81eca9 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan-member-list.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan-member-list.hh
@@ -81,6 +81,10 @@ HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(>), gpo
 HB_SUBSET_PLAN_MEMBER (hb_map_t, gsub_features)
 HB_SUBSET_PLAN_MEMBER (hb_map_t, gpos_features)
 
+//active features(with duplicates) old index -> new index mapping
+HB_SUBSET_PLAN_MEMBER (hb_map_t, gsub_features_w_duplicates)
+HB_SUBSET_PLAN_MEMBER (hb_map_t, gpos_features_w_duplicates)
+
 //active feature variation records/condition index with variations
 HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(>), gsub_feature_record_cond_idx_map)
 HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(>), gpos_feature_record_cond_idx_map)
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 3ba726d925e..8c3fd97899b 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc
@@ -418,7 +418,8 @@ _nameid_closure (hb_subset_plan_t* plan,
                  hb_set_t* drop_tables)
 {
 #ifndef HB_NO_STYLE
-  plan->source->table.STAT->collect_name_ids (&plan->user_axes_location, &plan->name_ids);
+  if (!drop_tables->has (HB_OT_TAG_STAT))
+    plan->source->table.STAT->collect_name_ids (&plan->user_axes_location, &plan->name_ids);
 #endif
 #ifndef HB_NO_VAR
   if (!plan->all_axes_pinned)
@@ -676,7 +677,8 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
     return;
 
 #ifndef HB_NO_VAR
-  normalize_axes_location (face, this);
+  if (!check_success (normalize_axes_location (face, this)))
+      return;
 #endif
 
   _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, this);
@@ -697,6 +699,15 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
     return;
   }
 
+#ifdef HB_EXPERIMENTAL_API
+  if ((input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS) &&
+      (input->flags & HB_SUBSET_FLAGS_RETAIN_NUM_GLYPHS)) {
+    // We've been requested to maintain the num glyphs count from the
+    // input face.
+    _num_output_glyphs = source->get_num_glyphs ();
+  }
+#endif
+
   _create_glyph_map_gsub (
       &_glyphset_gsub,
       glyph_map,
@@ -710,10 +721,10 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
         glyph_map->get(unicode_to_new_gid_list.arrayZ[i].second);
   }
 
-  bounds_width_vec.resize (_num_output_glyphs, false);
+  bounds_width_vec.resize_dirty  (_num_output_glyphs);
   for (auto &v : bounds_width_vec)
     v = 0xFFFFFFFF;
-  bounds_height_vec.resize (_num_output_glyphs, false);
+  bounds_height_vec.resize_dirty  (_num_output_glyphs);
   for (auto &v : bounds_height_vec)
     v = 0xFFFFFFFF;
 
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 8a6574365ed..0362ed7292e 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh
@@ -300,6 +300,7 @@ struct hb_subset_plan_t
 // compile times more reasonable:
 // - hb-subset-plan.cc
 // - hb-subset-plan-layout.cc
+// - hb-subset-plan-var.cc
 //
 // The functions below are those needed to connect the split files
 // above together.
@@ -332,7 +333,7 @@ generate_varstore_inner_maps (const hb_set_t& varidx_set,
                               unsigned subtable_count,
                               hb_vector_t &inner_maps /* OUT */);
 
-HB_INTERNAL void
+HB_INTERNAL bool
 normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan);
 
 HB_INTERNAL void
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset.cc
index 079c94eddfe..51134ed09ce 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset.cc
@@ -25,65 +25,19 @@
  */
 
 #include "hb.hh"
+
 #include "hb-open-type.hh"
+#include "hb-open-file.hh"
 
 #include "hb-subset.hh"
+#include "hb-subset-table.hh"
+#include "hb-subset-accelerator.hh"
 
-#include "hb-open-file.hh"
 #include "hb-ot-cmap-table.hh"
-#include "hb-ot-glyf-table.hh"
-#include "hb-ot-hdmx-table.hh"
-#include "hb-ot-head-table.hh"
-#include "hb-ot-hhea-table.hh"
-#include "hb-ot-hmtx-table.hh"
-#include "hb-ot-maxp-table.hh"
-#include "OT/Color/CBDT/CBDT.hh"
-#include "OT/Color/COLR/COLR.hh"
-#include "OT/Color/CPAL/CPAL.hh"
-#include "OT/Color/sbix/sbix.hh"
-#include "hb-ot-os2-table.hh"
-#include "hb-ot-post-table.hh"
-#include "hb-ot-post-table-v2subset.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-layout-base-table.hh"
-#include "hb-ot-layout-gsub-table.hh"
-#include "hb-ot-layout-gpos-table.hh"
-#include "hb-ot-var-avar-table.hh"
 #include "hb-ot-var-cvar-table.hh"
-#include "hb-ot-var-fvar-table.hh"
-#include "hb-ot-var-gvar-table.hh"
-#include "hb-ot-var-hvar-table.hh"
-#include "hb-ot-var-mvar-table.hh"
-#include "hb-ot-math-table.hh"
+#include "hb-ot-head-table.hh"
 #include "hb-ot-stat-table.hh"
-#include "hb-repacker.hh"
-#include "hb-subset-accelerator.hh"
-
-using OT::Layout::GSUB;
-using OT::Layout::GPOS;
-
-
-#ifndef HB_NO_SUBSET_CFF
-template<>
-struct hb_subset_plan_t::source_table_loader
-{
-  auto operator () (hb_subset_plan_t *plan)
-  HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff1_accel :
-                  plan->inprogress_accelerator ? plan->inprogress_accelerator->cff1_accel :
-                  plan->cff1_accel)
-};
-template<>
-struct hb_subset_plan_t::source_table_loader
-{
-  auto operator () (hb_subset_plan_t *plan)
-  HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff2_accel :
-                  plan->inprogress_accelerator ? plan->inprogress_accelerator->cff2_accel :
-                  plan->cff2_accel)
-};
-#endif
+#include "hb-ot-post-table-v2subset.hh"
 
 
 /**
@@ -116,56 +70,56 @@ hb_user_data_key_t _hb_subset_accelerator_user_data_key = {};
  * if we are unable to list the tables in a face.
  */
 static hb_tag_t known_tables[] {
-  HB_TAG ('a', 'v', 'a', 'r'),
-  HB_OT_TAG_BASE,
-  HB_OT_TAG_CBDT,
-  HB_OT_TAG_CBLC,
-  HB_OT_TAG_CFF1,
-  HB_OT_TAG_CFF2,
-  HB_OT_TAG_cmap,
-  HB_OT_TAG_COLR,
-  HB_OT_TAG_CPAL,
-  HB_TAG ('c', 'v', 'a', 'r'),
-  HB_TAG ('c', 'v', 't', ' '),
-  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 ('f', 'p', 'g', 'm'),
-  HB_TAG ('f', 'v', 'a', 'r'),
-  HB_TAG ('g', 'a', 's', 'p'),
-  HB_OT_TAG_GDEF,
-  HB_OT_TAG_glyf,
-  HB_OT_TAG_GPOS,
-  HB_OT_TAG_GSUB,
-  HB_OT_TAG_gvar,
-  HB_OT_TAG_hdmx,
-  HB_OT_TAG_head,
-  HB_OT_TAG_hhea,
-  HB_OT_TAG_hmtx,
-  HB_OT_TAG_HVAR,
-  HB_OT_TAG_JSTF,
-  HB_TAG ('k', 'e', 'r', 'n'),
-  HB_OT_TAG_loca,
-  HB_TAG ('L', 'T', 'S', 'H'),
-  HB_OT_TAG_MATH,
-  HB_OT_TAG_maxp,
-  HB_TAG ('M', 'E', 'R', 'G'),
-  HB_TAG ('m', 'e', 't', 'a'),
-  HB_TAG ('M', 'V', 'A', 'R'),
-  HB_TAG ('P', 'C', 'L', 'T'),
-  HB_OT_TAG_post,
-  HB_TAG ('p', 'r', 'e', 'p'),
-  HB_OT_TAG_sbix,
-  HB_TAG ('S', 'T', 'A', 'T'),
-  HB_TAG ('S', 'V', 'G', ' '),
-  HB_TAG ('V', 'D', 'M', 'X'),
-  HB_OT_TAG_vhea,
-  HB_OT_TAG_vmtx,
-  HB_OT_TAG_VORG,
-  HB_OT_TAG_VVAR,
-  HB_OT_TAG_name,
-  HB_OT_TAG_OS2
+  HB_TAG('a','v','a','r'),
+  HB_TAG('B','A','S','E'),
+  HB_TAG('C','B','D','T'),
+  HB_TAG('C','B','L','C'),
+  HB_TAG('C','F','F',' '),
+  HB_TAG('C','F','F','2'),
+  HB_TAG('c','m','a','p'),
+  HB_TAG('C','O','L','R'),
+  HB_TAG('C','P','A','L'),
+  HB_TAG('c','v','a','r'),
+  HB_TAG('c','v','t',' '),
+  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('f','p','g','m'),
+  HB_TAG('f','v','a','r'),
+  HB_TAG('g','a','s','p'),
+  HB_TAG('G','D','E','F'),
+  HB_TAG('g','l','y','f'),
+  HB_TAG('G','P','O','S'),
+  HB_TAG('G','S','U','B'),
+  HB_TAG('g','v','a','r'),
+  HB_TAG('h','d','m','x'),
+  HB_TAG('h','e','a','d'),
+  HB_TAG('h','h','e','a'),
+  HB_TAG('h','m','t','x'),
+  HB_TAG('H','V','A','R'),
+  HB_TAG('J','S','T','F'),
+  HB_TAG('k','e','r','n'),
+  HB_TAG('l','o','c','a'),
+  HB_TAG('L','T','S','H'),
+  HB_TAG('M','A','T','H'),
+  HB_TAG('m','a','x','p'),
+  HB_TAG('M','E','R','G'),
+  HB_TAG('m','e','t','a'),
+  HB_TAG('M','V','A','R'),
+  HB_TAG('P','C','L','T'),
+  HB_TAG('p','o','s','t'),
+  HB_TAG('p','r','e','p'),
+  HB_TAG('s','b','i','x'),
+  HB_TAG('S','T','A','T'),
+  HB_TAG('S','V','G',' '),
+  HB_TAG('V','D','M','X'),
+  HB_TAG('v','h','e','a'),
+  HB_TAG('v','m','t','x'),
+  HB_TAG('V','O','R','G'),
+  HB_TAG('V','V','A','R'),
+  HB_TAG('n','a','m','e'),
+  HB_TAG('O','S','/','2')
 };
 
 static bool _table_is_empty (const hb_face_t *face, hb_tag_t tag)
@@ -213,169 +167,6 @@ _get_table_tags (const hb_subset_plan_t* plan,
 }
 
 
-static unsigned
-_plan_estimate_subset_table_size (hb_subset_plan_t *plan,
-                                  unsigned table_len,
-                                  hb_tag_t table_tag)
-{
-  unsigned src_glyphs = plan->source->get_num_glyphs ();
-  unsigned dst_glyphs = plan->glyphset ()->get_population ();
-
-  unsigned bulk = 8192;
-  /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's
-   * because those are expensive to subset, so giving them more room is fine. */
-  bool same_size = table_tag == HB_OT_TAG_GSUB ||
-                   table_tag == HB_OT_TAG_GPOS ||
-                   table_tag == HB_OT_TAG_name;
-
-  if (plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS)
-  {
-    if (table_tag == HB_OT_TAG_CFF1)
-    {
-      /* Add some extra room for the CFF charset. */
-      bulk += src_glyphs * 16;
-    }
-    else if (table_tag == HB_OT_TAG_CFF2)
-    {
-      /* Just extra CharString offsets. */
-      bulk += src_glyphs * 4;
-    }
-  }
-
-  if (unlikely (!src_glyphs) || same_size)
-    return bulk + table_len;
-
-  return bulk + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs));
-}
-
-/*
- * Repack the serialization buffer if any offset overflows exist.
- */
-static hb_blob_t*
-_repack (hb_tag_t tag, const hb_serialize_context_t& c)
-{
-  if (!c.offset_overflow ())
-    return c.copy_blob ();
-
-  hb_blob_t* result = hb_resolve_overflows (c.object_graph (), tag);
-
-  if (unlikely (!result))
-  {
-    DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c offset overflow resolution failed.",
-               HB_UNTAG (tag));
-    return nullptr;
-  }
-
-  return result;
-}
-
-template
-static
-bool
-_try_subset (const TableType *table,
-             hb_vector_t* buf,
-             hb_subset_context_t* c /* OUT */)
-{
-  c->serializer->start_serialize ();
-  if (c->serializer->in_error ()) return false;
-
-  bool needed = table->subset (c);
-  if (!c->serializer->ran_out_of_room ())
-  {
-    c->serializer->end_serialize ();
-    return needed;
-  }
-
-  unsigned buf_size = buf->allocated;
-  buf_size = buf_size * 2 + 16;
-
-
-
-
-  DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.",
-             HB_UNTAG (c->table_tag), buf_size);
-
-  if (unlikely (buf_size > c->source_blob->length * 256 ||
-                !buf->alloc_exact (buf_size)))
-  {
-    DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.",
-               HB_UNTAG (c->table_tag), buf_size);
-    return needed;
-  }
-
-  c->serializer->reset (buf->arrayZ, buf->allocated);
-  return _try_subset (table, buf, c);
-}
-
-template 
-static auto _do_destroy (T &t, hb_priority<1>) HB_RETURN (void, t.destroy ())
-
-template 
-static void _do_destroy (T &t, hb_priority<0>) {}
-
-template
-static bool
-_subset (hb_subset_plan_t *plan, hb_vector_t &buf)
-{
-  auto &&source_blob = plan->source_table ();
-  auto *table = source_blob.get ();
-
-  hb_tag_t tag = TableType::tableTag;
-  hb_blob_t *blob = source_blob.get_blob();
-  if (unlikely (!blob || !blob->data))
-  {
-    DEBUG_MSG (SUBSET, nullptr,
-               "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag));
-    _do_destroy (source_blob, hb_prioritize);
-    return false;
-  }
-
-  unsigned buf_size = _plan_estimate_subset_table_size (plan, blob->length, TableType::tableTag);
-  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);
-    _do_destroy (source_blob, hb_prioritize);
-    return false;
-  }
-
-  bool needed = false;
-  hb_serialize_context_t serializer (buf.arrayZ, buf.allocated);
-  {
-    hb_subset_context_t c (blob, plan, &serializer, tag);
-    needed = _try_subset (table, &buf, &c);
-  }
-  _do_destroy (source_blob, hb_prioritize);
-
-  if (serializer.in_error () && !serializer.only_offset_overflow ())
-  {
-    DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset FAILED!", HB_UNTAG (tag));
-    return false;
-  }
-
-  if (!needed)
-  {
-    DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag));
-    return true;
-  }
-
-  bool result = false;
-  hb_blob_t *dest_blob = _repack (tag, serializer);
-  if (dest_blob)
-  {
-    DEBUG_MSG (SUBSET, nullptr,
-               "OT::%c%c%c%c final subset table size: %u bytes.",
-               HB_UNTAG (tag), dest_blob->length);
-    result = plan->add_table (tag, dest_blob);
-    hb_blob_destroy (dest_blob);
-  }
-
-  DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset %s",
-             HB_UNTAG (tag), result ? "success" : "FAILED!");
-  return result;
-}
-
 static bool
 _is_table_present (hb_face_t *source, hb_tag_t tag)
 {
@@ -407,34 +198,34 @@ _should_drop_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','a','r'): /* hint table, fallthrough */
     return plan->all_axes_pinned || (plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
 
-  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 */
+  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->flags & HB_SUBSET_FLAGS_NO_HINTING;
 
 #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'):
+  case HB_TAG('G','D','E','F'):
+  case HB_TAG('G','P','O','S'):
+  case HB_TAG('G','S','U','B'):
+  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
 
-  case HB_TAG ('a','v','a','r'):
-  case HB_TAG ('f','v','a','r'):
-  case HB_TAG ('g','v','a','r'):
-  case HB_OT_TAG_HVAR:
-  case HB_OT_TAG_VVAR:
-  case HB_TAG ('M','V','A','R'):
+  case HB_TAG('a','v','a','r'):
+  case HB_TAG('f','v','a','r'):
+  case HB_TAG('g','v','a','r'):
+  case HB_TAG('H','V','A','R'):
+  case HB_TAG('V','V','A','R'):
+  case HB_TAG('M','V','A','R'):
     return plan->all_axes_pinned;
 
   default:
@@ -442,15 +233,6 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
   }
 }
 
-static bool
-_passthrough (hb_subset_plan_t *plan, hb_tag_t tag)
-{
-  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;
-}
-
 static bool
 _dependencies_satisfied (hb_subset_plan_t *plan, hb_tag_t tag,
                          const hb_set_t &subsetted_tags,
@@ -458,13 +240,13 @@ _dependencies_satisfied (hb_subset_plan_t *plan, hb_tag_t tag,
 {
   switch (tag)
   {
-  case HB_OT_TAG_hmtx:
-  case HB_OT_TAG_vmtx:
-  case HB_OT_TAG_maxp:
-  case HB_OT_TAG_OS2:
-    return !plan->normalized_coords || !pending_subset_tags.has (HB_OT_TAG_glyf);
-  case HB_OT_TAG_GPOS:
-    return plan->all_axes_pinned || !pending_subset_tags.has (HB_OT_TAG_GDEF);
+  case HB_TAG('h','m','t','x'):
+  case HB_TAG('v','m','t','x'):
+  case HB_TAG('m','a','x','p'):
+  case HB_TAG('O','S','/','2'):
+    return !plan->normalized_coords || !pending_subset_tags.has (HB_TAG('g','l','y','f'));
+  case HB_TAG('G','P','O','S'):
+    return plan->all_axes_pinned || !pending_subset_tags.has (HB_TAG('G','D','E','F'));
   default:
     return true;
   }
@@ -476,88 +258,48 @@ _subset_table (hb_subset_plan_t *plan,
                hb_tag_t tag)
 {
   if (plan->no_subset_tables.has (tag)) {
-    return _passthrough (plan, tag);
+    return _hb_subset_table_passthrough (plan, tag);
   }
 
   DEBUG_MSG (SUBSET, nullptr, "subset %c%c%c%c", HB_UNTAG (tag));
+
+  bool success;
+  if (_hb_subset_table_layout (plan, buf, tag, &success) ||
+      _hb_subset_table_var (plan, buf, tag, &success) ||
+      _hb_subset_table_cff (plan, buf, tag, &success) ||
+      _hb_subset_table_color (plan, buf, tag, &success) ||
+      _hb_subset_table_other (plan, buf, tag, &success))
+    return success;
+
+
   switch (tag)
   {
-  case HB_OT_TAG_glyf: return _subset (plan, buf);
-  case HB_OT_TAG_hdmx: return _subset (plan, buf);
-  case HB_OT_TAG_name: return _subset (plan, buf);
-  case HB_OT_TAG_head:
-    if (_is_table_present (plan->source, HB_OT_TAG_glyf) && !_should_drop_table (plan, HB_OT_TAG_glyf))
+  case HB_TAG('h','e','a','d'):
+    if (_is_table_present (plan->source, HB_TAG('g','l','y','f')) && !_should_drop_table (plan, HB_TAG('g','l','y','f')))
       return true; /* skip head, handled by glyf */
-    return _subset (plan, buf);
-  case HB_OT_TAG_hhea: return true; /* skip hhea, handled by hmtx */
-  case HB_OT_TAG_hmtx: return _subset (plan, buf);
-  case HB_OT_TAG_vhea: return true; /* skip vhea, handled by vmtx */
-  case HB_OT_TAG_vmtx: return _subset (plan, buf);
-  case HB_OT_TAG_maxp: return _subset (plan, buf);
-  case HB_OT_TAG_sbix: return _subset (plan, buf);
-  case HB_OT_TAG_loca: return true; /* skip loca, handled by glyf */
-  case HB_OT_TAG_cmap: return _subset (plan, buf);
-  case HB_OT_TAG_OS2 : return _subset (plan, buf);
-  case HB_OT_TAG_post: return _subset (plan, buf);
-  case HB_OT_TAG_COLR: return _subset (plan, buf);
-  case HB_OT_TAG_CPAL: return _subset (plan, buf);
-  case HB_OT_TAG_CBLC: return _subset (plan, buf);
-  case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */
-  case HB_OT_TAG_MATH: return _subset (plan, buf);
-  case HB_OT_TAG_BASE: return _subset (plan, buf);
-
-#ifndef HB_NO_SUBSET_CFF
-  case HB_OT_TAG_CFF1: return _subset (plan, buf);
-  case HB_OT_TAG_CFF2: return _subset (plan, buf);
-  case HB_OT_TAG_VORG: return _subset (plan, buf);
-#endif
-
-#ifndef HB_NO_SUBSET_LAYOUT
-  case HB_OT_TAG_GDEF: return _subset (plan, buf);
-  case HB_OT_TAG_GSUB: return _subset (plan, buf);
-  case HB_OT_TAG_GPOS: return _subset (plan, buf);
-  case HB_OT_TAG_gvar: return _subset (plan, buf);
-  case HB_OT_TAG_HVAR: return _subset (plan, buf);
-  case HB_OT_TAG_VVAR: return _subset (plan, buf);
-#endif
-
-#ifndef HB_NO_VAR
-  case HB_OT_TAG_fvar:
-    if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
-    return _subset (plan, buf);
-  case HB_OT_TAG_avar:
-    if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
-    return _subset (plan, buf);
-  case HB_OT_TAG_cvar:
-    if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
-    return _subset (plan, buf);
-  case HB_OT_TAG_MVAR:
-    if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
-    return _subset (plan, buf);
-#endif
+    return _hb_subset_table (plan, buf);
 
-  case HB_OT_TAG_STAT:
-    if (!plan->user_axes_location.is_empty ()) return _subset (plan, buf);
-    else return _passthrough (plan, tag);
+  case HB_TAG('S','T','A','T'):
+    if (!plan->user_axes_location.is_empty ()) return _hb_subset_table (plan, buf);
+    else return _hb_subset_table_passthrough (plan, tag);
 
-  case HB_TAG ('c', 'v', 't', ' '):
+  case HB_TAG('c','v','t',' '):
 #ifndef HB_NO_VAR
-    if (_is_table_present (plan->source, HB_OT_TAG_cvar) &&
+    if (_is_table_present (plan->source, HB_TAG('c','v','a','r')) &&
         plan->normalized_coords && !plan->pinned_at_default)
     {
       auto &cvar = *plan->source->table.cvar;
       return OT::cvar::add_cvt_and_apply_deltas (plan, cvar.get_tuple_var_data (), &cvar);
     }
 #endif
-    return _passthrough (plan, tag);
+    return _hb_subset_table_passthrough (plan, tag);
+  }
 
-  default:
-    if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED)
-      return _passthrough (plan, tag);
+  if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED)
+    return _hb_subset_table_passthrough (plan, tag);
 
-    // Drop table
-    return true;
-  }
+  // Drop table
+  return true;
 }
 
 static void _attach_accelerator_data (hb_subset_plan_t* plan,
@@ -707,108 +449,4 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
 
 end:
   return success ? hb_face_reference (plan->dest) : nullptr;
-}
-
-
-#ifdef HB_EXPERIMENTAL_API
-
-#include "hb-ot-cff1-table.hh"
-
-template
-static hb_blob_t* get_charstrings_data(accel_t& accel, hb_codepoint_t glyph_index) {
-  if (!accel.is_valid()) {
-    return hb_blob_get_empty ();
-  }
-
-  hb_ubytes_t bytes = (*accel.charStrings)[glyph_index];
-  if (!bytes) {
-    return hb_blob_get_empty ();
-  }
-
-  hb_blob_t* cff_blob = accel.get_blob();
-  uint32_t length;
-  const char* cff_data = hb_blob_get_data(cff_blob, &length) ;
-
-  long int offset = (const char*) bytes.arrayZ - cff_data;
-  if (offset < 0 || offset > INT32_MAX) {
-    return hb_blob_get_empty ();
-  }
-
-  return hb_blob_create_sub_blob(cff_blob, (uint32_t) offset, bytes.length);
-}
-
-template
-static hb_blob_t* get_charstrings_index(accel_t& accel) {
-  if (!accel.is_valid()) {
-    return hb_blob_get_empty ();
-  }
-
-  const char* charstrings_start = (const char*) accel.charStrings;
-  unsigned charstrings_length = accel.charStrings->get_size();
-
-  hb_blob_t* cff_blob = accel.get_blob();
-  uint32_t length;
-  const char* cff_data = hb_blob_get_data(cff_blob, &length) ;
-
-  long int offset = charstrings_start - cff_data;
-  if (offset < 0 || offset > INT32_MAX) {
-    return hb_blob_get_empty ();
-  }
-
-  return hb_blob_create_sub_blob(cff_blob, (uint32_t) offset, charstrings_length);
-}
-
-/**
- * hb_subset_cff_get_charstring_data:
- * @face: A face object
- * @glyph_index: Glyph index to get data for.
- *
- * Returns the raw outline data from the CFF/CFF2 table associated with the given glyph index.
- *
- * XSince: EXPERIMENTAL
- **/
-HB_EXTERN hb_blob_t*
-hb_subset_cff_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph_index) {
-  return get_charstrings_data(*face->table.cff1, glyph_index);
-}
-
-/**
- * hb_subset_cff_get_charstrings_index:
- * @face: A face object
- *
- * Returns the raw CFF CharStrings INDEX from the CFF table.
- *
- * XSince: EXPERIMENTAL
- **/
-HB_EXTERN hb_blob_t*
-hb_subset_cff_get_charstrings_index (hb_face_t* face) {
-  return get_charstrings_index (*face->table.cff1);
-}
-
-/**
- * hb_subset_cff2_get_charstring_data:
- * @face: A face object
- * @glyph_index: Glyph index to get data for.
- *
- * Returns the raw outline data from the CFF/CFF2 table associated with the given glyph index.
- *
- * XSince: EXPERIMENTAL
- **/
-HB_EXTERN hb_blob_t*
-hb_subset_cff2_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph_index) {
-  return get_charstrings_data(*face->table.cff2, glyph_index);
-}
-
-/**
- * hb_subset_cff2_get_charstrings_index:
- * @face: A face object
- *
- * Returns the raw CFF2 CharStrings INDEX from the CFF2 table.
- *
- * XSince: EXPERIMENTAL
- **/
-HB_EXTERN hb_blob_t*
-hb_subset_cff2_get_charstrings_index (hb_face_t* face) {
-  return get_charstrings_index (*face->table.cff2);
-}
-#endif
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset.h b/src/java.desktop/share/native/libharfbuzz/hb-subset.h
index 3eccd25738e..fd2908e8308 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset.h
@@ -80,6 +80,10 @@ typedef struct hb_subset_plan_t hb_subset_plan_t;
  * @HB_SUBSET_FLAGS_IFTB_REQUIREMENTS: If set enforce requirements on the output subset
  * to allow it to be used with incremental font transfer IFTB patches. Primarily,
  * this forces all outline data to use long (32 bit) offsets. Since: EXPERIMENTAL
+ * @HB_SUBSET_FLAGS_RETAIN_NUM_GLYPHS: If this flag is set along side
+ * HB_SUBSET_FLAGS_RETAIN_GIDS then the number of glyphs in the font won't
+ * be reduced as a result of subsetting. If necessary empty glyphs will be
+ * included at the end of the font to keep the number of glyphs unchanged.
  *
  * List of boolean properties that can be configured on the subset input.
  *
@@ -101,6 +105,7 @@ typedef enum { /*< flags >*/
   HB_SUBSET_FLAGS_NO_BIDI_CLOSURE         =  0x00000800u,
 #ifdef HB_EXPERIMENTAL_API
   HB_SUBSET_FLAGS_IFTB_REQUIREMENTS       =  0x00001000u,
+  HB_SUBSET_FLAGS_RETAIN_NUM_GLYPHS  =  0x00002000u,
 #endif
 } hb_subset_flags_t;
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset.hh
index bc7c24c94de..009919764f5 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset.hh
@@ -70,5 +70,4 @@ struct hb_subset_context_t :
                         table_tag (table_tag_) {}
 };
 
-
 #endif /* HB_SUBSET_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh
index 8731a0bcf8d..868428ab1e7 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh
@@ -2,9 +2,9 @@
 /*
  * The following table is generated by running:
  *
- *   ./gen-ucd-table.py ucd.nounihan.grouped.xml
+ *   ./gen-ucd-table.py ucd.nounihan.grouped.xml hb-script-list.h
  *
- * on file with this description: Unicode 16.0.0
+ * on file with this description: Unicode 17.0.0
  */
 
 #ifndef HB_UCD_TABLE_HH
@@ -12,8 +12,9 @@
 
 #include "hb.hh"
 
-static const hb_script_t
-_hb_ucd_sc_map[172] =
+#include 
+
+static const hb_script_t _hb_ucd_sc_map[176]=
 {
                    HB_SCRIPT_COMMON,              HB_SCRIPT_INHERITED,
                   HB_SCRIPT_UNKNOWN,                 HB_SCRIPT_ARABIC,
@@ -101,1040 +102,805 @@ _hb_ucd_sc_map[172] =
              HB_SCRIPT_GURUNG_KHEMA,              HB_SCRIPT_KIRAT_RAI,
                   HB_SCRIPT_OL_ONAL,                HB_SCRIPT_SUNUWAR,
                    HB_SCRIPT_TODHRI,          HB_SCRIPT_TULU_TIGALARI,
+               HB_SCRIPT_BERIA_ERFE,                HB_SCRIPT_SIDETIC,
+                   HB_SCRIPT_TAI_YO,            HB_SCRIPT_TOLONG_SIKI,
 };
-static const uint16_t
-_hb_ucd_dm1_p0_map[825] =
+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,
+   0x003B, 0x004B, 0x0060, 0x00B4, 0x00B7, 0x00C5, 0x02B9, 0x0300,
+   0x0301, 0x0313, 0x0385, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C,
+   0x038E, 0x038F, 0x0390, 0x03A9, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+   0x03B0, 0x03B9, 0x03CC, 0x03CD, 0x03CE, 0x2002, 0x2003, 0x3008,
+   0x3009, 0x349E, 0x34B9, 0x34BB, 0x34DF, 0x3515, 0x36EE, 0x36FC,
+   0x3781, 0x382F, 0x3862, 0x387C, 0x38C7, 0x38E3, 0x391C, 0x393A,
+   0x3A2E, 0x3A6C, 0x3AE4, 0x3B08, 0x3B19, 0x3B49, 0x3B9D, 0x3C18,
+   0x3C4E, 0x3D33, 0x3D96, 0x3EAC, 0x3EB8, 0x3F1B, 0x3FFC, 0x4008,
+   0x4018, 0x4039, 0x4046, 0x4096, 0x40E3, 0x412F, 0x4202, 0x4227,
+   0x42A0, 0x4301, 0x4334, 0x4359, 0x43D5, 0x43D9, 0x440B, 0x446B,
+   0x452B, 0x455D, 0x4561, 0x456B, 0x45D7, 0x45F9, 0x4635, 0x46BE,
+   0x46C7, 0x4995, 0x49E6, 0x4A6E, 0x4A76, 0x4AB2, 0x4B33, 0x4BCE,
+   0x4CCE, 0x4CED, 0x4CF8, 0x4D56, 0x4E0D, 0x4E26, 0x4E32, 0x4E38,
+   0x4E39, 0x4E3D, 0x4E41, 0x4E82, 0x4E86, 0x4EAE, 0x4EC0, 0x4ECC,
+   0x4EE4, 0x4F60, 0x4F80, 0x4F86, 0x4F8B, 0x4FAE, 0x4FBB, 0x4FBF,
+   0x5002, 0x502B, 0x507A, 0x5099, 0x50CF, 0x50DA, 0x50E7, 0x5140,
+   0x5145, 0x514D, 0x5154, 0x5164, 0x5167, 0x5168, 0x5169, 0x516D,
+   0x5177, 0x5180, 0x518D, 0x5192, 0x5195, 0x5197, 0x51A4, 0x51AC,
+   0x51B5, 0x51B7, 0x51C9, 0x51CC, 0x51DC, 0x51DE, 0x51F5, 0x5203,
+   0x5207, 0x5217, 0x5229, 0x523A, 0x523B, 0x5246, 0x5272, 0x5277,
+   0x5289, 0x529B, 0x52A3, 0x52B3, 0x52C7, 0x52C9, 0x52D2, 0x52DE,
+   0x52E4, 0x52F5, 0x52FA, 0x5305, 0x5306, 0x5317, 0x533F, 0x5349,
+   0x5351, 0x535A, 0x5373, 0x5375, 0x537D, 0x537F, 0x53C3, 0x53CA,
+   0x53DF, 0x53E5, 0x53EB, 0x53F1, 0x5406, 0x540F, 0x541D, 0x5438,
+   0x5442, 0x5448, 0x5468, 0x549E, 0x54A2, 0x54BD, 0x54F6, 0x5510,
+   0x5553, 0x5555, 0x5563, 0x5584, 0x5587, 0x5599, 0x559D, 0x55AB,
+   0x55B3, 0x55C0, 0x55C2, 0x55E2, 0x5606, 0x5651, 0x5668, 0x5674,
+   0x56F9, 0x5716, 0x5717, 0x578B, 0x57CE, 0x57F4, 0x580D, 0x5831,
+   0x5832, 0x5840, 0x585A, 0x585E, 0x58A8, 0x58AC, 0x58B3, 0x58D8,
+   0x58DF, 0x58EE, 0x58F2, 0x58F7, 0x5906, 0x591A, 0x5922, 0x5944,
+   0x5948, 0x5951, 0x5954, 0x5962, 0x5973, 0x59D8, 0x59EC, 0x5A1B,
+   0x5A27, 0x5A62, 0x5A66, 0x5AB5, 0x5B08, 0x5B28, 0x5B3E, 0x5B85,
+   0x5BC3, 0x5BD8, 0x5BE7, 0x5BEE, 0x5BF3, 0x5BFF, 0x5C06, 0x5C22,
+   0x5C3F, 0x5C60, 0x5C62, 0x5C64, 0x5C65, 0x5C6E, 0x5C8D, 0x5CC0,
+   0x5D19, 0x5D43, 0x5D50, 0x5D6B, 0x5D6E, 0x5D7C, 0x5DB2, 0x5DBA,
+   0x5DE1, 0x5DE2, 0x5DFD, 0x5E28, 0x5E3D, 0x5E69, 0x5E74, 0x5EA6,
+   0x5EB0, 0x5EB3, 0x5EB6, 0x5EC9, 0x5ECA, 0x5ED2, 0x5ED3, 0x5ED9,
+   0x5EEC, 0x5EFE, 0x5F04, 0x5F22, 0x5F53, 0x5F62, 0x5F69, 0x5F6B,
+   0x5F8B, 0x5F9A, 0x5FA9, 0x5FAD, 0x5FCD, 0x5FD7, 0x5FF5, 0x5FF9,
+   0x6012, 0x601C, 0x6075, 0x6081, 0x6094, 0x60C7, 0x60D8, 0x60E1,
+   0x6108, 0x6144, 0x6148, 0x614C, 0x614E, 0x6160, 0x6168, 0x617A,
+   0x618E, 0x6190, 0x61A4, 0x61AF, 0x61B2, 0x61DE, 0x61F2, 0x61F6,
+   0x6200, 0x6210, 0x621B, 0x622E, 0x6234, 0x625D, 0x62B1, 0x62C9,
+   0x62CF, 0x62D3, 0x62D4, 0x62FC, 0x62FE, 0x633D, 0x6350, 0x6368,
+   0x637B, 0x6383, 0x63A0, 0x63A9, 0x63C4, 0x63C5, 0x63E4, 0x641C,
+   0x6422, 0x6452, 0x6469, 0x6477, 0x647E, 0x649A, 0x649D, 0x64C4,
+   0x654F, 0x6556, 0x656C, 0x6578, 0x6599, 0x65C5, 0x65E2, 0x65E3,
+   0x6613, 0x6649, 0x6674, 0x6688, 0x6691, 0x669C, 0x66B4, 0x66C6,
+   0x66F4, 0x66F8, 0x6700, 0x6717, 0x671B, 0x6721, 0x674E, 0x6753,
+   0x6756, 0x675E, 0x677B, 0x6785, 0x6797, 0x67F3, 0x67FA, 0x6817,
+   0x681F, 0x6852, 0x6881, 0x6885, 0x688E, 0x68A8, 0x6914, 0x6942,
+   0x69A3, 0x69EA, 0x6A02, 0x6A13, 0x6AA8, 0x6AD3, 0x6ADB, 0x6B04,
+   0x6B21, 0x6B54, 0x6B72, 0x6B77, 0x6B79, 0x6B9F, 0x6BAE, 0x6BBA,
+   0x6BBB, 0x6C4E, 0x6C67, 0x6C88, 0x6CBF, 0x6CCC, 0x6CCD, 0x6CE5,
+   0x6D16, 0x6D1B, 0x6D1E, 0x6D34, 0x6D3E, 0x6D41, 0x6D69, 0x6D6A,
+   0x6D77, 0x6D78, 0x6D85, 0x6DCB, 0x6DDA, 0x6DEA, 0x6DF9, 0x6E1A,
+   0x6E2F, 0x6E6E, 0x6E9C, 0x6EBA, 0x6EC7, 0x6ECB, 0x6ED1, 0x6EDB,
+   0x6F0F, 0x6F22, 0x6F23, 0x6F6E, 0x6FC6, 0x6FEB, 0x6FFE, 0x701B,
+   0x701E, 0x7039, 0x704A, 0x7070, 0x7077, 0x707D, 0x7099, 0x70AD,
+   0x70C8, 0x70D9, 0x7145, 0x7149, 0x716E, 0x719C, 0x71CE, 0x71D0,
+   0x7210, 0x721B, 0x7228, 0x722B, 0x7235, 0x7250, 0x7262, 0x7280,
+   0x7295, 0x72AF, 0x72C0, 0x72FC, 0x732A, 0x7375, 0x737A, 0x7387,
+   0x738B, 0x73A5, 0x73B2, 0x73DE, 0x7406, 0x7409, 0x7422, 0x7447,
+   0x745C, 0x7469, 0x7471, 0x7485, 0x7489, 0x7498, 0x74CA, 0x7506,
+   0x7524, 0x753B, 0x753E, 0x7559, 0x7565, 0x7570, 0x75E2, 0x7610,
+   0x761D, 0x761F, 0x7642, 0x7669, 0x76CA, 0x76DB, 0x76E7, 0x76F4,
+   0x7701, 0x771E, 0x771F, 0x7740, 0x774A, 0x778B, 0x77A7, 0x784E,
+   0x786B, 0x788C, 0x7891, 0x78CA, 0x78CC, 0x78FB, 0x792A, 0x793C,
+   0x793E, 0x7948, 0x7949, 0x7950, 0x7956, 0x795D, 0x795E, 0x7965,
+   0x797F, 0x798D, 0x798E, 0x798F, 0x79AE, 0x79CA, 0x79EB, 0x7A1C,
+   0x7A40, 0x7A4A, 0x7A4F, 0x7A81, 0x7AB1, 0x7ACB, 0x7AEE, 0x7B20,
+   0x7BC0, 0x7BC6, 0x7BC9, 0x7C3E, 0x7C60, 0x7C7B, 0x7C92, 0x7CBE,
+   0x7CD2, 0x7CD6, 0x7CE3, 0x7CE7, 0x7CE8, 0x7D00, 0x7D10, 0x7D22,
+   0x7D2F, 0x7D5B, 0x7D63, 0x7DA0, 0x7DBE, 0x7DC7, 0x7DF4, 0x7E02,
+   0x7E09, 0x7E37, 0x7E41, 0x7E45, 0x7F3E, 0x7F72, 0x7F79, 0x7F7A,
+   0x7F85, 0x7F95, 0x7F9A, 0x7FBD, 0x7FFA, 0x8001, 0x8005, 0x8046,
+   0x8060, 0x806F, 0x8070, 0x807E, 0x808B, 0x80AD, 0x80B2, 0x8103,
+   0x813E, 0x81D8, 0x81E8, 0x81ED, 0x8201, 0x8204, 0x8218, 0x826F,
+   0x8279, 0x828B, 0x8291, 0x829D, 0x82B1, 0x82B3, 0x82BD, 0x82E5,
+   0x82E6, 0x831D, 0x8323, 0x8336, 0x8352, 0x8353, 0x8363, 0x83AD,
+   0x83BD, 0x83C9, 0x83CA, 0x83CC, 0x83DC, 0x83E7, 0x83EF, 0x83F1,
+   0x843D, 0x8449, 0x8457, 0x84EE, 0x84F1, 0x84F3, 0x84FC, 0x8516,
+   0x8564, 0x85CD, 0x85FA, 0x8606, 0x8612, 0x862D, 0x863F, 0x8650,
+   0x865C, 0x8667, 0x8669, 0x8688, 0x86A9, 0x86E2, 0x870E, 0x8728,
+   0x876B, 0x8779, 0x8786, 0x87BA, 0x87E1, 0x8801, 0x881F, 0x884C,
+   0x8860, 0x8863, 0x88C2, 0x88CF, 0x88D7, 0x88DE, 0x88E1, 0x88F8,
+   0x88FA, 0x8910, 0x8941, 0x8964, 0x8986, 0x898B, 0x8996, 0x8AA0,
+   0x8AAA, 0x8ABF, 0x8ACB, 0x8AD2, 0x8AD6, 0x8AED, 0x8AF8, 0x8AFE,
+   0x8B01, 0x8B39, 0x8B58, 0x8B80, 0x8B8A, 0x8C48, 0x8C55, 0x8CAB,
+   0x8CC1, 0x8CC2, 0x8CC8, 0x8CD3, 0x8D08, 0x8D1B, 0x8D77, 0x8DBC,
+   0x8DCB, 0x8DEF, 0x8DF0, 0x8ECA, 0x8ED4, 0x8F26, 0x8F2A, 0x8F38,
+   0x8F3B, 0x8F62, 0x8F9E, 0x8FB0, 0x8FB6, 0x9023, 0x9038, 0x9072,
+   0x907C, 0x908F, 0x9094, 0x90CE, 0x90DE, 0x90F1, 0x90FD, 0x9111,
+   0x911B, 0x916A, 0x9199, 0x91B4, 0x91CC, 0x91CF, 0x91D1, 0x9234,
+   0x9238, 0x9276, 0x927C, 0x92D7, 0x92D8, 0x9304, 0x934A, 0x93F9,
+   0x9415, 0x958B, 0x95AD, 0x95B7, 0x962E, 0x964B, 0x964D, 0x9675,
+   0x9678, 0x967C, 0x9686, 0x96A3, 0x96B7, 0x96B8, 0x96C3, 0x96E2,
+   0x96E3, 0x96F6, 0x96F7, 0x9723, 0x9732, 0x9748, 0x9756, 0x97DB,
+   0x97E0, 0x97FF, 0x980B, 0x9818, 0x9829, 0x983B, 0x985E, 0x98E2,
+   0x98EF, 0x98FC, 0x9928, 0x9929, 0x99A7, 0x99C2, 0x99F1, 0x99FE,
+   0x9A6A, 0x9B12, 0x9B6F, 0x9C40, 0x9C57, 0x9CFD, 0x9D67, 0x9DB4,
+   0x9DFA, 0x9E1E, 0x9E7F, 0x9E97, 0x9E9F, 0x9EBB, 0x9ECE, 0x9EF9,
+   0x9EFE, 0x9F05, 0x9F0F, 0x9F16, 0x9F3B, 0x9F43, 0x9F8D, 0x9F8E,
+   0x9F9C,
 };
-static const uint16_t
-_hb_ucd_dm1_p2_map[110] =
+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,
+   0x0122, 0x051C, 0x0525, 0x054B, 0x063A, 0x0804, 0x08DE, 0x0A2C,
+   0x0B63, 0x14E4, 0x16A8, 0x16EA, 0x19C8, 0x1B18, 0x1D0B, 0x1DE4,
+   0x1DE6, 0x2183, 0x219F, 0x2331, 0x26D4, 0x2844, 0x284A, 0x2B0C,
+   0x2BF1, 0x300A, 0x32B8, 0x335F, 0x3393, 0x339C, 0x33C3, 0x33D5,
+   0x346D, 0x36A3, 0x38A7, 0x3A8D, 0x3AFA, 0x3CBC, 0x3D1E, 0x3ED1,
+   0x3F5E, 0x3F8E, 0x4263, 0x42EE, 0x43AB, 0x4608, 0x4735, 0x4814,
+   0x4C36, 0x4C92, 0x4FA1, 0x4FB8, 0x5044, 0x50F2, 0x50F3, 0x5119,
+   0x5133, 0x5249, 0x541D, 0x5626, 0x569A, 0x56C5, 0x597C, 0x5AA7,
+   0x5BAB, 0x5C80, 0x5CD0, 0x5F86, 0x61DA, 0x6228, 0x6247, 0x62D9,
+   0x633E, 0x64DA, 0x6523, 0x65A8, 0x67A7, 0x67B5, 0x6B3C, 0x6C36,
+   0x6CD5, 0x6D6B, 0x6F2C, 0x6FB1, 0x70D2, 0x73CA, 0x7667, 0x78AE,
+   0x7966, 0x7CA8, 0x7ED3, 0x7F2F, 0x85D2, 0x85ED, 0x872E, 0x8BFA,
+   0x8D77, 0x9145, 0x91DF, 0x921A, 0x940A, 0x9496, 0x95B6, 0x9B30,
+   0xA0CE, 0xA105, 0xA20E, 0xA291, 0xA392, 0xA600,
 };
-static const uint32_t
-_hb_ucd_dm2_u32_map[638] =
+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),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x003C, 0x0338, 0x226E),HB_CODEPOINT_ENCODE3_11_7_14 (0x003D, 0x0338, 0x2260),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x003E, 0x0338, 0x226F),HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0300, 0x00C0),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0301, 0x00C1),HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0302, 0x00C2),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0303, 0x00C3),HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0304, 0x0100),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0306, 0x0102),HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0307, 0x0226),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0308, 0x00C4),HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0309, 0x1EA2),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x030A, 0x00C5),HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x030C, 0x01CD),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x030F, 0x0200),HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0311, 0x0202),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0323, 0x1EA0),HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0325, 0x1E00),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0328, 0x0104),HB_CODEPOINT_ENCODE3_11_7_14 (0x0042, 0x0307, 0x1E02),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0042, 0x0323, 0x1E04),HB_CODEPOINT_ENCODE3_11_7_14 (0x0042, 0x0331, 0x1E06),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0043, 0x0301, 0x0106),HB_CODEPOINT_ENCODE3_11_7_14 (0x0043, 0x0302, 0x0108),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0043, 0x0307, 0x010A),HB_CODEPOINT_ENCODE3_11_7_14 (0x0043, 0x030C, 0x010C),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0043, 0x0327, 0x00C7),HB_CODEPOINT_ENCODE3_11_7_14 (0x0044, 0x0307, 0x1E0A),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0044, 0x030C, 0x010E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0044, 0x0323, 0x1E0C),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0044, 0x0327, 0x1E10),HB_CODEPOINT_ENCODE3_11_7_14 (0x0044, 0x032D, 0x1E12),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0044, 0x0331, 0x1E0E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0300, 0x00C8),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0301, 0x00C9),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0302, 0x00CA),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0303, 0x1EBC),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0304, 0x0112),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0306, 0x0114),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0307, 0x0116),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0308, 0x00CB),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0309, 0x1EBA),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x030C, 0x011A),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x030F, 0x0204),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0311, 0x0206),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0323, 0x1EB8),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0327, 0x0228),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0328, 0x0118),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x032D, 0x1E18),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0330, 0x1E1A),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0046, 0x0307, 0x1E1E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0047, 0x0301, 0x01F4),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0047, 0x0302, 0x011C),HB_CODEPOINT_ENCODE3_11_7_14 (0x0047, 0x0304, 0x1E20),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0047, 0x0306, 0x011E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0047, 0x0307, 0x0120),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0047, 0x030C, 0x01E6),HB_CODEPOINT_ENCODE3_11_7_14 (0x0047, 0x0327, 0x0122),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0048, 0x0302, 0x0124),HB_CODEPOINT_ENCODE3_11_7_14 (0x0048, 0x0307, 0x1E22),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0048, 0x0308, 0x1E26),HB_CODEPOINT_ENCODE3_11_7_14 (0x0048, 0x030C, 0x021E),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0048, 0x0323, 0x1E24),HB_CODEPOINT_ENCODE3_11_7_14 (0x0048, 0x0327, 0x1E28),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0048, 0x032E, 0x1E2A),HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0300, 0x00CC),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0301, 0x00CD),HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0302, 0x00CE),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0303, 0x0128),HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0304, 0x012A),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0306, 0x012C),HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0307, 0x0130),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0308, 0x00CF),HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0309, 0x1EC8),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x030C, 0x01CF),HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x030F, 0x0208),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0311, 0x020A),HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0323, 0x1ECA),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0328, 0x012E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0330, 0x1E2C),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004A, 0x0302, 0x0134),HB_CODEPOINT_ENCODE3_11_7_14 (0x004B, 0x0301, 0x1E30),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004B, 0x030C, 0x01E8),HB_CODEPOINT_ENCODE3_11_7_14 (0x004B, 0x0323, 0x1E32),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004B, 0x0327, 0x0136),HB_CODEPOINT_ENCODE3_11_7_14 (0x004B, 0x0331, 0x1E34),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004C, 0x0301, 0x0139),HB_CODEPOINT_ENCODE3_11_7_14 (0x004C, 0x030C, 0x013D),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004C, 0x0323, 0x1E36),HB_CODEPOINT_ENCODE3_11_7_14 (0x004C, 0x0327, 0x013B),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004C, 0x032D, 0x1E3C),HB_CODEPOINT_ENCODE3_11_7_14 (0x004C, 0x0331, 0x1E3A),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004D, 0x0301, 0x1E3E),HB_CODEPOINT_ENCODE3_11_7_14 (0x004D, 0x0307, 0x1E40),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004D, 0x0323, 0x1E42),HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x0300, 0x01F8),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x0301, 0x0143),HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x0303, 0x00D1),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x0307, 0x1E44),HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x030C, 0x0147),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x0323, 0x1E46),HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x0327, 0x0145),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x032D, 0x1E4A),HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x0331, 0x1E48),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0300, 0x00D2),HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0301, 0x00D3),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0302, 0x00D4),HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0303, 0x00D5),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0304, 0x014C),HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0306, 0x014E),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0307, 0x022E),HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0308, 0x00D6),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0309, 0x1ECE),HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x030B, 0x0150),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x030C, 0x01D1),HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x030F, 0x020C),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0311, 0x020E),HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x031B, 0x01A0),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0323, 0x1ECC),HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0328, 0x01EA),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0050, 0x0301, 0x1E54),HB_CODEPOINT_ENCODE3_11_7_14 (0x0050, 0x0307, 0x1E56),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0052, 0x0301, 0x0154),HB_CODEPOINT_ENCODE3_11_7_14 (0x0052, 0x0307, 0x1E58),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0052, 0x030C, 0x0158),HB_CODEPOINT_ENCODE3_11_7_14 (0x0052, 0x030F, 0x0210),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0052, 0x0311, 0x0212),HB_CODEPOINT_ENCODE3_11_7_14 (0x0052, 0x0323, 0x1E5A),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0052, 0x0327, 0x0156),HB_CODEPOINT_ENCODE3_11_7_14 (0x0052, 0x0331, 0x1E5E),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0053, 0x0301, 0x015A),HB_CODEPOINT_ENCODE3_11_7_14 (0x0053, 0x0302, 0x015C),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0053, 0x0307, 0x1E60),HB_CODEPOINT_ENCODE3_11_7_14 (0x0053, 0x030C, 0x0160),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0053, 0x0323, 0x1E62),HB_CODEPOINT_ENCODE3_11_7_14 (0x0053, 0x0326, 0x0218),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0053, 0x0327, 0x015E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0054, 0x0307, 0x1E6A),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0054, 0x030C, 0x0164),HB_CODEPOINT_ENCODE3_11_7_14 (0x0054, 0x0323, 0x1E6C),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0054, 0x0326, 0x021A),HB_CODEPOINT_ENCODE3_11_7_14 (0x0054, 0x0327, 0x0162),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0054, 0x032D, 0x1E70),HB_CODEPOINT_ENCODE3_11_7_14 (0x0054, 0x0331, 0x1E6E),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0300, 0x00D9),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0301, 0x00DA),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0302, 0x00DB),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0303, 0x0168),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0304, 0x016A),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0306, 0x016C),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0308, 0x00DC),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0309, 0x1EE6),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x030A, 0x016E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x030B, 0x0170),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x030C, 0x01D3),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x030F, 0x0214),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0311, 0x0216),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x031B, 0x01AF),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0323, 0x1EE4),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0324, 0x1E72),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0328, 0x0172),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x032D, 0x1E76),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0330, 0x1E74),HB_CODEPOINT_ENCODE3_11_7_14 (0x0056, 0x0303, 0x1E7C),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0056, 0x0323, 0x1E7E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0057, 0x0300, 0x1E80),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0057, 0x0301, 0x1E82),HB_CODEPOINT_ENCODE3_11_7_14 (0x0057, 0x0302, 0x0174),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0057, 0x0307, 0x1E86),HB_CODEPOINT_ENCODE3_11_7_14 (0x0057, 0x0308, 0x1E84),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0057, 0x0323, 0x1E88),HB_CODEPOINT_ENCODE3_11_7_14 (0x0058, 0x0307, 0x1E8A),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0058, 0x0308, 0x1E8C),HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0300, 0x1EF2),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0301, 0x00DD),HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0302, 0x0176),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0303, 0x1EF8),HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0304, 0x0232),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0307, 0x1E8E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0308, 0x0178),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0309, 0x1EF6),HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0323, 0x1EF4),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x005A, 0x0301, 0x0179),HB_CODEPOINT_ENCODE3_11_7_14 (0x005A, 0x0302, 0x1E90),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x005A, 0x0307, 0x017B),HB_CODEPOINT_ENCODE3_11_7_14 (0x005A, 0x030C, 0x017D),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x005A, 0x0323, 0x1E92),HB_CODEPOINT_ENCODE3_11_7_14 (0x005A, 0x0331, 0x1E94),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0300, 0x00E0),HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0301, 0x00E1),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0302, 0x00E2),HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0303, 0x00E3),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0304, 0x0101),HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0306, 0x0103),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0307, 0x0227),HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0308, 0x00E4),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0309, 0x1EA3),HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x030A, 0x00E5),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x030C, 0x01CE),HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x030F, 0x0201),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0311, 0x0203),HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0323, 0x1EA1),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0325, 0x1E01),HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0328, 0x0105),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0062, 0x0307, 0x1E03),HB_CODEPOINT_ENCODE3_11_7_14 (0x0062, 0x0323, 0x1E05),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0062, 0x0331, 0x1E07),HB_CODEPOINT_ENCODE3_11_7_14 (0x0063, 0x0301, 0x0107),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0063, 0x0302, 0x0109),HB_CODEPOINT_ENCODE3_11_7_14 (0x0063, 0x0307, 0x010B),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0063, 0x030C, 0x010D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0063, 0x0327, 0x00E7),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0064, 0x0307, 0x1E0B),HB_CODEPOINT_ENCODE3_11_7_14 (0x0064, 0x030C, 0x010F),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0064, 0x0323, 0x1E0D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0064, 0x0327, 0x1E11),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0064, 0x032D, 0x1E13),HB_CODEPOINT_ENCODE3_11_7_14 (0x0064, 0x0331, 0x1E0F),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0300, 0x00E8),HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0301, 0x00E9),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0302, 0x00EA),HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0303, 0x1EBD),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0304, 0x0113),HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0306, 0x0115),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0307, 0x0117),HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0308, 0x00EB),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0309, 0x1EBB),HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x030C, 0x011B),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x030F, 0x0205),HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0311, 0x0207),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0323, 0x1EB9),HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0327, 0x0229),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0328, 0x0119),HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x032D, 0x1E19),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0330, 0x1E1B),HB_CODEPOINT_ENCODE3_11_7_14 (0x0066, 0x0307, 0x1E1F),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0067, 0x0301, 0x01F5),HB_CODEPOINT_ENCODE3_11_7_14 (0x0067, 0x0302, 0x011D),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0067, 0x0304, 0x1E21),HB_CODEPOINT_ENCODE3_11_7_14 (0x0067, 0x0306, 0x011F),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0067, 0x0307, 0x0121),HB_CODEPOINT_ENCODE3_11_7_14 (0x0067, 0x030C, 0x01E7),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0067, 0x0327, 0x0123),HB_CODEPOINT_ENCODE3_11_7_14 (0x0068, 0x0302, 0x0125),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0068, 0x0307, 0x1E23),HB_CODEPOINT_ENCODE3_11_7_14 (0x0068, 0x0308, 0x1E27),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0068, 0x030C, 0x021F),HB_CODEPOINT_ENCODE3_11_7_14 (0x0068, 0x0323, 0x1E25),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0068, 0x0327, 0x1E29),HB_CODEPOINT_ENCODE3_11_7_14 (0x0068, 0x032E, 0x1E2B),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0068, 0x0331, 0x1E96),HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0300, 0x00EC),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0301, 0x00ED),HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0302, 0x00EE),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0303, 0x0129),HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0304, 0x012B),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0306, 0x012D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0308, 0x00EF),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0309, 0x1EC9),HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x030C, 0x01D0),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x030F, 0x0209),HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0311, 0x020B),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0323, 0x1ECB),HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0328, 0x012F),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0330, 0x1E2D),HB_CODEPOINT_ENCODE3_11_7_14 (0x006A, 0x0302, 0x0135),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006A, 0x030C, 0x01F0),HB_CODEPOINT_ENCODE3_11_7_14 (0x006B, 0x0301, 0x1E31),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006B, 0x030C, 0x01E9),HB_CODEPOINT_ENCODE3_11_7_14 (0x006B, 0x0323, 0x1E33),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006B, 0x0327, 0x0137),HB_CODEPOINT_ENCODE3_11_7_14 (0x006B, 0x0331, 0x1E35),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006C, 0x0301, 0x013A),HB_CODEPOINT_ENCODE3_11_7_14 (0x006C, 0x030C, 0x013E),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006C, 0x0323, 0x1E37),HB_CODEPOINT_ENCODE3_11_7_14 (0x006C, 0x0327, 0x013C),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006C, 0x032D, 0x1E3D),HB_CODEPOINT_ENCODE3_11_7_14 (0x006C, 0x0331, 0x1E3B),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006D, 0x0301, 0x1E3F),HB_CODEPOINT_ENCODE3_11_7_14 (0x006D, 0x0307, 0x1E41),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006D, 0x0323, 0x1E43),HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x0300, 0x01F9),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x0301, 0x0144),HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x0303, 0x00F1),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x0307, 0x1E45),HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x030C, 0x0148),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x0323, 0x1E47),HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x0327, 0x0146),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x032D, 0x1E4B),HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x0331, 0x1E49),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0300, 0x00F2),HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0301, 0x00F3),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0302, 0x00F4),HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0303, 0x00F5),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0304, 0x014D),HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0306, 0x014F),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0307, 0x022F),HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0308, 0x00F6),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0309, 0x1ECF),HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x030B, 0x0151),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x030C, 0x01D2),HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x030F, 0x020D),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0311, 0x020F),HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x031B, 0x01A1),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0323, 0x1ECD),HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0328, 0x01EB),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0070, 0x0301, 0x1E55),HB_CODEPOINT_ENCODE3_11_7_14 (0x0070, 0x0307, 0x1E57),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0072, 0x0301, 0x0155),HB_CODEPOINT_ENCODE3_11_7_14 (0x0072, 0x0307, 0x1E59),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0072, 0x030C, 0x0159),HB_CODEPOINT_ENCODE3_11_7_14 (0x0072, 0x030F, 0x0211),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0072, 0x0311, 0x0213),HB_CODEPOINT_ENCODE3_11_7_14 (0x0072, 0x0323, 0x1E5B),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0072, 0x0327, 0x0157),HB_CODEPOINT_ENCODE3_11_7_14 (0x0072, 0x0331, 0x1E5F),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0073, 0x0301, 0x015B),HB_CODEPOINT_ENCODE3_11_7_14 (0x0073, 0x0302, 0x015D),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0073, 0x0307, 0x1E61),HB_CODEPOINT_ENCODE3_11_7_14 (0x0073, 0x030C, 0x0161),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0073, 0x0323, 0x1E63),HB_CODEPOINT_ENCODE3_11_7_14 (0x0073, 0x0326, 0x0219),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0073, 0x0327, 0x015F),HB_CODEPOINT_ENCODE3_11_7_14 (0x0074, 0x0307, 0x1E6B),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0074, 0x0308, 0x1E97),HB_CODEPOINT_ENCODE3_11_7_14 (0x0074, 0x030C, 0x0165),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0074, 0x0323, 0x1E6D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0074, 0x0326, 0x021B),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0074, 0x0327, 0x0163),HB_CODEPOINT_ENCODE3_11_7_14 (0x0074, 0x032D, 0x1E71),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0074, 0x0331, 0x1E6F),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0300, 0x00F9),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0301, 0x00FA),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0302, 0x00FB),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0303, 0x0169),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0304, 0x016B),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0306, 0x016D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0308, 0x00FC),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0309, 0x1EE7),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x030A, 0x016F),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x030B, 0x0171),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x030C, 0x01D4),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x030F, 0x0215),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0311, 0x0217),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x031B, 0x01B0),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0323, 0x1EE5),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0324, 0x1E73),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0328, 0x0173),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x032D, 0x1E77),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0330, 0x1E75),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0076, 0x0303, 0x1E7D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0076, 0x0323, 0x1E7F),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0077, 0x0300, 0x1E81),HB_CODEPOINT_ENCODE3_11_7_14 (0x0077, 0x0301, 0x1E83),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0077, 0x0302, 0x0175),HB_CODEPOINT_ENCODE3_11_7_14 (0x0077, 0x0307, 0x1E87),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0077, 0x0308, 0x1E85),HB_CODEPOINT_ENCODE3_11_7_14 (0x0077, 0x030A, 0x1E98),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0077, 0x0323, 0x1E89),HB_CODEPOINT_ENCODE3_11_7_14 (0x0078, 0x0307, 0x1E8B),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0078, 0x0308, 0x1E8D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0300, 0x1EF3),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0301, 0x00FD),HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0302, 0x0177),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0303, 0x1EF9),HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0304, 0x0233),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0307, 0x1E8F),HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0308, 0x00FF),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0309, 0x1EF7),HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x030A, 0x1E99),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0323, 0x1EF5),HB_CODEPOINT_ENCODE3_11_7_14 (0x007A, 0x0301, 0x017A),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x007A, 0x0302, 0x1E91),HB_CODEPOINT_ENCODE3_11_7_14 (0x007A, 0x0307, 0x017C),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x007A, 0x030C, 0x017E),HB_CODEPOINT_ENCODE3_11_7_14 (0x007A, 0x0323, 0x1E93),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x007A, 0x0331, 0x1E95),HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8, 0x0300, 0x1FED),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8, 0x0301, 0x0385),HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8, 0x0342, 0x1FC1),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2, 0x0300, 0x1EA6),HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2, 0x0301, 0x1EA4),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2, 0x0303, 0x1EAA),HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2, 0x0309, 0x1EA8),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00C4, 0x0304, 0x01DE),HB_CODEPOINT_ENCODE3_11_7_14 (0x00C5, 0x0301, 0x01FA),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00C6, 0x0301, 0x01FC),HB_CODEPOINT_ENCODE3_11_7_14 (0x00C6, 0x0304, 0x01E2),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00C7, 0x0301, 0x1E08),HB_CODEPOINT_ENCODE3_11_7_14 (0x00CA, 0x0300, 0x1EC0),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00CA, 0x0301, 0x1EBE),HB_CODEPOINT_ENCODE3_11_7_14 (0x00CA, 0x0303, 0x1EC4),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00CA, 0x0309, 0x1EC2),HB_CODEPOINT_ENCODE3_11_7_14 (0x00CF, 0x0301, 0x1E2E),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4, 0x0300, 0x1ED2),HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4, 0x0301, 0x1ED0),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4, 0x0303, 0x1ED6),HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4, 0x0309, 0x1ED4),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5, 0x0301, 0x1E4C),HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5, 0x0304, 0x022C),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5, 0x0308, 0x1E4E),HB_CODEPOINT_ENCODE3_11_7_14 (0x00D6, 0x0304, 0x022A),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00D8, 0x0301, 0x01FE),HB_CODEPOINT_ENCODE3_11_7_14 (0x00DC, 0x0300, 0x01DB),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00DC, 0x0301, 0x01D7),HB_CODEPOINT_ENCODE3_11_7_14 (0x00DC, 0x0304, 0x01D5),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00DC, 0x030C, 0x01D9),HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2, 0x0300, 0x1EA7),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2, 0x0301, 0x1EA5),HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2, 0x0303, 0x1EAB),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2, 0x0309, 0x1EA9),HB_CODEPOINT_ENCODE3_11_7_14 (0x00E4, 0x0304, 0x01DF),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00E5, 0x0301, 0x01FB),HB_CODEPOINT_ENCODE3_11_7_14 (0x00E6, 0x0301, 0x01FD),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00E6, 0x0304, 0x01E3),HB_CODEPOINT_ENCODE3_11_7_14 (0x00E7, 0x0301, 0x1E09),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00EA, 0x0300, 0x1EC1),HB_CODEPOINT_ENCODE3_11_7_14 (0x00EA, 0x0301, 0x1EBF),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00EA, 0x0303, 0x1EC5),HB_CODEPOINT_ENCODE3_11_7_14 (0x00EA, 0x0309, 0x1EC3),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00EF, 0x0301, 0x1E2F),HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4, 0x0300, 0x1ED3),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4, 0x0301, 0x1ED1),HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4, 0x0303, 0x1ED7),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4, 0x0309, 0x1ED5),HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5, 0x0301, 0x1E4D),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5, 0x0304, 0x022D),HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5, 0x0308, 0x1E4F),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00F6, 0x0304, 0x022B),HB_CODEPOINT_ENCODE3_11_7_14 (0x00F8, 0x0301, 0x01FF),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00FC, 0x0300, 0x01DC),HB_CODEPOINT_ENCODE3_11_7_14 (0x00FC, 0x0301, 0x01D8),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x00FC, 0x0304, 0x01D6),HB_CODEPOINT_ENCODE3_11_7_14 (0x00FC, 0x030C, 0x01DA),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0102, 0x0300, 0x1EB0),HB_CODEPOINT_ENCODE3_11_7_14 (0x0102, 0x0301, 0x1EAE),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0102, 0x0303, 0x1EB4),HB_CODEPOINT_ENCODE3_11_7_14 (0x0102, 0x0309, 0x1EB2),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0103, 0x0300, 0x1EB1),HB_CODEPOINT_ENCODE3_11_7_14 (0x0103, 0x0301, 0x1EAF),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0103, 0x0303, 0x1EB5),HB_CODEPOINT_ENCODE3_11_7_14 (0x0103, 0x0309, 0x1EB3),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0112, 0x0300, 0x1E14),HB_CODEPOINT_ENCODE3_11_7_14 (0x0112, 0x0301, 0x1E16),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0113, 0x0300, 0x1E15),HB_CODEPOINT_ENCODE3_11_7_14 (0x0113, 0x0301, 0x1E17),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x014C, 0x0300, 0x1E50),HB_CODEPOINT_ENCODE3_11_7_14 (0x014C, 0x0301, 0x1E52),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x014D, 0x0300, 0x1E51),HB_CODEPOINT_ENCODE3_11_7_14 (0x014D, 0x0301, 0x1E53),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x015A, 0x0307, 0x1E64),HB_CODEPOINT_ENCODE3_11_7_14 (0x015B, 0x0307, 0x1E65),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0160, 0x0307, 0x1E66),HB_CODEPOINT_ENCODE3_11_7_14 (0x0161, 0x0307, 0x1E67),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0168, 0x0301, 0x1E78),HB_CODEPOINT_ENCODE3_11_7_14 (0x0169, 0x0301, 0x1E79),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x016A, 0x0308, 0x1E7A),HB_CODEPOINT_ENCODE3_11_7_14 (0x016B, 0x0308, 0x1E7B),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x017F, 0x0307, 0x1E9B),HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0, 0x0300, 0x1EDC),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0, 0x0301, 0x1EDA),HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0, 0x0303, 0x1EE0),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0, 0x0309, 0x1EDE),HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0, 0x0323, 0x1EE2),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1, 0x0300, 0x1EDD),HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1, 0x0301, 0x1EDB),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1, 0x0303, 0x1EE1),HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1, 0x0309, 0x1EDF),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1, 0x0323, 0x1EE3),HB_CODEPOINT_ENCODE3_11_7_14 (0x01AF, 0x0300, 0x1EEA),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x01AF, 0x0301, 0x1EE8),HB_CODEPOINT_ENCODE3_11_7_14 (0x01AF, 0x0303, 0x1EEE),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x01AF, 0x0309, 0x1EEC),HB_CODEPOINT_ENCODE3_11_7_14 (0x01AF, 0x0323, 0x1EF0),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0, 0x0300, 0x1EEB),HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0, 0x0301, 0x1EE9),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0, 0x0303, 0x1EEF),HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0, 0x0309, 0x1EED),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0, 0x0323, 0x1EF1),HB_CODEPOINT_ENCODE3_11_7_14 (0x01B7, 0x030C, 0x01EE),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x01EA, 0x0304, 0x01EC),HB_CODEPOINT_ENCODE3_11_7_14 (0x01EB, 0x0304, 0x01ED),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0226, 0x0304, 0x01E0),HB_CODEPOINT_ENCODE3_11_7_14 (0x0227, 0x0304, 0x01E1),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0228, 0x0306, 0x1E1C),HB_CODEPOINT_ENCODE3_11_7_14 (0x0229, 0x0306, 0x1E1D),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x022E, 0x0304, 0x0230),HB_CODEPOINT_ENCODE3_11_7_14 (0x022F, 0x0304, 0x0231),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0292, 0x030C, 0x01EF),HB_CODEPOINT_ENCODE3_11_7_14 (0x0308, 0x0301, 0x0000),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0391, 0x0300, 0x1FBA),HB_CODEPOINT_ENCODE3_11_7_14 (0x0391, 0x0301, 0x0386),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0391, 0x0304, 0x1FB9),HB_CODEPOINT_ENCODE3_11_7_14 (0x0391, 0x0306, 0x1FB8),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0391, 0x0313, 0x1F08),HB_CODEPOINT_ENCODE3_11_7_14 (0x0391, 0x0314, 0x1F09),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0391, 0x0345, 0x1FBC),HB_CODEPOINT_ENCODE3_11_7_14 (0x0395, 0x0300, 0x1FC8),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0395, 0x0301, 0x0388),HB_CODEPOINT_ENCODE3_11_7_14 (0x0395, 0x0313, 0x1F18),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0395, 0x0314, 0x1F19),HB_CODEPOINT_ENCODE3_11_7_14 (0x0397, 0x0300, 0x1FCA),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0397, 0x0301, 0x0389),HB_CODEPOINT_ENCODE3_11_7_14 (0x0397, 0x0313, 0x1F28),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0397, 0x0314, 0x1F29),HB_CODEPOINT_ENCODE3_11_7_14 (0x0397, 0x0345, 0x1FCC),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0399, 0x0300, 0x1FDA),HB_CODEPOINT_ENCODE3_11_7_14 (0x0399, 0x0301, 0x038A),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0399, 0x0304, 0x1FD9),HB_CODEPOINT_ENCODE3_11_7_14 (0x0399, 0x0306, 0x1FD8),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0399, 0x0308, 0x03AA),HB_CODEPOINT_ENCODE3_11_7_14 (0x0399, 0x0313, 0x1F38),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0399, 0x0314, 0x1F39),HB_CODEPOINT_ENCODE3_11_7_14 (0x039F, 0x0300, 0x1FF8),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x039F, 0x0301, 0x038C),HB_CODEPOINT_ENCODE3_11_7_14 (0x039F, 0x0313, 0x1F48),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x039F, 0x0314, 0x1F49),HB_CODEPOINT_ENCODE3_11_7_14 (0x03A1, 0x0314, 0x1FEC),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5, 0x0300, 0x1FEA),HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5, 0x0301, 0x038E),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5, 0x0304, 0x1FE9),HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5, 0x0306, 0x1FE8),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5, 0x0308, 0x03AB),HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5, 0x0314, 0x1F59),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9, 0x0300, 0x1FFA),HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9, 0x0301, 0x038F),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9, 0x0313, 0x1F68),HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9, 0x0314, 0x1F69),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9, 0x0345, 0x1FFC),HB_CODEPOINT_ENCODE3_11_7_14 (0x03AC, 0x0345, 0x1FB4),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03AE, 0x0345, 0x1FC4),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1, 0x0300, 0x1F70),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1, 0x0301, 0x03AC),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1, 0x0304, 0x1FB1),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1, 0x0306, 0x1FB0),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1, 0x0313, 0x1F00),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1, 0x0314, 0x1F01),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1, 0x0342, 0x1FB6),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1, 0x0345, 0x1FB3),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5, 0x0300, 0x1F72),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5, 0x0301, 0x03AD),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5, 0x0313, 0x1F10),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5, 0x0314, 0x1F11),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7, 0x0300, 0x1F74),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7, 0x0301, 0x03AE),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7, 0x0313, 0x1F20),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7, 0x0314, 0x1F21),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7, 0x0342, 0x1FC6),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7, 0x0345, 0x1FC3),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9, 0x0300, 0x1F76),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9, 0x0301, 0x03AF),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9, 0x0304, 0x1FD1),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9, 0x0306, 0x1FD0),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9, 0x0308, 0x03CA),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9, 0x0313, 0x1F30),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9, 0x0314, 0x1F31),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9, 0x0342, 0x1FD6),HB_CODEPOINT_ENCODE3_11_7_14 (0x03BF, 0x0300, 0x1F78),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03BF, 0x0301, 0x03CC),HB_CODEPOINT_ENCODE3_11_7_14 (0x03BF, 0x0313, 0x1F40),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03BF, 0x0314, 0x1F41),HB_CODEPOINT_ENCODE3_11_7_14 (0x03C1, 0x0313, 0x1FE4),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03C1, 0x0314, 0x1FE5),HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5, 0x0300, 0x1F7A),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5, 0x0301, 0x03CD),HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5, 0x0304, 0x1FE1),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5, 0x0306, 0x1FE0),HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5, 0x0308, 0x03CB),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5, 0x0313, 0x1F50),HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5, 0x0314, 0x1F51),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5, 0x0342, 0x1FE6),HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9, 0x0300, 0x1F7C),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9, 0x0301, 0x03CE),HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9, 0x0313, 0x1F60),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9, 0x0314, 0x1F61),HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9, 0x0342, 0x1FF6),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9, 0x0345, 0x1FF3),HB_CODEPOINT_ENCODE3_11_7_14 (0x03CA, 0x0300, 0x1FD2),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03CA, 0x0301, 0x0390),HB_CODEPOINT_ENCODE3_11_7_14 (0x03CA, 0x0342, 0x1FD7),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03CB, 0x0300, 0x1FE2),HB_CODEPOINT_ENCODE3_11_7_14 (0x03CB, 0x0301, 0x03B0),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03CB, 0x0342, 0x1FE7),HB_CODEPOINT_ENCODE3_11_7_14 (0x03CE, 0x0345, 0x1FF4),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x03D2, 0x0301, 0x03D3),HB_CODEPOINT_ENCODE3_11_7_14 (0x03D2, 0x0308, 0x03D4),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0406, 0x0308, 0x0407),HB_CODEPOINT_ENCODE3_11_7_14 (0x0410, 0x0306, 0x04D0),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0410, 0x0308, 0x04D2),HB_CODEPOINT_ENCODE3_11_7_14 (0x0413, 0x0301, 0x0403),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0415, 0x0300, 0x0400),HB_CODEPOINT_ENCODE3_11_7_14 (0x0415, 0x0306, 0x04D6),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0415, 0x0308, 0x0401),HB_CODEPOINT_ENCODE3_11_7_14 (0x0416, 0x0306, 0x04C1),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0416, 0x0308, 0x04DC),HB_CODEPOINT_ENCODE3_11_7_14 (0x0417, 0x0308, 0x04DE),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0418, 0x0300, 0x040D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0418, 0x0304, 0x04E2),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0418, 0x0306, 0x0419),HB_CODEPOINT_ENCODE3_11_7_14 (0x0418, 0x0308, 0x04E4),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x041A, 0x0301, 0x040C),HB_CODEPOINT_ENCODE3_11_7_14 (0x041E, 0x0308, 0x04E6),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0423, 0x0304, 0x04EE),HB_CODEPOINT_ENCODE3_11_7_14 (0x0423, 0x0306, 0x040E),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0423, 0x0308, 0x04F0),HB_CODEPOINT_ENCODE3_11_7_14 (0x0423, 0x030B, 0x04F2),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0427, 0x0308, 0x04F4),HB_CODEPOINT_ENCODE3_11_7_14 (0x042B, 0x0308, 0x04F8),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x042D, 0x0308, 0x04EC),HB_CODEPOINT_ENCODE3_11_7_14 (0x0430, 0x0306, 0x04D1),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0430, 0x0308, 0x04D3),HB_CODEPOINT_ENCODE3_11_7_14 (0x0433, 0x0301, 0x0453),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0435, 0x0300, 0x0450),HB_CODEPOINT_ENCODE3_11_7_14 (0x0435, 0x0306, 0x04D7),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0435, 0x0308, 0x0451),HB_CODEPOINT_ENCODE3_11_7_14 (0x0436, 0x0306, 0x04C2),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0436, 0x0308, 0x04DD),HB_CODEPOINT_ENCODE3_11_7_14 (0x0437, 0x0308, 0x04DF),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0438, 0x0300, 0x045D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0438, 0x0304, 0x04E3),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0438, 0x0306, 0x0439),HB_CODEPOINT_ENCODE3_11_7_14 (0x0438, 0x0308, 0x04E5),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x043A, 0x0301, 0x045C),HB_CODEPOINT_ENCODE3_11_7_14 (0x043E, 0x0308, 0x04E7),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0443, 0x0304, 0x04EF),HB_CODEPOINT_ENCODE3_11_7_14 (0x0443, 0x0306, 0x045E),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0443, 0x0308, 0x04F1),HB_CODEPOINT_ENCODE3_11_7_14 (0x0443, 0x030B, 0x04F3),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0447, 0x0308, 0x04F5),HB_CODEPOINT_ENCODE3_11_7_14 (0x044B, 0x0308, 0x04F9),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x044D, 0x0308, 0x04ED),HB_CODEPOINT_ENCODE3_11_7_14 (0x0456, 0x0308, 0x0457),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x0474, 0x030F, 0x0476),HB_CODEPOINT_ENCODE3_11_7_14 (0x0475, 0x030F, 0x0477),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x04D8, 0x0308, 0x04DA),HB_CODEPOINT_ENCODE3_11_7_14 (0x04D9, 0x0308, 0x04DB),
+  HB_CODEPOINT_ENCODE3_11_7_14 (0x04E8, 0x0308, 0x04EA),HB_CODEPOINT_ENCODE3_11_7_14 (0x04E9, 0x0308, 0x04EB),
 };
-static const uint64_t
-_hb_ucd_dm2_u64_map[408] =
+static const uint64_t _hb_ucd_dm2_u64_map[408]=
 {
-     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 (0x105D2u, 0x0307u, 0x105C9u), HB_CODEPOINT_ENCODE3 (0x105DAu, 0x0307u, 0x105E4u),
-  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 (0x11382u, 0x113C9u, 0x11383u),
-  HB_CODEPOINT_ENCODE3 (0x11384u, 0x113BBu, 0x11385u),HB_CODEPOINT_ENCODE3 (0x1138Bu, 0x113C2u, 0x1138Eu),
-  HB_CODEPOINT_ENCODE3 (0x11390u, 0x113C9u, 0x11391u),HB_CODEPOINT_ENCODE3 (0x113C2u, 0x113B8u, 0x113C7u),
-  HB_CODEPOINT_ENCODE3 (0x113C2u, 0x113C2u, 0x113C5u),HB_CODEPOINT_ENCODE3 (0x113C2u, 0x113C9u, 0x113C8u),
-  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 (0x1611Eu, 0x1611Eu, 0x16121u),HB_CODEPOINT_ENCODE3 (0x1611Eu, 0x1611Fu, 0x16123u),
-  HB_CODEPOINT_ENCODE3 (0x1611Eu, 0x16120u, 0x16125u),HB_CODEPOINT_ENCODE3 (0x1611Eu, 0x16129u, 0x16122u),
-  HB_CODEPOINT_ENCODE3 (0x16121u, 0x1611Fu, 0x16126u),HB_CODEPOINT_ENCODE3 (0x16121u, 0x16120u, 0x16128u),
-  HB_CODEPOINT_ENCODE3 (0x16122u, 0x1611Fu, 0x16127u),HB_CODEPOINT_ENCODE3 (0x16129u, 0x1611Fu, 0x16124u),
-  HB_CODEPOINT_ENCODE3 (0x16D63u, 0x16D67u, 0x16D69u),HB_CODEPOINT_ENCODE3 (0x16D67u, 0x16D67u, 0x16D68u),
-  HB_CODEPOINT_ENCODE3 (0x16D69u, 0x16D67u, 0x16D6Au), 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),
+     HB_CODEPOINT_ENCODE3 (0x05D0, 0x05B7, 0x0000),   HB_CODEPOINT_ENCODE3 (0x05D0, 0x05B8, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x05D0, 0x05BC, 0x0000),   HB_CODEPOINT_ENCODE3 (0x05D1, 0x05BC, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x05D1, 0x05BF, 0x0000),   HB_CODEPOINT_ENCODE3 (0x05D2, 0x05BC, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x05D3, 0x05BC, 0x0000),   HB_CODEPOINT_ENCODE3 (0x05D4, 0x05BC, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x05D5, 0x05B9, 0x0000),   HB_CODEPOINT_ENCODE3 (0x05D5, 0x05BC, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x05D6, 0x05BC, 0x0000),   HB_CODEPOINT_ENCODE3 (0x05D8, 0x05BC, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x05D9, 0x05B4, 0x0000),   HB_CODEPOINT_ENCODE3 (0x05D9, 0x05BC, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x05DA, 0x05BC, 0x0000),   HB_CODEPOINT_ENCODE3 (0x05DB, 0x05BC, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x05DB, 0x05BF, 0x0000),   HB_CODEPOINT_ENCODE3 (0x05DC, 0x05BC, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x05DE, 0x05BC, 0x0000),   HB_CODEPOINT_ENCODE3 (0x05E0, 0x05BC, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x05E1, 0x05BC, 0x0000),   HB_CODEPOINT_ENCODE3 (0x05E3, 0x05BC, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x05E4, 0x05BC, 0x0000),   HB_CODEPOINT_ENCODE3 (0x05E4, 0x05BF, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x05E6, 0x05BC, 0x0000),   HB_CODEPOINT_ENCODE3 (0x05E7, 0x05BC, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x05E8, 0x05BC, 0x0000),   HB_CODEPOINT_ENCODE3 (0x05E9, 0x05BC, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x05E9, 0x05C1, 0x0000),   HB_CODEPOINT_ENCODE3 (0x05E9, 0x05C2, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x05EA, 0x05BC, 0x0000),   HB_CODEPOINT_ENCODE3 (0x05F2, 0x05B7, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x0627, 0x0653, 0x0622),   HB_CODEPOINT_ENCODE3 (0x0627, 0x0654, 0x0623),
+     HB_CODEPOINT_ENCODE3 (0x0627, 0x0655, 0x0625),   HB_CODEPOINT_ENCODE3 (0x0648, 0x0654, 0x0624),
+     HB_CODEPOINT_ENCODE3 (0x064A, 0x0654, 0x0626),   HB_CODEPOINT_ENCODE3 (0x06C1, 0x0654, 0x06C2),
+     HB_CODEPOINT_ENCODE3 (0x06D2, 0x0654, 0x06D3),   HB_CODEPOINT_ENCODE3 (0x06D5, 0x0654, 0x06C0),
+     HB_CODEPOINT_ENCODE3 (0x0915, 0x093C, 0x0000),   HB_CODEPOINT_ENCODE3 (0x0916, 0x093C, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x0917, 0x093C, 0x0000),   HB_CODEPOINT_ENCODE3 (0x091C, 0x093C, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x0921, 0x093C, 0x0000),   HB_CODEPOINT_ENCODE3 (0x0922, 0x093C, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x0928, 0x093C, 0x0929),   HB_CODEPOINT_ENCODE3 (0x092B, 0x093C, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x092F, 0x093C, 0x0000),   HB_CODEPOINT_ENCODE3 (0x0930, 0x093C, 0x0931),
+     HB_CODEPOINT_ENCODE3 (0x0933, 0x093C, 0x0934),   HB_CODEPOINT_ENCODE3 (0x09A1, 0x09BC, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x09A2, 0x09BC, 0x0000),   HB_CODEPOINT_ENCODE3 (0x09AF, 0x09BC, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x09C7, 0x09BE, 0x09CB),   HB_CODEPOINT_ENCODE3 (0x09C7, 0x09D7, 0x09CC),
+     HB_CODEPOINT_ENCODE3 (0x0A16, 0x0A3C, 0x0000),   HB_CODEPOINT_ENCODE3 (0x0A17, 0x0A3C, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x0A1C, 0x0A3C, 0x0000),   HB_CODEPOINT_ENCODE3 (0x0A2B, 0x0A3C, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x0A32, 0x0A3C, 0x0000),   HB_CODEPOINT_ENCODE3 (0x0A38, 0x0A3C, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x0B21, 0x0B3C, 0x0000),   HB_CODEPOINT_ENCODE3 (0x0B22, 0x0B3C, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x0B47, 0x0B3E, 0x0B4B),   HB_CODEPOINT_ENCODE3 (0x0B47, 0x0B56, 0x0B48),
+     HB_CODEPOINT_ENCODE3 (0x0B47, 0x0B57, 0x0B4C),   HB_CODEPOINT_ENCODE3 (0x0B92, 0x0BD7, 0x0B94),
+     HB_CODEPOINT_ENCODE3 (0x0BC6, 0x0BBE, 0x0BCA),   HB_CODEPOINT_ENCODE3 (0x0BC6, 0x0BD7, 0x0BCC),
+     HB_CODEPOINT_ENCODE3 (0x0BC7, 0x0BBE, 0x0BCB),   HB_CODEPOINT_ENCODE3 (0x0C46, 0x0C56, 0x0C48),
+     HB_CODEPOINT_ENCODE3 (0x0CBF, 0x0CD5, 0x0CC0),   HB_CODEPOINT_ENCODE3 (0x0CC6, 0x0CC2, 0x0CCA),
+     HB_CODEPOINT_ENCODE3 (0x0CC6, 0x0CD5, 0x0CC7),   HB_CODEPOINT_ENCODE3 (0x0CC6, 0x0CD6, 0x0CC8),
+     HB_CODEPOINT_ENCODE3 (0x0CCA, 0x0CD5, 0x0CCB),   HB_CODEPOINT_ENCODE3 (0x0D46, 0x0D3E, 0x0D4A),
+     HB_CODEPOINT_ENCODE3 (0x0D46, 0x0D57, 0x0D4C),   HB_CODEPOINT_ENCODE3 (0x0D47, 0x0D3E, 0x0D4B),
+     HB_CODEPOINT_ENCODE3 (0x0DD9, 0x0DCA, 0x0DDA),   HB_CODEPOINT_ENCODE3 (0x0DD9, 0x0DCF, 0x0DDC),
+     HB_CODEPOINT_ENCODE3 (0x0DD9, 0x0DDF, 0x0DDE),   HB_CODEPOINT_ENCODE3 (0x0DDC, 0x0DCA, 0x0DDD),
+     HB_CODEPOINT_ENCODE3 (0x0F40, 0x0FB5, 0x0000),   HB_CODEPOINT_ENCODE3 (0x0F42, 0x0FB7, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x0F4C, 0x0FB7, 0x0000),   HB_CODEPOINT_ENCODE3 (0x0F51, 0x0FB7, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x0F56, 0x0FB7, 0x0000),   HB_CODEPOINT_ENCODE3 (0x0F5B, 0x0FB7, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x0F71, 0x0F72, 0x0000),   HB_CODEPOINT_ENCODE3 (0x0F71, 0x0F74, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x0F71, 0x0F80, 0x0000),   HB_CODEPOINT_ENCODE3 (0x0F90, 0x0FB5, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x0F92, 0x0FB7, 0x0000),   HB_CODEPOINT_ENCODE3 (0x0F9C, 0x0FB7, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x0FA1, 0x0FB7, 0x0000),   HB_CODEPOINT_ENCODE3 (0x0FA6, 0x0FB7, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x0FAB, 0x0FB7, 0x0000),   HB_CODEPOINT_ENCODE3 (0x0FB2, 0x0F80, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x0FB3, 0x0F80, 0x0000),   HB_CODEPOINT_ENCODE3 (0x1025, 0x102E, 0x1026),
+     HB_CODEPOINT_ENCODE3 (0x1B05, 0x1B35, 0x1B06),   HB_CODEPOINT_ENCODE3 (0x1B07, 0x1B35, 0x1B08),
+     HB_CODEPOINT_ENCODE3 (0x1B09, 0x1B35, 0x1B0A),   HB_CODEPOINT_ENCODE3 (0x1B0B, 0x1B35, 0x1B0C),
+     HB_CODEPOINT_ENCODE3 (0x1B0D, 0x1B35, 0x1B0E),   HB_CODEPOINT_ENCODE3 (0x1B11, 0x1B35, 0x1B12),
+     HB_CODEPOINT_ENCODE3 (0x1B3A, 0x1B35, 0x1B3B),   HB_CODEPOINT_ENCODE3 (0x1B3C, 0x1B35, 0x1B3D),
+     HB_CODEPOINT_ENCODE3 (0x1B3E, 0x1B35, 0x1B40),   HB_CODEPOINT_ENCODE3 (0x1B3F, 0x1B35, 0x1B41),
+     HB_CODEPOINT_ENCODE3 (0x1B42, 0x1B35, 0x1B43),   HB_CODEPOINT_ENCODE3 (0x1E36, 0x0304, 0x1E38),
+     HB_CODEPOINT_ENCODE3 (0x1E37, 0x0304, 0x1E39),   HB_CODEPOINT_ENCODE3 (0x1E5A, 0x0304, 0x1E5C),
+     HB_CODEPOINT_ENCODE3 (0x1E5B, 0x0304, 0x1E5D),   HB_CODEPOINT_ENCODE3 (0x1E62, 0x0307, 0x1E68),
+     HB_CODEPOINT_ENCODE3 (0x1E63, 0x0307, 0x1E69),   HB_CODEPOINT_ENCODE3 (0x1EA0, 0x0302, 0x1EAC),
+     HB_CODEPOINT_ENCODE3 (0x1EA0, 0x0306, 0x1EB6),   HB_CODEPOINT_ENCODE3 (0x1EA1, 0x0302, 0x1EAD),
+     HB_CODEPOINT_ENCODE3 (0x1EA1, 0x0306, 0x1EB7),   HB_CODEPOINT_ENCODE3 (0x1EB8, 0x0302, 0x1EC6),
+     HB_CODEPOINT_ENCODE3 (0x1EB9, 0x0302, 0x1EC7),   HB_CODEPOINT_ENCODE3 (0x1ECC, 0x0302, 0x1ED8),
+     HB_CODEPOINT_ENCODE3 (0x1ECD, 0x0302, 0x1ED9),   HB_CODEPOINT_ENCODE3 (0x1F00, 0x0300, 0x1F02),
+     HB_CODEPOINT_ENCODE3 (0x1F00, 0x0301, 0x1F04),   HB_CODEPOINT_ENCODE3 (0x1F00, 0x0342, 0x1F06),
+     HB_CODEPOINT_ENCODE3 (0x1F00, 0x0345, 0x1F80),   HB_CODEPOINT_ENCODE3 (0x1F01, 0x0300, 0x1F03),
+     HB_CODEPOINT_ENCODE3 (0x1F01, 0x0301, 0x1F05),   HB_CODEPOINT_ENCODE3 (0x1F01, 0x0342, 0x1F07),
+     HB_CODEPOINT_ENCODE3 (0x1F01, 0x0345, 0x1F81),   HB_CODEPOINT_ENCODE3 (0x1F02, 0x0345, 0x1F82),
+     HB_CODEPOINT_ENCODE3 (0x1F03, 0x0345, 0x1F83),   HB_CODEPOINT_ENCODE3 (0x1F04, 0x0345, 0x1F84),
+     HB_CODEPOINT_ENCODE3 (0x1F05, 0x0345, 0x1F85),   HB_CODEPOINT_ENCODE3 (0x1F06, 0x0345, 0x1F86),
+     HB_CODEPOINT_ENCODE3 (0x1F07, 0x0345, 0x1F87),   HB_CODEPOINT_ENCODE3 (0x1F08, 0x0300, 0x1F0A),
+     HB_CODEPOINT_ENCODE3 (0x1F08, 0x0301, 0x1F0C),   HB_CODEPOINT_ENCODE3 (0x1F08, 0x0342, 0x1F0E),
+     HB_CODEPOINT_ENCODE3 (0x1F08, 0x0345, 0x1F88),   HB_CODEPOINT_ENCODE3 (0x1F09, 0x0300, 0x1F0B),
+     HB_CODEPOINT_ENCODE3 (0x1F09, 0x0301, 0x1F0D),   HB_CODEPOINT_ENCODE3 (0x1F09, 0x0342, 0x1F0F),
+     HB_CODEPOINT_ENCODE3 (0x1F09, 0x0345, 0x1F89),   HB_CODEPOINT_ENCODE3 (0x1F0A, 0x0345, 0x1F8A),
+     HB_CODEPOINT_ENCODE3 (0x1F0B, 0x0345, 0x1F8B),   HB_CODEPOINT_ENCODE3 (0x1F0C, 0x0345, 0x1F8C),
+     HB_CODEPOINT_ENCODE3 (0x1F0D, 0x0345, 0x1F8D),   HB_CODEPOINT_ENCODE3 (0x1F0E, 0x0345, 0x1F8E),
+     HB_CODEPOINT_ENCODE3 (0x1F0F, 0x0345, 0x1F8F),   HB_CODEPOINT_ENCODE3 (0x1F10, 0x0300, 0x1F12),
+     HB_CODEPOINT_ENCODE3 (0x1F10, 0x0301, 0x1F14),   HB_CODEPOINT_ENCODE3 (0x1F11, 0x0300, 0x1F13),
+     HB_CODEPOINT_ENCODE3 (0x1F11, 0x0301, 0x1F15),   HB_CODEPOINT_ENCODE3 (0x1F18, 0x0300, 0x1F1A),
+     HB_CODEPOINT_ENCODE3 (0x1F18, 0x0301, 0x1F1C),   HB_CODEPOINT_ENCODE3 (0x1F19, 0x0300, 0x1F1B),
+     HB_CODEPOINT_ENCODE3 (0x1F19, 0x0301, 0x1F1D),   HB_CODEPOINT_ENCODE3 (0x1F20, 0x0300, 0x1F22),
+     HB_CODEPOINT_ENCODE3 (0x1F20, 0x0301, 0x1F24),   HB_CODEPOINT_ENCODE3 (0x1F20, 0x0342, 0x1F26),
+     HB_CODEPOINT_ENCODE3 (0x1F20, 0x0345, 0x1F90),   HB_CODEPOINT_ENCODE3 (0x1F21, 0x0300, 0x1F23),
+     HB_CODEPOINT_ENCODE3 (0x1F21, 0x0301, 0x1F25),   HB_CODEPOINT_ENCODE3 (0x1F21, 0x0342, 0x1F27),
+     HB_CODEPOINT_ENCODE3 (0x1F21, 0x0345, 0x1F91),   HB_CODEPOINT_ENCODE3 (0x1F22, 0x0345, 0x1F92),
+     HB_CODEPOINT_ENCODE3 (0x1F23, 0x0345, 0x1F93),   HB_CODEPOINT_ENCODE3 (0x1F24, 0x0345, 0x1F94),
+     HB_CODEPOINT_ENCODE3 (0x1F25, 0x0345, 0x1F95),   HB_CODEPOINT_ENCODE3 (0x1F26, 0x0345, 0x1F96),
+     HB_CODEPOINT_ENCODE3 (0x1F27, 0x0345, 0x1F97),   HB_CODEPOINT_ENCODE3 (0x1F28, 0x0300, 0x1F2A),
+     HB_CODEPOINT_ENCODE3 (0x1F28, 0x0301, 0x1F2C),   HB_CODEPOINT_ENCODE3 (0x1F28, 0x0342, 0x1F2E),
+     HB_CODEPOINT_ENCODE3 (0x1F28, 0x0345, 0x1F98),   HB_CODEPOINT_ENCODE3 (0x1F29, 0x0300, 0x1F2B),
+     HB_CODEPOINT_ENCODE3 (0x1F29, 0x0301, 0x1F2D),   HB_CODEPOINT_ENCODE3 (0x1F29, 0x0342, 0x1F2F),
+     HB_CODEPOINT_ENCODE3 (0x1F29, 0x0345, 0x1F99),   HB_CODEPOINT_ENCODE3 (0x1F2A, 0x0345, 0x1F9A),
+     HB_CODEPOINT_ENCODE3 (0x1F2B, 0x0345, 0x1F9B),   HB_CODEPOINT_ENCODE3 (0x1F2C, 0x0345, 0x1F9C),
+     HB_CODEPOINT_ENCODE3 (0x1F2D, 0x0345, 0x1F9D),   HB_CODEPOINT_ENCODE3 (0x1F2E, 0x0345, 0x1F9E),
+     HB_CODEPOINT_ENCODE3 (0x1F2F, 0x0345, 0x1F9F),   HB_CODEPOINT_ENCODE3 (0x1F30, 0x0300, 0x1F32),
+     HB_CODEPOINT_ENCODE3 (0x1F30, 0x0301, 0x1F34),   HB_CODEPOINT_ENCODE3 (0x1F30, 0x0342, 0x1F36),
+     HB_CODEPOINT_ENCODE3 (0x1F31, 0x0300, 0x1F33),   HB_CODEPOINT_ENCODE3 (0x1F31, 0x0301, 0x1F35),
+     HB_CODEPOINT_ENCODE3 (0x1F31, 0x0342, 0x1F37),   HB_CODEPOINT_ENCODE3 (0x1F38, 0x0300, 0x1F3A),
+     HB_CODEPOINT_ENCODE3 (0x1F38, 0x0301, 0x1F3C),   HB_CODEPOINT_ENCODE3 (0x1F38, 0x0342, 0x1F3E),
+     HB_CODEPOINT_ENCODE3 (0x1F39, 0x0300, 0x1F3B),   HB_CODEPOINT_ENCODE3 (0x1F39, 0x0301, 0x1F3D),
+     HB_CODEPOINT_ENCODE3 (0x1F39, 0x0342, 0x1F3F),   HB_CODEPOINT_ENCODE3 (0x1F40, 0x0300, 0x1F42),
+     HB_CODEPOINT_ENCODE3 (0x1F40, 0x0301, 0x1F44),   HB_CODEPOINT_ENCODE3 (0x1F41, 0x0300, 0x1F43),
+     HB_CODEPOINT_ENCODE3 (0x1F41, 0x0301, 0x1F45),   HB_CODEPOINT_ENCODE3 (0x1F48, 0x0300, 0x1F4A),
+     HB_CODEPOINT_ENCODE3 (0x1F48, 0x0301, 0x1F4C),   HB_CODEPOINT_ENCODE3 (0x1F49, 0x0300, 0x1F4B),
+     HB_CODEPOINT_ENCODE3 (0x1F49, 0x0301, 0x1F4D),   HB_CODEPOINT_ENCODE3 (0x1F50, 0x0300, 0x1F52),
+     HB_CODEPOINT_ENCODE3 (0x1F50, 0x0301, 0x1F54),   HB_CODEPOINT_ENCODE3 (0x1F50, 0x0342, 0x1F56),
+     HB_CODEPOINT_ENCODE3 (0x1F51, 0x0300, 0x1F53),   HB_CODEPOINT_ENCODE3 (0x1F51, 0x0301, 0x1F55),
+     HB_CODEPOINT_ENCODE3 (0x1F51, 0x0342, 0x1F57),   HB_CODEPOINT_ENCODE3 (0x1F59, 0x0300, 0x1F5B),
+     HB_CODEPOINT_ENCODE3 (0x1F59, 0x0301, 0x1F5D),   HB_CODEPOINT_ENCODE3 (0x1F59, 0x0342, 0x1F5F),
+     HB_CODEPOINT_ENCODE3 (0x1F60, 0x0300, 0x1F62),   HB_CODEPOINT_ENCODE3 (0x1F60, 0x0301, 0x1F64),
+     HB_CODEPOINT_ENCODE3 (0x1F60, 0x0342, 0x1F66),   HB_CODEPOINT_ENCODE3 (0x1F60, 0x0345, 0x1FA0),
+     HB_CODEPOINT_ENCODE3 (0x1F61, 0x0300, 0x1F63),   HB_CODEPOINT_ENCODE3 (0x1F61, 0x0301, 0x1F65),
+     HB_CODEPOINT_ENCODE3 (0x1F61, 0x0342, 0x1F67),   HB_CODEPOINT_ENCODE3 (0x1F61, 0x0345, 0x1FA1),
+     HB_CODEPOINT_ENCODE3 (0x1F62, 0x0345, 0x1FA2),   HB_CODEPOINT_ENCODE3 (0x1F63, 0x0345, 0x1FA3),
+     HB_CODEPOINT_ENCODE3 (0x1F64, 0x0345, 0x1FA4),   HB_CODEPOINT_ENCODE3 (0x1F65, 0x0345, 0x1FA5),
+     HB_CODEPOINT_ENCODE3 (0x1F66, 0x0345, 0x1FA6),   HB_CODEPOINT_ENCODE3 (0x1F67, 0x0345, 0x1FA7),
+     HB_CODEPOINT_ENCODE3 (0x1F68, 0x0300, 0x1F6A),   HB_CODEPOINT_ENCODE3 (0x1F68, 0x0301, 0x1F6C),
+     HB_CODEPOINT_ENCODE3 (0x1F68, 0x0342, 0x1F6E),   HB_CODEPOINT_ENCODE3 (0x1F68, 0x0345, 0x1FA8),
+     HB_CODEPOINT_ENCODE3 (0x1F69, 0x0300, 0x1F6B),   HB_CODEPOINT_ENCODE3 (0x1F69, 0x0301, 0x1F6D),
+     HB_CODEPOINT_ENCODE3 (0x1F69, 0x0342, 0x1F6F),   HB_CODEPOINT_ENCODE3 (0x1F69, 0x0345, 0x1FA9),
+     HB_CODEPOINT_ENCODE3 (0x1F6A, 0x0345, 0x1FAA),   HB_CODEPOINT_ENCODE3 (0x1F6B, 0x0345, 0x1FAB),
+     HB_CODEPOINT_ENCODE3 (0x1F6C, 0x0345, 0x1FAC),   HB_CODEPOINT_ENCODE3 (0x1F6D, 0x0345, 0x1FAD),
+     HB_CODEPOINT_ENCODE3 (0x1F6E, 0x0345, 0x1FAE),   HB_CODEPOINT_ENCODE3 (0x1F6F, 0x0345, 0x1FAF),
+     HB_CODEPOINT_ENCODE3 (0x1F70, 0x0345, 0x1FB2),   HB_CODEPOINT_ENCODE3 (0x1F74, 0x0345, 0x1FC2),
+     HB_CODEPOINT_ENCODE3 (0x1F7C, 0x0345, 0x1FF2),   HB_CODEPOINT_ENCODE3 (0x1FB6, 0x0345, 0x1FB7),
+     HB_CODEPOINT_ENCODE3 (0x1FBF, 0x0300, 0x1FCD),   HB_CODEPOINT_ENCODE3 (0x1FBF, 0x0301, 0x1FCE),
+     HB_CODEPOINT_ENCODE3 (0x1FBF, 0x0342, 0x1FCF),   HB_CODEPOINT_ENCODE3 (0x1FC6, 0x0345, 0x1FC7),
+     HB_CODEPOINT_ENCODE3 (0x1FF6, 0x0345, 0x1FF7),   HB_CODEPOINT_ENCODE3 (0x1FFE, 0x0300, 0x1FDD),
+     HB_CODEPOINT_ENCODE3 (0x1FFE, 0x0301, 0x1FDE),   HB_CODEPOINT_ENCODE3 (0x1FFE, 0x0342, 0x1FDF),
+     HB_CODEPOINT_ENCODE3 (0x2190, 0x0338, 0x219A),   HB_CODEPOINT_ENCODE3 (0x2192, 0x0338, 0x219B),
+     HB_CODEPOINT_ENCODE3 (0x2194, 0x0338, 0x21AE),   HB_CODEPOINT_ENCODE3 (0x21D0, 0x0338, 0x21CD),
+     HB_CODEPOINT_ENCODE3 (0x21D2, 0x0338, 0x21CF),   HB_CODEPOINT_ENCODE3 (0x21D4, 0x0338, 0x21CE),
+     HB_CODEPOINT_ENCODE3 (0x2203, 0x0338, 0x2204),   HB_CODEPOINT_ENCODE3 (0x2208, 0x0338, 0x2209),
+     HB_CODEPOINT_ENCODE3 (0x220B, 0x0338, 0x220C),   HB_CODEPOINT_ENCODE3 (0x2223, 0x0338, 0x2224),
+     HB_CODEPOINT_ENCODE3 (0x2225, 0x0338, 0x2226),   HB_CODEPOINT_ENCODE3 (0x223C, 0x0338, 0x2241),
+     HB_CODEPOINT_ENCODE3 (0x2243, 0x0338, 0x2244),   HB_CODEPOINT_ENCODE3 (0x2245, 0x0338, 0x2247),
+     HB_CODEPOINT_ENCODE3 (0x2248, 0x0338, 0x2249),   HB_CODEPOINT_ENCODE3 (0x224D, 0x0338, 0x226D),
+     HB_CODEPOINT_ENCODE3 (0x2261, 0x0338, 0x2262),   HB_CODEPOINT_ENCODE3 (0x2264, 0x0338, 0x2270),
+     HB_CODEPOINT_ENCODE3 (0x2265, 0x0338, 0x2271),   HB_CODEPOINT_ENCODE3 (0x2272, 0x0338, 0x2274),
+     HB_CODEPOINT_ENCODE3 (0x2273, 0x0338, 0x2275),   HB_CODEPOINT_ENCODE3 (0x2276, 0x0338, 0x2278),
+     HB_CODEPOINT_ENCODE3 (0x2277, 0x0338, 0x2279),   HB_CODEPOINT_ENCODE3 (0x227A, 0x0338, 0x2280),
+     HB_CODEPOINT_ENCODE3 (0x227B, 0x0338, 0x2281),   HB_CODEPOINT_ENCODE3 (0x227C, 0x0338, 0x22E0),
+     HB_CODEPOINT_ENCODE3 (0x227D, 0x0338, 0x22E1),   HB_CODEPOINT_ENCODE3 (0x2282, 0x0338, 0x2284),
+     HB_CODEPOINT_ENCODE3 (0x2283, 0x0338, 0x2285),   HB_CODEPOINT_ENCODE3 (0x2286, 0x0338, 0x2288),
+     HB_CODEPOINT_ENCODE3 (0x2287, 0x0338, 0x2289),   HB_CODEPOINT_ENCODE3 (0x2291, 0x0338, 0x22E2),
+     HB_CODEPOINT_ENCODE3 (0x2292, 0x0338, 0x22E3),   HB_CODEPOINT_ENCODE3 (0x22A2, 0x0338, 0x22AC),
+     HB_CODEPOINT_ENCODE3 (0x22A8, 0x0338, 0x22AD),   HB_CODEPOINT_ENCODE3 (0x22A9, 0x0338, 0x22AE),
+     HB_CODEPOINT_ENCODE3 (0x22AB, 0x0338, 0x22AF),   HB_CODEPOINT_ENCODE3 (0x22B2, 0x0338, 0x22EA),
+     HB_CODEPOINT_ENCODE3 (0x22B3, 0x0338, 0x22EB),   HB_CODEPOINT_ENCODE3 (0x22B4, 0x0338, 0x22EC),
+     HB_CODEPOINT_ENCODE3 (0x22B5, 0x0338, 0x22ED),   HB_CODEPOINT_ENCODE3 (0x2ADD, 0x0338, 0x0000),
+     HB_CODEPOINT_ENCODE3 (0x3046, 0x3099, 0x3094),   HB_CODEPOINT_ENCODE3 (0x304B, 0x3099, 0x304C),
+     HB_CODEPOINT_ENCODE3 (0x304D, 0x3099, 0x304E),   HB_CODEPOINT_ENCODE3 (0x304F, 0x3099, 0x3050),
+     HB_CODEPOINT_ENCODE3 (0x3051, 0x3099, 0x3052),   HB_CODEPOINT_ENCODE3 (0x3053, 0x3099, 0x3054),
+     HB_CODEPOINT_ENCODE3 (0x3055, 0x3099, 0x3056),   HB_CODEPOINT_ENCODE3 (0x3057, 0x3099, 0x3058),
+     HB_CODEPOINT_ENCODE3 (0x3059, 0x3099, 0x305A),   HB_CODEPOINT_ENCODE3 (0x305B, 0x3099, 0x305C),
+     HB_CODEPOINT_ENCODE3 (0x305D, 0x3099, 0x305E),   HB_CODEPOINT_ENCODE3 (0x305F, 0x3099, 0x3060),
+     HB_CODEPOINT_ENCODE3 (0x3061, 0x3099, 0x3062),   HB_CODEPOINT_ENCODE3 (0x3064, 0x3099, 0x3065),
+     HB_CODEPOINT_ENCODE3 (0x3066, 0x3099, 0x3067),   HB_CODEPOINT_ENCODE3 (0x3068, 0x3099, 0x3069),
+     HB_CODEPOINT_ENCODE3 (0x306F, 0x3099, 0x3070),   HB_CODEPOINT_ENCODE3 (0x306F, 0x309A, 0x3071),
+     HB_CODEPOINT_ENCODE3 (0x3072, 0x3099, 0x3073),   HB_CODEPOINT_ENCODE3 (0x3072, 0x309A, 0x3074),
+     HB_CODEPOINT_ENCODE3 (0x3075, 0x3099, 0x3076),   HB_CODEPOINT_ENCODE3 (0x3075, 0x309A, 0x3077),
+     HB_CODEPOINT_ENCODE3 (0x3078, 0x3099, 0x3079),   HB_CODEPOINT_ENCODE3 (0x3078, 0x309A, 0x307A),
+     HB_CODEPOINT_ENCODE3 (0x307B, 0x3099, 0x307C),   HB_CODEPOINT_ENCODE3 (0x307B, 0x309A, 0x307D),
+     HB_CODEPOINT_ENCODE3 (0x309D, 0x3099, 0x309E),   HB_CODEPOINT_ENCODE3 (0x30A6, 0x3099, 0x30F4),
+     HB_CODEPOINT_ENCODE3 (0x30AB, 0x3099, 0x30AC),   HB_CODEPOINT_ENCODE3 (0x30AD, 0x3099, 0x30AE),
+     HB_CODEPOINT_ENCODE3 (0x30AF, 0x3099, 0x30B0),   HB_CODEPOINT_ENCODE3 (0x30B1, 0x3099, 0x30B2),
+     HB_CODEPOINT_ENCODE3 (0x30B3, 0x3099, 0x30B4),   HB_CODEPOINT_ENCODE3 (0x30B5, 0x3099, 0x30B6),
+     HB_CODEPOINT_ENCODE3 (0x30B7, 0x3099, 0x30B8),   HB_CODEPOINT_ENCODE3 (0x30B9, 0x3099, 0x30BA),
+     HB_CODEPOINT_ENCODE3 (0x30BB, 0x3099, 0x30BC),   HB_CODEPOINT_ENCODE3 (0x30BD, 0x3099, 0x30BE),
+     HB_CODEPOINT_ENCODE3 (0x30BF, 0x3099, 0x30C0),   HB_CODEPOINT_ENCODE3 (0x30C1, 0x3099, 0x30C2),
+     HB_CODEPOINT_ENCODE3 (0x30C4, 0x3099, 0x30C5),   HB_CODEPOINT_ENCODE3 (0x30C6, 0x3099, 0x30C7),
+     HB_CODEPOINT_ENCODE3 (0x30C8, 0x3099, 0x30C9),   HB_CODEPOINT_ENCODE3 (0x30CF, 0x3099, 0x30D0),
+     HB_CODEPOINT_ENCODE3 (0x30CF, 0x309A, 0x30D1),   HB_CODEPOINT_ENCODE3 (0x30D2, 0x3099, 0x30D3),
+     HB_CODEPOINT_ENCODE3 (0x30D2, 0x309A, 0x30D4),   HB_CODEPOINT_ENCODE3 (0x30D5, 0x3099, 0x30D6),
+     HB_CODEPOINT_ENCODE3 (0x30D5, 0x309A, 0x30D7),   HB_CODEPOINT_ENCODE3 (0x30D8, 0x3099, 0x30D9),
+     HB_CODEPOINT_ENCODE3 (0x30D8, 0x309A, 0x30DA),   HB_CODEPOINT_ENCODE3 (0x30DB, 0x3099, 0x30DC),
+     HB_CODEPOINT_ENCODE3 (0x30DB, 0x309A, 0x30DD),   HB_CODEPOINT_ENCODE3 (0x30EF, 0x3099, 0x30F7),
+     HB_CODEPOINT_ENCODE3 (0x30F0, 0x3099, 0x30F8),   HB_CODEPOINT_ENCODE3 (0x30F1, 0x3099, 0x30F9),
+     HB_CODEPOINT_ENCODE3 (0x30F2, 0x3099, 0x30FA),   HB_CODEPOINT_ENCODE3 (0x30FD, 0x3099, 0x30FE),
+     HB_CODEPOINT_ENCODE3 (0xFB49, 0x05C1, 0x0000),   HB_CODEPOINT_ENCODE3 (0xFB49, 0x05C2, 0x0000),
+   HB_CODEPOINT_ENCODE3 (0x105D2, 0x0307, 0x105C9), HB_CODEPOINT_ENCODE3 (0x105DA, 0x0307, 0x105E4),
+  HB_CODEPOINT_ENCODE3 (0x11099, 0x110BA, 0x1109A),HB_CODEPOINT_ENCODE3 (0x1109B, 0x110BA, 0x1109C),
+  HB_CODEPOINT_ENCODE3 (0x110A5, 0x110BA, 0x110AB),HB_CODEPOINT_ENCODE3 (0x11131, 0x11127, 0x1112E),
+  HB_CODEPOINT_ENCODE3 (0x11132, 0x11127, 0x1112F),HB_CODEPOINT_ENCODE3 (0x11347, 0x1133E, 0x1134B),
+  HB_CODEPOINT_ENCODE3 (0x11347, 0x11357, 0x1134C),HB_CODEPOINT_ENCODE3 (0x11382, 0x113C9, 0x11383),
+  HB_CODEPOINT_ENCODE3 (0x11384, 0x113BB, 0x11385),HB_CODEPOINT_ENCODE3 (0x1138B, 0x113C2, 0x1138E),
+  HB_CODEPOINT_ENCODE3 (0x11390, 0x113C9, 0x11391),HB_CODEPOINT_ENCODE3 (0x113C2, 0x113B8, 0x113C7),
+  HB_CODEPOINT_ENCODE3 (0x113C2, 0x113C2, 0x113C5),HB_CODEPOINT_ENCODE3 (0x113C2, 0x113C9, 0x113C8),
+  HB_CODEPOINT_ENCODE3 (0x114B9, 0x114B0, 0x114BC),HB_CODEPOINT_ENCODE3 (0x114B9, 0x114BA, 0x114BB),
+  HB_CODEPOINT_ENCODE3 (0x114B9, 0x114BD, 0x114BE),HB_CODEPOINT_ENCODE3 (0x115B8, 0x115AF, 0x115BA),
+  HB_CODEPOINT_ENCODE3 (0x115B9, 0x115AF, 0x115BB),HB_CODEPOINT_ENCODE3 (0x11935, 0x11930, 0x11938),
+  HB_CODEPOINT_ENCODE3 (0x1611E, 0x1611E, 0x16121),HB_CODEPOINT_ENCODE3 (0x1611E, 0x1611F, 0x16123),
+  HB_CODEPOINT_ENCODE3 (0x1611E, 0x16120, 0x16125),HB_CODEPOINT_ENCODE3 (0x1611E, 0x16129, 0x16122),
+  HB_CODEPOINT_ENCODE3 (0x16121, 0x1611F, 0x16126),HB_CODEPOINT_ENCODE3 (0x16121, 0x16120, 0x16128),
+  HB_CODEPOINT_ENCODE3 (0x16122, 0x1611F, 0x16127),HB_CODEPOINT_ENCODE3 (0x16129, 0x1611F, 0x16124),
+  HB_CODEPOINT_ENCODE3 (0x16D63, 0x16D67, 0x16D69),HB_CODEPOINT_ENCODE3 (0x16D67, 0x16D67, 0x16D68),
+  HB_CODEPOINT_ENCODE3 (0x16D69, 0x16D67, 0x16D6A), HB_CODEPOINT_ENCODE3 (0x1D157, 0x1D165, 0x0000),
+   HB_CODEPOINT_ENCODE3 (0x1D158, 0x1D165, 0x0000), HB_CODEPOINT_ENCODE3 (0x1D15F, 0x1D16E, 0x0000),
+   HB_CODEPOINT_ENCODE3 (0x1D15F, 0x1D16F, 0x0000), HB_CODEPOINT_ENCODE3 (0x1D15F, 0x1D170, 0x0000),
+   HB_CODEPOINT_ENCODE3 (0x1D15F, 0x1D171, 0x0000), HB_CODEPOINT_ENCODE3 (0x1D15F, 0x1D172, 0x0000),
+   HB_CODEPOINT_ENCODE3 (0x1D1B9, 0x1D165, 0x0000), HB_CODEPOINT_ENCODE3 (0x1D1BA, 0x1D165, 0x0000),
+   HB_CODEPOINT_ENCODE3 (0x1D1BB, 0x1D16E, 0x0000), HB_CODEPOINT_ENCODE3 (0x1D1BB, 0x1D16F, 0x0000),
+   HB_CODEPOINT_ENCODE3 (0x1D1BC, 0x1D16E, 0x0000), HB_CODEPOINT_ENCODE3 (0x1D1BC, 0x1D16F, 0x0000),
 };
 
 #ifndef HB_OPTIMIZE_SIZE
 
-static const uint8_t
-_hb_ucd_u8[17612] =
+#include 
+
+static const uint8_t _hb_ucd_u8[19868]=
 {
-    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, 18, 19, 20, 21, 22, 23,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 24, 25, 26,  5, 27, 28,
-    5, 29, 30, 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,
-   31, 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, 32,
-    8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8, 33,
     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
-   16, 17, 18, 19, 20, 17, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
-   31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 33, 41, 42, 43, 44, 45,
-   46, 47, 48, 39, 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, 49, 17, 17,
-   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   50, 17, 17, 17, 51, 17, 52, 53, 54, 55, 56, 57, 17, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17, 58, 59, 59, 59, 59, 59, 59, 59, 59,
-   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, 17, 61, 62, 17, 63, 64, 65,
-   66, 67, 68, 69, 70, 71, 17, 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,
-   17, 17, 17, 97, 98, 99,100,100,100,100,100,100,100,100,100,101,
-   17, 17, 17, 17,102, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17,103, 17, 17,104,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,105,100,100,100,100,100,100, 17, 17,106,107,100,108,109,110,
-   17, 17, 17, 17, 17, 17, 17,111, 17, 17, 17, 17,112,113,100,100,
-  100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,114,
-   17,115,116,100,100,100,100,100,100,100,100,100,117,100,100,100,
-  100,100,100,100,100,100,100,100,100,100,100,100,118, 39,119,120,
-  121,122,123,124,125,126,127,128, 39, 39,129,100,100,100,100,130,
-  131,132,133,100,134,135,100,136,137,138,100,100,139,140,141,100,
-  142,143,144,145, 39, 39,146,147,148, 39,149,150,100,100,100,100,
-   17, 17, 17, 17, 17, 17,151, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17,152,153, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,154, 17,
-   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,155, 17, 17,156,100,
-  100,100,100,100,100,100,100,100, 17, 17,157,100,100,100,100,100,
-   17, 17, 17,158, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17,159,100,100,100,100,100,100,100,100,100,100,100,100,
-  160,161,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
-   60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,162,
-   60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,163,
+   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, 26,
+   28, 26, 29, 30, 31, 32, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 33, 34, 34, 34, 34,
+   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,
+   26, 56, 57, 58, 58, 58, 58, 59, 26, 26, 60, 26, 26, 26, 26, 26,
+   26, 61, 26, 62, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+   63, 58, 58, 58, 26, 64, 65, 66, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 67, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+   58, 58, 58, 58, 58, 58, 58, 68, 69, 70, 58, 58, 58, 58, 71, 58,
+   58, 58, 58, 58, 58, 58, 72, 73, 74, 75, 76, 77, 78, 79, 58, 80,
+   81, 82, 83, 84, 85, 58, 86, 87, 88, 89, 78, 90, 91, 92, 58, 58,
+   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, 93, 26, 26, 26, 26, 26, 26, 26, 26, 94, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 95, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 96, 26, 97, 58, 58, 58, 58, 26, 98, 58, 58,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 99, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26,100, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+  101, 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, 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, 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, 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, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,102,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,103,
     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,
@@ -1148,496 +914,529 @@ _hb_ucd_u8[17612] =
    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,
-   36, 36, 36, 36, 82, 36, 36, 61, 65, 44, 44, 57, 43, 43, 43, 43,
-   36, 36, 36, 36, 83, 43, 43, 43, 43, 84, 43, 43, 43, 43, 43, 43,
-   43, 85, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 85, 71, 86,
-   87, 43, 43, 43, 85, 86, 87, 86, 70, 43, 43, 43, 36, 36, 36, 36,
-   36, 43,  2,  7,  7,  7,  7,  7, 88, 36, 36, 36, 36, 36, 36, 36,
-   70, 86, 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, 86,
-   87, 43, 80, 89, 90, 89, 87, 61, 44, 44, 44, 89, 44, 44, 36, 62,
-   36, 43, 44,  7,  7,  7,  7,  7, 36, 20, 27, 27, 27, 56, 63, 80,
-   57, 85, 62, 36, 36, 61, 44, 62, 61, 36, 62, 61, 36, 44, 80, 86,
-   87, 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, 85, 62, 36, 36, 36, 36, 62, 36, 62, 36, 36, 36, 36, 36, 36,
-   61, 36, 62, 36, 36, 44, 71, 86, 87, 43, 43, 57, 85, 89, 87, 44,
-   61, 44, 44, 44, 44, 44, 44, 44, 66, 44, 44, 44, 62, 43, 43, 43,
-   57, 86, 62, 36, 36, 36, 61, 62, 61, 36, 62, 36, 36, 44, 71, 87,
-   87, 43, 80, 89, 90, 89, 87, 44, 44, 44, 57, 85, 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, 86, 85, 90, 44, 86, 90, 86, 87, 44,
-   61, 44, 44, 89, 44, 44, 44, 44, 27, 91, 67, 67, 56, 92, 44, 44,
-   85, 86, 71, 36, 36, 36, 61, 36, 61, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 44, 71, 43, 85, 86, 90, 43, 80, 43, 43, 44,
-   44, 44, 57, 80, 36, 61, 62, 44, 44, 44, 44, 93, 27, 27, 27, 91,
-   70, 86, 72, 36, 36, 36, 61, 36, 36, 36, 62, 36, 36, 44, 71, 87,
-   86, 86, 90, 85, 90, 86, 43, 44, 44, 44, 89, 90, 44, 44, 62, 61,
-   62, 94, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36,
-   36, 36, 36, 36, 36, 70, 71, 86, 87, 43, 80, 86, 90, 86, 87, 77,
-   44, 44, 36, 94, 27, 27, 27, 95, 27, 27, 27, 27, 91, 36, 36, 36,
-   57, 86, 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, 89,
-   86, 43, 80, 80, 86, 86, 86, 86, 44, 86, 64, 44, 44, 44, 44, 44,
-   62, 36, 36, 36, 36, 36, 36, 36, 70, 36, 43, 43, 43, 80, 44, 96,
-   36, 36, 36, 75, 43, 43, 43, 60,  7,  7,  7,  7,  7,  2, 44, 44,
-   44, 44, 44, 44, 44, 44, 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, 80,  7,  7,  7,  7,  7, 44, 36, 36,
-   77, 67,  2,  2,  2,  2,  2,  2,  2, 97, 97, 67, 43, 67, 67, 67,
-    7,  7,  7,  7,  7, 27, 27, 27, 27, 27, 50, 50, 50,  4,  4, 86,
-   36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44,
-   57, 43, 43, 43, 43, 43, 43, 85, 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, 92, 67,  2,  2, 97, 67, 21, 64, 44, 44,
-   36, 36, 36, 36, 36, 94, 87, 43, 85, 43, 43, 43, 87, 85, 87, 71,
-    7,  7,  7,  7,  7,  2,  2,  2, 36, 36, 36, 86, 43, 36, 36, 43,
-   71, 86, 98, 94, 86, 86, 86, 36, 70, 43, 71, 36, 36, 36, 36, 36,
-   36, 85, 87, 85, 86, 86, 87, 94,  7,  7,  7,  7,  7, 86, 87, 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, 99, 27, 27, 27, 27, 27, 27, 27, 27, 27,100, 44,
-   67, 67, 67, 67, 67, 44, 44, 44, 11, 11, 11, 44, 16, 16, 16, 44,
-  101, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 77, 72,
-  102, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,103,104, 44,
-   36, 36, 36, 36, 36, 63,  2,105,106, 36, 36, 36, 61, 44, 44, 44,
-   36, 43, 85, 44, 44, 44, 44, 62, 36, 43,107, 64, 44, 44, 44, 44,
-   36, 43, 44, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 61, 36,
-   61, 43, 44, 44, 44, 44, 44, 44, 36, 36, 43, 87, 43, 43, 43, 86,
-   86, 86, 86, 85, 87, 43, 43, 43, 43, 43,  2, 88,  2, 66, 70, 44,
-    7,  7,  7,  7,  7, 44, 44, 44, 27, 27, 27, 27, 27, 44, 44, 44,
-    2,  2,  2,108,  2, 59, 43, 84, 36, 83, 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, 85, 86, 87, 85, 86, 44, 44,
-   86, 85, 86, 86, 87, 43, 44, 44, 92, 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,100, 44, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-   36, 36, 36, 70, 85, 87, 44,  2, 36, 36, 94, 85, 43, 43, 43, 80,
-   85, 85, 87, 43, 43, 43, 85, 86, 86, 87, 43, 43, 43, 43, 80, 57,
-    2,  2,  2, 88,  2,  2,  2, 44, 43, 43, 43, 43, 43, 43, 43,109,
-   43, 43, 43, 43, 43, 43, 43, 80, 43, 43, 98, 36, 36, 36, 36, 36,
-   36, 36, 85, 43, 43, 85, 85, 86, 86, 85, 98, 36, 36, 36, 61,  2,
-   97, 67, 67, 67, 67, 50, 43, 43, 43, 43, 67, 67, 67, 67, 21,  2,
-   43, 98, 36, 36, 36, 36, 36, 36, 94, 43, 43, 86, 43, 87, 43, 36,
-   36, 36, 36, 85, 43, 86, 87, 87, 43, 86, 44, 44, 44, 44,  2,  2,
-   36, 36, 86, 86, 86, 86, 43, 43, 43, 43, 86, 43, 44, 93,  2,  2,
-    7,  7,  7,  7,  7, 44, 62, 36, 36, 36, 36, 36, 40, 40, 40,  2,
-   16, 16, 16, 16, 34,110, 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,
-   85, 43, 43, 43, 71, 36, 70, 36, 36, 36, 71, 94, 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,111, 40, 40,
-   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,112,112,112,112,
-   16, 16,110, 16, 11, 11,113,114, 41, 16,110, 16, 11, 11,113, 41,
-   16, 16, 44, 16, 11, 11,115, 41, 16, 16, 16, 16, 11, 11,116, 41,
-   44, 16,110, 16, 11, 11,113,117,118,118,118,118,118,119, 65, 65,
-  120,120,120,  2,121,122,121,122,  2,  2,  2,  2,123, 65, 65,124,
-    2,  2,  2,  2,125,126,  2,127,128,  2,129,130,  2,  2,  2,  2,
-    2,  9,128,  2,  2,  2,  2,131, 65, 65,132, 65, 65, 65, 65, 65,
-  133, 44, 27, 27, 27,  8,129,134, 27, 27, 27, 27, 27,  8,129,104,
-   40, 40, 40, 40, 40, 40, 81, 44, 20, 20, 20, 20, 20, 20, 20, 20,
-  135, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 43, 43,136, 51,
-  109, 51,109, 43, 43, 43, 43, 43, 80, 44, 44, 44, 44, 44, 44, 44,
-   67,137, 67,138, 67, 34, 11, 16, 11, 32,138, 67, 49, 11, 11, 67,
-   67, 67,137,137,137, 11, 11,139, 11, 11, 35, 36, 39, 67, 16, 11,
-    8,  8, 49, 16, 16, 26, 67,140, 27, 27, 27, 27, 27, 27, 27, 27,
-  105,105,105,105,105,105,105,105,105,141,142,105,143, 67, 44, 44,
-    8,  8,144, 67, 67,  8, 67, 67,144, 26, 67,144, 67, 67, 67,144,
-   67, 67, 67, 67, 67, 67, 67,  8, 67,144,144, 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,145,146, 67, 67,
-   67, 67, 67, 67, 67, 67,144, 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, 67, 67, 92, 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,129,147,  8,  8,  8,  8,
-    8,  8,  8,  4,  4,  4,  4,  4,  8,129,148,148,148,148,148,148,
-  148,148,148,148,147,  8,  8,  8,  8,  8,  8,  8,  4,  4,  8,  8,
-    8,  8,  8,  8,  8,  8,  4,  8,  8,  8,144, 26,  8,  8,144, 67,
-   67, 67, 44, 67, 67, 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 67,
-   32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 40, 11,
-   32, 32,140, 67, 67,138, 34,149, 43, 32, 44, 44, 93,  2, 99,  2,
-   16, 16, 16,150, 44, 44,150, 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,121,121,  2,125,126,121,  2,
-    2,  2,  2,  6,  2,108,121,  2,121,  4,  4,  4,  4,  2,  2, 88,
-    2,  2,  2,  2,  2,120,  2,  2,108,151,  2,  2,  2,  2,  2,  2,
-   67,  2,152,148,148,148,153, 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,
-    1,  2,154,155,  4,  4,  4,  4,  4, 67,  4,  4,  4,  4,156,157,
-  158,105,105,105,105, 43, 43, 86,159, 40, 40, 67,105,160, 63, 67,
-   36, 36, 36, 61, 57,161,162, 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, 44, 44, 44, 44, 55, 67, 67, 67, 67, 67, 67, 67, 92,
-   27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, 27,
-  163, 27, 27, 27, 27, 27, 27, 27, 36, 36, 83, 36, 36, 36, 36, 36,
-   67, 67, 67, 92, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36,164,  2,
-    7,  7,  7,  7,  7, 36, 44, 44, 32, 32, 32, 32, 32, 32, 32, 70,
-   51,165, 43, 43, 43, 43, 43, 88, 32, 32, 32, 32, 32, 32, 40, 43,
-   36, 36, 36,105,105,105,105,105, 43,  2,  2,  2, 44, 44, 44, 44,
-   41, 41, 41,162, 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,166, 34, 35, 32, 32, 16, 32, 32, 32, 32, 32,
+   16, 16, 36, 16, 16, 16, 16, 16, 39, 39, 39, 39, 39, 39, 39, 39,
+   39, 40, 40, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40,
+   39, 39, 41, 40, 40, 40, 41, 41, 40, 40, 40, 40, 40, 40, 40, 40,
+   42, 42, 42, 42, 42, 42, 42, 42, 32, 32, 41, 32, 43, 44, 16, 10,
+   43, 43, 40, 45, 11, 46, 46, 11, 34, 11, 11, 11, 11, 11, 11, 11,
+   11, 47, 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, 48, 34, 32, 34, 11,
+   32, 49, 42, 42, 50, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16,
+   47, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 46, 51,  2,  2,  2,
+   16, 16, 16, 16, 52, 53, 54, 55, 56, 42, 42, 42, 42, 42, 42, 42,
+   42, 42, 42, 42, 42, 42, 42, 57, 58, 59, 42, 58, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43, 61,
+   36, 62, 63, 43, 43, 43, 43, 43, 64, 64, 64,  8,  9, 65,  2, 66,
+   42, 42, 42, 42, 42, 59, 67,  2, 68, 36, 36, 36, 36, 69, 42, 42,
+    7,  7,  7,  7,  7,  2,  2, 36, 70, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 71, 42, 42, 42, 72, 49, 42, 42, 73, 74, 75, 42, 42, 36,
+    7,  7,  7,  7,  7, 36, 76, 77,  2,  2,  2,  2,  2,  2,  2, 78,
+   69, 36, 36, 36, 36, 36, 36, 36, 42, 42, 42, 42, 42, 79, 61, 36,
+   36, 36, 36, 42, 42, 42, 42, 42, 70, 43, 43, 43, 43, 43, 43, 43,
+    7,  7,  7,  7,  7, 36, 36, 36, 36, 36, 36, 36, 36, 69, 42, 42,
+   42, 42, 39, 21,  2, 80, 56, 20, 36, 36, 36, 42, 42, 74, 42, 42,
+   42, 42, 74, 42, 74, 42, 42, 43,  2,  2,  2,  2,  2,  2,  2, 63,
+   36, 36, 36, 36, 69, 42, 43, 63, 36, 36, 36, 36, 36, 60, 43, 43,
+   36, 36, 36, 36, 81, 36, 36, 36, 64, 43, 43, 56, 42, 42, 42, 42,
+   36, 36, 36, 36, 82, 42, 42, 42, 42, 83, 42, 42, 42, 42, 42, 42,
+   42, 84, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 84, 70, 85,
+   86, 42, 42, 42, 84, 85, 86, 85, 69, 42, 42, 42, 36, 36, 36, 36,
+   36, 42,  2,  7,  7,  7,  7,  7, 87, 36, 36, 36, 36, 36, 36, 36,
+   69, 85, 61, 36, 36, 36, 60, 61, 60, 61, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 60, 36, 36, 36, 60, 60, 43, 36, 36, 43, 70, 85,
+   86, 42, 79, 88, 89, 88, 86, 60, 43, 43, 43, 88, 43, 43, 36, 61,
+   36, 42, 43,  7,  7,  7,  7,  7, 36, 20, 27, 27, 27, 55, 62, 79,
+   56, 84, 61, 36, 36, 60, 43, 61, 60, 36, 61, 60, 36, 43, 79, 85,
+   86, 79, 43, 56, 79, 56, 42, 43, 56, 43, 43, 43, 61, 36, 60, 60,
+   43, 43, 43,  7,  7,  7,  7,  7, 42, 36, 69, 63, 43, 43, 43, 43,
+   56, 84, 61, 36, 36, 36, 36, 61, 36, 61, 36, 36, 36, 36, 36, 36,
+   60, 36, 61, 36, 36, 43, 70, 85, 86, 42, 42, 56, 84, 88, 86, 43,
+   60, 43, 43, 43, 43, 43, 43, 43, 65, 43, 43, 43, 61, 42, 42, 42,
+   56, 85, 61, 36, 36, 36, 60, 61, 60, 36, 61, 36, 36, 43, 70, 86,
+   86, 42, 79, 88, 89, 88, 86, 43, 43, 43, 56, 84, 43, 43, 36, 61,
+   77, 27, 27, 27, 43, 43, 43, 43, 43, 70, 61, 36, 36, 60, 43, 36,
+   60, 36, 36, 43, 61, 60, 60, 36, 43, 61, 60, 43, 36, 60, 43, 36,
+   36, 36, 36, 36, 36, 43, 43, 85, 84, 89, 43, 85, 89, 85, 86, 43,
+   60, 43, 43, 88, 43, 43, 43, 43, 27, 90, 66, 66, 55, 91, 43, 43,
+   84, 85, 70, 36, 36, 36, 60, 36, 60, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 43, 70, 42, 84, 85, 89, 42, 79, 42, 42, 43,
+   43, 43, 56, 79, 36, 60, 36, 43, 43, 43, 43, 92, 27, 27, 27, 90,
+   69, 85, 71, 36, 36, 36, 60, 36, 36, 36, 61, 36, 36, 43, 70, 86,
+   85, 85, 89, 84, 89, 85, 42, 43, 43, 43, 88, 89, 43, 43, 36, 60,
+   61, 93, 43, 43, 43, 43, 43, 43, 42, 85, 36, 36, 36, 36, 60, 36,
+   36, 36, 36, 36, 36, 69, 70, 85, 86, 42, 79, 85, 89, 85, 86, 76,
+   43, 43, 36, 93, 27, 27, 27, 94, 27, 27, 27, 27, 90, 36, 36, 36,
+   56, 85, 61, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43, 36, 36, 36,
+   36, 61, 36, 36, 36, 36, 61, 43, 36, 36, 36, 60, 43, 79, 43, 88,
+   85, 42, 79, 79, 85, 85, 85, 85, 43, 85, 63, 43, 43, 43, 43, 43,
+   61, 36, 36, 36, 36, 36, 36, 36, 69, 36, 42, 42, 42, 79, 43, 95,
+   36, 36, 36, 74, 42, 42, 42, 59,  7,  7,  7,  7,  7,  2, 43, 43,
+   43, 43, 43, 43, 43, 43, 43, 43, 61, 60, 60, 36, 36, 60, 36, 36,
+   36, 36, 61, 61, 36, 36, 36, 36, 69, 36, 42, 42, 42, 42, 70, 43,
+   36, 36, 60, 80, 42, 42, 42, 79,  7,  7,  7,  7,  7, 43, 36, 36,
+   76, 66,  2,  2,  2,  2,  2,  2,  2, 96, 96, 66, 42, 66, 66, 66,
+    7,  7,  7,  7,  7, 27, 27, 27, 27, 27, 49, 49, 49,  4,  4, 85,
+   36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43,
+   56, 42, 42, 42, 42, 42, 42, 84, 42, 42, 59, 42, 36, 36, 69, 42,
+   42, 42, 42, 42, 56, 42, 42, 42, 42, 42, 42, 42, 42, 42, 79, 66,
+   66, 66, 66, 75, 66, 66, 91, 66,  2,  2, 96, 66, 21, 63, 43, 43,
+   36, 36, 36, 36, 36, 93, 86, 42, 84, 42, 42, 42, 86, 84, 86, 70,
+    7,  7,  7,  7,  7,  2,  2,  2, 36, 36, 36, 85, 42, 36, 36, 42,
+   70, 85, 97, 93, 85, 85, 85, 36, 69, 42, 70, 36, 36, 36, 36, 36,
+   36, 84, 86, 84, 85, 85, 86, 93,  7,  7,  7,  7,  7, 85, 86, 66,
+   11, 11, 11, 47, 43, 43, 47, 43, 16, 16, 16, 16, 16, 52, 44, 16,
+   36, 36, 36, 36, 60, 36, 36, 43, 36, 36, 36, 60, 60, 36, 36, 43,
+   60, 36, 36, 43, 36, 36, 36, 60, 60, 36, 36, 43, 36, 36, 36, 36,
+   36, 36, 36, 60, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 56, 42,
+    2,  2,  2,  2, 98, 27, 27, 27, 27, 27, 27, 27, 27, 27, 99, 43,
+   66, 66, 66, 66, 66, 43, 43, 43, 11, 11, 11, 43, 16, 16, 16, 43,
+  100, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 76, 71,
+  101, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,102,103, 43,
+   36, 36, 36, 36, 36, 62,  2,104,105, 36, 36, 36, 60, 43, 43, 43,
+   36, 42, 84, 43, 43, 43, 43, 61, 36, 42,106, 63, 43, 43, 43, 43,
+   36, 42, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36, 60, 36,
+   60, 42, 43, 43, 43, 43, 43, 43, 36, 36, 42, 86, 42, 42, 42, 85,
+   85, 85, 85, 84, 86, 42, 42, 42, 42, 42,  2, 87,  2, 65, 69, 43,
+    7,  7,  7,  7,  7, 43, 43, 43, 27, 27, 27, 27, 27, 43, 43, 43,
+    2,  2,  2,107,  2, 58, 42, 83, 36, 82, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 60, 43, 43, 43, 36, 36, 69, 70, 36, 36, 36, 36,
+   36, 36, 36, 36, 69, 60, 43, 43, 36, 36, 36, 43, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 36, 36, 60, 42, 84, 85, 86, 84, 85, 43, 43,
+   85, 84, 85, 85, 86, 42, 43, 43, 91, 43,  2,  7,  7,  7,  7,  7,
+   36, 36, 36, 36, 36, 36, 36, 43, 36, 36, 60, 43, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 36, 43, 43, 36, 36, 36, 36, 36, 43, 43, 43,
+    7,  7,  7,  7,  7, 99, 43, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+   36, 36, 36, 69, 84, 86, 43,  2, 36, 36, 93, 84, 42, 42, 42, 79,
+   84, 84, 86, 42, 42, 42, 84, 85, 85, 86, 42, 42, 42, 42, 79, 56,
+    2,  2,  2, 87,  2,  2,  2, 43, 42, 42, 42, 42, 42, 42, 42,108,
+   42, 42, 42, 42, 42, 42, 42, 43, 42, 42, 42, 42, 42, 42, 43, 43,
+   42, 42, 97, 36, 36, 36, 36, 36, 36, 36, 84, 42, 42, 84, 84, 85,
+   85, 84, 97, 36, 36, 36, 60,  2, 96, 66, 66, 66, 66, 49, 42, 42,
+   42, 42, 66, 66, 66, 66, 21,  2, 42, 97, 36, 36, 36, 36, 36, 36,
+   93, 42, 42, 85, 42, 86, 42, 36, 36, 36, 36, 84, 42, 85, 86, 86,
+   42, 85, 43, 43, 43, 43,  2,  2, 36, 36, 85, 85, 85, 85, 42, 42,
+   42, 42, 85, 42, 43, 92,  2,  2,  7,  7,  7,  7,  7, 43, 61, 36,
+   36, 36, 36, 36, 39, 39, 39,  2, 16, 16, 16, 16, 34,109, 43, 43,
+   11, 11, 11, 11, 11, 46, 47, 11,  2,  2,  2,  2, 43, 43, 43, 43,
+   42, 59, 42, 42, 42, 42, 42, 42, 84, 42, 42, 42, 70, 36, 69, 36,
+   36, 36, 70, 93, 42, 60, 43, 43, 16, 16, 16, 16, 16, 16, 39, 39,
+   39, 39, 39, 39, 39, 44, 16, 16, 16, 16, 16, 16, 44, 16, 16, 16,
+   16, 16, 16, 16, 16,110, 39, 39, 32, 32, 32, 16, 16, 16, 16, 32,
+   16, 16, 16, 16, 11, 11, 11, 11, 16, 16, 16, 43, 11, 11, 11, 43,
+   16, 16, 16, 16, 47, 47, 47, 47, 16, 16, 16, 16, 16, 16, 16, 43,
+   16, 16, 16, 16,111,111,111,111, 16, 16,109, 16, 11, 11,112,113,
+   40, 16,109, 16, 11, 11,112, 40, 16, 16, 43, 16, 11, 11,114, 40,
+   16, 16, 16, 16, 11, 11,115, 40, 43, 16,109, 16, 11, 11,112,116,
+  117,117,117,117,117,118, 64, 64,119,119,119,  2,120,121,120,121,
+    2,  2,  2,  2,122, 64, 64,123,  2,  2,  2,  2,124,125,  2,126,
+  127,  2,128,129,  2,  2,  2,  2,  2,  9,127,  2,  2,  2,  2,130,
+   64, 64,131, 64, 64, 64, 64, 64,132, 43, 27, 27, 27,  8,128,133,
+   27, 27, 27, 27, 27,  8,128,103, 39, 39, 39, 39, 39, 39, 80, 43,
+   20, 20, 20, 20, 20, 20, 20, 20, 20, 43, 43, 43, 43, 43, 43, 43,
+   42, 42, 42, 42, 42, 42,134, 50,108, 50,108, 42, 42, 42, 42, 42,
+   79, 43, 43, 43, 43, 43, 43, 43, 66,135, 66,136, 66, 34, 11, 16,
+   11, 32,136, 66, 48, 11, 11, 66, 66, 66,135,135,135, 11, 11,137,
+   11, 11, 35, 36,138, 66, 16, 11,  8,  8, 48, 16, 16, 26, 66,139,
+   27, 27, 27, 27, 27, 27, 27, 27,104,104,104,104,104,104,104,104,
+  104,140,141,104,142, 66, 43, 43,  8,  8,143, 66, 66,  8, 66, 66,
+  143, 26, 66,143, 66, 66, 66,143, 66, 66, 66, 66, 66, 66, 66,  8,
+   66,143,143, 66, 66, 66, 66, 66, 66, 66,  8,  8,  8,  8,  8,  8,
+    8,  8,  8,  8,  8,  8,  8,  8, 66, 66, 66, 66,  4,  4, 66, 66,
+    8, 66, 66, 66,144,145, 66, 66, 66, 66, 66, 66, 66, 66,143, 66,
+   66, 66, 66, 66, 66, 26,  8,  8,  8,  8, 66, 66, 66, 66, 66, 66,
+   66, 66, 66, 66, 66, 66,  8,  8,  8, 66, 66, 66, 66, 66, 66, 66,
+   66, 66, 66, 66, 66, 91, 43, 43, 27, 27, 27, 27, 27, 27, 66, 66,
+   66, 66, 66, 66, 66, 27, 27, 27, 66, 66, 66, 26, 66, 66, 66, 66,
+   26, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,  8,  8,  8,  8,
+   66, 66, 66, 66, 66, 66, 66, 26, 66, 66, 66, 66,  4,  4,  4,  4,
+    4,  4,  4, 27, 27, 27, 27, 27, 27, 27, 66, 66, 66, 66, 66, 66,
+    8,  8,128,146,  8,  8,  8,  8,  8,  8,  8,  4,  4,  4,  4,  4,
+    8,128,147,147,147,147,147,147,147,147,147,147,146,  8,  8,  8,
+    8,  8,  8,  8,  4,  4,  8,  8,  8,  8,  8,  8,  8,  8,  4,  8,
+    8,  8,143, 26,  8,  8,143, 66, 66, 66, 43, 66, 66, 66, 66, 66,
+   32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 39, 11,
+   32, 32,139, 66, 66,136, 34,148, 42, 32, 43, 43, 92,  2, 98,  2,
+   16, 16, 16,149, 43, 43,149, 43, 36, 36, 36, 36, 43, 43, 43, 51,
+   63, 43, 43, 43, 43, 43, 43, 56, 36, 36, 36, 60, 43, 43, 43, 43,
+   36, 36, 36, 60, 36, 36, 36, 60,  2,120,120,  2,124,125,120,  2,
+    2,  2,  2,  6,  2,107,120,  2,120,  4,  4,  4,  4,  2,  2, 87,
+    2,  2,  2,  2,  2,119,  2,  2,107,150,  2,  2,  2,  2,  2,  2,
+   66,  2,151,147,147,147,152, 43, 66, 66, 66, 66, 66, 54, 66, 66,
+   66, 66, 43, 43, 43, 43, 43, 43, 66, 66, 66, 43, 43, 43, 43, 43,
+    1,  2,153,154,  4,  4,  4,  4,  4, 66,  4,  4,  4,  4,155,156,
+  157,104,104,104,104, 42, 42, 85,158, 39, 39, 66,104,159, 62, 66,
+   36, 36, 36, 60, 56,160,161, 68, 36, 36, 36, 36, 36, 62, 39, 68,
+   43, 43, 61, 36, 36, 36, 36, 36, 66, 27, 27, 66, 66, 66, 66, 66,
+   66, 66, 66, 43, 43, 43, 43, 54, 66, 66, 66, 66, 66, 66, 66, 91,
+   27, 27, 27, 27, 27, 66, 66, 66, 66, 66, 66, 66, 27, 27, 27, 27,
+  162, 27, 27, 27, 27, 27, 27, 27, 36, 36, 82, 36, 36, 36, 36, 36,
+   66, 66, 66, 91, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36,163,  2,
+    7,  7,  7,  7,  7, 36, 43, 43, 32, 32, 32, 32, 32, 32, 32, 69,
+   50,164, 42, 42, 42, 42, 42, 87, 32, 32, 32, 32, 32, 32, 39, 42,
+   36, 36, 36,104,104,104,104,104, 42,  2,  2,  2, 43, 43, 43, 43,
+   40, 40, 40,161, 39, 39, 39, 39, 40, 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, 41,165, 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,
-   32, 32, 11, 11, 34, 34, 32, 44, 32,150,150, 32, 32, 32, 47, 44,
-   44, 40,167, 35, 40, 35, 36, 36, 36, 71, 36, 71, 36, 70, 36, 36,
-   36, 94, 87, 85, 67, 67, 80, 44, 27, 27, 27, 67,168, 44, 44, 44,
-   36, 36,  2,  2, 44, 44, 44, 44, 86, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 86, 86, 86, 86, 86, 86, 86, 86, 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, 86, 44, 44, 44, 44, 44, 93,
-   36, 70, 86, 43, 43, 86, 43, 86,107,  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, 85,
-   87, 85, 87, 80, 44, 44, 44, 44, 36, 70, 36, 36, 36, 36, 85, 44,
-    7,  7,  7,  7,  7, 44,  2,  2, 69, 36, 36, 77, 67, 94, 85, 36,
-   71, 43, 71, 70, 71, 36, 36, 43, 70, 61, 44, 44, 44, 44, 44, 44,
-   44, 44, 44, 44, 44, 62, 83,  2, 36, 36, 36, 36, 36, 94, 43, 86,
-    2, 83,169, 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,114, 40, 40,
-   16, 16, 16, 16,111, 41, 44, 44, 36, 94, 87, 86, 85,107, 87, 44,
-   36, 36, 44, 44, 44, 44, 44, 44, 36, 36, 36, 61, 44, 62, 36, 36,
-  170,170,170,170,170,170,170,170,171,171,171,171,171,171,171,171,
-   16, 16, 16,110, 44, 44, 44, 44, 44,150, 16, 16, 44, 44, 62, 71,
-   36, 36, 36, 36,172, 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,117, 44, 44, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36,148, 44, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 44, 44, 44, 55, 36, 36, 36, 36, 36, 36,168, 67,
-    2,  2,  2,152,130, 44, 44, 44,  6,173,174,148,148,148,148,148,
-  148,148,130,152,130,  2,127,175,  2, 64,  2,  2,156,148,148,130,
-    2,176,  8,177, 66,  2, 44, 44, 36, 36, 61, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 61, 79, 93,  2,  3,  2,  4,  5,  6,  2,
-   16, 16, 16, 16, 16, 17, 18,129,130,  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,178, 56,135, 26,  8,144, 92, 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,179, 27, 27, 27, 27, 27, 27, 44, 55, 67, 67, 67, 67,
-  105,105,143, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 27, 67, 92,
-   67, 67, 67, 67, 67, 67, 92, 44, 92, 44, 44, 44, 44, 44, 44, 44,
-   67, 67, 67, 67, 67, 67, 50, 44,180, 27, 27, 27, 27, 27, 27, 27,
-   27, 27, 27, 27, 27, 27, 44, 44, 27, 27, 44, 44, 44, 44, 62, 36,
-  155, 36, 36, 36, 36,181, 44, 44, 36, 36, 36, 43, 43, 80, 44, 44,
-   36, 36, 36, 36, 36, 36, 36, 93, 36, 36, 44, 44, 36, 36, 36, 36,
-  182,105,105, 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, 36, 36, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44, 44, 93,
-   11, 11, 11, 11, 11, 47, 11, 11, 11, 47, 11,150, 16, 16, 16, 16,
-   16,150, 16, 16, 16, 16, 16, 16, 16,150, 16, 16, 16,150,110, 44,
-   40, 40, 40, 52, 40, 40, 40, 40, 81, 40, 40, 40, 40, 81, 44, 44,
-   36, 36, 36, 44, 61, 36, 36, 36, 36, 36, 36, 62, 61, 44, 61, 62,
-   36, 36, 36, 93, 27, 27, 27, 27, 36, 36, 36, 77,163, 27, 27, 27,
-   44, 44, 44,179, 27, 27, 27, 27, 36, 61, 36, 44, 44,179, 27, 27,
-   36, 36, 36, 27, 27, 27, 44, 93, 36, 36, 36, 36, 36, 44, 44, 93,
-   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,100, 44, 44, 44,
-    2,  2,  2,  2, 64, 44, 44, 44, 36, 36, 36, 36, 36, 36,183, 30,
-   36, 36, 36, 36, 36, 36,183, 27, 36, 36, 36, 36, 78, 36, 36, 36,
-   36, 36, 70, 80, 44,179, 27, 27,  2,  2,  2, 64, 44, 44, 44, 44,
-   36, 36, 36, 44, 93,  2,  2,  2, 36, 36, 36, 44, 27, 27, 27, 27,
-   36, 61, 44, 44, 27, 27, 27, 27, 36, 44, 44, 44, 93,  2, 64, 44,
-   44, 44, 44, 44,179, 27, 27, 27, 11, 47, 44, 44, 44, 44, 44, 44,
-   16,110, 44, 44, 44, 27, 27, 27, 36, 36, 43, 43, 44, 44, 44, 44,
-    7,  7,  7,  7,  7, 36, 36, 69, 11, 11, 11, 44, 57, 43, 43,159,
-   16, 16, 16, 44, 44, 44, 44,  8, 27, 27, 27, 27, 27, 27, 27,100,
-   36, 36, 36, 36, 36, 57,184, 44, 36, 44, 44, 44, 44, 44, 44, 44,
-   44, 36, 61, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 43, 43,
-   27, 27, 27, 95, 44, 44, 44, 44,180, 27, 30,  2,  2, 44, 44, 44,
-   36, 43, 43,  2,  2, 44, 44, 44, 36, 36,183, 27, 27, 27, 44, 44,
-   87, 98, 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,
-   71, 70, 71, 44, 44, 44, 44, 57, 86, 87, 43, 85, 87, 60,185,  2,
-    2, 80, 44, 44, 44, 44, 79, 44, 43, 71, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 70, 43, 43, 87, 43, 43, 43, 80,  7,  7,  7,  7,  7,
-    2,  2, 94, 98, 44, 44, 44, 44, 36, 70,  2, 61, 44, 44, 44, 44,
-   36, 94, 86, 43, 43, 43, 43, 85, 98, 36, 63,  2, 59, 43, 60, 87,
-    7,  7,  7,  7,  7, 63, 63,  2,179, 27, 27, 27, 27, 27, 27, 27,
-   27, 27,100, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 86, 87,
-   43, 86, 85, 43,  2,  2,  2, 71, 70, 44, 44, 44, 44, 44, 44, 44,
-   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,
-   86, 87, 43, 43, 43, 80, 44, 44, 43, 86, 62, 36, 36, 36, 61, 62,
-   61, 36, 62, 36, 36, 57, 71, 86, 85, 86, 90, 89, 90, 89, 86, 44,
-   61, 44, 44, 89, 44, 44, 62, 36, 36, 86, 44, 43, 43, 43, 80, 44,
-   43, 43, 80, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 62, 44, 61,
-   36, 36, 36, 62, 86, 87, 43, 43, 80, 90, 89, 89, 86, 90, 86, 85,
-   71, 71,  2, 93, 64, 44, 44, 44, 57, 80, 44, 44, 44, 44, 44, 44,
-   36, 36, 94, 86, 43, 43, 43, 43, 86, 43, 85, 71, 36, 63,  2,  2,
-    7,  7,  7,  7,  7,  2, 93, 71, 86, 87, 43, 43, 85, 85, 86, 87,
-   85, 43, 36, 72, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 94,
-   86, 43, 43, 44, 86, 86, 43, 87, 60,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2, 36, 36, 43, 44, 86, 87, 43, 43, 43, 85, 87, 87,
-   60,  2, 61, 44, 44, 44, 44, 44,  2,  2,  2,  2,  2,  2, 64, 44,
-   36, 36, 36, 36, 36, 70, 87, 86, 43, 43, 43, 87, 63, 44, 44, 44,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 44, 44, 44, 44, 44, 44,
-   36, 36, 36, 36, 36, 61, 57, 87, 86, 43, 43, 87, 43, 43, 44, 44,
-    7,  7,  7,  7,  7, 27,  2, 97, 43, 43, 43, 43, 87, 60, 44, 44,
-   27,100, 44, 44, 44, 44, 44, 62, 36, 36, 36, 61, 62, 44, 36, 36,
-   36, 36, 62, 61, 36, 36, 36, 36, 86, 86, 86, 89, 90, 57, 85, 71,
-   98, 87,  2, 64, 44, 44, 44, 44, 36, 36, 36, 36, 44, 36, 36, 36,
-   94, 86, 43, 43, 44, 43, 86, 86, 71, 72, 90, 44, 44, 44, 44, 44,
-   70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 85, 70, 43, 60,
-    2,  2,  2, 59, 44, 44, 44, 44, 70, 43, 43, 85, 87, 43, 36, 36,
-   36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 85, 43,  2, 72,  2,
-    2, 64, 44, 44, 44, 44, 44, 44,  2,  2,  2,  2,  2, 44, 44, 44,
-   63, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 80, 43, 43, 43, 87,
-   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, 89, 43, 43, 43,
-   85, 43, 87, 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, 86, 86, 90,
-   43, 89, 87, 87, 61, 44, 44, 44, 36, 70, 85,107, 64, 44, 44, 44,
-   43, 94, 36, 36, 36, 36, 36, 36, 36, 36, 86, 43, 43, 80, 44, 86,
-   85, 60,  2,  2,  2,  2,  2,  2,  7,  7,  7,  7,  7, 80, 44, 44,
-   27, 27, 91, 67, 67, 67, 56, 20,168, 67, 67, 67, 67, 67, 67, 67,
-   67, 44, 44, 44, 44, 44, 44, 93,105,105,105,105,105,105,105,181,
-    2,  2, 64, 44, 44, 44, 44, 44, 63, 64, 44, 44, 44, 44, 44, 44,
-   65, 65, 65, 65, 65, 65, 65, 65, 71, 36, 36, 70, 43, 43, 43, 43,
-   43, 43, 43, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 43,
-   43, 43, 43, 43, 43, 86, 87, 43, 43, 43, 60, 44, 44, 44, 44, 44,
-   43, 43, 43, 60,  2,  2, 67, 67, 40, 40, 97, 44, 44, 44, 44, 44,
-    7,  7,  7,  7,  7,179, 27, 27, 27, 62, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 44, 44, 62, 36, 40, 69, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 83,164,  2, 27, 27, 27, 30,  2, 64, 44, 44,
-   36, 36, 36, 36, 36, 61, 44, 57, 94, 86, 86, 86, 86, 86, 86, 86,
-   86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 44, 44, 44, 57,
-   43, 74, 40, 40, 40, 40, 40, 40, 40, 88, 80, 44, 44, 44, 44, 44,
-   86, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 62,
-   40, 40, 52, 40, 40, 40, 52, 81, 36, 61, 44, 44, 44, 44, 44, 44,
-   44, 61, 44, 44, 44, 44, 44, 44, 36, 61, 62, 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, 43, 43, 43, 43, 43, 43, 43, 44,
-   43, 43, 43, 80, 44, 44, 44, 44, 67, 67, 67, 92, 55, 67, 67, 67,
-   67, 67,186, 87, 43, 67,186, 86, 86,187, 65, 65, 65, 84, 43, 43,
-   43, 76, 50, 43, 43, 43, 67, 67, 67, 67, 67, 67, 67, 43, 43, 67,
-   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,110, 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,150,150, 16,
-   16, 16,150, 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, 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,
-   16, 16, 16, 16, 16, 39, 16, 16, 16, 16, 16, 16, 16, 16, 16,110,
-   44, 44,150, 16, 16,110, 44, 44, 43, 43, 43, 80, 43, 43, 43, 43,
-   43, 43, 43, 43, 80, 57, 43, 43, 43, 57, 80, 43, 43, 80, 44, 44,
-   40, 40, 40, 40, 40, 40, 40, 44, 44, 44, 44, 44, 44, 44, 44, 57,
-   43, 43, 43, 74, 40, 40, 40, 44,  7,  7,  7,  7,  7, 44, 44, 77,
-   36, 36, 36, 36, 36, 36, 36, 80, 36, 36, 36, 36, 36, 36, 43, 43,
-    7,  7,  7,  7,  7, 44, 44, 96, 36, 36, 36, 36, 36, 83, 43, 43,
-  188,  7,  7,  7,  7,189, 44, 93, 36, 36, 36, 61, 36, 36, 62, 61,
-   36, 36, 61,179, 27, 27, 27, 27, 16, 16, 43, 43, 43, 74, 44, 44,
-   27, 27, 27, 27, 27, 27,163, 27,190, 27,100, 44, 44, 44, 44, 44,
-   27, 27, 27, 27, 27, 27, 27,163, 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,
-   67, 67, 67, 67, 67, 67, 44, 44, 55, 67, 67, 67, 67, 67, 67, 67,
-   27, 27, 27, 27, 27, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 44,
-   44, 44, 44, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44, 44, 44,
-   67, 67, 67, 67, 92, 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, 67, 67,
-   67, 67, 67, 92, 44, 55, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44,
-   67, 67, 67, 67, 67, 44, 44, 55, 67, 67, 67, 92, 44, 44, 44, 67,
-   67, 67, 67, 67, 67, 67, 92, 55, 67, 92, 67, 67, 67, 67, 67, 67,
-   79, 44, 44, 44, 44, 44, 44, 44,171,171,171,171,171,171,171, 44,
-  171,171,171,171,171,171,171,  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, 21,  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, 24,  7,  7,  6,
-    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, 10, 21,
-   17, 21, 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,
-    1,  2, 15,  6, 18,  6, 23,  2, 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, 21, 22, 18, 17, 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,  6,  9, 23, 26,  6, 10,  4,  4,  3,  3,
-    7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 25,  2, 25, 24,  2, 15,
-   12, 15, 14,  2, 21, 14,  7, 15, 12, 17, 21,  1, 26, 10, 10,  1,
-    7, 13, 13,  2, 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,
+   32, 32, 11, 11, 34, 34, 32, 32, 32, 32, 32, 32, 32, 32, 46, 43,
+   51, 39,166, 35, 39, 35, 36, 36, 36, 70, 36, 70, 36, 69, 36, 36,
+   36, 93, 86, 84, 66, 66, 79, 43, 27, 27, 27, 66,167, 43, 43, 43,
+   36, 36,  2,  2, 43, 43, 43, 43, 85, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 85, 85, 85, 85, 85, 85, 85, 85, 42, 43, 43, 43, 43,  2,
+   42, 36, 36, 36,  2, 71, 71, 69, 36, 36, 36, 42, 42, 42, 42,  2,
+   36, 36, 36, 69, 42, 42, 42, 42, 42, 85, 43, 43, 43, 43, 43, 92,
+   36, 69, 85, 42, 42, 85, 42, 85,106,  2,  2,  2,  2,  2,  2, 51,
+    7,  7,  7,  7,  7, 43, 43,  2, 36, 36, 69, 68, 36, 36, 36, 36,
+    7,  7,  7,  7,  7, 36, 36, 60, 36, 36, 36, 36, 69, 42, 42, 84,
+   86, 84, 86, 79, 43, 43, 43, 43, 36, 69, 36, 36, 36, 36, 84, 43,
+    7,  7,  7,  7,  7, 43,  2,  2, 68, 36, 36, 76, 66, 93, 84, 36,
+   70, 42, 70, 69, 70, 36, 36, 42, 69, 60, 43, 43, 43, 43, 43, 43,
+   43, 43, 43, 43, 43, 61, 82,  2, 36, 36, 36, 36, 36, 93, 42, 85,
+    2, 82,168, 79, 43, 43, 43, 43, 61, 36, 36, 60, 61, 36, 36, 60,
+   61, 36, 36, 60, 43, 43, 43, 43, 16, 16, 16, 16, 16,113, 39, 39,
+   16, 16, 16, 16,110, 40, 43, 43, 36, 93, 86, 85, 84,106, 86, 43,
+   36, 36, 43, 43, 43, 43, 43, 43, 36, 36, 36, 60, 43, 61, 36, 36,
+  169,169,169,169,169,169,169,169,170,170,170,170,170,170,170,170,
+   16, 16, 16,109, 43, 43, 43, 43, 43,149, 16, 16, 43, 43, 61, 70,
+   36, 36, 36, 36,171, 36, 36, 36, 36, 36, 36, 60, 36, 36, 60, 60,
+   36, 61, 60, 36, 36, 36, 36, 36, 36, 40, 40, 40, 40, 40, 40, 40,
+   40, 22, 66, 66, 66, 66, 66, 66, 66, 77, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36,147, 66, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 66, 66, 66, 66, 36, 36, 36, 36, 36, 36,167, 66,
+    2,  2,  2,151,129, 43, 43, 43,  6,172,173,147,147,147,147,147,
+  147,147,129,151,129,  2,126,174,  2, 63,  2,  2,155,147,147,129,
+    2,175,  8,176, 65,  2, 43, 43, 36, 36, 60, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 60, 78, 92,  2,  3,  2,  4,  5,  6,  2,
+   16, 16, 16, 16, 16, 17, 18,128,129,  4,  2, 36, 36, 36, 36, 36,
+   68, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 39,
+   43, 36, 36, 36, 43, 36, 36, 36, 43, 36, 36, 36, 43, 36, 60, 43,
+   20,177, 55,178, 26,  8,143, 91, 43, 43, 43, 43, 78, 64, 66, 43,
+   36, 36, 36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 60, 36, 61,
+    2, 63, 43,179, 27, 27, 27, 27, 27, 27, 43, 54, 66, 66, 66, 66,
+  104,104,142, 27, 90, 66, 66, 66, 66, 66, 66, 66, 66, 27, 66, 91,
+   66, 66, 66, 66, 66, 66, 91, 43, 91, 43, 43, 43, 43, 43, 43, 43,
+   66, 66, 66, 66, 66, 66, 49, 43,180, 27, 27, 27, 27, 27, 27, 27,
+   27, 27, 27, 27, 27, 27, 43, 43, 27, 27, 43, 43, 43, 43, 61, 36,
+  154, 36, 36, 36, 36,181, 43, 43, 36, 36, 36, 42, 42, 79, 43, 43,
+   36, 36, 36, 36, 36, 36, 36, 92, 36, 36, 43, 43, 36, 36, 36, 36,
+  182,104,104, 43, 43, 43, 43, 43, 11, 11, 11, 11, 16, 16, 16, 16,
+   11, 11, 43, 43, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 43, 43,
+   36, 36, 36, 36, 43, 43, 43, 43, 36, 36, 43, 43, 43, 43, 43, 92,
+   11, 11, 11, 11, 11, 46, 11, 11, 11, 46, 11,149, 16, 16, 16, 16,
+   16,149, 16, 16, 16, 16, 16, 16, 16,149, 16, 16, 16,149,109, 43,
+   39, 39, 39, 51, 39, 39, 39, 39, 80, 39, 39, 39, 39, 80, 43, 43,
+   36, 36, 36, 43, 60, 36, 36, 36, 36, 36, 36, 61, 60, 43, 60, 61,
+   36, 36, 36, 92, 27, 27, 27, 27, 36, 36, 36, 76,162, 27, 27, 27,
+   43, 43, 43,179, 27, 27, 27, 27, 36, 60, 36, 43, 43,179, 27, 27,
+   36, 36, 36, 27, 27, 27, 43, 92, 36, 36, 36, 36, 36, 43, 43, 92,
+   36, 36, 36, 36, 43, 43, 27, 36, 43, 27, 27, 27, 27, 27, 27, 27,
+   69, 42, 56, 79, 43, 43, 42, 42, 36, 36, 61, 36, 61, 36, 36, 36,
+   36, 36, 36, 43, 42, 79, 43, 56, 27, 27, 27, 27, 99, 43, 43, 43,
+    2,  2,  2,  2, 63, 43, 43, 43, 36, 36, 36, 36, 36, 36,183, 30,
+   36, 36, 36, 36, 36, 36,183, 27, 36, 36, 36, 36, 77, 36, 36, 36,
+   36, 36, 69, 79, 43,179, 27, 27,  2,  2,  2, 63, 43, 43, 43, 43,
+   36, 36, 36, 43, 92,  2,  2,  2, 36, 36, 36, 43, 27, 27, 27, 27,
+   36, 60, 43, 43, 27, 27, 27, 27, 36, 43, 43, 43, 92,  2, 63, 43,
+   43, 43, 43, 43,179, 27, 27, 27, 11, 46, 43, 43, 43, 43, 43, 43,
+   16,109, 43, 43, 43, 27, 27, 27, 36, 36, 42, 42, 43, 43, 43, 43,
+    7,  7,  7,  7,  7, 36, 36, 68, 11, 11, 11, 43, 56, 42, 42,158,
+   16, 16, 16, 43, 43, 43, 43,  8, 27, 27, 27, 27, 27, 27, 27, 99,
+   36, 36, 36, 36, 36, 56,184, 43, 36, 43, 43, 43, 43, 43, 43, 43,
+   43, 36, 82, 36, 43, 43, 43, 43, 96, 66, 66, 66, 91, 43, 43, 43,
+   43, 43, 43, 43, 43, 42, 42, 42, 27, 27, 27, 94, 43, 43, 43, 43,
+  180, 27, 30,  2,  2, 43, 43, 43, 36, 42, 42,  2,  2, 43, 43, 43,
+   36, 36,183, 27, 27, 27, 43, 43, 86, 97, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 42, 42, 42, 42, 42, 42, 42, 59,  2,  2,  2, 43,
+   27, 27, 27,  7,  7,  7,  7,  7, 70, 69, 70, 43, 43, 43, 43, 56,
+   85, 86, 42, 84, 86, 59,185,  2,  2, 79, 43, 43, 43, 43, 78, 43,
+   42, 70, 36, 36, 36, 36, 36, 36, 36, 36, 36, 69, 42, 42, 86, 42,
+   42, 42, 79,  7,  7,  7,  7,  7,  2,  2, 93, 97, 43, 43, 43, 43,
+   36, 69,  2, 60, 43, 43, 43, 43, 36, 93, 85, 42, 42, 42, 42, 84,
+   97, 36, 62,  2, 58, 42, 59, 86,  7,  7,  7,  7,  7, 62, 62,  2,
+  179, 27, 27, 27, 27, 27, 27, 27, 27, 27, 99, 43, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 36, 85, 86, 42, 85, 84, 42,  2,  2,  2, 70,
+   69, 43, 43, 43, 43, 43, 43, 43, 36, 36, 36, 60, 60, 36, 36, 61,
+   36, 36, 36, 36, 36, 36, 36, 61, 36, 36, 36, 36, 62, 43, 43, 43,
+   36, 36, 36, 36, 36, 36, 36, 69, 85, 86, 42, 42, 42, 79, 43, 43,
+   42, 85, 61, 36, 36, 36, 60, 61, 60, 36, 61, 36, 36, 56, 70, 85,
+   84, 85, 89, 88, 89, 88, 85, 43, 60, 43, 43, 88, 43, 43, 61, 36,
+   36, 85, 43, 42, 42, 42, 79, 43, 42, 42, 79, 43, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 61, 43, 60, 36, 36, 36, 61, 85, 86, 42, 42,
+   79, 89, 88, 88, 85, 89, 85, 84, 70, 70,  2, 92, 63, 43, 43, 43,
+   56, 79, 43, 43, 43, 43, 43, 43, 36, 36, 93, 85, 42, 42, 42, 42,
+   85, 42, 84, 70, 36, 62,  2,  2,  7,  7,  7,  7,  7,  2, 92, 70,
+   85, 86, 42, 42, 84, 84, 85, 86, 84, 42, 36, 71, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 36, 36, 93, 85, 42, 42, 43, 85, 85, 42, 86,
+   59,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 36, 36, 42, 43,
+   85, 86, 42, 42, 42, 84, 86, 86, 59,  2, 60, 43, 43, 43, 43, 43,
+    2,  2,  2,  2,  2,  2, 63, 43, 36, 36, 36, 36, 36, 69, 86, 85,
+   42, 42, 42, 86, 62, 43, 43, 43,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 60, 56, 86,
+   85, 42, 42, 86, 42, 42, 43, 43,  7,  7,  7,  7,  7, 27,  2, 96,
+   42, 42, 42, 42, 86, 59, 43, 43, 27, 99, 43, 43, 43, 43, 43, 61,
+   36, 36, 36, 60, 61, 43, 36, 36, 36, 36, 61, 60, 36, 36, 36, 36,
+   85, 85, 85, 88, 89, 56, 84, 70, 97, 86,  2, 63, 43, 43, 43, 43,
+   36, 36, 36, 36, 43, 36, 36, 36, 93, 85, 42, 42, 43, 42, 85, 85,
+   70, 71, 89, 43, 43, 43, 43, 43, 69, 42, 42, 42, 42, 70, 36, 36,
+   36, 69, 42, 42, 84, 69, 42, 59,  2,  2,  2, 58, 43, 43, 43, 43,
+   69, 42, 42, 84, 86, 42, 36, 36, 36, 36, 36, 36, 36, 42, 42, 42,
+   42, 42, 42, 84, 42,  2, 71,  2,  2, 63, 43, 43, 43, 43, 43, 43,
+    2,  2,  2,  2,  2, 43, 43, 43, 84, 42, 84, 84, 43, 43, 43, 43,
+   62, 43, 43, 43, 43, 43, 43, 43, 42, 42, 42, 79, 42, 42, 42, 86,
+   62,  2,  2, 43, 43, 43, 43, 43,  2, 36, 36, 36, 36, 36, 36, 36,
+   43, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 88, 42, 42, 42,
+   84, 42, 86, 79, 43, 43, 43, 43, 36, 36, 36, 60, 36, 61, 36, 36,
+   69, 42, 42, 79, 43, 79, 42, 56, 42, 42, 42, 69, 43, 43, 43, 43,
+   36, 36, 36, 61, 60, 36, 36, 36, 36, 36, 36, 36, 36, 85, 85, 89,
+   42, 88, 86, 86, 60, 43, 43, 43, 36, 36, 36, 36, 82, 36, 43, 43,
+   36, 69, 84,106, 63, 43, 43, 43, 42, 93, 36, 36, 36, 36, 36, 36,
+   36, 36, 85, 42, 42, 79, 43, 85, 84, 59,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7, 79, 43, 43, 27, 27, 90, 66, 66, 66, 55, 20,
+  167, 66, 66, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43, 43, 43, 92,
+  104,104,104,104,104,104,104,181,  2,  2, 63, 43, 43, 43, 43, 43,
+   62, 63, 43, 43, 43, 43, 43, 43, 64, 64, 64, 64, 64, 64, 64, 64,
+   70, 36, 36, 69, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 36, 36, 42, 42, 42, 42, 42, 42, 85, 86, 42,
+   42, 42, 59, 43, 43, 43, 43, 43, 42, 42, 42, 59,  2,  2, 66, 66,
+   39, 39, 96, 43, 43, 43, 43, 43,  7,  7,  7,  7,  7,179, 27, 27,
+   27, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 61, 36,
+   39, 68, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 82,163,  2,
+   27, 27, 27, 30,  2, 63, 43, 43, 11, 11, 11, 11, 46,149, 16, 16,
+   16, 16, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 60, 43, 56,
+   93, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+   85, 85, 85, 85, 43, 43, 43, 56, 42, 73, 39, 39, 39, 39, 39, 39,
+   39, 87, 79, 43, 43, 43, 43, 43, 85, 39,104,181, 43, 43, 43, 43,
+   43, 43, 43, 43, 43, 43, 43, 61, 36, 60, 43, 43, 43, 43, 43, 43,
+   39, 39, 51, 39, 39, 39, 51, 80, 43, 60, 43, 43, 43, 43, 43, 43,
+   36, 60, 61, 43, 43, 43, 43, 43, 43, 43, 36, 36, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 43, 49, 59, 64, 64, 43, 43, 43, 43, 43, 43,
+    7,  7,  7,  7,  7, 66, 91, 43, 66, 66, 43, 43, 43, 66, 66, 66,
+  176, 43, 43, 43, 43, 43, 43, 43, 42, 42, 42, 79, 43, 43, 43, 43,
+   66, 66, 66, 91, 54, 66, 66, 66, 66, 66,186, 86, 42, 66,186, 85,
+   85,187, 64, 64, 64, 83, 42, 42, 42, 75, 49, 42, 42, 42, 66, 66,
+   66, 66, 66, 66, 66, 42, 42, 66, 66, 42, 75, 43, 43, 43, 43, 43,
+   27, 27, 43, 43, 43, 43, 43, 43, 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,109, 16, 16, 16, 16, 16, 11, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 46, 11, 43, 46, 47, 46, 47, 11, 46, 11,
+   11, 11, 11, 16, 16,149,149, 16, 16, 16,149, 16, 16, 16, 16, 16,
+   16, 16, 11, 47, 11, 46, 47, 11, 11, 11, 46, 11, 11, 11, 46, 16,
+   16, 16, 16, 16, 11, 47, 11, 46, 11, 11, 46, 46, 43, 11, 11, 11,
+   46, 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, 43, 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, 43,  7,
+   42, 42, 42, 75, 66, 49, 42, 42, 42, 42, 42, 42, 42, 42, 75, 66,
+   66, 66, 49, 66, 66, 66, 66, 66, 66, 66, 75, 21,  2,  2, 43, 43,
+   43, 43, 43, 43, 43, 56, 42, 42, 16, 16, 16, 16, 16,138, 16, 16,
+   16, 16, 16, 16, 16, 16, 16,109, 43, 43,149, 16, 16,109, 43, 43,
+   42, 42, 42, 79, 42, 42, 42, 42, 42, 42, 42, 42, 79, 56, 42, 42,
+   42, 56, 79, 42, 42, 79, 43, 43, 39, 39, 39, 39, 39, 39, 39, 43,
+   43, 43, 43, 43, 43, 43, 43, 56, 42, 42, 42, 73, 39, 39, 39, 43,
+    7,  7,  7,  7,  7, 43, 43, 76, 36, 36, 36, 36, 36, 36, 36, 79,
+   36, 36, 36, 36, 36, 36, 42, 42,  7,  7,  7,  7,  7, 43, 43, 95,
+   36, 36, 36, 36, 36, 82, 42, 42,188,  7,  7,  7,  7,189, 43, 92,
+   36, 69, 36, 70, 36, 36, 36, 42, 36, 36, 69, 43, 43, 43, 43, 82,
+   36, 36, 36, 60, 36, 36, 61, 60, 36, 36, 60,179, 27, 27, 27, 27,
+   16, 16, 42, 42, 42, 73, 43, 43, 27, 27, 27, 27, 27, 27,162, 27,
+  190, 27, 99, 43, 43, 43, 43, 43, 27, 27, 27, 27, 27, 27, 27,162,
+   27, 27, 27, 27, 27, 27, 27, 43, 36, 36, 61, 36, 36, 36, 36, 36,
+   61, 60, 60, 61, 61, 36, 36, 36, 36, 60, 36, 36, 61, 61, 43, 43,
+   43, 60, 43, 61, 61, 61, 61, 36, 61, 60, 60, 61, 61, 61, 61, 61,
+   61, 60, 60, 61, 36, 60, 36, 36, 36, 60, 36, 36, 61, 36, 60, 60,
+   36, 36, 36, 36, 36, 61, 36, 36, 61, 36, 61, 36, 36, 61, 36, 36,
+    8, 43, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 66, 66, 43, 43,
+   54, 66, 66, 66, 66, 66, 66, 66, 27, 27, 27, 27, 27, 27, 90, 66,
+   66, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43, 66, 66, 66, 66, 66,
+   66, 91, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 91, 43, 43, 43,
+   66, 43, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 66, 25, 40, 40,
+   66, 66, 66, 66, 91, 43, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43,
+    8,  8,  8,  8,176, 43, 43, 43, 66, 66, 66, 66, 66, 91, 43, 66,
+   66, 66, 66, 91, 91, 43, 54, 66, 66, 66, 66, 66, 66, 66, 91, 54,
+   66, 66, 66, 66, 66, 91, 43, 54, 66, 91, 66, 66, 66, 66, 66, 66,
+    7,  7,  7,  7,  7, 91, 43, 43, 78, 43, 43, 43, 43, 43, 43, 43,
+  170,170,170,170,170,170,170, 43,170,170,170,170,170,170,170,  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,  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, 21,  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, 24,  7,  7,  6,  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, 10, 21, 17, 21, 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,  1,  2, 15,  6, 18,  6, 12, 11,  9, 26,
+   26,  9, 26,  5,  7,  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, 21, 22,
+   18, 17, 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,  6,  9, 23, 26,
+    6, 10,  4,  4,  3,  3,  7, 25, 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,  7, 13, 13,  2, 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,  0,  0,  0,  0,  0,  0,  0,  0, 17, 18, 19,  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, 34,  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, 34,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 35,  0,
+    0,  0,  0, 36,  0, 37,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 35,  0,  0,  0,  0, 36,  0, 37,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 38,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 39, 40,  0,  0,  0,  0,  0,  0, 41, 42,
+   43, 44, 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,  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, 21,  0, 22, 23,  0, 24, 25,  0,
+    0, 24, 26, 27,  0, 24, 26,  0,  0, 24, 26,  0,  0, 24, 26,  0,
+    0,  0, 26,  0,  0, 24, 28,  0,  0, 24, 26,  0,  0, 29, 26,  0,
+    0,  0, 30,  0,  0, 31, 32,  0,  0, 33, 34,  0, 35, 36,  0, 37,
+   38,  0, 39,  0,  0, 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, 42,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 43, 44,  0,  0,
+    0,  0, 45,  0,  0,  0,  0,  0,  0, 46,  0,  0,  0, 47,  0,  0,
+    0,  0,  0,  0, 48,  0,  0, 49,  0, 50, 51, 52,  0, 53, 54, 55,
+    0, 56,  0, 57,  0, 58,  0,  0,  0,  0, 59, 60,  0,  0,  0,  0,
+    0,  0, 61, 62,  0,  0,  0,  0,  0,  0, 63, 64,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 65,  0,  0,  0, 66,
+    0,  0,  0, 67,  0, 68,  0,  0, 69,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 70, 71,  0,  0, 72,  0,  0,  0,  0,
+    0,  0,  0,  0, 73, 74,  0,  0,  0,  0, 54, 75,  0, 76, 77,  0,
+    0, 78, 79,  0,  0,  0,  0,  0,  0, 80, 81, 82,  0,  0,  0,  0,
+    0,  0,  0, 26,  0,  0,  0,  0,  0,  0,  0,  0, 83,  0,  0,  0,
+    0,  0,  0,  0,  0, 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,  0,  0, 85,  0,  0,  0,  0,  0,  0,  0, 86,  0,  0,  0, 87,
+    0,  0,  0,  0, 88, 89,  0,  0,  0,  0,  0, 90,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 91,  0, 92,
+    0,  0,  0,  0,  0,  0,  0,  0,  0, 93,  0, 94,  0,  0, 95,  0,
+   96,  0,  0,  0,  0,  0, 73, 97,  0, 98,  0,  0, 99,100,  0, 78,
+    0,  0,101,  0,  0,102,  0,  0,  0,  0,  0,103,  0,104, 26,105,
+    0,  0,106,  0,  0,  0,107,  0,  0,  0,108,  0,  0,  0,  0,  0,
+    0, 66,109,  0,  0, 66,  0,  0,  0,110,  0,  0,  0,111,  0,  0,
+    0,  0,  0,  0,  0, 98,  0,  0,  0,  0,  0,  0,  0,112,113,  0,
+    0,  0,  0, 79,  0, 44,114,  0,115,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 66,  0,  0,  0,  0,  0,  0,  0,  0,116,  0,
+  117,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,118,  0,
+    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,120,  0,121,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0, 38,  0,  0,  0,  0,  0,  0,  0,  0,  0, 39, 40,
-    0,  0,  0,  0,  0,  0, 41, 42, 43,  0, 44,  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, 14, 15,
-   16, 17, 16, 18, 16, 19, 16, 19, 16, 19,  0, 19, 16, 20, 16, 19,
-   21, 19,  0, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,  0, 32,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0, 33,  0,  0,  0,  0,  0,  0,
-   34,  0,  0, 35,  0,  0, 36,  0, 37,  0,  0,  0, 38, 39, 40, 41,
-   42, 43, 44, 45, 46,  0,  0, 47,  0,  0,  0, 48,  0,  0,  0, 49,
-    0,  0,  0,  0,  0,  0,  0, 50,  0, 51,  0, 52, 53,  0, 54,  0,
-    0,  0,  0,  0,  0, 55, 56, 57,  0,  0,  0,  0, 58,  0,  0, 59,
-   60, 61, 62, 63,  0,  0, 64, 65,  0,  0,  0, 66,  0,  0,  0,  0,
-   67,  0,  0,  0, 68,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0, 69,  0,  0,  0, 70,  0, 71,  0,  0, 72,  0,  0, 73,
-    0,  0,  0,  0,  0,  0,  0,  0, 74, 75,  0,  0,  0,  0, 76, 77,
-    0, 78, 79,  0,  0, 80, 81,  0, 82, 62,  0, 83, 84,  0,  0, 85,
-   86, 87,  0, 88,  0, 89,  0, 90,  0,  0, 51, 91, 51,  0, 92,  0,
-   93,  0,  0,  0, 81,  0,  0,  0, 94, 95,  0, 96, 97, 98, 99,  0,
-    0,  0,  0,  0, 51,  0,  0,  0,  0,100,101,  0,  0,  0,  0,  0,
-    0,102,  0,  0,  0,  0,  0,  0,103,  0,  0,  0,  0,  0,  0,104,
-  105,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,106,  0,  0,107,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,108,109,  0,  0,110,  0,  0,
-    0,  0,  0,  0,111,  0,112,  0,105,  0,  0,  0,  0,  0,113,114,
-    0,  0,  0,  0,  0,  0,  0,115,  0,  0,  0,116,  0,  0,  0,117,
-    0,118,  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,  0,  0,
-   28, 29, 30, 31,  0,  0,  0, 32, 33, 34,  0,  0, 33,  0,  0, 35,
-   33,  0,  0,  0, 33, 36,  0,  0,  0,  0,  0, 37, 38,  0,  0,  0,
-    0,  0,  0, 39, 40,  0,  0,  0,  0,  0,  0, 41, 42,  0,  0,  0,
-    0, 43,  0, 44,  0,  0,  0, 45, 46,  0,  0,  0, 47,  0,  0,  0,
-    0,  0,  0, 48, 49,  0,  0,  0,  0, 50,  0,  0,  0, 51,  0, 52,
-    0, 53,  0,  0,  0,  0, 54,  0,  0,  0,  0, 55,  0, 56,  0,  0,
-    0,  0, 57, 58,  0,  0,  0, 59, 60,  0,  0,  0,  0,  0,  0, 61,
-   52,  0, 62, 63,  0,  0, 64,  0,  0,  0, 65, 66,  0,  0,  0, 67,
-    0, 68, 69, 70, 71, 72,  1, 73,  0, 74, 75, 76,  0,  0, 77, 78,
-    0,  0,  0, 79,  0,  0,  1,  1,  0,  0, 80,  0,  0, 81,  0,  0,
-    0,  0, 77, 82,  0, 83,  0,  0,  0,  0,  0, 78, 84,  0, 85,  0,
-   52,  0,  1, 78,  0,  0, 86,  0,  0, 87,  0,  0,  0,  0,  0, 88,
-   57,  0,  0,  0,  0,  0,  0, 89, 90,  0,  0, 84,  0,  0, 33,  0,
-    0, 91,  0,  0,  0,  0, 92,  0,  0,  0,  0, 49,  0,  0, 93,  0,
-    0,  0,  0, 94, 95,  0,  0, 96,  0,  0, 97,  0,  0,  0, 98,  0,
-    0,  0, 99,  0,  0,  0,100,  0,  0,  0,  0,101,102, 93,  0,  0,
-  103,  0,  0,  0, 84,  0,  0,104,  0,  0,  0,105,106,  0,  0,107,
-  108,  0,  0,  0,  0,  0,  0,109,  0,  0,110,  0,  0,  0,  0,111,
-   33,  0,112,113,114, 57,  0,  0,115, 35,  0,  0,116,  0,  0,  0,
-  117,  0,  0,  0,  0,  0,  0,118,  0,  0,119,  0,  0,  0,  0,120,
-   88,  0,  0,  0,  0,  0, 57,  0,  0,  0,  0, 52,121,  0,  0,  0,
-    0,122,  0,  0,123,  0,  0,  0,  0,121,  0,  0,124,  0,  0,  0,
-    0,  0, 79,  0,  0,  0,  0,125,  0,  0,  0,126,  0,  0,  0,127,
-    0,128,  0,  0,  0,  0,129,130,131,  0,132,  0,133,  0,  0,  0,
-  134,135,136,  0, 77,  0,  0,  0,  0,  0, 35,  0,  0,  0,137,  0,
-    0,  0,138,  0,  0,  0,139,  0,  0,140,  0,  0,141,  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,  0, 19, 52,  1,
-    0,  0, 38, 14,  4,  1,  1,  1, 53, 21, 43, 52, 54, 21, 35,  1,
-    0,  0,  0, 55,  0,  0,  0, 56, 57, 58,  0,  0,  0,  0,  0, 59,
-    0, 60,  0,  0,  0,  0, 61, 62,  0,  0, 63,  0,  0,  0, 64,  0,
-    0,  0, 65,  0,  0,  0, 66,  0,  0,  0, 67,  0,  0,  0, 68,  0,
-    0, 69, 70,  0, 71, 72, 73, 74, 75, 76,  0,  0,  0, 77,  0,  0,
-    0, 78, 79,  0,  0,  0,  0, 47,  0,  0,  0, 49,  0, 80,  0,  0,
-    0, 62,  0,  0, 63,  0,  0, 81,  0,  0, 82,  0,  0,  0, 83,  0,
-    0, 19, 84,  0, 62,  0,  0,  0,  0, 49,  1, 85,  1, 52, 15, 86,
-   36, 10, 21, 87,  0, 55,  0,  0,  0,  0, 19, 10,  1,  0,  0,  0,
-    0,  0, 88,  0,  0, 89,  0,  0, 88,  0,  0,  0,  0, 78,  0,  0,
-   87,  9, 12,  4, 90,  8, 91, 47,  0, 58, 50,  0, 21,  1, 21, 92,
-   93,  1,  1,  1,  1, 94, 95, 96, 97,  1, 98, 58, 81, 99,100,  4,
-   58,  0,  0,  0,  0,  0,  0, 19, 50,  0,  0,  0,  0,  0,  0, 61,
-    0,  0,101,102,  0,  0,103,  0,  0,  1,  1, 50,  0,  0,  0, 38,
-    0, 63,  0,  0,  0,  0,  0, 62,  0,  0,104, 68, 61,  0,  0,  0,
-   78,  0,  0,  0,105,106, 58, 38, 81,  0,  0,  0,  0,  0,  0,107,
-    1, 14,  4, 12, 84,  0,  0,  0,  0, 38, 87,  0,  0,  0,  0,108,
-    0,  0,109, 61,  0,110,  0,  0,  0,  1,  0,  0,  0,  0, 49, 50,
-    0,  0, 19, 58,  0,  0,  0, 51,  0,111, 14, 52,112, 41,  0,  0,
-   62,  0,  0, 61,  0,  0,113,  0, 87,  0,  0,  0, 61, 62,  0,  0,
-   62,  0, 89,  0,  0,113,  0,  0,  0,  0,114,  0,  0,  0, 78, 55,
-    0, 38,  1, 58,  1, 58,  0,  0,  0,  0,  0, 88, 63, 89,  0,  0,
-  115,  0,  0,  0, 55,  0,  0,  0,  0,115,  0,  0,  0,  0, 61,  0,
-    0,  0,  0, 79,  0, 61,  0,  0,  0,  0, 56,  0, 89, 80,  0,  0,
-   79,  0,  0,  0,  8, 91,  0,  0,  1, 87,  0,  0,116,  0,  0,  0,
-    0,  0,  0,117,  0,118,119,120,121,  0,104,  4,122, 49, 23,  0,
-    0,  0, 38, 50, 38, 58,  0,  0,  1, 87,  1,  1,  1,  1, 39,  1,
-   48,105, 87,  0,  0,  0,  0,  1,  0,  0,  0,123,  0,  0,  0,112,
-    4,122,  0,  0,  0,  1,124,  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,230,220,220,220,230,230,  0,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,  9,  9,  0,  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,230,230,230,  0,  0,  0,  9,  9,  0,  0,  7,  0,
+    0,  0,  0,122,  0,  0,  0,  0,123,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,124,
+  125,126,  0,  0,  0,  0,127,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,128,129,  0,  0,130,  0,  0,  0,  0,121,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,131,  0,132,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,133,  0,  0,  0,  0,
+    0,  0,  0,134,  0,  0,  0,  0,  0,  0,  0,135,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,136,  0,  0,  0,137,  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,
+    0, 19, 52,  1,  0,  0, 38, 14,  4,  1,  1,  1, 53, 21, 43, 52,
+   54, 21, 35,  1,  0,  0,  0,  0,  0,  0,  0, 55,  0,  0,  0, 56,
+   57, 58,  0,  0,  0,  0,  0, 56,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0, 59,  0,  0,  0, 56,  0, 60,  0,  0,  0,  0,  0,  0,
+    0,  0, 61, 62,  0,  0, 63,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 64,  0,  0,  0, 65,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 66,  0,  0,  0, 67,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 68,  0,  0,  0,  0,  0,  0, 69, 70,  0,  0,  0,  0,  0,
+   71, 72, 73, 74, 75, 76,  0,  0,  0,  0,  0,  0,  0, 77,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0, 78, 79,  0,  0,  0,  0, 47,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 49,  0,  0,  0,  0,
+    0, 80,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0,  0,  0,  0,  0,
+   63,  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, 62,  0,  0,  0,
+    0, 49,  1, 85,  0,  0,  0,  0,  1, 52, 15, 86, 36, 10, 21,  1,
+    1,  1,  1, 41,  1, 21, 87,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 55,  0,  0,  0, 62,  0,  0,  0,  0,  0,  0,  0,  0, 19, 10,
+    1,  0,  0,  0,  0,  0, 88,  0,  0,  0,  0,  0,  0, 89,  0,  0,
+   88,  0,  0,  0,  0,  0,  0,  0,  0, 78,  0,  0,  0,  0,  0,  0,
+   90,  9, 12,  4, 91,  8, 92, 47,  0, 58, 50,  0, 21,  1, 21, 93,
+   94,  1,  1,  1,  1,  1,  1,  1,  1, 95, 96, 97,  0,  0,  0,  0,
+   98,  1, 99, 58, 81,100,101,  4, 58,  0,  0,  0,  0,  0,  0, 19,
+   50,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 61,  1,  1,  1,  1,
+    1,  1,  1,  1,  0,  0,102,103,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,104,  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, 63,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 62,  0,  0,  0,  0,  1,  1,  1,  1,
+   50,  0,  0,  0,  0,  0,105, 68,  0,  0,  0,  0,  0,  0,  0,  0,
+   61,  0,  0,  0,  0,  0,  0,  0, 78,  0,  0,  0, 62,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,106,107, 58, 38, 81,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0, 63,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,108,  1, 14,  4, 12,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0, 47, 84,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 38, 90,  0,  0,  0,  0,109,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,110, 61,  0,111,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,
+    0,  0,  0,  0,  0,  0, 49, 50,  0,  0,  0,  0,  0,  0, 19, 58,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,112, 51,  0,112, 14, 52,
+   84,  0,  0,  0,113, 41,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   62,  0,  0, 61,  0,  0,  0,  0,  0,  0,114,  0, 90,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 61, 62,  0,  0, 62,  0, 89,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,114,  0,  0,  0,  0,115,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 78, 55,  0, 38,  1, 58,
+    1, 58,  0,  0,  0,  0,  0, 88, 62,  0,  0,  0, 63, 89,  0,  0,
+    0,  0,  0, 59,116,  0,  0,  0,  0,  0,  0,  0, 55,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,116,  0,  0,  0,  0, 61,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 79, 78,  0,  0,  0,
+    0,  0,  0,  0,  0, 61,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 56,  0, 89, 80,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 61,  0,  0, 79,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 61,
+    0,  0,  0,  0,  0,  0,  0,  0,  8, 92,  0,  0,  0,  0,  0,  0,
+    1, 90,  0,  0,  0,  0,  0,  0,117,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,118,  0,119,120,121,122,  0,105,  4,123, 49, 23,  0,
+    0,  0,  0,  0,  0,  0, 38, 50,  0,  0,  0,  0, 38, 58,  0,  0,
+    0,  0,  0,  0,  1, 90,  1,  1,  1,  1, 39,  1, 48,106, 90,  0,
+    0,  0,  0,  0,  0,  0,  0, 19,  0,  0,  0,  0,  0,  0,  0, 59,
+    0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,124,
+    0,  0,  0,  0,  0,  0,  0,113,  0,  0,  0,  0, 19, 59,  0, 38,
+    0, 81,  0,  0,  0,  0,  0,  0,  4,123,  0,  0,  0,  1,125,  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,230,220,220,220,230,230,  0,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,  9,  9,  0,  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,
+  230,230,230,234,  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,218,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,
@@ -1683,63 +1482,81 @@ _hb_ucd_u8[17612] =
     0,  0,  0,  0,  0,  0,  0,  0,  0, 26, 34,  9,  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,  8,  9, 10, 11,
-   12, 13, 13, 13, 13, 13, 13, 14, 13, 13, 13, 13, 13, 13, 13, 13,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 16, 17, 18,
-   18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 20, 20, 20, 20, 20, 20,
-   20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 20, 33,
-   34, 35, 34, 34, 36, 37, 20, 20, 20, 20, 20, 20, 38, 20, 39, 40,
-   41, 41, 41, 41, 41, 42, 43, 44, 20, 20, 20, 20, 20, 20, 20, 45,
-   46, 20, 20, 47, 20, 20, 20, 48, 49, 50, 51, 52, 53, 54, 55, 56,
-   57, 58, 59, 20, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    0,  0,  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, 12, 13,
+   13, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 13, 13, 13,
+   24, 25, 26, 26, 26, 27, 13, 13, 13, 28, 29, 30, 13, 31, 32, 33,
+   34, 35, 36, 37,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7, 38,  7,  7, 39,  7, 40,  7,  7,
+    7, 41, 13, 42,  7,  7, 43,  7,  7,  7, 44, 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, 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, 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, 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, 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, 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, 13, 13, 13, 13, 13, 13, 60, 13, 13,
-   13, 61, 62, 13, 13, 13, 13, 63, 13, 13, 13, 13, 13, 13, 64, 65,
-   20, 20, 66, 20, 13, 13, 13, 13, 67, 13, 13, 13, 68, 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,
-   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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
-   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, 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, 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, 69,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 19,
+   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, 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, 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, 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, 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, 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, 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, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 45,  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, 59, 63, 64,
+   65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 59, 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, 69, 69, 69,
+   69, 78, 69, 69, 69, 69, 79, 79, 79, 79, 79, 79, 79, 79, 79, 80,
+   81, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 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, 94, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+   95, 95, 95, 95, 95, 95, 95, 95, 69, 69, 96, 97, 98, 99, 99, 99,
+  100,101,102,103,104,105,106,107,108,109, 95,110,111,112,113,114,
+  115,116,117,117,118,119,120,121,122,123,124,125,126,127,128,129,
+  130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,
+   95,146,147,148,149, 95,150,151,152,153,154,155,156,157,158,159,
+  160,161, 95,162,163,164,165,165,165,165,165,165,165,166,167,165,
+  168, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+   95, 95, 95, 95, 95,169,170,170,170,170,170,170,170,170,171,170,
+  170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,
+  170,170,170,170,170,170,170,170,170,170,170,170,170,172,173,173,
+  173,173,174, 95, 95, 95, 95, 95,175, 95, 95, 95, 95, 95, 95, 95,
+   95, 95, 95, 95, 95, 95,176,176,176,176,177,178,179,180, 95, 95,
+  181, 95,182,183,184,185,186,186,186,186,186,186,186,186,186,186,
+  186,186,186,186,186,186,186,186,186,186,186,186,187,187,187,188,
+  189,190, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+   95, 95, 95, 95, 95,191,192,193,194,195,195,196, 95, 95, 95, 95,
+   95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,197,198,
+   95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 59,199,
+   59, 59, 59,200,201,202, 59,203,204,205,206,207,208, 95,209,210,
+  211, 59, 59,212, 59,213,214,214,214,214,214,215, 95, 95, 95, 95,
+   95, 95, 95, 95,216, 95,217,218,219, 95, 95,220, 95, 95, 95,221,
+   95,222, 95,223, 95,224,225,226,227, 95, 95, 95, 95, 95,228,229,
+  230, 95,231,232, 95, 95,233,234, 59,235,236, 95, 59, 59, 59, 59,
+   59, 59, 59,237, 59,238,239,240, 59, 59,241,242, 59,243, 95, 95,
+   95, 95, 95, 95, 95, 95, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+   69, 69, 69,244, 69, 69,245, 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,246, 69, 69, 69, 69, 69, 69, 69, 69, 69,247, 69, 69,
+   69, 69,248, 95, 95, 95, 69, 69, 69, 69,249, 95, 95, 95, 95, 95,
+   95, 95, 95, 95, 95, 95, 69, 69, 69, 69, 69, 69,250, 69, 69, 69,
+   69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,251, 95,
+   95, 95, 95, 95, 95, 95,252, 95,253,254,  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,
@@ -1764,46 +1581,46 @@ _hb_ucd_u8[17612] =
    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,  3,  3,  2,  3,  3,
-    2,  2,  2,  2,  2,  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, 23, 23, 23, 23, 23,  2,
-   23, 23, 23, 23,  2,  2,  2,  2,  2,  2,  2, 23, 23,  2, 23, 23,
-   23,  2,  2, 23,  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, 16, 16,
+   37,  2,  2,  2,  2,  2,  3,  3,  2,  2,  2,  2,  2,  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, 23, 23, 23, 23, 23,  2, 23, 23, 23, 23,  2,  2,  2,  2,
+    2,  2,  2, 23, 23,  2, 23, 23, 23,  2, 23, 23,  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, 16, 16, 16,  2, 16, 16,
    16, 16,  2,  2, 16, 16,  2, 16, 16, 16,  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,
@@ -1850,137 +1667,135 @@ _hb_ucd_u8[17612] =
    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,  1,
-    1,  1,  1,  1,  1,  2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
-   62, 62, 62,  2, 62, 62, 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,  6,  6,  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,  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,  2,
-    2,  2,  2,  2,  2,  2,  1,  2,  2,  2,  2,  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,
-    2,  2,  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, 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,  0,  0,  0,  0,  0,  0,  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,  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,  2,  2,  2,  2,  2,  2,  2,  0, 12, 12,
-   12, 12, 12, 12, 12,  0, 17, 17, 17, 17, 17, 17, 17,  0, 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, 19, 19, 19, 19, 19, 19,  2,  2, 19, 19,
-    2, 19,  2, 19, 19, 19,  2,  2, 19, 19, 19, 19, 19, 19, 60, 60,
-   60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,  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,  3,  2,  2,  2,  2,  2,  2,  2,
-    2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  0,  2,  2,
-    3,  3,  3,  3,  3,  3,  2,  2,  2,  2,  2,  2,  2,  3,  1,  1,
-    1,  1,  1,  1,  6,  6,  0,  0,  0,  2,  0,  0,  0,  0,  0,  0,
-    0,  0,  2,  2,  2,  2,  3,  3,  3,  3,  3,  2,  3,  3,  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,161,161,
-  161,161,161,161,161,161,161,161,161,  2,161,161,161,161,161,161,
-  161,  2,161,161,  2,161,161,161,  2,161,161,161,161,161,161,161,
-    2,161,161,  2,  2,  2,170,170,170,170,170,170,170,170,170,170,
-  170,170,  2,  2,  2,  2,110,110,110,110,110,110,110,110,110,110,
-  110,110,110,110,110,  2,110,110,110,110,110,110,  2,  2, 19, 19,
-   19, 19, 19, 19,  2, 19, 19,  2, 19, 19, 19, 19, 19, 19, 19, 19,
-   19,  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,  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,165,165,
-  165,165,165,165,165,165,165,165,165,165,165,165,  2,  2,  2,165,
-  165,165,165,165,165,165,  2,  2,  2,  2,  2,  2,165,165,156,156,
+    1,  1,  1,  1,  2,  2,  1,  1,  1,  1,  2,  2,  2,  2, 62, 62,
+   62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,  2, 62, 62, 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,  6,
+    6,  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,  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,  2,  2,  2,  2,  2,  2,  1,  2,
+    2,  2,  2,  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, 56, 56,
+   56, 56, 56, 56, 56, 56, 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,  0,  0,
+    0,  0,  0,  0,  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,  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,  2,  2,
+    2,  2,  2,  2,  2,  0, 12, 12, 12, 12, 12, 12, 12,  0, 17, 17,
+   17, 17, 17, 17, 17,  0, 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, 19,
+   19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+   60, 60, 60,  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,
+    3,  3,  3,  3,  0,  0,  1,  1,  1,  1,  1,  1,  6,  6,  0,  0,
+    0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  2,  2,  2,  2,  3,  3,
+    3,  3,  3,  2,  3,  3,  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,161,161,161,161,161,161,161,161,161,161,
+  161,  2,161,161,161,161,161,161,161,  2,161,161,  2,161,161,161,
+    2,161,161,161,161,161,161,161,  2,161,161,  2,  2,  2,170,170,
+  170,170,170,170,170,170,170,170,170,170,  2,  2,  2,  2,110,110,
+  110,110,110,110,110,110,110,110,110,110,110,110,110,  2,110,110,
+  110,110,110,110,  2,  2, 19, 19, 19, 19, 19, 19,  2, 19, 19,  2,
+   19, 19, 19, 19, 19, 19, 19, 19, 19,  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,  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,173,173,
+  173,173,173,173,173,173,173,173,  2,  2,  2,  2,  2,  2, 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,165,165,165,165,165,165,165,165,165,165,
+  165,165,165,165,  2,  2,  2,165,165,165,165,165,165,165,  2,  2,
+    2,  2,  2,  2,165,165,  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,  2,  2,  3,  3,  3,  2,  2,  2,  2,  2,
-    2,  2,  3,  3,  3,  3,147,147,147,147,147,147,147,147,148,148,
+    2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,  2,
+    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,158,158,
   158,158,158,158,158,158,158,158,  2,  2,  2,  2,  2,  2,153,153,
   153,153,153,153,153,153,153,153,153,153,  2,  2,  2,  2,149,149,
@@ -2039,46 +1854,51 @@ _hb_ucd_u8[17612] =
   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,163,163,163,163,163,163,163,163,163,  2,
-  163,163,163,163,163,163,163,163,163,  2,  2,  2,163,163,163,163,
-  163,  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,157,157,157,157,157,157,157,157,157,157,
-  157,  2,  2,  2,  2,  2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
-   80, 80, 80, 80,  2,  2, 80, 80, 80,  2,  2,  2,  2,  2,127,127,
-  127,127,127,127,127,127,127,127,127,127,127,127,127,  2,166,166,
-  166,166,166,166,166,166,166,166,  2,  2,  2,  2,  2,  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,159,159,
-  159,159,159,159,159,159,159,159,159,159,159,159,159,  2,159,159,
-    2,  2,  2,  2,  2,  2,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,167,167,167,167,167,167,167,167,167,167,
-    2,  2,  2,  2,  2,  2,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,
+    2,  2,  2,  2,  2,  2,175,175,175,175,175,175,175,175,175,175,
+  175,175,  2,  2,  2,  2,175,175,  2,  2,  2,  2,  2,  2,145,145,
+  145,145,145,145,145,145,145,  2,  2,  2,  2,  2,  2,  2,163,163,
+  163,163,163,163,163,163,163,  2,163,163,163,163,163,163,163,163,
+  163,  2,  2,  2,163,163,163,163,163,  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,157,157,
+  157,157,157,157,157,157,157,157,157,  2,  2,  2,  2,  2, 80, 80,
+   80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,  2,  2, 80, 80,
+   80,  2,  2,  2,  2,  2,127,127,127,127,127,127,127,127,127,127,
+  127,127,127,127,127,  2,166,166,166,166,166,166,166,166,166,166,
+    2,  2,  2,  2,  2,  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,159,159,159,159,159,159,159,159,159,159,
+  159,159,159,159,159,  2,159,159,  2,  2,  2,  2,  2,  2,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,167,167,
+  167,167,167,167,167,167,167,167,  2,  2,  2,  2,  2,  2,146,146,
+  146,146,146,146,146,146,146,146,146,  2,  2,  2,  2,  2,172,172,
+  172,172,172,172,172,172,172,  2,  2,172,172,172,172,172,172,172,
+  172,172,  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,
-   13, 13,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,  2,  2,
-    2,  2,  2,  2,  2,155,136,  2,  2,  2,  2,  2,  2,  2, 17, 17,
+   13, 13,155,  2,  2,  2, 13, 13, 13, 13, 13, 13, 13,  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,  2,  2,  2,  2,  2,  2,  2,155,136,136,
+  136,136,136,136,136,  2,136,136,136,  2,  2,  2,  2,  2, 17, 17,
    17, 17,  2, 17, 17, 17, 17, 17, 17, 17,  2, 17, 17,  2, 17, 15,
    15, 15, 15, 15, 15, 15, 17, 17, 17,  2,  2,  2,  2,  2,  2,  2,
    15,  2,  2,  2,  2,  2, 15, 15, 15,  2,  2, 17,  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,  1,  1,
-    1,  1,  1,  1,  2,  2,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,
+    2,  2,  2,  2,  2,  2,105,105,  2,  2,105,105,105,105,  2,  2,
+    0,  0,  0,  0,  0,  0,  0,  2,  2,  2,  2,  2,  2,  2,  1,  1,
+    1,  1,  1,  1,  1,  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,  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,
+    0,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  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,  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,  2,  2,
     2,  2,  2, 19, 19, 19, 56, 56, 56, 56, 56, 56, 56,  2, 56,  2,
@@ -2090,7 +1910,9 @@ _hb_ucd_u8[17612] =
   160,160,160,160,160,  2,152,152,152,152,152,152,152,152,152,152,
     2,  2,  2,  2,  2,152,164,164,164,164,164,164,164,164,164,164,
     2,  2,  2,  2,  2,  2,168,168,168,168,168,168,168,168,168,168,
-  168,  2,  2,  2,  2,168, 30, 30, 30, 30,  2, 30, 30,  2,113,113,
+  168,  2,  2,  2,  2,168,174,174,174,174,174,174,174,174,174,174,
+  174,174,174,174,174,  2,174,174,174,174,174,174,  2,  2,  2,  2,
+    2,  2,  2,  2,174,174, 30, 30, 30, 30,  2, 30, 30,  2,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,
@@ -2101,8 +1923,8 @@ _hb_ucd_u8[17612] =
     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,  3,  3,
     2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0, 15,  0,
-    0,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  2,  2,
-    2,  0,  0,  0,  0,  0,  0,  0,  2,  2,  2,  2,  2,  0,  0,  0,
+    0,  2,  2,  2,  2,  2,  0,  2,  2,  2,  0,  0,  0,  0,  0,  0,
+    0,  2,  2,  2,  0,  0,  0,  2,  2,  2,  2,  0,  0,  0,  0,  0,
     0,  0,  0,  2,  2,  0, 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,
@@ -2186,8 +2008,7 @@ _hb_ucd_u8[17612] =
     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[10400] =
+static const uint16_t _hb_ucd_u16[10832]=
 {
      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,
@@ -2210,27 +2031,29 @@ _hb_ucd_u16[10400] =
     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,
     48, 184,  48, 185,  48, 186, 187, 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, 140, 140, 140,
-   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,  32,
-    13,  13,  13,  13,  13,  13,  13,  13,  13, 240,  13,  13,  13,  13,  13,  13,
-   241, 242, 241, 241, 242, 243, 241, 244, 245, 245, 245, 246, 247, 248, 249, 250,
-   251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 261, 262, 263, 264, 265,
-   266, 267, 268, 269, 270, 271, 272, 272, 273, 274, 275, 209, 276, 277, 209, 278,
-   279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279,
-   280, 209, 281, 209, 209, 209, 209, 282, 209, 283, 279, 284, 209, 285, 286, 209,
-   209, 209, 176, 140, 287, 140, 271, 271, 271, 288, 209, 209, 209, 209, 289, 271,
-   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, 271, 296, 209, 209, 297, 279, 298, 279,
+    48, 210,  48,  48,  48, 211, 212, 213, 192, 192, 214, 215,  32, 216, 217, 140,
+   218,  48,  48, 219, 220, 160, 221, 222, 223,  48, 224,  64,  48,  48, 225, 226,
+    48,  48, 227, 228, 229,  64,  48, 230, 231,   9,   9, 232, 233, 234, 235, 236,
+    11,  11, 237,  27,  27,  27, 238, 239,  11, 240,  27,  27,  32,  32,  32,  32,
+    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, 263, 264, 265, 266,
+   267, 268, 269, 270, 271, 272, 273, 273, 274, 275, 276, 209, 277, 278, 209, 279,
+   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280,
+   281, 209, 282, 209, 209, 209, 209, 283, 209, 284, 280, 285, 209, 286, 287, 209,
+   209, 209, 176, 140, 288, 140, 272, 272, 272, 289, 209, 209, 209, 209, 290, 272,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 291, 292, 209, 209, 293,
+   209, 209, 209, 209, 209, 209, 294, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+   209, 209, 209, 209, 209, 209, 295, 296, 272, 297, 209, 209, 298, 280, 299, 280,
    209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
-   279, 279, 279, 279, 279, 279, 279, 279, 299, 300, 279, 279, 279, 301, 279, 302,
-   209, 209, 209, 279, 303, 209, 209, 304, 209, 305, 209, 209, 209, 209, 209, 209,
+   280, 280, 280, 280, 280, 280, 280, 280, 300, 301, 280, 280, 280, 302, 280, 303,
+   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280,
+   209, 209, 209, 280, 304, 209, 209, 305, 209, 209, 209, 209, 209, 209, 209, 209,
      9,   9,   9,  11,  11,  11, 306, 307,  13,  13,  13,  13,  13,  13, 308, 309,
     11,  11, 310,  48,  48,  48, 311, 312,  48, 313, 314, 314, 314, 314,  32,  32,
    315, 316, 317, 318, 319, 320, 140, 140, 209, 321, 209, 209, 209, 209, 209, 322,
@@ -2238,226 +2061,201 @@ _hb_ucd_u16[10400] =
    324, 325, 326, 327, 136,  48,  48,  48,  48, 328, 178,  48,  48,  48,  48, 329,
    330,  48,  48, 136,  48,  48,  48,  48, 200, 331,  48,  48, 209, 209, 332,  48,
    209, 333, 334, 209, 335, 336, 209, 209, 334, 209, 209, 336, 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, 337,  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, 338,  48,  48, 229,
+    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, 338,  48,  48, 230,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
    339,  48, 340, 140,  13,  13, 341, 342,  13, 343,  48,  48,  48,  48, 344, 345,
     31, 346, 347, 348,  13,  13,  13, 349, 350, 351, 352, 353, 354, 355, 140, 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,  76,  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, 314,  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, 140, 140,
    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, 209,  48,  48,  48,  48, 401,  48,  48, 402, 140, 140, 403,
     32, 404,  32, 405, 406, 407, 408, 409,  48,  48,  48,  48,  48,  48,  48, 410,
    411,   2,   3,   4,   5, 412, 413, 414,  48, 415,  48, 200, 416, 417, 418, 419,
    420,  48, 172, 421, 204, 204, 140, 140,  48,  48,  48,  48,  48,  48,  48,  71,
-   422, 271, 271, 423, 272, 272, 272, 424, 425, 426, 427, 140, 140, 209, 209, 428,
+   422, 272, 272, 423, 273, 273, 273, 424, 425, 426, 427, 140, 140, 209, 209, 428,
    140, 140, 140, 140, 140, 140, 140, 140,  48, 151,  48,  48,  48, 100, 429, 430,
     48,  48, 431,  48, 432,  48,  48, 433,  48, 434,  48,  48, 435, 436, 140, 140,
      9,   9, 437,  11,  11,  48,  48,  48,  48, 204, 192,   9,   9, 438,  11, 439,
     48,  48, 440,  48,  48,  48, 441, 442, 442, 443, 444, 445,  48,  48,  48, 388,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
     48,  48,  48, 313,  48, 199, 440, 140, 446,  27,  27, 447, 140, 140, 140, 140,
    448,  48,  48, 449,  48, 450,  48, 451,  48, 200, 452, 140, 140, 140,  48, 453,
-    48, 454,  48, 455, 140, 140, 140, 140,  48,  48,  48, 456, 271, 457, 271, 271,
+    48, 454,  48, 455,  48, 207, 140, 140,  48,  48,  48, 456, 272, 457, 272, 272,
    458, 459,  48, 460, 461, 462,  48, 463,  48, 464, 140, 140, 465,  48, 466, 467,
     48,  48,  48, 468,  48, 469,  48, 470,  48, 471, 472, 140, 140, 140, 140, 140,
     48,  48,  48,  48, 196, 140, 140, 140,   9,   9,   9, 473,  11,  11,  11, 474,
     48,  48, 475, 192, 476,   9, 477,  11, 478, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 271, 479,  48,  48, 480, 481, 482, 140, 140, 483,
-    48, 464, 484,  48,  62, 485, 140,  48, 486, 140, 140,  48, 487, 140,  48, 313,
-   488,  48,  48, 489, 490, 457, 491, 492, 222,  48,  48, 493, 494,  48, 196, 192,
-   495,  48, 496, 497, 498,  48,  48, 499, 222,  48,  48, 500, 501, 502, 503, 504,
-    48,  97, 505, 506, 507, 140, 140, 140, 508, 509, 510,  48,  48, 511, 512, 192,
-   513,  83,  84, 514, 515, 516, 517, 518, 519,  48,  48, 520, 521, 522, 523, 140,
-    48,  48,  48, 524, 525, 526, 481, 140,  48,  48,  48, 527, 528, 192, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140,  48,  48, 529, 530, 531, 532, 140, 140,
-    48,  48,  48, 533, 534, 192, 535, 140,  48,  48, 536, 537, 192, 538, 539, 140,
-    48, 540, 541, 542, 313, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-    48,  48, 505, 543, 140, 140, 140, 140, 140, 140,   9,   9,  11,  11, 148, 544,
-   545, 546,  48, 547, 548, 192, 140, 140, 140, 140, 549,  48,  48, 550, 551, 140,
-   552,  48,  48, 553, 554, 555,  48,  48, 556, 557, 558,  48,  48,  48,  48, 196,
-   559, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48,  48, 560, 192,
-    84,  48, 529, 561, 562, 148, 175, 563,  48, 564, 565, 566, 140, 140, 140, 140,
-   567,  48,  48, 568, 569, 192, 570,  48, 571, 572, 192, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 573,
-   574, 115,  48, 575, 576, 577, 140, 140, 140, 140, 140, 100, 271, 578, 579, 580,
+   140, 140, 140, 140, 140, 140, 272, 479,  48,  48, 480, 481, 482, 483, 140, 484,
+    48, 464, 485,  48,  62, 486, 140,  48, 487, 140, 140,  48, 488, 140,  48, 313,
+   489,  48,  48, 490, 491, 457, 492, 493, 223,  48,  48, 494, 495,  48, 196, 192,
+   496,  48, 497, 498, 499,  48,  48, 500, 223,  48,  48, 501, 502, 503, 504, 505,
+    48,  97, 506, 507, 508, 140, 140, 140, 509, 510, 511,  48,  48, 512, 513, 192,
+   514,  83,  84, 515, 516, 517, 518, 519, 520,  48,  48, 521, 522, 523, 524, 140,
+    48,  48,  48, 525, 526, 527, 481, 140,  48,  48,  48, 528, 529, 192, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 140,  48,  48, 530, 531, 532, 533, 140, 140,
+    48,  48,  48, 534, 535, 192, 536, 140,  48,  48, 537, 538, 192, 539, 540, 140,
+    48, 541, 542, 543, 313, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+    48,  48, 506, 544, 140, 140, 140, 140, 140, 140,   9,   9,  11,  11, 148, 545,
+   546, 547,  48, 548, 549, 192, 140, 140, 140, 140, 550,  48,  48, 551, 552, 140,
+   553,  48,  48, 554, 555, 556,  48,  48, 557, 558, 559,  48,  48,  48,  48, 196,
+   560, 140, 140, 140, 140, 140, 561, 140, 140, 140, 140, 140,  48,  48, 562, 192,
+    84,  48, 530, 563, 564, 148, 175, 565,  48, 566, 567, 568, 140, 140, 140, 140,
+   569,  48,  48, 570, 571, 192, 572,  48, 573, 574, 192,  48,  48, 575, 192, 140,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 576,
+   577, 115,  48, 578, 579, 580, 140, 140, 140, 140, 140, 100, 272, 581, 582, 583,
+    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, 140, 140, 140, 140, 140, 140,
-   272, 272, 272, 272, 272, 272, 581, 582,  48,  48,  48,  48,  48,  48,  48,  48,
+   273, 273, 273, 273, 273, 273, 584, 585,  48,  48,  48,  48,  48,  48,  48,  48,
     48,  48,  48,  48, 388, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140,  48,  48,  48,  48,  48,  48, 583,
-    48,  48,  48, 584, 585, 586,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 140, 140,  48,  48,  48,  48,  48,  48, 586,
+    48,  48,  48, 587, 588, 589,  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,  71,
     48,  48,  48,  48, 313, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-    48, 587, 588, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-    48,  48,  48, 196,  48, 200, 370,  48,  48,  48,  48, 200, 192,  48, 204, 589,
-    48,  48,  48, 590, 591, 592, 593, 594,  48, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 595,  48, 596, 192, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140,   9,   9,  11,  11, 271, 597, 140, 140, 140, 140, 140, 140,
-    48,  48,  48,  48, 598, 599, 600, 600, 601, 602, 140, 140, 140, 140, 603, 604,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 440,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 199, 140, 605,
-   196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 606,
-    48,  48, 607, 608, 140, 609, 610,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+    48, 590, 591, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+    48,  48,  48, 196,  48, 200, 370,  48,  48,  48,  48, 200, 192,  48, 204, 592,
+    48,  48,  48, 593, 594, 595, 596, 597,  48, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 598,  48, 599, 192, 140, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140,   9,   9,  11,  11, 272, 600,   9, 601,  11, 602, 140, 140,
+    48,  48,  48,  48, 603, 604, 605, 605, 606, 607, 140, 140, 140, 140, 608, 609,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 199, 140, 610,
+    48, 200, 140, 140, 140, 140, 140, 140,  48,  48,  48,  48,  48,  48,  48, 611,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 612,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48, 611, 613, 140, 614, 615,  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,
-    48,  48,  48,  48,  48,  48,  71, 151, 196, 611, 612, 140, 140, 140, 140, 140,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 192,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 322, 140, 140, 140, 140,
-    32,  32, 613,  32, 614, 209, 209, 209, 209, 209, 209, 209, 322, 140, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+    48,  48,  48,  48,  48,  48,  71, 151, 196, 616, 617, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 618,
+   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, 619, 209, 427, 209, 620,
+    32,  32, 216,  32, 621, 209, 209, 209, 209, 209, 209, 209, 322, 140, 140, 140,
    209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 323,
-   209, 209, 615, 209, 209, 209, 616, 617, 618, 209, 619, 209, 209, 209, 287, 140,
-   209, 209, 209, 209, 620, 140, 140, 140, 140, 140, 140, 140, 271, 621, 271, 621,
-   209, 209, 209, 209, 209, 338, 271, 461, 140, 140, 140, 140, 140, 140, 140, 140,
-     9, 622,  11, 623, 624, 625, 241,   9, 626, 627, 628, 629, 630,   9, 622,  11,
-   631, 632,  11, 633, 634, 635, 636,   9, 637,  11,   9, 622,  11, 623, 624,  11,
-   241,   9, 626, 636,   9, 637,  11,   9, 622,  11, 638,   9, 639, 640, 641, 642,
-    11, 643,   9, 644, 645, 646, 647,  11, 648,   9, 649,  11, 650, 538, 538, 538,
-    32,  32,  32, 651,  32,  32, 652, 653, 654, 655,  45, 140, 140, 140, 140, 140,
-   656, 657, 658, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   659, 660, 661,  27,  27,  27, 662, 140, 663, 140, 140, 140, 140, 140, 140, 140,
-    48,  48, 151, 664, 665, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 666, 140,  48,  48, 667, 668,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 669, 192,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 587, 670,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 671, 200,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 672, 614, 140, 140,
-     9,   9, 626,  11, 673, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 503, 271, 271, 674, 675, 140, 140, 140, 140,
-   503, 271, 676, 677, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   678,  48, 679, 680, 681, 682, 683, 684, 685, 206, 686, 206, 140, 140, 140, 687,
-   209, 209, 688, 209, 209, 209, 209, 209, 209, 322, 333, 689, 689, 689, 209, 323,
-   690, 209, 209, 209, 209, 209, 209, 209, 209, 209, 691, 140, 140, 140, 692, 209,
-   693, 209, 209, 688, 694, 695, 323, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 696,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 697, 426, 426,
-   209, 209, 209, 209, 209, 209, 209, 698, 209, 209, 209, 209, 209, 176, 688, 427,
-   688, 209, 209, 209, 699, 176, 209, 209, 699, 209, 691, 688, 695, 140, 140, 140,
-   209, 209, 209, 209, 209, 322, 691, 426, 700, 209, 209, 209, 701, 702, 176, 694,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 703, 209, 209, 209, 209, 209, 192,
+   209, 209, 622, 209, 209, 209, 623, 624, 625, 209, 626, 209, 209, 209, 288, 140,
+   209, 209, 209, 209, 627, 140, 140, 140, 140, 140, 140, 140, 272, 628, 272, 628,
+   209, 209, 209, 209, 209, 338, 272, 461, 140, 140, 140, 140, 140, 140, 140, 140,
+     9, 629,  11, 630, 631, 632, 242,   9, 633, 634, 635, 636, 637,   9, 629,  11,
+   638, 639,  11, 640, 641, 642, 643,   9, 644,  11,   9, 629,  11, 630, 631,  11,
+   242,   9, 633, 643,   9, 644,  11,   9, 629,  11, 645,   9, 646, 647, 648, 649,
+    11, 650,   9, 651, 652, 653, 654,  11, 655,   9, 656,  11, 657, 539, 539, 539,
+   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, 658,  32,  32, 659, 660, 661, 662,  45, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   663, 664, 665, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   666, 667, 668,  27,  27,  27, 669, 140, 670, 140, 140, 140, 140, 140, 140, 140,
+    48,  48, 151, 671, 672, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 673, 140,  48,  48, 674, 675,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 676, 192,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 590, 677,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 200, 678, 679,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 680, 200,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 681, 621, 140, 140,
+     9,   9, 633,  11, 682, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 504, 272, 272, 683, 684, 140, 140, 140, 140,
+   504, 272, 685, 686, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   687,  48, 688, 689, 690, 691, 692, 693, 694, 206, 695, 206, 140, 140, 140, 696,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   209, 209, 697, 209, 209, 209, 209, 209, 209, 322, 333, 698, 698, 698, 209, 323,
+   699, 209, 209, 209, 209, 209, 209, 209, 209, 209, 700, 140, 140, 140, 701, 209,
+   702, 209, 209, 697, 703, 704, 323, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 705,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 706, 426, 426,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 176, 697, 427,
+   697, 209, 209, 209, 707, 176, 209, 209, 707, 209, 700, 697, 704, 708, 140, 140,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+   209, 209, 209, 209, 209, 707, 700, 426, 709, 209, 209, 209, 710, 711, 712, 703,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 713, 209, 209, 209, 209, 209, 714,
     48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 140, 140,
-    48,  48,  48, 207,  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, 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, 481,  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, 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,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 100,  48,
     48,  48,  48,  48,  48, 204, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
     48, 204, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
     48,  48,  48,  48,  71,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 140, 140, 140, 140, 140,
-   704, 140, 584, 584, 584, 584, 584, 584, 140, 140, 140, 140, 140, 140, 140, 140,
-    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32, 140,
-   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 705,
-   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 706,
-     0,   1,   2,   3,   4,   4,   4,   4,   4,   4,   5,   6,   7,   8,   9,  10,
-    11,  11,  12,  11,  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,  53,  54,  55,  56,
-    57,  57,  58,  59,  60,  60,  60,  60,  61,  62,  63,  64,  65,  66,  67,  68,
-    69,  69,  69,  69,  69,  69,  69,  69,  69,  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,   7,   4,   4,   4,   4,  99, 100, 101, 102,
-   103, 104, 105, 106, 107, 108, 109,   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,
-   112, 112, 112, 112,   0,   0,   0,   0,   0,   0,   0,   0,   0, 113, 114,   0,
-   115, 116, 117, 118, 119, 120, 121, 122,   0, 123, 124, 125, 126, 126, 126, 127,
-   128, 129, 130, 131, 132,  60, 133, 134, 135, 136,   0, 137, 138, 139,   0,   0,
-   126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
-   126, 126, 126, 126, 126, 126, 126,   0, 126, 126, 126, 126, 126, 126, 126, 126,
+    48,  48,  48,  48,  48,  48,  48, 207, 140, 140, 140, 140, 140, 140, 140, 140,
    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 141, 142, 143, 143, 143, 143, 144,  11, 145, 146, 147,   4, 148, 149,
-   150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165,
-    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,  60, 166, 167,
-   168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168,
-   168, 168, 168, 168, 126, 126, 126, 126, 126, 169, 126, 170, 171, 172,  19, 173,
-    19,  19,  19,  19, 174,  19, 175, 176, 177, 178,  19, 179, 180, 181, 182, 183,
-   184, 185, 186, 187, 188, 189, 190, 191, 168, 168, 192, 193, 194, 195, 196, 197,
-   198, 199, 200, 201, 202, 203, 204, 205, 206, 206, 206, 206, 207, 208, 209, 168,
-   210, 211, 212, 213, 214, 168, 215, 216, 217, 218, 219, 220, 221, 222, 223, 168,
-   224, 225, 226, 227, 228, 229, 230, 168, 168, 231, 232, 233, 234, 235, 236, 237,
-   238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253,
-   254, 255, 256, 257, 168, 168, 258, 259, 260, 261, 262, 263, 264, 265, 168, 168,
-   266, 168, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 168, 168, 278,
-   279, 280, 281, 168, 282, 283, 284, 168, 168, 168, 168, 285, 286, 287, 288, 289,
-   290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 291, 168,
-   290, 292, 290, 290, 290, 293, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168,
-   168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 294, 295,
-   296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-   296, 297, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-   296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 298,
-   299, 299, 299, 299, 299, 299, 299, 299, 299, 300, 168, 168, 168, 168, 168, 168,
-   168, 168, 168, 168, 301, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168,
-   302, 302, 302, 302, 302, 302, 302, 302, 303, 304, 305, 306, 307, 308, 309, 168,
-   168, 168, 168, 168, 168, 310, 168, 168, 168, 311, 312, 168, 313, 314, 315, 316,
-   317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317,
-   317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 318,
-   317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 319, 319, 319, 319,
-   319, 319, 319, 320, 321, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168,
-   168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 322,
-   323, 324, 324, 324, 325, 326, 327, 327, 327, 327, 327, 328, 168, 168, 168, 168,
-   329, 330, 331, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168,
-     0,   0,   0, 332,   0,   0,   0,   0,   0,   0, 333, 168, 334, 335,   0, 336,
-     0,   0,   0, 337, 338, 339, 340, 341, 189, 342, 168, 343,   0, 344, 168, 168,
-     0, 345, 346, 347, 348, 349,   0,   0,   0,   0, 350,   0,   0,   0,   0, 351,
-   352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 353, 168, 168, 168, 168, 168,
-   168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 354, 168, 168, 168,
-   355, 356, 357, 168, 358, 359, 168, 168, 168, 168, 360, 361, 168, 168, 168, 168,
-   168, 168, 168, 362, 168, 168, 168, 363, 168, 168, 168, 168, 168, 168, 168, 364,
-   365, 365, 365, 366, 367, 368, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168,
-   168, 369, 370, 168, 371, 168, 168, 168, 372, 373, 374, 375, 168, 168, 168, 168,
-   376,   0, 377, 378,   0,   0, 379, 380, 381, 382, 168, 168,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 383,   0, 384,   0, 385,
-   386, 387, 388, 389,   0,   0,   0,   0,   0, 390, 391, 392,   0,   0, 393, 332,
-   126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 394, 126, 126, 126, 126,
-   126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 395, 126, 126, 126,
-   396, 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, 397, 126, 126, 126, 126, 126,
-   126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 398,
-   126, 126, 126, 126, 126, 126, 126, 126, 126, 399, 168, 168, 168, 168, 168, 168,
-   126, 126, 126, 126, 126, 126, 126, 126, 399, 168, 168, 168, 168, 168, 168, 168,
-   126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 400, 126, 126,
-   126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 401, 168,
-   402,   0, 168, 168,   7,   7,   7, 403,   0,   1,   2,   3,   4,   4,   4,   4,
+   715, 140, 587, 587, 587, 587, 587, 587, 140, 140, 140, 140, 140, 140, 140, 140,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32, 140,
+   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, 716,
+   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, 717,
      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,   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,
-    19,  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,  31,  31,  31,  50,  51,  31,  31,  31,  31,  31,
-    31,  31,  31,  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, 128, 129, 122, 130,  26, 131, 132, 133, 131, 131, 131, 131, 131,
-   132, 133, 134, 131, 135, 131, 131, 131, 136, 137, 138, 139, 137, 137, 140, 141,
-   138, 142, 143, 137, 144, 137, 145,  26, 146, 147, 147, 147, 147, 147, 147, 148,
-   147, 147, 147, 149,  26,  26,  26,  26, 150, 151, 152, 152, 153, 152, 152, 154,
-   155, 156, 152, 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,
+     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,  31,  31,
+    31,  31,  50,  31,  31,  31,  31,  31,  31,  31,  31,  31,  51,  31,  31,  31,
+    52,  52,  52,  52,  52,  52,  52,  52,  52,  52,  53,  52,  54,  52,  52,  52,
+    55,  56,  57,  58,  58,  59,  60,  61,  56,  62,  63,  64,  65,  58,  58,  66,
+    67,  68,  69,  70,  70,  71,  72,  73,  68,  74,  75,  76,  77,  70,  78,  26,
+    79,  80,  81,  82,  82,  83,  84,  85,  80,  86,  87,  26,  88,  82,  89,  90,
+    91,  92,  93,  94,  94,  95,  96,  97,  92,  98,  99, 100, 101,  94,  94,  26,
+   102, 103, 104, 105, 106, 103, 107, 108, 103, 104, 109,  26, 110, 107, 107, 111,
+   112, 113, 114, 112, 112, 114, 112, 115, 113, 116, 117, 118, 119, 112, 120, 112,
+   121, 122, 123, 121, 121, 123, 124, 125, 122, 126, 127, 128, 129, 121, 130,  26,
+   131, 132, 133, 131, 131, 131, 131, 131, 132, 133, 134, 131, 135, 131, 131, 131,
+   136, 137, 138, 139, 137, 137, 140, 141, 138, 142, 143, 137, 144, 137, 145,  26,
+   146, 147, 147, 147, 147, 147, 147, 148, 147, 147, 147, 149,  26,  26,  26,  26,
+   150, 151, 152, 152, 153, 152, 152, 154, 155, 156, 152, 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, 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,
+   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, 184, 185, 186, 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,
@@ -2466,165 +2264,215 @@ _hb_ucd_u16[10400] =
    203, 203, 203, 204, 203, 205, 203, 205, 206, 203, 207, 207, 207, 208, 209,  26,
    210, 210, 210, 210, 210, 211, 210, 210, 210, 212, 210, 213, 194, 194, 194, 194,
    214, 214, 214, 215, 216, 216, 216, 216, 216, 216, 216, 217, 216, 216, 216, 218,
-   216, 219, 216, 219, 216, 220,   9,   9,   9, 221,  26,  26,  26,  26,  26,  26,
-   222, 222, 222, 222, 222, 222, 222, 222, 222, 223, 222, 222, 222, 222, 222, 222,
-   224, 224, 224, 224, 224, 224, 224, 224, 225, 225, 225, 225, 225, 225, 226, 227,
-   228, 228, 228, 228, 228, 228, 228, 229, 228, 230, 231, 231, 231, 231, 231, 231,
-    18, 232, 165, 165, 165, 165, 165, 233, 224,  26, 234,   9, 235, 236, 237, 238,
-     2,   2,   2,   2, 239, 240,   2,   2,   2,   2,   2, 241, 242, 243,   2, 244,
-     2,   2,   2,   2,   2,   2,   2, 245,  14,  14, 246, 246,  14,  14,  14,  14,
-   246, 246,  14, 247,  14,  14,  14, 246,  14,  14,  14,  14,  14,  14, 248,  14,
-   248,  14, 249, 250,  14,  14, 251, 252,   0, 253,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0, 254,   0, 255, 256,   0, 257,   2, 258,   0,   0,   0,   0,
-   259,  26,   9,   9,   9,   9, 260,  26,   0,   0,   0,   0, 261, 262,   4,   0,
-     0, 263,   0,   0,   2,   2,   2,   2,   2, 264,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0, 265,  26,  26,   0, 266,  26,  26,   0,   0,   0,   0,
-   267, 267, 267, 267, 267, 267, 267, 267,   0,   0,   0,   0,   0,   0, 268,   0,
-     0,   0, 269,   0,   0,   0,   0,   0, 270, 270, 270, 270, 270, 270, 270, 270,
-   270, 270, 270, 270,   2,   2,   2,   2,  17,  17,  17,  17,  17,  17,  17,  17,
-    17,  17,  17,  17,  17,  17, 271, 272, 165, 165, 165, 165, 166, 167, 273, 273,
-   273, 273, 273, 273, 273, 274, 275, 274, 170, 170, 172,  26, 172, 172, 172, 172,
-   172, 172, 172, 172,  18,  18,  18,  18,   0,   0,   0, 276,  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, 280,  26,  26,  26,   0,   0,
-   281,   0,   0,   0, 282, 283,   0, 284, 285, 286, 286, 286, 286, 286, 286, 286,
-   286, 286, 287, 288, 289, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 291,
-   292, 293, 293, 293, 293, 293, 294, 169, 169, 295,   0,   0, 293, 293, 293, 293,
-     0,   0,   0,   0, 276, 296, 290, 290, 169, 169, 169, 295,   0,   0,   0,   0,
-     0,   0,   0,   0, 169, 169, 169, 297,   0,   0, 290, 290, 290, 290, 290, 298,
-   290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,   0,   0,   0,   0,   0,
-   299, 299, 299, 299, 299, 299, 299, 299, 299, 300, 299, 299, 299, 299, 299, 299,
-   301,  26, 302, 302, 302, 302, 302, 302, 303, 303, 303, 303, 303, 303, 303, 303,
-   303, 303, 303, 303, 303, 304,  26,  26,  18,  18,  18,  18, 305, 305, 305, 305,
-   305, 305, 305, 305, 305, 305, 305,  26,   0,   0,   0,   0, 306,   2,   2,   2,
-     2, 307,   2,   2,   2,   2,   2,   2,   2, 308, 309, 258,  26,  26, 310,   2,
-   311, 311, 311, 311, 311, 312,   0, 265, 313, 313, 313, 313, 313, 313, 313,  26,
-   314, 314, 314, 314, 314, 314, 314, 314, 315, 316, 314, 317,  53,  53,  53,  53,
-   318, 318, 318, 318, 318, 319, 320, 320, 320, 320, 321, 322, 169, 169, 169, 323,
-   324, 324, 324, 324, 324, 324, 324, 324, 324, 325, 324, 326, 164, 164, 164, 327,
-   328, 328, 328, 328, 328, 328, 329,  26, 328, 330, 328, 331, 164, 164, 164, 164,
-   332, 332, 332, 332, 332, 332, 332, 332, 333,  26,  26, 334, 335, 335, 336,  26,
-   337, 337, 337,  26, 172, 172,   2,   2,   2,   2,   2, 338, 339, 340, 176, 176,
-   176, 176, 176, 176, 176, 176, 176, 176, 335, 335, 335, 335, 335, 341, 335, 342,
-   169, 169, 169, 169, 343,  26, 169, 169, 295, 344, 169, 169, 169, 169, 169, 343,
-    26,  26,  26,  26,  26,  26,  26,  26, 277, 277, 277, 277, 277, 280, 277, 277,
-   277, 277, 277, 345,  26,  26,  26,  26, 346,  26, 347, 348,  25,  25, 349, 350,
-   351,  25,  31,  31,  31,  31,  31,  31, 352,  26, 353,  31,  31,  31,  31,  31,
-    31,  31,  31,  31,  31,  31,  31, 354,  31,  31, 355,  31,  31,  31,  31,  31,
-    31, 356,  26,  26,  26,  26,  31,  31,   9,   9,   0, 265,   9, 357,   0,   0,
-     0,   0, 358,   0, 257, 359, 360,  31,  31,  31,  31,  31,  31,  31,  31, 361,
-   362,   0,   0,   0,   1,   2,   2,   3,   1,   2,   2,   3, 363, 290, 289, 290,
-   290, 290, 290, 364, 169, 169, 169, 295, 365, 365, 365, 366, 257, 257,  26, 367,
-   368, 369, 368, 368, 370, 368, 368, 371, 368, 372, 368, 372,  26,  26,  26,  26,
-   368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 373,
-   374,   0,   0,   0,   0,   0, 375,   0,  14,  14,  14,  14,  14,  14,  14,  14,
-    14, 252,   0, 376, 377,  26,  26,  26,  26,  26,   0,   0,   0,   0,   0, 378,
-   379, 379, 379, 380, 381, 381, 381, 381, 381, 381, 382,  26, 383,   0,   0, 359,
-   384, 384, 384, 384, 385, 386, 387, 387, 387, 388, 389, 389, 389, 389, 389, 390,
-   391, 391, 391, 392, 393, 393, 393, 393, 394, 393, 395,  26,  26,  26,  26,  26,
-   396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 397, 397, 397, 397, 397, 397,
-   398, 398, 398, 399, 398, 400, 401, 401, 401, 401, 402, 401, 401, 401, 401, 402,
-   403, 403, 403, 403, 403,  26, 404, 404, 404, 404, 404, 404, 405, 406, 407, 408,
-   407, 408, 409, 407, 410, 407, 410, 411, 412, 412, 412, 412, 412, 412, 413,  26,
-   414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 415,  26,
-   414, 414, 416,  26, 414,  26,  26,  26, 417,   2,   2,   2,   2,   2, 418, 419,
-   420, 421, 422, 422, 422, 422, 423, 424, 425, 425, 426, 425, 427, 427, 427, 427,
-   428, 428, 428, 429, 430, 428,  26,  26,  26,  26,  26,  26, 431, 431, 432, 433,
-   434, 434, 434, 435, 436, 436, 436, 437, 438, 438, 438, 438, 439, 439, 439, 440,
-   439, 439, 441, 439, 439, 439, 439, 439, 442, 443, 444, 445, 446, 446, 447, 448,
-   446, 449, 446, 449, 450, 450, 450, 450, 451, 451, 451, 451,  26,  26,  26,  26,
-   452, 452, 452, 452, 453, 454, 453,  26, 455, 455, 455, 455, 455, 455, 456, 457,
-   458, 458, 459, 458, 460, 460, 461, 460, 462, 462, 463, 464,  26, 465,  26,  26,
-   466, 466, 466, 466, 466, 466, 466, 466, 466, 467,  26,  26,  26,  26,  26,  26,
-   468, 468, 468, 468, 468, 468, 469,  26, 468, 468, 468, 468, 468, 468, 469, 470,
-   471, 471, 471, 471, 471,  26, 471, 472, 473, 473, 473, 473, 474, 475, 473, 473,
-   474, 476,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  31,  31,  31,  50,
-   477, 477, 477, 477, 477, 478, 479,  26, 480,  26,  26,  26,  26,  26,  26, 481,
-   482, 482, 482, 482, 482,  26, 483, 483, 483, 483, 483, 484,  26,  26, 485, 485,
-   485, 486,  26,  26,  26,  26, 487, 487, 487, 488,  26,  26, 489, 489, 490,  26,
-   491, 491, 491, 491, 491, 491, 491, 491, 491, 492, 493, 491, 491, 491, 492, 494,
-   495, 495, 495, 495, 495, 495, 495, 495, 496, 497, 498, 498, 498, 499, 498, 500,
-   501, 501, 501, 501, 501, 501, 502, 501, 501,  26, 503, 503, 503, 503, 504,  26,
-   505, 505, 505, 505, 505, 505, 505, 505, 505, 505, 505, 505, 506, 137, 507,  26,
-   508, 508, 509, 508, 508, 508, 508, 508, 510,  26,  26,  26,  26,  26,  26,  26,
-   511, 512, 513, 514, 513, 515, 516, 516, 516, 516, 516, 516, 516, 517, 516, 518,
-   519, 520, 521, 522, 522, 523, 524, 525, 520, 526, 527, 528, 529, 530, 530,  26,
-   531, 532, 531, 531, 531, 531, 533, 531, 534, 535, 533, 536, 537,  26,  26,  26,
-   538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 539, 540,  26,  26,  26,
-   541, 541, 541, 541, 541, 541, 541, 541, 541,  26, 541, 542,  26,  26,  26,  26,
-   543, 543, 543, 543, 543, 543, 544, 543, 543, 543, 543, 544,  26,  26,  26,  26,
-   545, 545, 545, 545, 545, 545, 545, 545, 546,  26, 545, 547, 198, 548,  26,  26,
-   549, 549, 549, 549, 549, 549, 549, 550, 549, 550, 164, 164, 551,  26,  26,  26,
-   552, 552, 552, 553, 552, 554, 552, 552, 555,  26,  26,  26,  26,  26,  26,  26,
-   556, 556, 556, 556, 556, 556, 556, 557,  26,  26,  26,  26, 558, 558, 558, 558,
-   558, 558, 558, 558, 558, 558, 559, 560, 561, 562, 563, 564, 564, 564, 565, 566,
-   561,  26, 564, 567,  26,  26,  26,  26,  26,  26,  26,  26, 568, 569, 568, 568,
-   568, 568, 568, 569, 570,  26,  26,  26, 571, 571, 571, 571, 571, 571, 571, 571,
-   571,  26, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 573,  26, 178, 178,
-   574, 574, 574, 574, 574, 574, 574, 575,  53, 576,  26,  26,  26,  26,  26,  26,
-   577, 577, 577, 577, 578,  26, 577, 578, 579, 580, 579, 579, 579, 579, 581, 579,
-   582,  26, 579, 579, 579, 583, 584, 584, 584, 584, 585, 584, 584, 586, 587,  26,
-   588, 589, 590, 590, 590, 590, 588, 591, 590,  26, 590, 592, 593, 594, 595, 595,
-   595, 596, 597, 598, 595, 599,  26,  26,  26,  26,  26,  26, 600, 600, 600, 601,
-   602, 602, 603, 602, 602, 602, 602, 604, 602, 602, 602, 605,  26,  26,  26,  26,
-    26,  26,  26,  26,  26,  26, 606,  26, 108, 108, 108, 108, 108, 108, 607, 608,
-   609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 610,  26,  26,  26,  26,
-   609, 609, 609, 609, 609, 611, 612,  26, 613,  26,  26,  26,  26,  26,  26,  26,
-    26,  26, 614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 615,  26,
-   616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 617,  26, 616, 616, 616, 616,
-   616, 616, 616, 616, 616, 616, 616, 618, 619, 619, 619, 619, 619, 619, 619, 619,
-   620,  26,  26,  26,  26,  26,  26,  26, 621, 621, 621, 621, 621, 621, 621, 622,
-   305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 623,
-   624, 624, 624, 625, 624, 626, 627, 627, 627, 627, 627, 627, 627, 627, 627, 628,
-   627, 629, 630, 630, 630, 631, 631,  26, 632, 632, 632, 632, 632, 632, 632, 632,
-   633,  26, 632, 634, 634, 632, 632, 635, 632, 632,  26,  26,  26,  26,  26,  26,
-   636, 636, 636, 636, 636, 636, 636, 637, 638, 638, 638, 638, 638, 638, 638, 638,
-   638, 638, 638, 639,  26,  26,  26,  26, 640, 640, 640, 640, 640, 640, 640, 640,
-   640, 641, 640, 640, 640, 640, 640, 640, 640, 642, 640, 640,  26,  26,  26,  26,
-    26,  26,  26,  26, 643,  26, 345,  26, 644, 644, 644, 644, 644, 644, 644, 644,
-   644, 644, 644, 644, 644, 644, 644,  26, 645, 645, 645, 645, 645, 645, 645, 645,
-   645, 645, 646,  26,  26,  26,  26, 647, 644, 648,  26,  26,  26,  26,  26,  26,
-    26,  26,  26,  26,  26,  26, 649, 650, 651, 286, 286, 286, 286, 286, 286, 286,
-   286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 652,  26, 653,  26,
-    26,  26, 654,  26, 655,  26, 656, 656, 656, 656, 656, 656, 656, 656, 656, 656,
-   656, 656, 656, 656, 656, 656, 656, 657, 658, 658, 658, 658, 658, 658, 658, 658,
-   658, 658, 658, 658, 658, 659, 658, 660, 658, 661, 658, 662, 359,  26,  26,  26,
-     0,   0,   0,   0,   0,   0,   0, 265,   0,   0,   0,   0,   0,   0, 359,  26,
-     9,   9,   9,   9,   9, 663,   9,   9, 221,  26,   0,   0,   0,   0,   0,   0,
-   359,  26,  26,  26,  26,  26,  26,  26,   0,   0,   0,   0,   0,   0, 276,  26,
-     0,   0,   0,   0, 257, 362,   0,   0,   0,   0,   0,   0, 664, 665,   0, 666,
-   667, 668,   0,   0,   0, 669,   0,   0,   0,   0,   0,   0,   0, 266,  26,  26,
-   246,  26,  26,  26,  26,  26,  26,  26,   0,   0, 359,  26,   0,   0, 359,  26,
-     0,   0, 257,  26,   0,   0,   0, 259,   0,   0, 254,   0,   0,   0,   0,   0,
-     0,   0,   0, 254, 670, 671,   0, 672, 673,   0,   0,   0,   0,   0,   0,   0,
-   269, 674, 254, 254,   0,   0,   0, 675, 676, 677, 678,   0,   0,   0,   0,   0,
-     0,   0,   0,   0, 276,   0,   0,   0,   0, 268,   0,   0,   0,   0,   0,   0,
-   679, 679, 679, 679, 679, 679, 679, 679, 679, 680,  26, 681, 682, 679,  26,  26,
-     2,   2,   2, 346, 683, 419,  26,  26, 684, 270, 270, 685, 686, 687,  18,  18,
-    18,  18,  18,  18,  18, 688,  26,  26,  26, 689,  26,  26,  26,  26,  26,  26,
-   690, 690, 690, 690, 690, 691, 690, 692, 690, 693,  26,  26,  26,  26,  26,  26,
-    26,  26, 694, 694, 694, 695,  26,  26, 696, 696, 696, 696, 696, 696, 696, 697,
-    26,  26, 698, 698, 698, 698, 698, 699,  26,  26, 700, 700, 700, 700, 700, 701,
-    26,  26,  26,  26, 172, 702, 170, 172, 703, 703, 703, 703, 703, 703, 703, 703,
-   704, 703, 705,  26,  26,  26,  26,  26, 706, 706, 706, 706, 706, 706, 706, 706,
-   706, 707, 706, 708,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 362,   0,
-     0,   0,   0,   0,   0,   0, 376,  26, 362,   0,   0,   0,   0,   0,   0, 276,
-   709,  31,  31,  31, 710, 711, 712, 713, 714, 715, 710, 716, 710, 712, 712, 717,
-    31, 718,  31, 719, 720, 718,  31, 719,  26,  26,  26,  26,  26,  26, 721,  26,
-     0,   0,   0,   0,   0, 359,   0,   0,   0,   0, 359,  26,   0, 257, 362,   0,
-   362,   0, 362,   0,   0,   0, 276,  26,   0,   0,   0,   0,   0, 276,  26,  26,
-    26,  26,  26,  26, 722,   0,   0,   0, 723,  26,   0,   0,   0,   0,   0, 359,
-     0, 259, 265,  26, 276,  26,  26,  26,   0,   0,   0, 724,   0, 376,   0, 376,
-     0,   0,   0,   0,   0,   0, 257, 725,   0,   0,   0, 265,   0, 359, 259,  26,
-     0, 359,   0,   0,   0,   0,   0,   0,   0,  26,   0, 265,   0,   0,   0,   0,
-     0,  26,   0,   0,   0, 276,   0, 359, 265,  26,  26,  26,  26,  26,  26,  26,
-     0,   0, 359,  26,   0, 276,   0, 376,   0, 726,   0,   0,   0,   0,   0,   0,
-   257, 722,   0, 727,   0, 265,   0, 259,   0,   0, 358,   0,   0,   0,   0,   0,
-   277, 277, 277, 277,  26,  26,  26,  26, 277, 277, 277, 277, 277, 277, 277, 345,
-   277, 277, 277, 280, 277, 277, 277, 277, 277, 277, 277, 277, 345,  26, 277, 277,
-   277, 277, 277, 277, 728,  26, 277, 277, 277, 277, 277, 280,  26,  26,  26,  26,
-   277, 729, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,  26,  26,
-   730,  26,  26,  26,   0,   0,   0,   0,   9,   9,   9,   9,   9,   9,   0,   0,
+   216, 219, 216, 219, 216, 220,   9,   9,   9,   9,   9, 221,   9, 222,  26,  26,
+   223, 223, 223, 223, 223, 223, 223, 223, 223, 224, 223, 223, 223, 223, 223, 223,
+   225, 225, 225, 225, 225, 225, 225, 225, 226, 226, 226, 226, 226, 226, 227, 228,
+   229, 229, 229, 229, 229, 229, 229, 230, 229, 231, 232, 232, 232, 232, 232, 232,
+    18, 233, 165, 165, 165, 165, 165, 234, 225,  26, 235,   9, 236, 237, 238, 239,
+     2,   2,   2,   2, 240, 241,   2,   2,   2,   2,   2, 242, 243, 244,   2, 245,
+     2,   2,   2,   2,   2,   2,   2, 246,   9,   9,   9,   9,   9,   9,   9,   9,
+    14,  14, 247, 247,  14,  14,  14,  14, 247, 247,  14, 248,  14,  14,  14, 247,
+    14,  14,  14,  14,  14,  14, 249,  14, 249,  14, 250, 251,  14,  14, 252, 253,
+     0, 254,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 255,   0, 256, 257,
+     0, 258,   2, 259,   0,   0,   0,   0, 260,  26,   9,   9,   9,   9, 261,  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,   0, 260,  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,
+   269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269,   2,   2,   2,   2,
+    17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17, 270, 271,
+   165, 165, 165, 165, 166, 167, 272, 272, 272, 272, 272, 272, 272, 273, 274, 273,
+   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,   0, 275,  26,  26,  26,  26,
+   276, 276, 276, 277, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 278,  26,
+   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
+   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279,  26,  26,  26,   0,   0,
+   280,   0,   0,   0, 281, 282,   0, 283, 284, 285, 285, 285, 285, 285, 285, 285,
+   285, 285, 286, 287, 288, 289, 289, 289, 289, 289, 289, 289, 289, 289, 289, 290,
+   291, 292, 292, 292, 292, 292, 293, 169, 169, 169, 169, 169, 169, 169, 169, 169,
+   169, 294,   0,   0, 292, 292, 292, 292,   0,   0,   0,   0, 275, 295, 289, 289,
+   169, 169, 169, 294,   0,   0,   0,   0,   0,   0,   0,   0, 169, 169, 169, 296,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 289, 289, 289, 289, 289, 297,
+   289, 289, 289, 289, 289, 289, 289, 289, 289, 289, 289,   0,   0,   0,   0,   0,
+   276, 276, 276, 276, 276, 276, 276, 276,   0,   0,   0,   0,   0,   0,   0,   0,
+   298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298,
+   298, 299, 298, 298, 298, 298, 298, 298, 300,  26, 301, 301, 301, 301, 301, 301,
+   302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302,
+   302, 302, 302, 302, 302, 303,  26,  26,  18,  18,  18,  18,  18,  18,  18,  18,
+    18,  18,  18,  18, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304,  26,
+     0,   0,   0,   0, 305,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+     2, 306,   2,   2,   2,   2,   2,   2,   2,   2,   2, 259,  26,  26, 307,   2,
+   308, 308, 308, 308, 308, 309,   0, 260, 310, 310, 310, 310, 310, 310, 310,  26,
+   311, 311, 311, 311, 311, 311, 311, 311, 312, 313, 311, 314,  52,  52,  52,  52,
+   315, 315, 315, 315, 315, 316, 317, 317, 317, 317, 318, 319, 169, 169, 169, 320,
+   321, 321, 321, 321, 321, 321, 321, 321, 321, 322, 321, 323, 164, 164, 164, 324,
+   325, 325, 325, 325, 325, 325, 326,  26, 325, 327, 325, 328, 164, 164, 164, 164,
+   329, 329, 329, 329, 329, 329, 329, 329, 330,  26,  26, 331, 332, 332, 333,  26,
+   334, 334, 334,  26, 172, 172,   2,   2,   2,   2,   2, 335, 336, 337, 176, 176,
+   176, 176, 176, 176, 176, 176, 176, 176, 332, 332, 332, 332, 332, 338, 332, 339,
+   169, 169, 169, 169, 340,  26, 169, 169, 294, 341, 169, 169, 169, 169, 169, 340,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 276, 276,
+   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 342,  26,  26,  26,  26,
+   343,  26, 344, 345,  25,  25, 346, 347, 348,  25,  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, 349,  31,  31,  31,  31,  31,  31,  31,  31,
+    31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  26,  26,  26,  26,  31,  31,
+     9,   9,   0, 260,   9, 350,   0,   0,   0,   0, 351,   0, 258, 352, 353,  31,
+    31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31, 354,
+   355,   0,   0,   0,   1,   2,   2,   3,   1,   2,   2,   3, 356, 289, 288, 289,
+   289, 289, 289, 357, 169, 169, 169, 294, 358, 358, 358, 359, 258, 258,  26, 360,
+   361, 362, 361, 361, 363, 361, 361, 364, 361, 365, 361, 365,  26,  26,  26,  26,
+   361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 366,
+   367,   0,   0,   0,   0,   0, 368,   0,  14,  14,  14,  14,  14,  14,  14,  14,
+    14, 253,   0, 369, 370,  26,  26,  26,  26,  26,   0,   0,   0,   0,   0, 371,
+   372, 372, 372, 373, 374, 374, 374, 374, 374, 374, 375,  26, 376,   0,   0, 352,
+   377, 377, 377, 377, 378, 379, 380, 380, 380, 381, 382, 382, 382, 382, 382, 383,
+   384, 384, 384, 385, 386, 386, 386, 386, 387, 386, 388,  26,  26,  26,  26,  26,
+   389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 390, 390, 390, 390, 390, 390,
+   391, 391, 391, 392, 391, 393, 394, 394, 394, 394, 395, 394, 394, 394, 394, 395,
+   396, 396, 396, 396, 396,  26, 397, 397, 397, 397, 397, 397, 398, 399, 400, 401,
+   400, 401, 402, 400, 403, 400, 403, 404, 405, 405, 405, 405, 405, 405, 406,  26,
+   407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407,
+   407, 407, 407, 407, 407, 407, 408,  26, 407, 407, 409,  26, 407,  26,  26,  26,
+   410,   2,   2,   2,   2,   2, 411, 412,  26,  26,  26,  26,  26,  26,  26,  26,
+   413, 414, 415, 415, 415, 415, 416, 417, 418, 418, 419, 418, 420, 420, 420, 420,
+   421, 421, 421, 422, 423, 421,  26,  26,  26,  26,  26,  26, 424, 424, 425, 426,
+   427, 427, 427, 428, 429, 429, 429, 430, 431, 431, 431, 432,  26,  26,  26,  26,
+   433, 433, 433, 433, 434, 434, 434, 435, 434, 434, 436, 434, 434, 434, 434, 434,
+   437, 438, 439, 440, 441, 441, 442, 443, 441, 444, 441, 444, 445, 445, 445, 445,
+   446, 446, 446, 446,  26,  26,  26,  26, 447, 447, 447, 447, 448, 449, 448,  26,
+   450, 450, 450, 450, 450, 450, 451, 452, 453, 453, 454, 453, 455, 455, 456, 455,
+   457, 457, 458, 459,  26, 460,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   461, 461, 461, 461, 461, 461, 461, 461, 461, 462,  26,  26,  26,  26,  26,  26,
+   463, 463, 463, 463, 463, 463, 464,  26, 463, 463, 463, 463, 463, 463, 464, 465,
+   466, 466, 466, 466, 466,  26, 466, 467, 468, 468, 468, 468, 469, 470, 468, 468,
+   469, 471,  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,  31,  31,  31, 472,
+   473, 473, 473, 473, 473, 474, 475,  26, 476,  26,  31, 477,  26,  26,  26, 476,
+   478, 478, 478, 478, 478,  26, 479, 479, 479, 479, 479, 480,  26,  26, 481, 481,
+   481, 482,  26,  26,  26,  26, 483, 483, 483, 484,  26,  26, 485, 485, 486,  26,
+   487, 487, 487, 487, 487, 487, 487, 487, 487, 488, 489, 487, 487, 487, 488, 490,
+   491, 491, 491, 491, 491, 491, 491, 491, 492, 493, 494, 494, 494, 495, 494, 496,
+   497, 497, 497, 497, 497, 497, 498, 497, 497,  26, 499, 499, 499, 499, 500,  26,
+   501, 501, 501, 501, 501, 501, 501, 501, 501, 501, 501, 501, 502, 137, 503,  26,
+   504, 504, 505, 504, 504, 504, 504, 504, 506,  26,  26,  26,  26,  26,  26,  26,
+   507, 508, 509, 510, 509, 511, 512, 512, 512, 512, 512, 512, 512, 513, 512, 514,
+   515, 516, 517, 518, 518, 519, 520, 521, 516, 522, 523, 524, 525, 526, 526,  26,
+   527, 528, 527, 527, 527, 527, 529, 527, 530, 531, 529, 532, 533,  26,  26,  26,
+   534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 535, 536,  26,  26,  26,
+   537, 537, 537, 537, 537, 537, 537, 537, 537,  26, 537, 538,  26,  26,  26,  26,
+   539, 539, 539, 539, 539, 539, 540, 539, 539, 539, 539, 540,  26,  26,  26,  26,
+   541, 541, 541, 541, 541, 541, 541, 541, 542,  26, 541, 543, 198, 544,  26,  26,
+   545, 545, 545, 545, 545, 545, 545, 546, 545, 546, 164, 164, 547,  26,  26,  26,
+   548, 548, 548, 549, 548, 550, 548, 548, 551,  26,  26,  26,  26,  26,  26,  26,
+   552, 552, 552, 552, 552, 552, 552, 553,  26,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 555, 556,
+   557, 558, 559, 560, 560, 560, 561, 562, 557,  26, 560, 563,  26,  26,  26,  26,
+    26,  26,  26,  26, 564, 565, 564, 564, 564, 564, 564, 565, 566,  26,  26,  26,
+   567, 567, 567, 567, 567, 567, 567, 567, 567,  26, 568, 568, 568, 568, 568, 568,
+   568, 568, 568, 568, 569,  26, 178, 178, 570, 570, 570, 570, 570, 570, 570, 571,
+    52, 572,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 501,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26, 573, 573, 573, 573, 574,  26, 573, 574,
+   575, 576, 575, 575, 575, 575, 577, 575, 578,  26, 575, 575, 575, 579, 580, 580,
+   580, 580, 581, 580, 580, 582, 583,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   584, 585, 586, 586, 586, 586, 584, 587, 586,  26, 586, 588, 589, 590, 591, 591,
+   591, 592, 593, 594, 591, 595, 596, 596, 596, 596, 596, 597, 596, 598,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 599, 599, 599, 600,
+   601, 601, 602, 601, 601, 601, 601, 603, 601, 601, 601, 604,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26, 605,  26, 107, 107, 107, 107, 107, 107, 606, 607,
+   608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608,
+   608, 608, 608, 609,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 610, 611,  26,
+   608, 608, 608, 608, 608, 608, 608, 608, 612,  26,  26,  26,  26,  26,  26,  26,
+    26,  26, 613, 613, 613, 613, 613, 613, 613, 613, 613, 613, 613, 613, 614,  26,
+   615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615,
+   615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 616,  26, 615, 615, 615, 615,
+   615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 617,
+   618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618,
+   618, 618, 618, 618, 618, 618, 618, 618, 619,  26,  26,  26,  26,  26,  26,  26,
+   620, 620, 620, 620, 620, 620, 620, 621,  26,  26,  26,  26,  26,  26,  26,  26,
+   304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304,
+   304, 304, 304, 304, 304, 304, 304, 622, 623, 623, 623, 624, 623, 625, 626, 626,
+   626, 626, 626, 626, 626, 626, 626, 627, 626, 628, 629, 629, 629, 630, 630,  26,
+   631, 631, 631, 631, 631, 631, 631, 631, 632,  26, 631, 633, 633, 631, 631, 634,
+   631, 631,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26, 635, 635, 635, 635, 635, 635, 635, 636,
+    26,  26,  26,  26,  26,  26,  26,  26, 637, 637, 637, 637, 637, 637, 637, 637,
+   637, 637, 637, 638, 639, 639, 639, 640, 639, 639, 641,  26,  26,  26,  26,  26,
+   642, 642, 642, 642, 642, 642, 642, 642, 642, 643, 642, 642, 642, 642, 642, 642,
+   642, 644, 642, 642,  26,  26,  26,  26,  26,  26,  26,  26, 645,  26, 646,  26,
+   647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647,
+   648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648,
+   648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 649,  26,  26,  26,  26, 650,
+   647, 647, 647, 651,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 652,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 653, 654,
+   655, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285,
+   285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285,
+   285, 285, 285, 285, 656,  26, 657,  26,  26,  26, 658,  26, 659,  26, 660, 660,
+   660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660,
+   660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 661,
+   662, 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, 663, 662, 664,
+   662, 665, 662, 666, 352,  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,   0, 369,
+     0,   0,   0,   0,   0,   0, 352, 667,   0,   0, 668,  26,   0,   0, 668,  26,
+     9,   9,   9,   9,   9, 221,   9,   9, 669,  26,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0, 352,  26,  26,  26,  26,  26,  26,  26,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 275,  26,
+     0,   0,   0,   0, 258, 355,   0,   0,   0,   0,   0,   0, 670, 671,   0, 672,
+   673, 674,   0,   0,   0, 675,   0,   0,   0,   0,   0,   0,   0, 266,  26,  26,
+    14,  14,  14,  14,  14,  14,  14,  14, 247,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,   0,   0, 352,  26,   0,   0, 352,  26,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 258,  26,   0,   0,   0, 668,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 255,   0,   0,   0,   0,   0,
+     0,   0,   0, 255, 676, 677,   0, 678, 679,   0,   0,   0,   0,   0,   0,   0,
+   680, 681, 255, 255,   0,   0,   0, 682, 683, 667, 684,   0,   0,   0,   0,   0,
+     0,   0,   0,   0, 275,   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,
+   685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685,
+   685, 686,  26, 687, 688, 685,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+     2,   2,   2, 343, 689, 412,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   690, 269, 269, 691, 692, 693,  18,  18,  18,  18,  18,  18,  18, 694,  26,  26,
+    26, 695,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   696, 696, 696, 696, 696, 697, 696, 698, 696, 699,  26,  26,  26,  26,  26,  26,
+    26,  26, 700, 700, 700, 701,  26,  26, 702, 702, 702, 702, 702, 702, 702, 703,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 704, 704, 704, 704, 704, 705,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 706, 706, 706, 706, 706, 707,
+    26,  26,  26,  26,  26,  26,  26,  26, 708, 708, 708, 709, 708, 708, 710, 711,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 172, 712, 170, 172,
+   713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713,
+   713, 713, 713, 713, 713, 713, 713, 713, 714, 713, 715,  26,  26,  26,  26,  26,
+   716, 716, 716, 716, 716, 716, 716, 716, 716, 717, 716, 718,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 355,   0,
+     0,   0,   0,   0,   0,   0, 369,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   355,   0,   0,   0,   0,   0,   0, 275,  26,  26,  26,  26,  26,  26,  26,  26,
+   719,  31,  31,  31, 720, 721, 722, 723, 724, 725, 720, 726, 720, 722, 722, 727,
+    31, 728,  31, 729, 730, 728,  31, 729,  26,  26,  26,  26,  26,  26, 731,  26,
+     0,   0,   0,   0,   0, 352,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0, 352,  26,   0, 258, 355,   0, 355,   0, 355,   0,   0,   0, 275,  26,
+     0,   0,   0,   0,   0, 275,  26,  26,  26,  26,  26,  26, 732,   0,   0,   0,
+   733,  26,   0,   0,   0,   0,   0, 352,   0, 668, 260,  26, 275,  26,  26,  26,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 734,   0, 369,   0, 369,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 260,   0, 352, 668,  26,
+     0, 352,   0,   0,   0,   0,   0,   0,   0,  26,   0, 260,   0,   0,   0,   0,
+     0,  26,   0,   0,   0, 275,   0, 352, 260,  26,   0, 668,  26,  26,  26,  26,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  26,   0, 275,   0, 369,
+     0, 735,   0,   0,   0,   0,   0,   0, 258, 736,   0, 737,   0, 367,   0, 668,
+     0,   0, 351,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 266,
+   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,  26,  26,  26,  26,
+   276, 276, 276, 279, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
+   276, 276, 276, 276, 276, 279, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
+   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 738,  26, 276, 276,
+   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279,  26,  26,  26,  26,
+   276, 276, 276, 279,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   276, 276, 276, 276, 276, 276, 276, 276, 276, 739, 276, 276, 276, 276, 276, 276,
+   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 342,
+   740,  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,
@@ -2840,8 +2688,7 @@ _hb_ucd_u16[10400] =
    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] =
+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,
@@ -2858,47 +2705,42 @@ _hb_ucd_i16[196] =
      -1,    0,    1,   -1,
 };
 
-static inline uint_fast8_t
-_hb_ucd_gc (unsigned u)
+static inline uint8_t _hb_ucd_gc (unsigned u)
 {
-  return u<1114110u?_hb_ucd_u8[6472+(((_hb_ucd_u8[816+(((_hb_ucd_u16[((_hb_ucd_u8[272+(((_hb_ucd_u8[u>>1>>3>>4>>4])<<4)+((u>>1>>3>>4)&15u))])<<4)+((u>>1>>3)&15u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+  return u<1114110 ? _hb_ucd_u8[7920u+((_hb_ucd_u8[2176u+((_hb_ucd_u16[((_hb_ucd_u8[((((((u)>>1))>>3))>>5)])<<5)+((((((u)>>1))>>3))&31)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : 2;
 }
-static inline uint_fast8_t
-_hb_ucd_ccc (unsigned u)
+static inline uint8_t _hb_ucd_ccc (unsigned u)
 {
-  return u<125259u?_hb_ucd_u8[8504+(((_hb_ucd_u8[7936+(((_hb_ucd_u8[7460+(((_hb_ucd_u8[7100+(((_hb_ucd_u8[6854+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
+  return u<125259 ? _hb_ucd_u8[10388u+((_hb_ucd_u8[9284u+((_hb_ucd_u8[8548u+((_hb_ucd_u8[8302u+((((((u)>>2))>>3))>>4)])<<4)+((((((u)>>2))>>3))&15)])<<3)+((((u)>>2))&7)])<<2)+((u)&3)] : 0;
 }
-static inline unsigned
-_hb_ucd_b4 (const uint8_t* a, unsigned i)
+static inline uint8_t _hb_ucd_b4 (const uint8_t* a, unsigned i)
 {
-  return (a[i>>1]>>((i&1u)<<2))&15u;
+  return (a[i>>1]>>((i&1)<<2))&15;
 }
-static inline int_fast16_t
-_hb_ucd_bmg (unsigned u)
+static inline int16_t _hb_ucd_bmg (unsigned u)
 {
-  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9252+(((_hb_ucd_u8[9132+(((_hb_ucd_b4(9004+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
+  return u<65380 ? _hb_ucd_i16[((_hb_ucd_u8[11140u+((_hb_ucd_u8[11020u+((_hb_ucd_b4(_hb_ucd_u8+10892u,((((((u)>>2))>>3))>>3)))<<3)+((((((u)>>2))>>3))&7)])<<3)+((((u)>>2))&7)])<<2)+((u)&3)] : 0;
 }
-static inline uint_fast8_t
-_hb_ucd_sc (unsigned u)
+static inline uint8_t _hb_ucd_sc (unsigned u)
 {
-  return u<918000u?_hb_ucd_u8[10486+(((_hb_ucd_u16[3744+(((_hb_ucd_u16[2624+(((_hb_ucd_u8[9588+(u>>3>>3>>4)])<<4)+((u>>3>>3)&15u))])<<3)+((u>>3)&7u))])<<3)+((u)&7u))]:2;
+  return u<918000 ? _hb_ucd_u8[12662u+((_hb_ucd_u16[3328u+((_hb_ucd_u8[11926u+((_hb_ucd_u8[11476u+((((((u)>>3))>>4))>>4)])<<4)+((((((u)>>3))>>4))&15)])<<4)+((((u)>>3))&15)])<<3)+((u)&7)] : 2;
 }
-static inline uint_fast16_t
-_hb_ucd_dm (unsigned u)
+static inline uint16_t _hb_ucd_dm (unsigned u)
 {
-  return u<195102u?_hb_ucd_u16[6976+(((_hb_ucd_u8[16716+(((_hb_ucd_u8[16334+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+  return u<195102 ? _hb_ucd_u16[7408u+((_hb_ucd_u8[18972u+((_hb_ucd_u8[18590u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)] : 0;
 }
 
 
 #elif !defined(HB_NO_UCD_UNASSIGNED)
 
-static const uint8_t
-_hb_ucd_u8[17524] =
+#include 
+
+static const uint8_t _hb_ucd_u8[14800]=
 {
     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, 18, 19, 20, 21, 22, 23,
     5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 24, 25, 26,  5, 27, 28,
-    5, 29, 30, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+    5, 29,  5, 30, 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,
@@ -2929,23 +2771,23 @@ _hb_ucd_u8[17524] =
    17, 17, 17,103, 17, 17,104,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,105,100,100,100,100,100,100, 17, 17,106,107,100,108,109,110,
-   17, 17, 17, 17, 17, 17, 17,111, 17, 17, 17, 17,112,113,100,100,
-  100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,114,
-   17,115,116,100,100,100,100,100,100,100,100,100,117,100,100,100,
-  100,100,100,100,100,100,100,100,100,100,100,100,118, 39,119,120,
-  121,122,123,124,125,126,127,128, 39, 39,129,100,100,100,100,130,
-  131,132,133,100,134,135,100,136,137,138,100,100,139,140,141,100,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,111,112,100,100,
+  100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,113,
+   17,114,115,100,100,100,100,100,100,100,100,100,116,100,100,100,
+  100,100,100,100,100,100,100,100,100,100,100,100,117, 39,118,119,
+  120,121,122,123,124,125,126,127, 39, 39,128,100,100,100,100,129,
+  130,131,132,100,133,134,135,136,137,138,100,100,139,140,141,100,
   142,143,144,145, 39, 39,146,147,148, 39,149,150,100,100,100,100,
    17, 17, 17, 17, 17, 17,151, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17,152,153, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,154, 17,
-   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,155, 17, 17,156,100,
-  100,100,100,100,100,100,100,100, 17, 17,157,100,100,100,100,100,
-   17, 17, 17,158, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17,159,100,100,100,100,100,100,100,100,100,100,100,100,
-  160,161,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
+   17, 17, 17, 17, 17, 17, 17, 17,152, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,153, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,154, 17, 17,155,100,
+  100,100,100,100,100,100,100,100, 17, 17,156,100,100,100,100,100,
+   17, 17, 17,157, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17,158,100,100,100,100,100,100,100,100,100,100,100,
+  159,160,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
+   60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,161,
    60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,162,
-   60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,163,
     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,
@@ -2959,409 +2801,415 @@ _hb_ucd_u8[17524] =
    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,
-   36, 36, 36, 36, 82, 36, 36, 61, 65, 44, 44, 57, 43, 43, 43, 43,
-   36, 36, 36, 36, 83, 43, 43, 43, 43, 84, 43, 43, 43, 43, 43, 43,
-   43, 85, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 85, 71, 86,
-   87, 43, 43, 43, 85, 86, 87, 86, 70, 43, 43, 43, 36, 36, 36, 36,
-   36, 43,  2,  7,  7,  7,  7,  7, 88, 36, 36, 36, 36, 36, 36, 36,
-   70, 86, 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, 86,
-   87, 43, 80, 89, 90, 89, 87, 61, 44, 44, 44, 89, 44, 44, 36, 62,
-   36, 43, 44,  7,  7,  7,  7,  7, 36, 20, 27, 27, 27, 56, 63, 80,
-   57, 85, 62, 36, 36, 61, 44, 62, 61, 36, 62, 61, 36, 44, 80, 86,
-   87, 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, 85, 62, 36, 36, 36, 36, 62, 36, 62, 36, 36, 36, 36, 36, 36,
-   61, 36, 62, 36, 36, 44, 71, 86, 87, 43, 43, 57, 85, 89, 87, 44,
-   61, 44, 44, 44, 44, 44, 44, 44, 66, 44, 44, 44, 62, 43, 43, 43,
-   57, 86, 62, 36, 36, 36, 61, 62, 61, 36, 62, 36, 36, 44, 71, 87,
-   87, 43, 80, 89, 90, 89, 87, 44, 44, 44, 57, 85, 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, 86, 85, 90, 44, 86, 90, 86, 87, 44,
-   61, 44, 44, 89, 44, 44, 44, 44, 27, 91, 67, 67, 56, 92, 44, 44,
-   85, 86, 71, 36, 36, 36, 61, 36, 61, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 44, 71, 43, 85, 86, 90, 43, 80, 43, 43, 44,
-   44, 44, 57, 80, 36, 61, 62, 44, 44, 44, 44, 93, 27, 27, 27, 91,
-   70, 86, 72, 36, 36, 36, 61, 36, 36, 36, 62, 36, 36, 44, 71, 87,
-   86, 86, 90, 85, 90, 86, 43, 44, 44, 44, 89, 90, 44, 44, 62, 61,
-   62, 94, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36,
-   36, 36, 36, 36, 36, 70, 71, 86, 87, 43, 80, 86, 90, 86, 87, 77,
-   44, 44, 36, 94, 27, 27, 27, 95, 27, 27, 27, 27, 91, 36, 36, 36,
-   57, 86, 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, 89,
-   86, 43, 80, 80, 86, 86, 86, 86, 44, 86, 64, 44, 44, 44, 44, 44,
-   62, 36, 36, 36, 36, 36, 36, 36, 70, 36, 43, 43, 43, 80, 44, 96,
-   36, 36, 36, 75, 43, 43, 43, 60,  7,  7,  7,  7,  7,  2, 44, 44,
-   44, 44, 44, 44, 44, 44, 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, 80,  7,  7,  7,  7,  7, 44, 36, 36,
-   77, 67,  2,  2,  2,  2,  2,  2,  2, 97, 97, 67, 43, 67, 67, 67,
-    7,  7,  7,  7,  7, 27, 27, 27, 27, 27, 50, 50, 50,  4,  4, 86,
-   36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44,
-   57, 43, 43, 43, 43, 43, 43, 85, 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, 92, 67,  2,  2, 97, 67, 21, 64, 44, 44,
-   36, 36, 36, 36, 36, 94, 87, 43, 85, 43, 43, 43, 87, 85, 87, 71,
-    7,  7,  7,  7,  7,  2,  2,  2, 36, 36, 36, 86, 43, 36, 36, 43,
-   71, 86, 98, 94, 86, 86, 86, 36, 70, 43, 71, 36, 36, 36, 36, 36,
-   36, 85, 87, 85, 86, 86, 87, 94,  7,  7,  7,  7,  7, 86, 87, 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, 99, 27, 27, 27, 27, 27, 27, 27, 27, 27,100, 44,
-   67, 67, 67, 67, 67, 44, 44, 44, 11, 11, 11, 44, 16, 16, 16, 44,
-  101, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 77, 72,
-  102, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,103,104, 44,
-   36, 36, 36, 36, 36, 63,  2,105,106, 36, 36, 36, 61, 44, 44, 44,
-   36, 43, 85, 44, 44, 44, 44, 62, 36, 43,107, 64, 44, 44, 44, 44,
-   36, 43, 44, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 61, 36,
-   61, 43, 44, 44, 44, 44, 44, 44, 36, 36, 43, 87, 43, 43, 43, 86,
-   86, 86, 86, 85, 87, 43, 43, 43, 43, 43,  2, 88,  2, 66, 70, 44,
-    7,  7,  7,  7,  7, 44, 44, 44, 27, 27, 27, 27, 27, 44, 44, 44,
-    2,  2,  2,108,  2, 59, 43, 84, 36, 83, 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, 85, 86, 87, 85, 86, 44, 44,
-   86, 85, 86, 86, 87, 43, 44, 44, 92, 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,100, 44, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-   36, 36, 36, 70, 85, 87, 44,  2, 36, 36, 94, 85, 43, 43, 43, 80,
-   85, 85, 87, 43, 43, 43, 85, 86, 86, 87, 43, 43, 43, 43, 80, 57,
-    2,  2,  2, 88,  2,  2,  2, 44, 43, 43, 43, 43, 43, 43, 43,109,
-   43, 43, 43, 43, 43, 43, 43, 80, 43, 43, 98, 36, 36, 36, 36, 36,
-   36, 36, 85, 43, 43, 85, 85, 86, 86, 85, 98, 36, 36, 36, 61,  2,
-   97, 67, 67, 67, 67, 50, 43, 43, 43, 43, 67, 67, 67, 67, 21,  2,
-   43, 98, 36, 36, 36, 36, 36, 36, 94, 43, 43, 86, 43, 87, 43, 36,
-   36, 36, 36, 85, 43, 86, 87, 87, 43, 86, 44, 44, 44, 44,  2,  2,
-   36, 36, 86, 86, 86, 86, 43, 43, 43, 43, 86, 43, 44, 93,  2,  2,
-    7,  7,  7,  7,  7, 44, 62, 36, 36, 36, 36, 36, 40, 40, 40,  2,
-   16, 16, 16, 16, 34,110, 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,
-   85, 43, 43, 43, 71, 36, 70, 36, 36, 36, 71, 94, 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,111, 40, 40,
-   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,112,112,112,112,
-   16, 16,110, 16, 11, 11,113,114, 41, 16,110, 16, 11, 11,113, 41,
-   16, 16, 44, 16, 11, 11,115, 41, 16, 16, 16, 16, 11, 11,116, 41,
-   44, 16,110, 16, 11, 11,113,117,118,118,118,118,118,119, 65, 65,
-  120,120,120,  2,121,122,121,122,  2,  2,  2,  2,123, 65, 65,124,
-    2,  2,  2,  2,125,126,  2,127,128,  2,129,130,  2,  2,  2,  2,
-    2,  9,128,  2,  2,  2,  2,131, 65, 65,132, 65, 65, 65, 65, 65,
-  133, 44, 27, 27, 27,  8,129,134, 27, 27, 27, 27, 27,  8,129,104,
-   40, 40, 40, 40, 40, 40, 81, 44, 20, 20, 20, 20, 20, 20, 20, 20,
-  135, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 43, 43,136, 51,
-  109, 51,109, 43, 43, 43, 43, 43, 80, 44, 44, 44, 44, 44, 44, 44,
-   67,137, 67,138, 67, 34, 11, 16, 11, 32,138, 67, 49, 11, 11, 67,
-   67, 67,137,137,137, 11, 11,139, 11, 11, 35, 36, 39, 67, 16, 11,
-    8,  8, 49, 16, 16, 26, 67,140, 27, 27, 27, 27, 27, 27, 27, 27,
-  105,105,105,105,105,105,105,105,105,141,142,105,143, 67, 44, 44,
-    8,  8,144, 67, 67,  8, 67, 67,144, 26, 67,144, 67, 67, 67,144,
-   67, 67, 67, 67, 67, 67, 67,  8, 67,144,144, 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,145,146, 67, 67,
-   67, 67, 67, 67, 67, 67,144, 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, 67, 67, 92, 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,129,147,  8,  8,  8,  8,
-    8,  8,  8,  4,  4,  4,  4,  4,  8,129,148,148,148,148,148,148,
-  148,148,148,148,147,  8,  8,  8,  8,  8,  8,  8,  4,  4,  8,  8,
-    8,  8,  8,  8,  8,  8,  4,  8,  8,  8,144, 26,  8,  8,144, 67,
-   67, 67, 44, 67, 67, 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 67,
-   32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 40, 11,
-   32, 32,140, 67, 67,138, 34,149, 43, 32, 44, 44, 93,  2, 99,  2,
-   16, 16, 16,150, 44, 44,150, 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,121,121,  2,125,126,121,  2,
-    2,  2,  2,  6,  2,108,121,  2,121,  4,  4,  4,  4,  2,  2, 88,
-    2,  2,  2,  2,  2,120,  2,  2,108,151,  2,  2,  2,  2,  2,  2,
-   67,  2,152,148,148,148,153, 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,
-    1,  2,154,155,  4,  4,  4,  4,  4, 67,  4,  4,  4,  4,156,157,
-  158,105,105,105,105, 43, 43, 86,159, 40, 40, 67,105,160, 63, 67,
-   36, 36, 36, 61, 57,161,162, 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, 44, 44, 44, 44, 55, 67, 67, 67, 67, 67, 67, 67, 92,
-   27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, 27,
-  163, 27, 27, 27, 27, 27, 27, 27, 36, 36, 83, 36, 36, 36, 36, 36,
-   67, 67, 67, 92, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36,164,  2,
-    7,  7,  7,  7,  7, 36, 44, 44, 32, 32, 32, 32, 32, 32, 32, 70,
-   51,165, 43, 43, 43, 43, 43, 88, 32, 32, 32, 32, 32, 32, 40, 43,
-   36, 36, 36,105,105,105,105,105, 43,  2,  2,  2, 44, 44, 44, 44,
-   41, 41, 41,162, 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,166, 34, 35, 32, 32, 16, 32, 32, 32, 32, 32,
+   16, 16, 36, 16, 16, 16, 16, 16, 39, 39, 39, 39, 39, 39, 39, 39,
+   39, 40, 40, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40,
+   39, 39, 41, 40, 40, 40, 41, 41, 40, 40, 40, 40, 40, 40, 40, 40,
+   42, 42, 42, 42, 42, 42, 42, 42, 32, 32, 41, 32, 43, 44, 16, 10,
+   43, 43, 40, 45, 11, 46, 46, 11, 34, 11, 11, 11, 11, 11, 11, 11,
+   11, 47, 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, 48, 34, 32, 34, 11,
+   32, 49, 42, 42, 50, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16,
+   47, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 46, 51,  2,  2,  2,
+   16, 16, 16, 16, 52, 53, 54, 55, 56, 42, 42, 42, 42, 42, 42, 42,
+   42, 42, 42, 42, 42, 42, 42, 57, 58, 59, 42, 58, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43, 61,
+   36, 62, 63, 43, 43, 43, 43, 43, 64, 64, 64,  8,  9, 65,  2, 66,
+   42, 42, 42, 42, 42, 59, 67,  2, 68, 36, 36, 36, 36, 69, 42, 42,
+    7,  7,  7,  7,  7,  2,  2, 36, 70, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 71, 42, 42, 42, 72, 49, 42, 42, 73, 74, 75, 42, 42, 36,
+    7,  7,  7,  7,  7, 36, 76, 77,  2,  2,  2,  2,  2,  2,  2, 78,
+   69, 36, 36, 36, 36, 36, 36, 36, 42, 42, 42, 42, 42, 79, 61, 36,
+   36, 36, 36, 42, 42, 42, 42, 42, 70, 43, 43, 43, 43, 43, 43, 43,
+    7,  7,  7,  7,  7, 36, 36, 36, 36, 36, 36, 36, 36, 69, 42, 42,
+   42, 42, 39, 21,  2, 80, 56, 20, 36, 36, 36, 42, 42, 74, 42, 42,
+   42, 42, 74, 42, 74, 42, 42, 43,  2,  2,  2,  2,  2,  2,  2, 63,
+   36, 36, 36, 36, 69, 42, 43, 63, 36, 36, 36, 36, 36, 60, 43, 43,
+   36, 36, 36, 36, 81, 36, 36, 36, 64, 43, 43, 56, 42, 42, 42, 42,
+   36, 36, 36, 36, 82, 42, 42, 42, 42, 83, 42, 42, 42, 42, 42, 42,
+   42, 84, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 84, 70, 85,
+   86, 42, 42, 42, 84, 85, 86, 85, 69, 42, 42, 42, 36, 36, 36, 36,
+   36, 42,  2,  7,  7,  7,  7,  7, 87, 36, 36, 36, 36, 36, 36, 36,
+   69, 85, 61, 36, 36, 36, 60, 61, 60, 61, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 60, 36, 36, 36, 60, 60, 43, 36, 36, 43, 70, 85,
+   86, 42, 79, 88, 89, 88, 86, 60, 43, 43, 43, 88, 43, 43, 36, 61,
+   36, 42, 43,  7,  7,  7,  7,  7, 36, 20, 27, 27, 27, 55, 62, 79,
+   56, 84, 61, 36, 36, 60, 43, 61, 60, 36, 61, 60, 36, 43, 79, 85,
+   86, 79, 43, 56, 79, 56, 42, 43, 56, 43, 43, 43, 61, 36, 60, 60,
+   43, 43, 43,  7,  7,  7,  7,  7, 42, 36, 69, 63, 43, 43, 43, 43,
+   56, 84, 61, 36, 36, 36, 36, 61, 36, 61, 36, 36, 36, 36, 36, 36,
+   60, 36, 61, 36, 36, 43, 70, 85, 86, 42, 42, 56, 84, 88, 86, 43,
+   60, 43, 43, 43, 43, 43, 43, 43, 65, 43, 43, 43, 61, 42, 42, 42,
+   56, 85, 61, 36, 36, 36, 60, 61, 60, 36, 61, 36, 36, 43, 70, 86,
+   86, 42, 79, 88, 89, 88, 86, 43, 43, 43, 56, 84, 43, 43, 36, 61,
+   77, 27, 27, 27, 43, 43, 43, 43, 43, 70, 61, 36, 36, 60, 43, 36,
+   60, 36, 36, 43, 61, 60, 60, 36, 43, 61, 60, 43, 36, 60, 43, 36,
+   36, 36, 36, 36, 36, 43, 43, 85, 84, 89, 43, 85, 89, 85, 86, 43,
+   60, 43, 43, 88, 43, 43, 43, 43, 27, 90, 66, 66, 55, 91, 43, 43,
+   84, 85, 70, 36, 36, 36, 60, 36, 60, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 43, 70, 42, 84, 85, 89, 42, 79, 42, 42, 43,
+   43, 43, 56, 79, 36, 60, 36, 43, 43, 43, 43, 92, 27, 27, 27, 90,
+   69, 85, 71, 36, 36, 36, 60, 36, 36, 36, 61, 36, 36, 43, 70, 86,
+   85, 85, 89, 84, 89, 85, 42, 43, 43, 43, 88, 89, 43, 43, 36, 60,
+   61, 93, 43, 43, 43, 43, 43, 43, 42, 85, 36, 36, 36, 36, 60, 36,
+   36, 36, 36, 36, 36, 69, 70, 85, 86, 42, 79, 85, 89, 85, 86, 76,
+   43, 43, 36, 93, 27, 27, 27, 94, 27, 27, 27, 27, 90, 36, 36, 36,
+   56, 85, 61, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43, 36, 36, 36,
+   36, 61, 36, 36, 36, 36, 61, 43, 36, 36, 36, 60, 43, 79, 43, 88,
+   85, 42, 79, 79, 85, 85, 85, 85, 43, 85, 63, 43, 43, 43, 43, 43,
+   61, 36, 36, 36, 36, 36, 36, 36, 69, 36, 42, 42, 42, 79, 43, 95,
+   36, 36, 36, 74, 42, 42, 42, 59,  7,  7,  7,  7,  7,  2, 43, 43,
+   43, 43, 43, 43, 43, 43, 43, 43, 61, 60, 60, 36, 36, 60, 36, 36,
+   36, 36, 61, 61, 36, 36, 36, 36, 69, 36, 42, 42, 42, 42, 70, 43,
+   36, 36, 60, 80, 42, 42, 42, 79,  7,  7,  7,  7,  7, 43, 36, 36,
+   76, 66,  2,  2,  2,  2,  2,  2,  2, 96, 96, 66, 42, 66, 66, 66,
+    7,  7,  7,  7,  7, 27, 27, 27, 27, 27, 49, 49, 49,  4,  4, 85,
+   36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43,
+   56, 42, 42, 42, 42, 42, 42, 84, 42, 42, 59, 42, 36, 36, 69, 42,
+   42, 42, 42, 42, 56, 42, 42, 42, 42, 42, 42, 42, 42, 42, 79, 66,
+   66, 66, 66, 75, 66, 66, 91, 66,  2,  2, 96, 66, 21, 63, 43, 43,
+   36, 36, 36, 36, 36, 93, 86, 42, 84, 42, 42, 42, 86, 84, 86, 70,
+    7,  7,  7,  7,  7,  2,  2,  2, 36, 36, 36, 85, 42, 36, 36, 42,
+   70, 85, 97, 93, 85, 85, 85, 36, 69, 42, 70, 36, 36, 36, 36, 36,
+   36, 84, 86, 84, 85, 85, 86, 93,  7,  7,  7,  7,  7, 85, 86, 66,
+   11, 11, 11, 47, 43, 43, 47, 43, 16, 16, 16, 16, 16, 52, 44, 16,
+   36, 36, 36, 36, 60, 36, 36, 43, 36, 36, 36, 60, 60, 36, 36, 43,
+   60, 36, 36, 43, 36, 36, 36, 60, 60, 36, 36, 43, 36, 36, 36, 36,
+   36, 36, 36, 60, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 56, 42,
+    2,  2,  2,  2, 98, 27, 27, 27, 27, 27, 27, 27, 27, 27, 99, 43,
+   66, 66, 66, 66, 66, 43, 43, 43, 11, 11, 11, 43, 16, 16, 16, 43,
+  100, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 76, 71,
+  101, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,102,103, 43,
+   36, 36, 36, 36, 36, 62,  2,104,105, 36, 36, 36, 60, 43, 43, 43,
+   36, 42, 84, 43, 43, 43, 43, 61, 36, 42,106, 63, 43, 43, 43, 43,
+   36, 42, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36, 60, 36,
+   60, 42, 43, 43, 43, 43, 43, 43, 36, 36, 42, 86, 42, 42, 42, 85,
+   85, 85, 85, 84, 86, 42, 42, 42, 42, 42,  2, 87,  2, 65, 69, 43,
+    7,  7,  7,  7,  7, 43, 43, 43, 27, 27, 27, 27, 27, 43, 43, 43,
+    2,  2,  2,107,  2, 58, 42, 83, 36, 82, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 60, 43, 43, 43, 36, 36, 69, 70, 36, 36, 36, 36,
+   36, 36, 36, 36, 69, 60, 43, 43, 36, 36, 36, 43, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 36, 36, 60, 42, 84, 85, 86, 84, 85, 43, 43,
+   85, 84, 85, 85, 86, 42, 43, 43, 91, 43,  2,  7,  7,  7,  7,  7,
+   36, 36, 36, 36, 36, 36, 36, 43, 36, 36, 60, 43, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 36, 43, 43, 36, 36, 36, 36, 36, 43, 43, 43,
+    7,  7,  7,  7,  7, 99, 43, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+   36, 36, 36, 69, 84, 86, 43,  2, 36, 36, 93, 84, 42, 42, 42, 79,
+   84, 84, 86, 42, 42, 42, 84, 85, 85, 86, 42, 42, 42, 42, 79, 56,
+    2,  2,  2, 87,  2,  2,  2, 43, 42, 42, 42, 42, 42, 42, 42,108,
+   42, 42, 42, 42, 42, 42, 42, 43, 42, 42, 42, 42, 42, 42, 43, 43,
+   42, 42, 97, 36, 36, 36, 36, 36, 36, 36, 84, 42, 42, 84, 84, 85,
+   85, 84, 97, 36, 36, 36, 60,  2, 96, 66, 66, 66, 66, 49, 42, 42,
+   42, 42, 66, 66, 66, 66, 21,  2, 42, 97, 36, 36, 36, 36, 36, 36,
+   93, 42, 42, 85, 42, 86, 42, 36, 36, 36, 36, 84, 42, 85, 86, 86,
+   42, 85, 43, 43, 43, 43,  2,  2, 36, 36, 85, 85, 85, 85, 42, 42,
+   42, 42, 85, 42, 43, 92,  2,  2,  7,  7,  7,  7,  7, 43, 61, 36,
+   36, 36, 36, 36, 39, 39, 39,  2, 16, 16, 16, 16, 34,109, 43, 43,
+   11, 11, 11, 11, 11, 46, 47, 11,  2,  2,  2,  2, 43, 43, 43, 43,
+   42, 59, 42, 42, 42, 42, 42, 42, 84, 42, 42, 42, 70, 36, 69, 36,
+   36, 36, 70, 93, 42, 60, 43, 43, 16, 16, 16, 16, 16, 16, 39, 39,
+   39, 39, 39, 39, 39, 44, 16, 16, 16, 16, 16, 16, 44, 16, 16, 16,
+   16, 16, 16, 16, 16,110, 39, 39, 32, 32, 32, 16, 16, 16, 16, 32,
+   16, 16, 16, 16, 11, 11, 11, 11, 16, 16, 16, 43, 11, 11, 11, 43,
+   16, 16, 16, 16, 47, 47, 47, 47, 16, 16, 16, 16, 16, 16, 16, 43,
+   16, 16, 16, 16,111,111,111,111, 16, 16,109, 16, 11, 11,112,113,
+   40, 16,109, 16, 11, 11,112, 40, 16, 16, 43, 16, 11, 11,114, 40,
+   16, 16, 16, 16, 11, 11,115, 40, 43, 16,109, 16, 11, 11,112,116,
+  117,117,117,117,117,118, 64, 64,119,119,119,  2,120,121,120,121,
+    2,  2,  2,  2,122, 64, 64,123,  2,  2,  2,  2,124,125,  2,126,
+  127,  2,128,129,  2,  2,  2,  2,  2,  9,127,  2,  2,  2,  2,130,
+   64, 64,131, 64, 64, 64, 64, 64,132, 43, 27, 27, 27,  8,128,133,
+   27, 27, 27, 27, 27,  8,128,103, 39, 39, 39, 39, 39, 39, 80, 43,
+   20, 20, 20, 20, 20, 20, 20, 20, 20, 43, 43, 43, 43, 43, 43, 43,
+   42, 42, 42, 42, 42, 42,134, 50,108, 50,108, 42, 42, 42, 42, 42,
+   79, 43, 43, 43, 43, 43, 43, 43, 66,135, 66,136, 66, 34, 11, 16,
+   11, 32,136, 66, 48, 11, 11, 66, 66, 66,135,135,135, 11, 11,137,
+   11, 11, 35, 36,138, 66, 16, 11,  8,  8, 48, 16, 16, 26, 66,139,
+   27, 27, 27, 27, 27, 27, 27, 27,104,104,104,104,104,104,104,104,
+  104,140,141,104,142, 66, 43, 43,  8,  8,143, 66, 66,  8, 66, 66,
+  143, 26, 66,143, 66, 66, 66,143, 66, 66, 66, 66, 66, 66, 66,  8,
+   66,143,143, 66, 66, 66, 66, 66, 66, 66,  8,  8,  8,  8,  8,  8,
+    8,  8,  8,  8,  8,  8,  8,  8, 66, 66, 66, 66,  4,  4, 66, 66,
+    8, 66, 66, 66,144,145, 66, 66, 66, 66, 66, 66, 66, 66,143, 66,
+   66, 66, 66, 66, 66, 26,  8,  8,  8,  8, 66, 66, 66, 66, 66, 66,
+   66, 66, 66, 66, 66, 66,  8,  8,  8, 66, 66, 66, 66, 66, 66, 66,
+   66, 66, 66, 66, 66, 91, 43, 43, 27, 27, 27, 27, 27, 27, 66, 66,
+   66, 66, 66, 66, 66, 27, 27, 27, 66, 66, 66, 26, 66, 66, 66, 66,
+   26, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,  8,  8,  8,  8,
+   66, 66, 66, 66, 66, 66, 66, 26, 66, 66, 66, 66,  4,  4,  4,  4,
+    4,  4,  4, 27, 27, 27, 27, 27, 27, 27, 66, 66, 66, 66, 66, 66,
+    8,  8,128,146,  8,  8,  8,  8,  8,  8,  8,  4,  4,  4,  4,  4,
+    8,128,147,147,147,147,147,147,147,147,147,147,146,  8,  8,  8,
+    8,  8,  8,  8,  4,  4,  8,  8,  8,  8,  8,  8,  8,  8,  4,  8,
+    8,  8,143, 26,  8,  8,143, 66, 66, 66, 43, 66, 66, 66, 66, 66,
+   32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 39, 11,
+   32, 32,139, 66, 66,136, 34,148, 42, 32, 43, 43, 92,  2, 98,  2,
+   16, 16, 16,149, 43, 43,149, 43, 36, 36, 36, 36, 43, 43, 43, 51,
+   63, 43, 43, 43, 43, 43, 43, 56, 36, 36, 36, 60, 43, 43, 43, 43,
+   36, 36, 36, 60, 36, 36, 36, 60,  2,120,120,  2,124,125,120,  2,
+    2,  2,  2,  6,  2,107,120,  2,120,  4,  4,  4,  4,  2,  2, 87,
+    2,  2,  2,  2,  2,119,  2,  2,107,150,  2,  2,  2,  2,  2,  2,
+   66,  2,151,147,147,147,152, 43, 66, 66, 66, 66, 66, 54, 66, 66,
+   66, 66, 43, 43, 43, 43, 43, 43, 66, 66, 66, 43, 43, 43, 43, 43,
+    1,  2,153,154,  4,  4,  4,  4,  4, 66,  4,  4,  4,  4,155,156,
+  157,104,104,104,104, 42, 42, 85,158, 39, 39, 66,104,159, 62, 66,
+   36, 36, 36, 60, 56,160,161, 68, 36, 36, 36, 36, 36, 62, 39, 68,
+   43, 43, 61, 36, 36, 36, 36, 36, 66, 27, 27, 66, 66, 66, 66, 66,
+   66, 66, 66, 43, 43, 43, 43, 54, 66, 66, 66, 66, 66, 66, 66, 91,
+   27, 27, 27, 27, 27, 66, 66, 66, 66, 66, 66, 66, 27, 27, 27, 27,
+  162, 27, 27, 27, 27, 27, 27, 27, 36, 36, 82, 36, 36, 36, 36, 36,
+   66, 66, 66, 91, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36,163,  2,
+    7,  7,  7,  7,  7, 36, 43, 43, 32, 32, 32, 32, 32, 32, 32, 69,
+   50,164, 42, 42, 42, 42, 42, 87, 32, 32, 32, 32, 32, 32, 39, 42,
+   36, 36, 36,104,104,104,104,104, 42,  2,  2,  2, 43, 43, 43, 43,
+   40, 40, 40,161, 39, 39, 39, 39, 40, 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, 41,165, 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,
-   32, 32, 11, 11, 34, 34, 32, 44, 32,150,150, 32, 32, 32, 47, 44,
-   44, 40,167, 35, 40, 35, 36, 36, 36, 71, 36, 71, 36, 70, 36, 36,
-   36, 94, 87, 85, 67, 67, 80, 44, 27, 27, 27, 67,168, 44, 44, 44,
-   36, 36,  2,  2, 44, 44, 44, 44, 86, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 86, 86, 86, 86, 86, 86, 86, 86, 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, 86, 44, 44, 44, 44, 44, 93,
-   36, 70, 86, 43, 43, 86, 43, 86,107,  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, 85,
-   87, 85, 87, 80, 44, 44, 44, 44, 36, 70, 36, 36, 36, 36, 85, 44,
-    7,  7,  7,  7,  7, 44,  2,  2, 69, 36, 36, 77, 67, 94, 85, 36,
-   71, 43, 71, 70, 71, 36, 36, 43, 70, 61, 44, 44, 44, 44, 44, 44,
-   44, 44, 44, 44, 44, 62, 83,  2, 36, 36, 36, 36, 36, 94, 43, 86,
-    2, 83,169, 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,114, 40, 40,
-   16, 16, 16, 16,111, 41, 44, 44, 36, 94, 87, 86, 85,107, 87, 44,
-   36, 36, 44, 44, 44, 44, 44, 44, 36, 36, 36, 61, 44, 62, 36, 36,
-  170,170,170,170,170,170,170,170,171,171,171,171,171,171,171,171,
-   16, 16, 16,110, 44, 44, 44, 44, 44,150, 16, 16, 44, 44, 62, 71,
-   36, 36, 36, 36,172, 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,117, 44, 44, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36,148, 44, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 44, 44, 44, 55, 36, 36, 36, 36, 36, 36,168, 67,
-    2,  2,  2,152,130, 44, 44, 44,  6,173,174,148,148,148,148,148,
-  148,148,130,152,130,  2,127,175,  2, 64,  2,  2,156,148,148,130,
-    2,176,  8,177, 66,  2, 44, 44, 36, 36, 61, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 61, 79, 93,  2,  3,  2,  4,  5,  6,  2,
-   16, 16, 16, 16, 16, 17, 18,129,130,  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,178, 56,135, 26,  8,144, 92, 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,179, 27, 27, 27, 27, 27, 27, 44, 55, 67, 67, 67, 67,
-  105,105,143, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 27, 67, 92,
-   67, 67, 67, 67, 67, 67, 92, 44, 92, 44, 44, 44, 44, 44, 44, 44,
-   67, 67, 67, 67, 67, 67, 50, 44,180, 27, 27, 27, 27, 27, 27, 27,
-   27, 27, 27, 27, 27, 27, 44, 44, 27, 27, 44, 44, 44, 44, 62, 36,
-  155, 36, 36, 36, 36,181, 44, 44, 36, 36, 36, 43, 43, 80, 44, 44,
-   36, 36, 36, 36, 36, 36, 36, 93, 36, 36, 44, 44, 36, 36, 36, 36,
-  182,105,105, 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, 36, 36, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44, 44, 93,
-   11, 11, 11, 11, 11, 47, 11, 11, 11, 47, 11,150, 16, 16, 16, 16,
-   16,150, 16, 16, 16, 16, 16, 16, 16,150, 16, 16, 16,150,110, 44,
-   40, 40, 40, 52, 40, 40, 40, 40, 81, 40, 40, 40, 40, 81, 44, 44,
-   36, 36, 36, 44, 61, 36, 36, 36, 36, 36, 36, 62, 61, 44, 61, 62,
-   36, 36, 36, 93, 27, 27, 27, 27, 36, 36, 36, 77,163, 27, 27, 27,
-   44, 44, 44,179, 27, 27, 27, 27, 36, 61, 36, 44, 44,179, 27, 27,
-   36, 36, 36, 27, 27, 27, 44, 93, 36, 36, 36, 36, 36, 44, 44, 93,
-   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,100, 44, 44, 44,
-    2,  2,  2,  2, 64, 44, 44, 44, 36, 36, 36, 36, 36, 36,183, 30,
-   36, 36, 36, 36, 36, 36,183, 27, 36, 36, 36, 36, 78, 36, 36, 36,
-   36, 36, 70, 80, 44,179, 27, 27,  2,  2,  2, 64, 44, 44, 44, 44,
-   36, 36, 36, 44, 93,  2,  2,  2, 36, 36, 36, 44, 27, 27, 27, 27,
-   36, 61, 44, 44, 27, 27, 27, 27, 36, 44, 44, 44, 93,  2, 64, 44,
-   44, 44, 44, 44,179, 27, 27, 27, 11, 47, 44, 44, 44, 44, 44, 44,
-   16,110, 44, 44, 44, 27, 27, 27, 36, 36, 43, 43, 44, 44, 44, 44,
-    7,  7,  7,  7,  7, 36, 36, 69, 11, 11, 11, 44, 57, 43, 43,159,
-   16, 16, 16, 44, 44, 44, 44,  8, 27, 27, 27, 27, 27, 27, 27,100,
-   36, 36, 36, 36, 36, 57,184, 44, 36, 44, 44, 44, 44, 44, 44, 44,
-   44, 36, 61, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 43, 43,
-   27, 27, 27, 95, 44, 44, 44, 44,180, 27, 30,  2,  2, 44, 44, 44,
-   36, 43, 43,  2,  2, 44, 44, 44, 36, 36,183, 27, 27, 27, 44, 44,
-   87, 98, 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,
-   71, 70, 71, 44, 44, 44, 44, 57, 86, 87, 43, 85, 87, 60,185,  2,
-    2, 80, 44, 44, 44, 44, 79, 44, 43, 71, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 70, 43, 43, 87, 43, 43, 43, 80,  7,  7,  7,  7,  7,
-    2,  2, 94, 98, 44, 44, 44, 44, 36, 70,  2, 61, 44, 44, 44, 44,
-   36, 94, 86, 43, 43, 43, 43, 85, 98, 36, 63,  2, 59, 43, 60, 87,
-    7,  7,  7,  7,  7, 63, 63,  2,179, 27, 27, 27, 27, 27, 27, 27,
-   27, 27,100, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 86, 87,
-   43, 86, 85, 43,  2,  2,  2, 71, 70, 44, 44, 44, 44, 44, 44, 44,
-   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,
-   86, 87, 43, 43, 43, 80, 44, 44, 43, 86, 62, 36, 36, 36, 61, 62,
-   61, 36, 62, 36, 36, 57, 71, 86, 85, 86, 90, 89, 90, 89, 86, 44,
-   61, 44, 44, 89, 44, 44, 62, 36, 36, 86, 44, 43, 43, 43, 80, 44,
-   43, 43, 80, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 62, 44, 61,
-   36, 36, 36, 62, 86, 87, 43, 43, 80, 90, 89, 89, 86, 90, 86, 85,
-   71, 71,  2, 93, 64, 44, 44, 44, 57, 80, 44, 44, 44, 44, 44, 44,
-   36, 36, 94, 86, 43, 43, 43, 43, 86, 43, 85, 71, 36, 63,  2,  2,
-    7,  7,  7,  7,  7,  2, 93, 71, 86, 87, 43, 43, 85, 85, 86, 87,
-   85, 43, 36, 72, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 94,
-   86, 43, 43, 44, 86, 86, 43, 87, 60,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2, 36, 36, 43, 44, 86, 87, 43, 43, 43, 85, 87, 87,
-   60,  2, 61, 44, 44, 44, 44, 44,  2,  2,  2,  2,  2,  2, 64, 44,
-   36, 36, 36, 36, 36, 70, 87, 86, 43, 43, 43, 87, 63, 44, 44, 44,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 44, 44, 44, 44, 44, 44,
-   36, 36, 36, 36, 36, 61, 57, 87, 86, 43, 43, 87, 43, 43, 44, 44,
-    7,  7,  7,  7,  7, 27,  2, 97, 43, 43, 43, 43, 87, 60, 44, 44,
-   27,100, 44, 44, 44, 44, 44, 62, 36, 36, 36, 61, 62, 44, 36, 36,
-   36, 36, 62, 61, 36, 36, 36, 36, 86, 86, 86, 89, 90, 57, 85, 71,
-   98, 87,  2, 64, 44, 44, 44, 44, 36, 36, 36, 36, 44, 36, 36, 36,
-   94, 86, 43, 43, 44, 43, 86, 86, 71, 72, 90, 44, 44, 44, 44, 44,
-   70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 85, 70, 43, 60,
-    2,  2,  2, 59, 44, 44, 44, 44, 70, 43, 43, 85, 87, 43, 36, 36,
-   36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 85, 43,  2, 72,  2,
-    2, 64, 44, 44, 44, 44, 44, 44,  2,  2,  2,  2,  2, 44, 44, 44,
-   63, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 80, 43, 43, 43, 87,
-   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, 89, 43, 43, 43,
-   85, 43, 87, 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, 86, 86, 90,
-   43, 89, 87, 87, 61, 44, 44, 44, 36, 70, 85,107, 64, 44, 44, 44,
-   43, 94, 36, 36, 36, 36, 36, 36, 36, 36, 86, 43, 43, 80, 44, 86,
-   85, 60,  2,  2,  2,  2,  2,  2,  7,  7,  7,  7,  7, 80, 44, 44,
-   27, 27, 91, 67, 67, 67, 56, 20,168, 67, 67, 67, 67, 67, 67, 67,
-   67, 44, 44, 44, 44, 44, 44, 93,105,105,105,105,105,105,105,181,
-    2,  2, 64, 44, 44, 44, 44, 44, 63, 64, 44, 44, 44, 44, 44, 44,
-   65, 65, 65, 65, 65, 65, 65, 65, 71, 36, 36, 70, 43, 43, 43, 43,
-   43, 43, 43, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 43,
-   43, 43, 43, 43, 43, 86, 87, 43, 43, 43, 60, 44, 44, 44, 44, 44,
-   43, 43, 43, 60,  2,  2, 67, 67, 40, 40, 97, 44, 44, 44, 44, 44,
-    7,  7,  7,  7,  7,179, 27, 27, 27, 62, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 44, 44, 62, 36, 40, 69, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 83,164,  2, 27, 27, 27, 30,  2, 64, 44, 44,
-   36, 36, 36, 36, 36, 61, 44, 57, 94, 86, 86, 86, 86, 86, 86, 86,
-   86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 44, 44, 44, 57,
-   43, 74, 40, 40, 40, 40, 40, 40, 40, 88, 80, 44, 44, 44, 44, 44,
-   86, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 62,
-   40, 40, 52, 40, 40, 40, 52, 81, 36, 61, 44, 44, 44, 44, 44, 44,
-   44, 61, 44, 44, 44, 44, 44, 44, 36, 61, 62, 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, 43, 43, 43, 43, 43, 43, 43, 44,
-   43, 43, 43, 80, 44, 44, 44, 44, 67, 67, 67, 92, 55, 67, 67, 67,
-   67, 67,186, 87, 43, 67,186, 86, 86,187, 65, 65, 65, 84, 43, 43,
-   43, 76, 50, 43, 43, 43, 67, 67, 67, 67, 67, 67, 67, 43, 43, 67,
-   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,110, 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,150,150, 16,
-   16, 16,150, 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, 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,
-   16, 16, 16, 16, 16, 39, 16, 16, 16, 16, 16, 16, 16, 16, 16,110,
-   44, 44,150, 16, 16,110, 44, 44, 43, 43, 43, 80, 43, 43, 43, 43,
-   43, 43, 43, 43, 80, 57, 43, 43, 43, 57, 80, 43, 43, 80, 44, 44,
-   40, 40, 40, 40, 40, 40, 40, 44, 44, 44, 44, 44, 44, 44, 44, 57,
-   43, 43, 43, 74, 40, 40, 40, 44,  7,  7,  7,  7,  7, 44, 44, 77,
-   36, 36, 36, 36, 36, 36, 36, 80, 36, 36, 36, 36, 36, 36, 43, 43,
-    7,  7,  7,  7,  7, 44, 44, 96, 36, 36, 36, 36, 36, 83, 43, 43,
-  188,  7,  7,  7,  7,189, 44, 93, 36, 36, 36, 61, 36, 36, 62, 61,
-   36, 36, 61,179, 27, 27, 27, 27, 16, 16, 43, 43, 43, 74, 44, 44,
-   27, 27, 27, 27, 27, 27,163, 27,190, 27,100, 44, 44, 44, 44, 44,
-   27, 27, 27, 27, 27, 27, 27,163, 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,
-   67, 67, 67, 67, 67, 67, 44, 44, 55, 67, 67, 67, 67, 67, 67, 67,
-   27, 27, 27, 27, 27, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 44,
-   44, 44, 44, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44, 44, 44,
-   67, 67, 67, 67, 92, 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, 67, 67,
-   67, 67, 67, 92, 44, 55, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44,
-   67, 67, 67, 67, 67, 44, 44, 55, 67, 67, 67, 92, 44, 44, 44, 67,
-   67, 67, 67, 67, 67, 67, 92, 55, 67, 92, 67, 67, 67, 67, 67, 67,
-   79, 44, 44, 44, 44, 44, 44, 44,171,171,171,171,171,171,171, 44,
-  171,171,171,171,171,171,171,  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, 21,  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, 24,  7,  7,  6,
-    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, 10, 21,
-   17, 21, 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,
-    1,  2, 15,  6, 18,  6, 23,  2, 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, 21, 22, 18, 17, 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,  6,  9, 23, 26,  6, 10,  4,  4,  3,  3,
-    7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 25,  2, 25, 24,  2, 15,
-   12, 15, 14,  2, 21, 14,  7, 15, 12, 17, 21,  1, 26, 10, 10,  1,
-    7, 13, 13,  2, 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,
+   32, 32, 11, 11, 34, 34, 32, 32, 32, 32, 32, 32, 32, 32, 46, 43,
+   51, 39,166, 35, 39, 35, 36, 36, 36, 70, 36, 70, 36, 69, 36, 36,
+   36, 93, 86, 84, 66, 66, 79, 43, 27, 27, 27, 66,167, 43, 43, 43,
+   36, 36,  2,  2, 43, 43, 43, 43, 85, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 85, 85, 85, 85, 85, 85, 85, 85, 42, 43, 43, 43, 43,  2,
+   42, 36, 36, 36,  2, 71, 71, 69, 36, 36, 36, 42, 42, 42, 42,  2,
+   36, 36, 36, 69, 42, 42, 42, 42, 42, 85, 43, 43, 43, 43, 43, 92,
+   36, 69, 85, 42, 42, 85, 42, 85,106,  2,  2,  2,  2,  2,  2, 51,
+    7,  7,  7,  7,  7, 43, 43,  2, 36, 36, 69, 68, 36, 36, 36, 36,
+    7,  7,  7,  7,  7, 36, 36, 60, 36, 36, 36, 36, 69, 42, 42, 84,
+   86, 84, 86, 79, 43, 43, 43, 43, 36, 69, 36, 36, 36, 36, 84, 43,
+    7,  7,  7,  7,  7, 43,  2,  2, 68, 36, 36, 76, 66, 93, 84, 36,
+   70, 42, 70, 69, 70, 36, 36, 42, 69, 60, 43, 43, 43, 43, 43, 43,
+   43, 43, 43, 43, 43, 61, 82,  2, 36, 36, 36, 36, 36, 93, 42, 85,
+    2, 82,168, 79, 43, 43, 43, 43, 61, 36, 36, 60, 61, 36, 36, 60,
+   61, 36, 36, 60, 43, 43, 43, 43, 16, 16, 16, 16, 16,113, 39, 39,
+   16, 16, 16, 16,110, 40, 43, 43, 36, 93, 86, 85, 84,106, 86, 43,
+   36, 36, 43, 43, 43, 43, 43, 43, 36, 36, 36, 60, 43, 61, 36, 36,
+  169,169,169,169,169,169,169,169,170,170,170,170,170,170,170,170,
+   16, 16, 16,109, 43, 43, 43, 43, 43,149, 16, 16, 43, 43, 61, 70,
+   36, 36, 36, 36,171, 36, 36, 36, 36, 36, 36, 60, 36, 36, 60, 60,
+   36, 61, 60, 36, 36, 36, 36, 36, 36, 40, 40, 40, 40, 40, 40, 40,
+   40, 22, 66, 66, 66, 66, 66, 66, 66, 77, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36,147, 66, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 66, 66, 66, 66, 36, 36, 36, 36, 36, 36,167, 66,
+    2,  2,  2,151,129, 43, 43, 43,  6,172,173,147,147,147,147,147,
+  147,147,129,151,129,  2,126,174,  2, 63,  2,  2,155,147,147,129,
+    2,175,  8,176, 65,  2, 43, 43, 36, 36, 60, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 60, 78, 92,  2,  3,  2,  4,  5,  6,  2,
+   16, 16, 16, 16, 16, 17, 18,128,129,  4,  2, 36, 36, 36, 36, 36,
+   68, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 39,
+   43, 36, 36, 36, 43, 36, 36, 36, 43, 36, 36, 36, 43, 36, 60, 43,
+   20,177, 55,178, 26,  8,143, 91, 43, 43, 43, 43, 78, 64, 66, 43,
+   36, 36, 36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 60, 36, 61,
+    2, 63, 43,179, 27, 27, 27, 27, 27, 27, 43, 54, 66, 66, 66, 66,
+  104,104,142, 27, 90, 66, 66, 66, 66, 66, 66, 66, 66, 27, 66, 91,
+   66, 66, 66, 66, 66, 66, 91, 43, 91, 43, 43, 43, 43, 43, 43, 43,
+   66, 66, 66, 66, 66, 66, 49, 43,180, 27, 27, 27, 27, 27, 27, 27,
+   27, 27, 27, 27, 27, 27, 43, 43, 27, 27, 43, 43, 43, 43, 61, 36,
+  154, 36, 36, 36, 36,181, 43, 43, 36, 36, 36, 42, 42, 79, 43, 43,
+   36, 36, 36, 36, 36, 36, 36, 92, 36, 36, 43, 43, 36, 36, 36, 36,
+  182,104,104, 43, 43, 43, 43, 43, 11, 11, 11, 11, 16, 16, 16, 16,
+   11, 11, 43, 43, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 43, 43,
+   36, 36, 36, 36, 43, 43, 43, 43, 36, 36, 43, 43, 43, 43, 43, 92,
+   11, 11, 11, 11, 11, 46, 11, 11, 11, 46, 11,149, 16, 16, 16, 16,
+   16,149, 16, 16, 16, 16, 16, 16, 16,149, 16, 16, 16,149,109, 43,
+   39, 39, 39, 51, 39, 39, 39, 39, 80, 39, 39, 39, 39, 80, 43, 43,
+   36, 36, 36, 43, 60, 36, 36, 36, 36, 36, 36, 61, 60, 43, 60, 61,
+   36, 36, 36, 92, 27, 27, 27, 27, 36, 36, 36, 76,162, 27, 27, 27,
+   43, 43, 43,179, 27, 27, 27, 27, 36, 60, 36, 43, 43,179, 27, 27,
+   36, 36, 36, 27, 27, 27, 43, 92, 36, 36, 36, 36, 36, 43, 43, 92,
+   36, 36, 36, 36, 43, 43, 27, 36, 43, 27, 27, 27, 27, 27, 27, 27,
+   69, 42, 56, 79, 43, 43, 42, 42, 36, 36, 61, 36, 61, 36, 36, 36,
+   36, 36, 36, 43, 42, 79, 43, 56, 27, 27, 27, 27, 99, 43, 43, 43,
+    2,  2,  2,  2, 63, 43, 43, 43, 36, 36, 36, 36, 36, 36,183, 30,
+   36, 36, 36, 36, 36, 36,183, 27, 36, 36, 36, 36, 77, 36, 36, 36,
+   36, 36, 69, 79, 43,179, 27, 27,  2,  2,  2, 63, 43, 43, 43, 43,
+   36, 36, 36, 43, 92,  2,  2,  2, 36, 36, 36, 43, 27, 27, 27, 27,
+   36, 60, 43, 43, 27, 27, 27, 27, 36, 43, 43, 43, 92,  2, 63, 43,
+   43, 43, 43, 43,179, 27, 27, 27, 11, 46, 43, 43, 43, 43, 43, 43,
+   16,109, 43, 43, 43, 27, 27, 27, 36, 36, 42, 42, 43, 43, 43, 43,
+    7,  7,  7,  7,  7, 36, 36, 68, 11, 11, 11, 43, 56, 42, 42,158,
+   16, 16, 16, 43, 43, 43, 43,  8, 27, 27, 27, 27, 27, 27, 27, 99,
+   36, 36, 36, 36, 36, 56,184, 43, 36, 43, 43, 43, 43, 43, 43, 43,
+   43, 36, 82, 36, 43, 43, 43, 43, 96, 66, 66, 66, 91, 43, 43, 43,
+   43, 43, 43, 43, 43, 42, 42, 42, 27, 27, 27, 94, 43, 43, 43, 43,
+  180, 27, 30,  2,  2, 43, 43, 43, 36, 42, 42,  2,  2, 43, 43, 43,
+   36, 36,183, 27, 27, 27, 43, 43, 86, 97, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 42, 42, 42, 42, 42, 42, 42, 59,  2,  2,  2, 43,
+   27, 27, 27,  7,  7,  7,  7,  7, 70, 69, 70, 43, 43, 43, 43, 56,
+   85, 86, 42, 84, 86, 59,185,  2,  2, 79, 43, 43, 43, 43, 78, 43,
+   42, 70, 36, 36, 36, 36, 36, 36, 36, 36, 36, 69, 42, 42, 86, 42,
+   42, 42, 79,  7,  7,  7,  7,  7,  2,  2, 93, 97, 43, 43, 43, 43,
+   36, 69,  2, 60, 43, 43, 43, 43, 36, 93, 85, 42, 42, 42, 42, 84,
+   97, 36, 62,  2, 58, 42, 59, 86,  7,  7,  7,  7,  7, 62, 62,  2,
+  179, 27, 27, 27, 27, 27, 27, 27, 27, 27, 99, 43, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 36, 85, 86, 42, 85, 84, 42,  2,  2,  2, 70,
+   69, 43, 43, 43, 43, 43, 43, 43, 36, 36, 36, 60, 60, 36, 36, 61,
+   36, 36, 36, 36, 36, 36, 36, 61, 36, 36, 36, 36, 62, 43, 43, 43,
+   36, 36, 36, 36, 36, 36, 36, 69, 85, 86, 42, 42, 42, 79, 43, 43,
+   42, 85, 61, 36, 36, 36, 60, 61, 60, 36, 61, 36, 36, 56, 70, 85,
+   84, 85, 89, 88, 89, 88, 85, 43, 60, 43, 43, 88, 43, 43, 61, 36,
+   36, 85, 43, 42, 42, 42, 79, 43, 42, 42, 79, 43, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 61, 43, 60, 36, 36, 36, 61, 85, 86, 42, 42,
+   79, 89, 88, 88, 85, 89, 85, 84, 70, 70,  2, 92, 63, 43, 43, 43,
+   56, 79, 43, 43, 43, 43, 43, 43, 36, 36, 93, 85, 42, 42, 42, 42,
+   85, 42, 84, 70, 36, 62,  2,  2,  7,  7,  7,  7,  7,  2, 92, 70,
+   85, 86, 42, 42, 84, 84, 85, 86, 84, 42, 36, 71, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 36, 36, 93, 85, 42, 42, 43, 85, 85, 42, 86,
+   59,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 36, 36, 42, 43,
+   85, 86, 42, 42, 42, 84, 86, 86, 59,  2, 60, 43, 43, 43, 43, 43,
+    2,  2,  2,  2,  2,  2, 63, 43, 36, 36, 36, 36, 36, 69, 86, 85,
+   42, 42, 42, 86, 62, 43, 43, 43,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 60, 56, 86,
+   85, 42, 42, 86, 42, 42, 43, 43,  7,  7,  7,  7,  7, 27,  2, 96,
+   42, 42, 42, 42, 86, 59, 43, 43, 27, 99, 43, 43, 43, 43, 43, 61,
+   36, 36, 36, 60, 61, 43, 36, 36, 36, 36, 61, 60, 36, 36, 36, 36,
+   85, 85, 85, 88, 89, 56, 84, 70, 97, 86,  2, 63, 43, 43, 43, 43,
+   36, 36, 36, 36, 43, 36, 36, 36, 93, 85, 42, 42, 43, 42, 85, 85,
+   70, 71, 89, 43, 43, 43, 43, 43, 69, 42, 42, 42, 42, 70, 36, 36,
+   36, 69, 42, 42, 84, 69, 42, 59,  2,  2,  2, 58, 43, 43, 43, 43,
+   69, 42, 42, 84, 86, 42, 36, 36, 36, 36, 36, 36, 36, 42, 42, 42,
+   42, 42, 42, 84, 42,  2, 71,  2,  2, 63, 43, 43, 43, 43, 43, 43,
+    2,  2,  2,  2,  2, 43, 43, 43, 84, 42, 84, 84, 43, 43, 43, 43,
+   62, 43, 43, 43, 43, 43, 43, 43, 42, 42, 42, 79, 42, 42, 42, 86,
+   62,  2,  2, 43, 43, 43, 43, 43,  2, 36, 36, 36, 36, 36, 36, 36,
+   43, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 88, 42, 42, 42,
+   84, 42, 86, 79, 43, 43, 43, 43, 36, 36, 36, 60, 36, 61, 36, 36,
+   69, 42, 42, 79, 43, 79, 42, 56, 42, 42, 42, 69, 43, 43, 43, 43,
+   36, 36, 36, 61, 60, 36, 36, 36, 36, 36, 36, 36, 36, 85, 85, 89,
+   42, 88, 86, 86, 60, 43, 43, 43, 36, 36, 36, 36, 82, 36, 43, 43,
+   36, 69, 84,106, 63, 43, 43, 43, 42, 93, 36, 36, 36, 36, 36, 36,
+   36, 36, 85, 42, 42, 79, 43, 85, 84, 59,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7, 79, 43, 43, 27, 27, 90, 66, 66, 66, 55, 20,
+  167, 66, 66, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43, 43, 43, 92,
+  104,104,104,104,104,104,104,181,  2,  2, 63, 43, 43, 43, 43, 43,
+   62, 63, 43, 43, 43, 43, 43, 43, 64, 64, 64, 64, 64, 64, 64, 64,
+   70, 36, 36, 69, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 36, 36, 42, 42, 42, 42, 42, 42, 85, 86, 42,
+   42, 42, 59, 43, 43, 43, 43, 43, 42, 42, 42, 59,  2,  2, 66, 66,
+   39, 39, 96, 43, 43, 43, 43, 43,  7,  7,  7,  7,  7,179, 27, 27,
+   27, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 61, 36,
+   39, 68, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 82,163,  2,
+   27, 27, 27, 30,  2, 63, 43, 43, 11, 11, 11, 11, 46,149, 16, 16,
+   16, 16, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 60, 43, 56,
+   93, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+   85, 85, 85, 85, 43, 43, 43, 56, 42, 73, 39, 39, 39, 39, 39, 39,
+   39, 87, 79, 43, 43, 43, 43, 43, 85, 39,104,181, 43, 43, 43, 43,
+   43, 43, 43, 43, 43, 43, 43, 61, 36, 60, 43, 43, 43, 43, 43, 43,
+   39, 39, 51, 39, 39, 39, 51, 80, 43, 60, 43, 43, 43, 43, 43, 43,
+   36, 60, 61, 43, 43, 43, 43, 43, 43, 43, 36, 36, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 43, 49, 59, 64, 64, 43, 43, 43, 43, 43, 43,
+    7,  7,  7,  7,  7, 66, 91, 43, 66, 66, 43, 43, 43, 66, 66, 66,
+  176, 43, 43, 43, 43, 43, 43, 43, 42, 42, 42, 79, 43, 43, 43, 43,
+   66, 66, 66, 91, 54, 66, 66, 66, 66, 66,186, 86, 42, 66,186, 85,
+   85,187, 64, 64, 64, 83, 42, 42, 42, 75, 49, 42, 42, 42, 66, 66,
+   66, 66, 66, 66, 66, 42, 42, 66, 66, 42, 75, 43, 43, 43, 43, 43,
+   27, 27, 43, 43, 43, 43, 43, 43, 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,109, 16, 16, 16, 16, 16, 11, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 46, 11, 43, 46, 47, 46, 47, 11, 46, 11,
+   11, 11, 11, 16, 16,149,149, 16, 16, 16,149, 16, 16, 16, 16, 16,
+   16, 16, 11, 47, 11, 46, 47, 11, 11, 11, 46, 11, 11, 11, 46, 16,
+   16, 16, 16, 16, 11, 47, 11, 46, 11, 11, 46, 46, 43, 11, 11, 11,
+   46, 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, 43, 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, 43,  7,
+   42, 42, 42, 75, 66, 49, 42, 42, 42, 42, 42, 42, 42, 42, 75, 66,
+   66, 66, 49, 66, 66, 66, 66, 66, 66, 66, 75, 21,  2,  2, 43, 43,
+   43, 43, 43, 43, 43, 56, 42, 42, 16, 16, 16, 16, 16,138, 16, 16,
+   16, 16, 16, 16, 16, 16, 16,109, 43, 43,149, 16, 16,109, 43, 43,
+   42, 42, 42, 79, 42, 42, 42, 42, 42, 42, 42, 42, 79, 56, 42, 42,
+   42, 56, 79, 42, 42, 79, 43, 43, 39, 39, 39, 39, 39, 39, 39, 43,
+   43, 43, 43, 43, 43, 43, 43, 56, 42, 42, 42, 73, 39, 39, 39, 43,
+    7,  7,  7,  7,  7, 43, 43, 76, 36, 36, 36, 36, 36, 36, 36, 79,
+   36, 36, 36, 36, 36, 36, 42, 42,  7,  7,  7,  7,  7, 43, 43, 95,
+   36, 36, 36, 36, 36, 82, 42, 42,188,  7,  7,  7,  7,189, 43, 92,
+   36, 69, 36, 70, 36, 36, 36, 42, 36, 36, 69, 43, 43, 43, 43, 82,
+   36, 36, 36, 60, 36, 36, 61, 60, 36, 36, 60,179, 27, 27, 27, 27,
+   16, 16, 42, 42, 42, 73, 43, 43, 27, 27, 27, 27, 27, 27,162, 27,
+  190, 27, 99, 43, 43, 43, 43, 43, 27, 27, 27, 27, 27, 27, 27,162,
+   27, 27, 27, 27, 27, 27, 27, 43, 36, 36, 61, 36, 36, 36, 36, 36,
+   61, 60, 60, 61, 61, 36, 36, 36, 36, 60, 36, 36, 61, 61, 43, 43,
+   43, 60, 43, 61, 61, 61, 61, 36, 61, 60, 60, 61, 61, 61, 61, 61,
+   61, 60, 60, 61, 36, 60, 36, 36, 36, 60, 36, 36, 61, 36, 60, 60,
+   36, 36, 36, 36, 36, 61, 36, 36, 61, 36, 61, 36, 36, 61, 36, 36,
+    8, 43, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 66, 66, 43, 43,
+   54, 66, 66, 66, 66, 66, 66, 66, 27, 27, 27, 27, 27, 27, 90, 66,
+   66, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43, 66, 66, 66, 66, 66,
+   66, 91, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 91, 43, 43, 43,
+   66, 43, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 66, 25, 40, 40,
+   66, 66, 66, 66, 91, 43, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43,
+    8,  8,  8,  8,176, 43, 43, 43, 66, 66, 66, 66, 66, 91, 43, 66,
+   66, 66, 66, 91, 91, 43, 54, 66, 66, 66, 66, 66, 66, 66, 91, 54,
+   66, 66, 66, 66, 66, 91, 43, 54, 66, 91, 66, 66, 66, 66, 66, 66,
+    7,  7,  7,  7,  7, 91, 43, 43, 78, 43, 43, 43, 43, 43, 43, 43,
+  170,170,170,170,170,170,170, 43,170,170,170,170,170,170,170,  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,  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, 21,  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, 24,  7,  7,  6,  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, 10, 21, 17, 21, 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,  1,  2, 15,  6, 18,  6, 12, 11,  9, 26,
+   26,  9, 26,  5,  7,  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, 21, 22,
+   18, 17, 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,  6,  9, 23, 26,
+    6, 10,  4,  4,  3,  3,  7, 25, 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,  7, 13, 13,  2, 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, 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, 34,  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, 35,  0,  0,  0,  0, 36,  0, 37,  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, 34,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 35,  0,
+    0,  0,  0, 36,  0, 37,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0, 38,  0,  0,  0,  0,  0,  0,  0,  0,  0, 39, 40,
-    0,  0,  0,  0,  0,  0, 41, 42, 43,  0, 44,  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, 14, 15,
-   16, 17, 16, 18, 16, 19, 16, 19, 16, 19,  0, 19, 16, 20, 16, 19,
-   21, 19,  0, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,  0, 32,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0, 33,  0,  0,  0,  0,  0,  0,
-   34,  0,  0, 35,  0,  0, 36,  0, 37,  0,  0,  0, 38, 39, 40, 41,
-   42, 43, 44, 45, 46,  0,  0, 47,  0,  0,  0, 48,  0,  0,  0, 49,
-    0,  0,  0,  0,  0,  0,  0, 50,  0, 51,  0, 52, 53,  0, 54,  0,
-    0,  0,  0,  0,  0, 55, 56, 57,  0,  0,  0,  0, 58,  0,  0, 59,
-   60, 61, 62, 63,  0,  0, 64, 65,  0,  0,  0, 66,  0,  0,  0,  0,
-   67,  0,  0,  0, 68,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0, 69,  0,  0,  0, 70,  0, 71,  0,  0, 72,  0,  0, 73,
-    0,  0,  0,  0,  0,  0,  0,  0, 74, 75,  0,  0,  0,  0, 76, 77,
-    0, 78, 79,  0,  0, 80, 81,  0, 82, 62,  0, 83, 84,  0,  0, 85,
-   86, 87,  0, 88,  0, 89,  0, 90,  0,  0, 51, 91, 51,  0, 92,  0,
-   93,  0,  0,  0, 81,  0,  0,  0, 94, 95,  0, 96, 97, 98, 99,  0,
-    0,  0,  0,  0, 51,  0,  0,  0,  0,100,101,  0,  0,  0,  0,  0,
-    0,102,  0,  0,  0,  0,  0,  0,103,  0,  0,  0,  0,  0,  0,104,
-  105,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,106,  0,  0,107,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,108,109,  0,  0,110,  0,  0,
-    0,  0,  0,  0,111,  0,112,  0,105,  0,  0,  0,  0,  0,113,114,
-    0,  0,  0,  0,  0,  0,  0,115,  0,  0,  0,116,  0,  0,  0,117,
-    0,118,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 38,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 39, 40,  0,  0,  0,  0,  0,  0, 41, 42,
+   43, 44, 45,  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, 14, 15, 16, 17, 16, 18, 16, 19, 16, 19,
+   16, 19,  0, 19, 16, 20, 16, 19, 21, 19,  0, 22, 23, 24, 25, 26,
+   27, 28, 29, 30, 31,  0, 32,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 33,  0,  0,  0,  0,  0,  0, 34,  0,  0, 35,  0,  0, 36,  0,
+   37,  0,  0,  0, 38, 39, 40, 41, 42, 43, 44, 45, 46,  0,  0, 47,
+    0,  0,  0, 48,  0,  0,  0, 49,  0,  0,  0,  0,  0,  0,  0, 50,
+    0, 51,  0, 52, 53,  0, 54,  0,  0,  0,  0,  0,  0, 55, 56, 57,
+    0,  0,  0,  0, 58,  0,  0, 59, 60, 61, 62, 63,  0,  0, 64, 65,
+    0,  0,  0, 66,  0,  0,  0,  0, 67,  0,  0,  0, 68,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 69,  0,  0,  0, 70,
+    0, 71,  0,  0, 72,  0,  0, 73,  0,  0,  0,  0,  0,  0,  0,  0,
+   74, 75,  0,  0,  0,  0, 76, 77,  0, 78, 79,  0,  0, 80, 81,  0,
+   82, 62,  0, 83, 84,  0,  0, 85, 86, 87,  0, 88,  0, 89,  0, 90,
+    0,  0, 51, 91, 51,  0, 92,  0, 93,  0,  0,  0, 81,  0,  0,  0,
+   94, 95,  0, 96, 97, 98, 99,  0,  0,  0,  0,  0, 51,  0,  0,  0,
+    0,100,101,  0,  0,  0,  0,  0,  0,102,  0,  0,  0,  0,  0,  0,
+  103,  0,  0,  0,  0,  0,  0,104,105,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,106,  0,  0,107,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,108,109,  0,  0,110,  0,  0,  0,  0,  0,  0,111,  0,112,  0,
+  105,  0,  0,  0,  0,  0,113,114,  0,  0,  0,  0,  0,  0,  0,115,
+    0,  0,  0,116,  0,  0,  0,117,  0,  0,  0,  0,  0,  0,  0,118,
+    0,119,  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,  0,  0,
@@ -3371,629 +3219,451 @@ _hb_ucd_u8[17524] =
     0, 43,  0, 44,  0,  0,  0, 45, 46,  0,  0,  0, 47,  0,  0,  0,
     0,  0,  0, 48, 49,  0,  0,  0,  0, 50,  0,  0,  0, 51,  0, 52,
     0, 53,  0,  0,  0,  0, 54,  0,  0,  0,  0, 55,  0, 56,  0,  0,
-    0,  0, 57, 58,  0,  0,  0, 59, 60,  0,  0,  0,  0,  0,  0, 61,
-   52,  0, 62, 63,  0,  0, 64,  0,  0,  0, 65, 66,  0,  0,  0, 67,
-    0, 68, 69, 70, 71, 72,  1, 73,  0, 74, 75, 76,  0,  0, 77, 78,
-    0,  0,  0, 79,  0,  0,  1,  1,  0,  0, 80,  0,  0, 81,  0,  0,
-    0,  0, 77, 82,  0, 83,  0,  0,  0,  0,  0, 78, 84,  0, 85,  0,
-   52,  0,  1, 78,  0,  0, 86,  0,  0, 87,  0,  0,  0,  0,  0, 88,
-   57,  0,  0,  0,  0,  0,  0, 89, 90,  0,  0, 84,  0,  0, 33,  0,
-    0, 91,  0,  0,  0,  0, 92,  0,  0,  0,  0, 49,  0,  0, 93,  0,
-    0,  0,  0, 94, 95,  0,  0, 96,  0,  0, 97,  0,  0,  0, 98,  0,
-    0,  0, 99,  0,  0,  0,100,  0,  0,  0,  0,101,102, 93,  0,  0,
-  103,  0,  0,  0, 84,  0,  0,104,  0,  0,  0,105,106,  0,  0,107,
-  108,  0,  0,  0,  0,  0,  0,109,  0,  0,110,  0,  0,  0,  0,111,
-   33,  0,112,113,114, 57,  0,  0,115, 35,  0,  0,116,  0,  0,  0,
-  117,  0,  0,  0,  0,  0,  0,118,  0,  0,119,  0,  0,  0,  0,120,
-   88,  0,  0,  0,  0,  0, 57,  0,  0,  0,  0, 52,121,  0,  0,  0,
-    0,122,  0,  0,123,  0,  0,  0,  0,121,  0,  0,124,  0,  0,  0,
-    0,  0, 79,  0,  0,  0,  0,125,  0,  0,  0,126,  0,  0,  0,127,
-    0,128,  0,  0,  0,  0,129,130,131,  0,132,  0,133,  0,  0,  0,
-  134,135,136,  0, 77,  0,  0,  0,  0,  0, 35,  0,  0,  0,137,  0,
-    0,  0,138,  0,  0,  0,139,  0,  0,140,  0,  0,141,  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,  0, 19, 52,  1,
-    0,  0, 38, 14,  4,  1,  1,  1, 53, 21, 43, 52, 54, 21, 35,  1,
-    0,  0,  0, 55,  0,  0,  0, 56, 57, 58,  0,  0,  0,  0,  0, 59,
-    0, 60,  0,  0,  0,  0, 61, 62,  0,  0, 63,  0,  0,  0, 64,  0,
-    0,  0, 65,  0,  0,  0, 66,  0,  0,  0, 67,  0,  0,  0, 68,  0,
-    0, 69, 70,  0, 71, 72, 73, 74, 75, 76,  0,  0,  0, 77,  0,  0,
-    0, 78, 79,  0,  0,  0,  0, 47,  0,  0,  0, 49,  0, 80,  0,  0,
-    0, 62,  0,  0, 63,  0,  0, 81,  0,  0, 82,  0,  0,  0, 83,  0,
-    0, 19, 84,  0, 62,  0,  0,  0,  0, 49,  1, 85,  1, 52, 15, 86,
-   36, 10, 21, 87,  0, 55,  0,  0,  0,  0, 19, 10,  1,  0,  0,  0,
-    0,  0, 88,  0,  0, 89,  0,  0, 88,  0,  0,  0,  0, 78,  0,  0,
-   87,  9, 12,  4, 90,  8, 91, 47,  0, 58, 50,  0, 21,  1, 21, 92,
-   93,  1,  1,  1,  1, 94, 95, 96, 97,  1, 98, 58, 81, 99,100,  4,
-   58,  0,  0,  0,  0,  0,  0, 19, 50,  0,  0,  0,  0,  0,  0, 61,
-    0,  0,101,102,  0,  0,103,  0,  0,  1,  1, 50,  0,  0,  0, 38,
-    0, 63,  0,  0,  0,  0,  0, 62,  0,  0,104, 68, 61,  0,  0,  0,
-   78,  0,  0,  0,105,106, 58, 38, 81,  0,  0,  0,  0,  0,  0,107,
-    1, 14,  4, 12, 84,  0,  0,  0,  0, 38, 87,  0,  0,  0,  0,108,
-    0,  0,109, 61,  0,110,  0,  0,  0,  1,  0,  0,  0,  0, 49, 50,
-    0,  0, 19, 58,  0,  0,  0, 51,  0,111, 14, 52,112, 41,  0,  0,
-   62,  0,  0, 61,  0,  0,113,  0, 87,  0,  0,  0, 61, 62,  0,  0,
-   62,  0, 89,  0,  0,113,  0,  0,  0,  0,114,  0,  0,  0, 78, 55,
-    0, 38,  1, 58,  1, 58,  0,  0,  0,  0,  0, 88, 63, 89,  0,  0,
-  115,  0,  0,  0, 55,  0,  0,  0,  0,115,  0,  0,  0,  0, 61,  0,
-    0,  0,  0, 79,  0, 61,  0,  0,  0,  0, 56,  0, 89, 80,  0,  0,
-   79,  0,  0,  0,  8, 91,  0,  0,  1, 87,  0,  0,116,  0,  0,  0,
-    0,  0,  0,117,  0,118,119,120,121,  0,104,  4,122, 49, 23,  0,
-    0,  0, 38, 50, 38, 58,  0,  0,  1, 87,  1,  1,  1,  1, 39,  1,
-   48,105, 87,  0,  0,  0,  0,  1,  0,  0,  0,123,  0,  0,  0,112,
-    4,122,  0,  0,  0,  1,124,  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,230,220,220,220,230,230,  0,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,  9,  9,  0,  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,230,230,230,  0,  0,  0,  9,  9,  0,  0,  7,  0,
-  230,  0,  1,  1,  1,  0,  0,  0,230,234,214,220,202,230,230,230,
-  230,230,232,228,228,220,218,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,  0,  0,  0,220,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,  0,230,220,  0,  9,  7,  0,
-    0,  7,  9,  0,  0,  0,  9,  7,  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,232,232,220,230,230,230,  7,  0, 16, 17, 17, 33,
-   17, 49, 17, 17, 84, 97,135,145, 26, 17, 17, 17, 17, 17, 17, 17,
+    0,  0, 57, 58,  0,  0,  0, 59, 60, 61, 62,  0,  0,  0,  0, 63,
+   52,  0, 64, 65,  0,  0, 66,  0,  0,  0, 67, 68,  0,  0,  0, 69,
+    0, 70, 71, 72, 73, 74,  1, 75,  0, 76, 77, 78,  0,  0, 79, 80,
+    0,  0,  0, 81,  0,  0,  1,  1,  0,  0, 82,  0,  0, 83,  0,  0,
+    0,  0, 79, 84,  0, 85,  0,  0,  0,  0,  0, 80, 86,  0, 87,  0,
+   52,  0,  1, 80,  0,  0, 88,  0,  0, 89,  0,  0,  0,  0,  0, 90,
+   57,  0,  0,  0,  0,  0,  0, 91, 92,  0,  0, 86,  0,  0, 33,  0,
+    0, 93,  0,  0,  0,  0, 94,  0,  0,  0,  0, 49,  0,  0, 95,  0,
+    0,  0,  0, 96, 97,  0,  0, 98,  0,  0, 99,  0,  0,  0,100,  0,
+    0,  0,101,  0,  0,  0,102,  0,  0,  0,  0,103,104, 95,  0,  0,
+  105,  0,  0,  0, 86,  0,  0,106,  0,  0,  0,107,108,  0,  0,109,
+  110,  0,  0,  0,  0,  0,  0,111,  0,  0,112,  0,  0,  0,  0,113,
+   33,  0,114,115,116, 57,  0,  0,117, 35,  0,  0,118,  0,  0,  0,
+  119,  0,  0,  0,  0,  0,  0,120,  0,  0,121,  0,  0,  0,  0,122,
+   90,  0,  0,  0,  0,  0, 57,  0,  0,  0,  0, 52,123,  0,  0,  0,
+    0,124,  0,  0,125,  0,  0,  0,  0,123,  0,  0,126,  0,  0,  0,
+    0,  0, 81,  0,  0,  0,  0,127,  0,  0,  0,128,  0,  0,  0,129,
+    0,130,  0,  0,  0,  0,131,132,133,  0,134,  0,135,  0,  0,  0,
+  136,137,138,  0, 79,  0,  0,  0,  0,  0, 35,  0,  0,  0,139,  0,
+    0,  0,140,  0,  0,  0,141,  0,  0,  0,142,143,  0,144,  0,  0,
+  145,  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,
+    0, 19, 52,  1,  0,  0, 38, 14,  4,  1,  1,  1, 53, 21, 43, 52,
+   54, 21, 35,  1,  0,  0,  0, 55,  0,  0,  0, 56, 57, 58,  0,  0,
+    0,  0,  0, 59,  0, 60,  0,  0,  0,  0, 61, 62,  0,  0, 63,  0,
+    0,  0, 64,  0,  0,  0, 65,  0,  0,  0, 66,  0,  0,  0, 67,  0,
+    0,  0, 68,  0,  0, 69, 70,  0, 71, 72, 73, 74, 75, 76,  0,  0,
+    0, 77,  0,  0,  0, 78, 79,  0,  0,  0,  0, 47,  0,  0,  0, 49,
+    0, 80,  0,  0,  0, 62,  0,  0, 63,  0,  0, 81,  0,  0, 82,  0,
+    0,  0, 83,  0,  0, 19, 84,  0, 62,  0,  0,  0,  0, 49,  1, 85,
+    1, 52, 15, 86, 36, 10, 21,  1,  1,  1,  1, 41,  1, 21, 87,  0,
+    0, 55,  0,  0,  0,  0, 19, 10,  1,  0,  0,  0,  0,  0, 88,  0,
+    0, 89,  0,  0, 88,  0,  0,  0,  0, 78,  0,  0, 90,  9, 12,  4,
+   91,  8, 92, 47,  0, 58, 50,  0, 21,  1, 21, 93, 94,  1,  1,  1,
+    1, 95, 96, 97, 98,  1, 99, 58, 81,100,101,  4, 58,  0,  0,  0,
+    0,  0,  0, 19, 50,  0,  0,  0,  0,  0,  0, 61,  0,  0,102,103,
+    0,  0,104,  0,  0,  1,  1, 50,  0,  0,  0, 38,  0, 63,  0,  0,
+    0,  0,  0, 62,  0,  0,105, 68, 61,  0,  0,  0, 78,  0,  0,  0,
+  106,107, 58, 38, 81,  0,  0,  0,  0,  0,  0,108,  1, 14,  4, 12,
+   84,  0,  0,  0,  0, 38, 90,  0,  0,  0,  0,109,  0,  0,110, 61,
+    0,111,  0,  0,  0,  1,  0,  0,  0,  0, 49, 50,  0,  0, 19, 58,
+    0,  0,112, 51,  0,112, 14, 52,113, 41,  0,  0, 62,  0,  0, 61,
+    0,  0,114,  0, 90,  0,  0,  0, 61, 62,  0,  0, 62,  0, 89,  0,
+    0,114,  0,  0,  0,  0,115,  0,  0,  0, 78, 55,  0, 38,  1, 58,
+    1, 58,  0,  0,  0,  0,  0, 88, 63, 89,  0,  0,116,  0,  0,  0,
+   55,  0,  0,  0,  0,116,  0,  0,  0,  0, 61,  0,  0,  0,  0, 79,
+    0, 61,  0,  0,  0,  0, 56,  0, 89, 80,  0,  0, 79,  0,  0,  0,
+    8, 92,  0,  0,  1, 90,  0,  0,117,  0,  0,  0,  0,  0,  0,118,
+    0,119,120,121,122,  0,105,  4,123, 49, 23,  0,  0,  0, 38, 50,
+   38, 58,  0,  0,  1, 90,  1,  1,  1,  1, 39,  1, 48,106, 90,  0,
+    0,  0,  0,  1,  0,  0,  0,124,  0,  0,  0,113, 19, 59,  0, 38,
+    0, 81,  0,  0,  4,123,  0,  0,  0,  1,125,  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,230,220,220,220,
+  230,230,  0,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,  9,  9,  0,  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,230,230,230,234,  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,218,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,
+    0,  0,  0,220,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,  0,230,220,  0,  9,  7,  0,  0,  7,  9,  0,  0,  0,  9,  7,
+    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,232,232,220,230,
+  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, 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, 24,  3,  3,  3,  3,  3,  3, 25,  3,  3,  3,
-    3,  3,  3,  3,  3, 26,  3,  3, 27, 28,  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,  0, 56, 57,
-    0,  0,  0,  0,  0, 19, 58, 31,  0,  0,  0,  0,  0,  0,  0, 59,
-   14,  0,  0,  0,  0,  1,  0,  2,  0,  0,  0,  3,  0,  0,  0, 60,
-   61,  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,  0,  0,  8, 21, 21, 21,  9,  0,  1,  0,  1,  1,
-    8, 21, 21,  9,  0,  4,  5,  8,  9,  1,  0,  0,  0,  1,  2,  3,
-    4,  5,  5,  5,  5,  5,  6,  7,  7,  8,  9, 10, 11, 12, 13, 14,
-   15,  9, 16, 17, 18,  9, 19, 20, 21, 22, 23, 24,  5,  5,  5,  5,
-    5,  5,  5,  5,  5,  5, 25, 26, 27,  5, 28, 29,  5, 30, 31,  9,
+   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, 24,  3,  3,
+    3,  3,  3,  3, 25,  3,  3,  3,  3,  3,  3,  3,  3, 26,  3,  3,
+   27, 28,  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,  0, 56, 57,  0,  0,  0,  0,  0, 19, 58, 31,
+    0,  0,  0,  0,  0,  0,  0, 59, 14,  0,  0,  0,  0,  1,  0,  2,
+    0,  0,  0,  3,  0,  0,  0, 60, 61,  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,  0,  0,  8, 21,
+   21, 21,  9,  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, 12, 13,
+   13, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 13, 13, 13,
+   24, 25, 26, 26, 26, 27, 13, 13, 13, 28, 29, 30, 13, 31, 32, 33,
+   34, 35, 36, 37,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7, 38,  7,  7, 39,  7, 40,  7,  7,
+    7, 41, 13, 42,  7,  7, 43,  7,  7,  7, 44, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 13, 13, 13,
+   13, 13, 13, 13, 45,  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, 59, 63, 64,
+   65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 59, 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, 69, 69, 69,
+   69, 78, 69, 69, 69, 69, 79, 79, 79, 79, 79, 79, 79, 79, 79, 80,
+   81, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 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, 94, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+   95, 95, 95, 95, 95, 95, 95, 95, 69, 69, 96, 97, 98, 99, 99, 99,
+  100,101,102,103,104,105,106,107,108,109, 95,110,111,112,113,114,
+  115,116,117,117,118,119,120,121,122,123,124,125,126,127,128,129,
+  130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,
+   95,146,147,148,149, 95,150,151,152,153,154,155,156,157,158,159,
+  160,161, 95,162,163,164,165,165,165,165,165,165,165,166,167,165,
+  168, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+   95, 95, 95, 95, 95,169,170,170,170,170,170,170,170,170,171,170,
+  170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,
+  170,170,170,170,170,170,170,170,170,170,170,170,170,172,173,173,
+  173,173,174, 95, 95, 95, 95, 95,175, 95, 95, 95, 95, 95, 95, 95,
+   95, 95, 95, 95, 95, 95,176,176,176,176,177,178,179,180, 95, 95,
+  181, 95,182,183,184,185,186,186,186,186,186,186,186,186,186,186,
+  186,186,186,186,186,186,186,186,186,186,186,186,187,187,187,188,
+  189,190, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+   95, 95, 95, 95, 95,191,192,193,194,195,195,196, 95, 95, 95, 95,
+   95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,197,198,
+   95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 59,199,
+   59, 59, 59,200,201,202, 59,203,204,205,206,207,208, 95,209,210,
+  211, 59, 59,212, 59,213,214,214,214,214,214,215, 95, 95, 95, 95,
+   95, 95, 95, 95,216, 95,217,218,219, 95, 95,220, 95, 95, 95,221,
+   95,222, 95,223, 95,224,225,226,227, 95, 95, 95, 95, 95,228,229,
+  230, 95,231,232, 95, 95,233,234, 59,235,236, 95, 59, 59, 59, 59,
+   59, 59, 59,237, 59,238,239,240, 59, 59,241,242, 59,243, 95, 95,
+   95, 95, 95, 95, 95, 95, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+   69, 69, 69,244, 69, 69,245, 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,246, 69, 69, 69, 69, 69, 69, 69, 69, 69,247, 69, 69,
+   69, 69,248, 95, 95, 95, 69, 69, 69, 69,249, 95, 95, 95, 95, 95,
+   95, 95, 95, 95, 95, 95, 69, 69, 69, 69, 69, 69,250, 69, 69, 69,
+   69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,251, 95,
+   95, 95, 95, 95, 95, 95,252, 95,253,254,  0,  1,  2,  2,  0,  1,
+    2,  2,  2,  3,  4,  5,  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,  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,  2,  9,  9,  9, 55, 55, 55, 55,
+   55, 55,  6,  6,  6,  6,  6,  1,  1,  6,  2,  4,  4,  4,  4,  4,
+    4,  4,  4,  4,  4,  2,  2, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14,  2,  2,  2,  2, 14, 14,  2,  2,  2,  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, 37, 37,  2, 37, 37, 37,
+   37,  2,  2, 37, 37, 37, 38, 38, 38, 38, 38, 38,  2,  2, 64, 64,
+   64, 64, 64, 64, 64,  2,  2, 64, 64, 64, 90, 90, 90, 90, 90, 90,
+    2,  2, 90, 90, 90,  2, 95, 95, 95, 95,  2,  2, 95,  2,  3,  3,
+    2,  2,  2,  2,  2,  3,  3,  3,  0,  3,  7,  7,  7,  7,  7,  1,
+    1,  1,  1,  7,  7,  7,  0,  0,  7,  7,  5,  5,  5,  5,  2,  5,
+    5,  5,  5,  2,  2,  5,  5,  2,  5,  5,  5,  2,  5,  2,  2,  2,
+    5,  5,  5,  5,  2,  2,  5,  5,  5,  2,  2,  2,  2,  5,  5,  5,
+    2,  5,  2, 11, 11, 11, 11, 11, 11,  2,  2,  2,  2, 11, 11,  2,
+    2, 11, 11, 11, 11, 11, 11,  2, 11, 11,  2, 11, 11,  2, 11, 11,
+    2,  2,  2, 11,  2,  2, 11,  2, 11,  2,  2,  2, 11, 11,  2, 10,
+   10, 10, 10, 10, 10, 10, 10, 10,  2, 10, 10,  2, 10, 10, 10, 10,
+    2,  2, 10,  2,  2,  2,  2,  2, 10, 10,  2, 21, 21, 21, 21, 21,
+   21, 21, 21,  2,  2, 21, 21,  2, 21, 21, 21, 21,  2,  2, 21, 21,
+    2, 21,  2,  2, 21, 21,  2,  2, 22, 22,  2, 22, 22, 22, 22, 22,
+   22,  2, 22,  2, 22, 22, 22, 22,  2,  2,  2, 22, 22,  2,  2,  2,
+    2, 22, 22,  2,  2,  2, 22, 22, 22, 22, 23, 23, 23, 23, 23,  2,
+   23, 23, 23, 23,  2,  2,  2, 23, 23,  2, 23, 23, 23,  2,  2,  2,
+   23, 23,  2,  2,  2, 23, 16, 16, 16, 16, 16,  2, 16, 16,  2, 16,
+   16, 16, 16, 16,  2,  2,  2, 16, 16,  2, 16, 16, 16,  2,  2,  2,
+   16, 16, 20, 20, 20, 20, 20,  2, 20, 20,  2,  2, 20, 20,  2, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36,  2,  2,  2, 36, 36, 36, 36,
+    2, 36,  2, 36,  2,  2,  2,  2, 36,  2,  2,  2,  2, 36, 36,  2,
+   36,  2, 36,  2,  2,  2,  2, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+   24,  2,  2,  2,  2,  0,  2, 18, 18,  2, 18,  2, 18, 18, 18, 18,
+   18,  2, 18, 18, 18, 18,  2, 18,  2, 18, 18, 18,  2,  2, 18,  2,
+   18,  2, 25, 25, 25, 25,  2, 25, 25, 25, 25,  2,  2,  2, 25,  2,
+   25, 25, 25,  0,  0,  0,  0, 25, 25,  2, 33, 33, 33, 33,  8,  8,
+    8,  8,  8,  8,  2,  8,  2,  8,  2,  2,  8,  8,  8,  0, 12, 12,
+   12, 12, 30, 30, 30, 30, 30,  2, 30, 30, 30, 30,  2,  2, 30, 30,
+   30,  2,  2, 30, 30, 30, 30,  2,  2,  2, 29, 29, 29, 29, 29, 29,
+    2,  2, 28, 28, 28, 28, 34, 34, 34, 34, 34,  2,  2,  2, 35, 35,
+   35, 35, 35, 35, 35,  0,  0,  0, 35, 35, 35,  2,  2,  2, 45, 45,
+   45, 45, 45, 45,  2,  2,  2,  2,  2, 45, 44, 44, 44, 44, 44,  0,
+    0,  2, 43, 43, 43, 43, 46, 46, 46, 46, 46,  2, 46, 46, 31, 31,
+   31, 31, 31, 31,  2,  2, 32, 32,  0,  0, 32,  0, 32, 32, 32, 32,
+   32, 32, 32, 32,  2,  2, 32,  2,  2,  2, 32, 32, 32,  2, 28, 28,
+    2,  2, 48, 48, 48, 48, 48, 48, 48,  2, 48,  2,  2,  2, 52, 52,
+   52, 52, 52, 52,  2,  2, 52,  2,  2,  2, 58, 58, 58, 58, 58, 58,
+    2,  2, 58, 58, 58,  2,  2,  2, 58, 58, 54, 54, 54, 54,  2,  2,
+   54, 54, 91, 91, 91, 91, 91, 91, 91,  2, 91,  2,  2, 91, 91, 91,
+    2,  2,  1,  1,  2,  2, 62, 62, 62, 62, 62,  2, 62, 62, 76, 76,
+   76, 76, 93, 93, 93, 93, 70, 70, 70, 70,  2,  2,  2, 70, 70, 70,
+    2,  2,  2, 70, 70, 70, 73, 73, 73, 73,  6,  6,  6,  2,  8,  8,
+    8,  2,  2,  8,  8,  8,  1,  1,  1,  0,  1,  0,  1,  1,  1,  0,
+    0,  0,  0,  1,  0,  0,  1,  1,  0,  2, 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,  9,  9,  2,  2,  2,  9,  2,  9,  2,  9,
+    9,  9,  1,  1,  0,  0,  0,  2,  0,  0,  0, 19,  2,  2,  0,  0,
+    0, 19,  0,  0,  0,  2, 19,  2,  2,  2,  0,  0,  2,  2,  1,  2,
+    2,  2,  0,  0,  9,  0,  0,  0, 19, 19, 27, 27, 27, 27,  2,  2,
+    0,  0, 56, 56, 56, 56,  2, 55, 55, 55, 61, 61, 61, 61,  2,  2,
+    2, 61, 61,  2,  2,  2, 13, 13, 13, 13, 13, 13,  2, 13, 13, 13,
+    2,  2,  0, 13,  0, 13,  0, 13, 13, 13, 13, 13,  1,  1,  1,  1,
+   12, 12,  2, 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,  0,  2, 26, 26, 26, 26, 26, 26, 26,  2, 12, 12, 12, 12, 12,
+   12,  2, 12, 12, 12,  0, 39, 39, 39, 39, 39,  2,  2,  2, 39, 39,
+   39,  2, 86, 86, 86, 86, 77, 77, 77, 77, 79, 79, 79, 79,  2, 19,
+   19, 19, 60, 60, 60, 60, 60,  2,  2,  2, 65, 65, 65, 65, 75, 75,
+   75, 75, 75, 75,  2,  2,  2,  2, 75, 75, 69, 69, 69, 69, 69, 69,
+    0, 69, 74, 74, 74, 74,  2,  2,  2, 74, 12,  2,  2,  2, 84, 84,
+   84, 84, 84, 84,  2,  0, 84, 84,  2,  2,  2,  2, 84, 84, 33, 33,
+   33,  2, 68, 68, 68, 68, 68, 68, 68,  2, 68, 68,  2,  2, 92, 92,
+   92, 92, 92, 92, 92,  2,  2,  2,  2, 92, 87, 87, 87, 87, 87, 87,
+   87,  2, 19,  9, 19, 19, 19, 19,  0,  0, 87, 87,  2,  2,  2,  2,
+    2, 12, 19, 19, 19,  2,  2,  2,  2,  4, 14,  2, 14,  2, 14, 14,
+    2, 14, 14,  2, 14, 14,  3,  3,  0,  0,  1,  1,  6,  6,  3,  2,
+    3,  3,  3,  2,  2,  0,  2,  0,  0,  0,  0,  0, 17, 17, 17, 17,
+    0,  0,  2,  2, 12, 12, 49, 49, 49, 49,  2, 49, 49, 49, 49, 49,
+   49,  2, 49, 49,  2, 49, 49, 49,  2,  2,  0,  2,  2,  2,  9,  2,
+    2,  2,  0,  1,  2,  2, 71, 71, 71, 71, 71,  2,  2,  2, 67, 67,
+   67, 67, 67,  2,  2,  2, 42, 42, 42, 42,  2, 42, 42, 42, 41, 41,
+   41, 41, 41, 41, 41,  2,118,118,118,118,118,118,118,  2, 53, 53,
+   53, 53, 53, 53,  2, 53, 59, 59, 59, 59, 59, 59,  2,  2, 40, 40,
+   40, 40, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50,  2,  2,135,135,
+  135,135,106,106,106,106,104,104,104,104,  2,  2,  2,104,161,161,
+  161,161,161,161,161,  2,161,161,  2,161,161,  2,  2,  2,170,170,
+  170,170,110,110,110,110,110,110,110,  2,110,110,  2,  2, 19, 19,
+    2, 19, 19,  2, 19, 19, 47, 47, 47, 47, 47, 47,  2,  2, 47,  2,
+   47, 47, 47, 47,  2, 47, 47,  2,  2,  2, 47,  2,  2, 47, 81, 81,
+   81, 81, 81, 81,  2, 81,120,120,120,120,116,116,116,116,116,116,
+  116,  2,  2,  2,  2,116,128,128,128,128,128,128,128,  2,128,128,
+    2,  2,  2,  2,  2,128, 66, 66, 66, 66,  2,  2,  2, 66, 72, 72,
+   72, 72, 72, 72,  2,  2,  2,  2,  2, 72,173,173,173,173,173,173,
+    2,  2, 98, 98, 98, 98, 97, 97, 97, 97,  2,  2, 97, 97, 57, 57,
+   57, 57,  2, 57, 57,  2,  2, 57, 57, 57, 57, 57,  2,  2, 57, 57,
+   57,  2,  2,  2,  2, 57, 57,  2,  2,  2, 88, 88, 88, 88,117,117,
+  117,117,112,112,112,112,112,112,112,  2,  2,  2,  2,112, 78, 78,
+   78, 78, 78, 78,  2,  2,  2, 78, 78, 78, 83, 83, 83, 83, 83, 83,
+    2,  2, 82, 82, 82, 82, 82, 82, 82,  2,122,122,122,122,122,122,
+    2,  2,  2,122,122,122,122,  2,  2,  2, 89, 89, 89, 89, 89,  2,
+    2,  2,130,130,130,130,130,130,130,  2,  2,  2,130,130,144,144,
+  144,144,144,144,  2,  2,165,165,165,165,165,165,  2,  2,  2,165,
+  165,165,  2,  2,165,165,  3,  3,  3,  2,156,156,156,156,156,156,
+    2,156,156,156,  2,  2,  2,  2,  3,  3,  3,  2,  2,  2,147,147,
+  147,147,148,148,148,148,148,148,  2,  2,158,158,158,158,158,158,
+    2,  2,153,153,153,153,149,149,149,149,149,149,149,  2, 94, 94,
+   94, 94, 94, 94,  2,  2,  2,  2, 94, 94,  2,  2,  2, 94, 85, 85,
+   85, 85, 85, 85, 85,  2,  2, 85,  2,  2,101,101,101,101,101,  2,
+    2,  2,101,101,  2,  2, 96, 96, 96, 96, 96,  2, 96, 96,111,111,
+  111,111,111,111,111,  2,100,100,100,100,108,108,108,108,108,108,
+    2,108,108,108,  2,  2,129,129,129,129,129,129,129,  2,129,  2,
+  129,129,129,129,  2,129,129,129,  2,  2,109,109,109,109,109,109,
+  109,  2,109,109,  2,  2,107,107,107,107,  2,107,107,107,107,  2,
+    2,107,107,  2,107,107,107,107,  2,  1,107,107,  2,  2,107,  2,
+    2,  2,  2,  2,  2,107,  2,  2,107,107,171,171,171,171,171,171,
+    2,171,  2,  2,171,  2,171,  2,171,  2,  2,171,  2,171,171,171,
+  171,  2,171,  2,  2,  2,  2,171,171,  2,137,137,137,137,  2,137,
+  137,137,137,137,  2,  2,124,124,124,124,124,124,  2,  2,123,123,
+  123,123,123,123,  2,  2,114,114,114,114,114,  2,  2,  2,114,114,
+    2,  2,102,102,102,102,102,102,  2,  2,126,126,126,126,126,126,
+  126,  2,  2,126,126,126,142,142,142,142,125,125,125,125,125,125,
+  125,  2,  2,  2,  2,125,154,154,154,154,154,154,154,  2,  2,154,
+    2,  2,  2,154,154,  2,154,154,  2,154,154,  2,  2,154,154,154,
+    2,  2,150,150,150,150,  2,  2,150,150,150,  2,  2,  2,141,141,
+  141,141,140,140,140,140,140,140,140,  2,121,121,121,121,121,  2,
+    2,  2,  7,  7,  2,  2,169,169,169,169,169,169,  2,  2,133,133,
+  133,133,133,  2,133,133,133,133,133,  2,133,133,  2,  2,133,  2,
+    2,  2,134,134,134,134,  2,  2,134,134,  2,134,134,134,134,134,
+  134,  2,138,138,138,138,138,138,138,  2,138,138,  2,138,  2,  2,
+  138,  2,138,138,  2,  2,143,143,143,143,143,143,  2,143,143,  2,
+  143,143,143,143,143,  2,143,  2,  2,  2,143,143,  2,  2,175,175,
+  175,175,175,175,  2,  2,145,145,145,145,145,  2,  2,  2,163,163,
+  163,163,163,  2,163,163,163,163,163,  2,  2,  2,163,163, 86,  2,
+    2,  2, 63, 63, 63, 63, 63, 63,  2,  2, 63, 63, 63,  2, 63,  2,
+    2,  2,157,157,157,157,157,157,157,  2, 80, 80, 80, 80, 80, 80,
+    2,  2, 80, 80, 80,  2,127,127,127,127,127,127,127,  2,166,166,
+  166,166,166,166,  2,  2, 79,  2,  2,  2,115,115,115,115,115,115,
+  115,  2,115,115,  2,  2,  2,  2,115,115,159,159,159,159,159,159,
+  159,  2,159,159,  2,  2,103,103,103,103,103,103,  2,  2,119,119,
+  119,119,119,119,  2,  2,119,119,  2,119,  2,119,119,119,167,167,
+  167,167,167,167,  2,  2,146,146,146,146,146,146,146,  2,172,172,
+  172,172,172,  2,  2,172, 99, 99, 99, 99, 99, 99, 99,  2,  2,  2,
+    2, 99,136,139, 13, 13,155,  2,  2,  2, 13, 13, 13,  2,136,136,
+  136,136,155,155,155,155,155,155,  2,  2,  2,  2,  2,155,136,136,
+  136,  2,  2, 17, 17, 17,  2, 17, 17,  2, 17, 15, 15, 15, 17, 17,
+   17,  2,  2,  2, 15,  2,  2, 17,  2,  2,139,139,139,139,105,105,
+  105,105,105,105,105,  2,105,  2,  2,  2,105,105,  2,  2,  1,  1,
+    1,  2,  0,  0,  0,  1,  0,  1,  1,  1,  0,  0,  1,  1,  2,  2,
+    0,  2,  2,  0,  0,  2,  0,  0,  2,  0,  0,  2,  0,  2,131,131,
+  131,131,  2,  2,  2,131,  2,131,131,131, 56, 56, 56,  2, 56,  2,
+    2, 56, 56, 56,  2, 56, 56,  2, 56, 56,  6,  6,  2,  2,  2,  2,
+    2,  6,151,151,151,151,151,  2,  2,  2,151,151,  2,  2,  2,  2,
+  151,151,160,160,160,160,160,160,160,  2,152,152,152,152,152,152,
+    2,  2,  2,  2,  2,152,164,164,164,164,164,164,  2,  2,168,168,
+  168,168,168,168,168,  2,  2,  2,  2,168,174,174,174,174,174,174,
+  174,  2,174,174,  2,  2,  2,  2,174,174,  2, 30, 30,  2,113,113,
+  113,113,113,  2,  2,113,113,113,113,  2,132,132,132,132,132,132,
+    2,  2,  2,  2,132,132,  2,  3,  3,  3,  2,  3,  3,  2,  3,  2,
+    2,  3,  2,  3,  2,  3,  2,  2,  3,  2,  3,  2,  3,  2,  3,  3,
+    2,  3, 15,  0,  0,  2,  0,  2,  2,  0, 13,  2,  2,  2,  2,  0,
+    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, 18,  9,  9,  9,  9,  9, 19, 20, 21,  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, 23,  9,  9,  9,  9,  9, 24,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 32,  0,  0,  1,
-    2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
-   18, 19, 20, 20, 21, 22, 23, 24, 25, 26, 27, 28,  1, 29, 30, 31,
-   32, 32, 33, 32, 32, 32, 34, 32, 32, 35, 36, 37, 38, 39, 40, 41,
-   42, 43, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-   44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 44, 44, 44, 44,
-   44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 46, 46,
-   46, 46, 47, 48, 49, 50, 51, 52, 53, 54, 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, 55, 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, 56, 56, 44, 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, 95,
-   95, 96, 97, 98, 56, 56, 56, 56, 56, 56, 56, 56, 56, 99,100,100,
-  100,100,101,100,100,100,100,100,100,100,100,100,100,100,100,100,
-  100,102,103,103,104, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,105,
-   56, 56, 56, 56, 56, 56,106,106,107,108, 56,109,110,111,112,112,
-  112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
-  112,112,112,112,112,113,112,112,112,114,115,116, 56, 56, 56, 56,
-   56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,117,118,119,
-  120, 56, 56, 56, 56, 56, 56, 56, 56, 56,121, 56, 56, 56, 56, 56,
-   56, 56, 56, 56, 56, 56, 56, 56, 56, 56,122, 32,123,124,125,126,
-  127,128,129,130,131,132,133,133,134, 56, 56, 56, 56,135,136,137,
-  138, 56,139,140, 56,141,142,143, 56, 56,144,145,146, 56,147,148,
-  149, 32, 32, 32,150,151,152, 32,153,154, 56, 56, 56, 56, 44, 44,
-   44, 44, 44, 44,155, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-   44, 44, 44, 44, 44,156,157, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-   44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,158, 44, 44, 44,
-   44, 44, 44, 44, 44, 44, 44, 44, 44,159, 44, 44,160, 56, 56, 56,
-   56, 56, 56, 56, 56, 56, 44, 44,161, 56, 56, 56, 56, 56, 44, 44,
-   44,162, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-   44,163, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,164,165,
-    0,  1,  0,  1,  2,  3,  0,  1,  2,  3,  4,  5,  6,  7,  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,  3,  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,  3,  3,  2,  3,  3,  2,  2,  2,  2,  2,  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, 23, 23, 23, 23, 23,  2, 23, 23, 23, 23,  2,  2,  2,  2,
-    2,  2,  2, 23, 23,  2, 23, 23, 23,  2,  2, 23,  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, 16, 16, 16, 16,  2,  2, 16, 16,  2, 16,
-   16, 16,  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,
-   18, 18, 18, 18, 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, 45,  2,  2,  2,  2,
-    2,  2,  2,  2,  2, 45, 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, 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,  1,  1,  1,  1,  1,  1,  2, 62, 62,
-   62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,  2, 62, 62, 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,  6,
-    6,  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,  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,  2,  2,  2,  2,  2,  2,  2,  1,  2,
-    2,  2,  2,  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,  2,  2,  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, 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,  0,  0,
-    0,  0,  0,  0,  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,  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,  2,  2,
-    2,  2,  2,  2,  2,  0, 12, 12, 12, 12, 12, 12, 12,  0, 17, 17,
-   17, 17, 17, 17, 17,  0, 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, 19, 19,
-   19, 19, 19, 19,  2,  2, 19, 19,  2, 19,  2, 19, 19, 19,  2,  2,
-   19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
-   60, 60, 60,  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,
-    3,  2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,
-    3,  3,  3,  3,  0,  0,  2,  2,  3,  3,  3,  3,  3,  3,  2,  2,
-    2,  2,  2,  2,  2,  3,  1,  1,  1,  1,  1,  1,  6,  6,  0,  0,
-    0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  2,  2,  2,  2,  3,  3,
-    3,  3,  3,  2,  3,  3,  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,161,161,161,161,161,161,161,161,161,161,
-  161,  2,161,161,161,161,161,161,161,  2,161,161,  2,161,161,161,
-    2,161,161,161,161,161,161,161,  2,161,161,  2,  2,  2,170,170,
-  170,170,170,170,170,170,170,170,170,170,  2,  2,  2,  2,110,110,
-  110,110,110,110,110,110,110,110,110,110,110,110,110,  2,110,110,
-  110,110,110,110,  2,  2, 19, 19, 19, 19, 19, 19,  2, 19, 19,  2,
-   19, 19, 19, 19, 19, 19, 19, 19, 19,  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,  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,165,165,165,165,165,165,165,165,165,165,
-  165,165,165,165,  2,  2,  2,165,165,165,165,165,165,165,  2,  2,
-    2,  2,  2,  2,165,165,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,
-    3,  3,  3,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,147,147,
-  147,147,147,147,147,147,148,148,148,148,148,148,148,148,148,148,
-    2,  2,  2,  2,  2,  2,158,158,158,158,158,158,158,158,158,158,
-    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,
-   85,  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,
-    2,  2,  2,  2,  2,  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,171,171,171,171,171,171,171,171,171,171,
-    2,171,  2,  2,171,  2,171,171,171,171,171,171,  2,171,171,  2,
-  171,  2,  2,171,  2,171,171,171,171,  2,171,171,171,171,171,  2,
-    2,  2,  2,  2,  2,  2,  2,171,171,  2,  2,  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,102,
-    2,  2,  2,  2,  2,  2, 33, 33, 33, 33,  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,126,126,126,126,126,126,126,  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,  7,  7,
-    2,  2,  2,  2,  2,  2,169,169,169,169,169,169,169,169,169,169,
-    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,163,163,
-  163,163,163,163,163,163,163,  2,163,163,163,163,163,163,163,163,
-  163,  2,  2,  2,163,163,163,163,163,  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,157,157,
-  157,157,157,157,157,157,157,157,157,  2,  2,  2,  2,  2, 80, 80,
-   80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,  2,  2, 80, 80,
-   80,  2,  2,  2,  2,  2,127,127,127,127,127,127,127,127,127,127,
-  127,127,127,127,127,  2,166,166,166,166,166,166,166,166,166,166,
-    2,  2,  2,  2,  2,  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,159,159,159,159,159,159,159,159,159,159,
-  159,159,159,159,159,  2,159,159,  2,  2,  2,  2,  2,  2,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,167,167,
-  167,167,167,167,167,167,167,167,  2,  2,  2,  2,  2,  2,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, 13, 13,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,  2,  2,  2,  2,  2,  2,  2,155,136,  2,
-    2,  2,  2,  2,  2,  2, 17, 17, 17, 17,  2, 17, 17, 17, 17, 17,
-   17, 17,  2, 17, 17,  2, 17, 15, 15, 15, 15, 15, 15, 15, 17, 17,
-   17,  2,  2,  2,  2,  2,  2,  2, 15,  2,  2,  2,  2,  2, 15, 15,
-   15,  2,  2, 17,  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,  1,  1,  1,  1,  1,  1,  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,  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,  2,  2,  2,  2,  2, 19, 19, 19, 56, 56,
-   56, 56, 56, 56, 56,  2, 56,  2,  2, 56, 56, 56, 56, 56, 56, 56,
-    2, 56, 56,  2, 56, 56, 56, 56, 56,  2,  2,  2,  2,  2,  6,  6,
-    6,  6,  6,  6,  2,  2,  2,  2,  2,  2,  2,  2,  2,  6,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,160,160,
-  160,160,160,160,160,160,160,160,160,160,160,160,160,  2,152,152,
-  152,152,152,152,152,152,152,152,  2,  2,  2,  2,  2,152,164,164,
-  164,164,164,164,164,164,164,164,  2,  2,  2,  2,  2,  2,168,168,
-  168,168,168,168,168,168,168,168,168,  2,  2,  2,  2,168, 30, 30,
-   30, 30,  2, 30, 30,  2,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,  3,  3,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  0,  0, 15,  0,  0,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  0,  0,  0,  0,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,
-    2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  2,  2,  0, 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, 25,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  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, 18,  9,  9,  9,  9,  9, 19, 20,
-   21,  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, 23,  9,  9,  9,  9,  9, 24,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  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,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9, 26, 27,  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,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 26, 27,
+    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,  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, 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, 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,
+   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,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,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,
-  162,  0,163,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,164,165,  0,
-    0,  0,  0,  0,  0,  0,166,  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,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,167,  0,  0,  0,168,169,  0,  0,
-  170,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,171,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,172,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,162,  0,163,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,164,165,  0,  0,  0,  0,  0,
+    0,  0,166,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,173,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,167,  0,  0,  0,168,169,  0,  0,170,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,171,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,172,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,174,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,173,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,175,  0,  0,  0,  0,  0,
+    0,  0,174,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,176,177,  0,  0,  0,  0,178,
-  179,  0,  0,  0,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,207,
-  208,209,210,211,212,213,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,175,  0,  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,176,177,  0,  0,  0,  0,178,179,  0,  0,  0,
+  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,207,208,209,210,211,
+  212,213,  0,  0,  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[9668] =
+static const uint16_t _hb_ucd_u16[10904]=
 {
      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,
@@ -4020,23 +3690,23 @@ _hb_ucd_u16[9668] =
     48, 184,  48, 185,  48, 186, 187, 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, 140, 140, 140,
-   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,  32,
-    13,  13,  13,  13,  13,  13,  13,  13,  13, 240,  13,  13,  13,  13,  13,  13,
-   241, 242, 241, 241, 242, 243, 241, 244, 245, 245, 245, 246, 247, 248, 249, 250,
-   251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 261, 262, 263, 264, 265,
-   266, 267, 268, 269, 270, 271, 272, 272, 273, 274, 275, 209, 276, 277, 209, 278,
-   279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279,
-   280, 209, 281, 209, 209, 209, 209, 282, 209, 283, 279, 284, 209, 285, 286, 209,
-   209, 209, 176, 140, 287, 140, 271, 271, 271, 288, 209, 209, 209, 209, 289, 271,
-   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, 271, 296, 209, 209, 297, 279, 298, 279,
+    48, 210,  48,  48,  48, 211, 212, 213, 192, 192, 214, 215,  32, 216, 217, 140,
+   218,  48,  48, 219, 220, 160, 221, 222, 223,  48, 224,  64,  48,  48, 225, 226,
+    48,  48, 227, 228, 229,  64,  48, 230, 231,   9,   9, 232, 233, 234, 235, 236,
+    11,  11, 237,  27,  27,  27, 238, 239,  11, 240,  27,  27,  32,  32,  32,  32,
+    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, 263, 264, 265, 266,
+   267, 268, 269, 270, 271, 272, 273, 273, 274, 275, 276, 209, 277, 278, 209, 279,
+   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280,
+   281, 209, 282, 209, 209, 209, 209, 283, 209, 284, 280, 285, 209, 286, 287, 209,
+   209, 209, 176, 140, 288, 140, 272, 272, 272, 289, 209, 209, 209, 209, 290, 272,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 291, 292, 209, 209, 293,
+   209, 209, 209, 209, 209, 209, 294, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+   209, 209, 209, 209, 209, 209, 295, 296, 272, 297, 209, 209, 298, 280, 299, 280,
    209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
-   279, 279, 279, 279, 279, 279, 279, 279, 299, 300, 279, 279, 279, 301, 279, 302,
-   209, 209, 209, 279, 303, 209, 209, 304, 209, 305, 209, 209, 209, 209, 209, 209,
+   280, 280, 280, 280, 280, 280, 280, 280, 300, 301, 280, 280, 280, 302, 280, 303,
+   209, 209, 209, 280, 304, 209, 209, 305, 209, 209, 209, 209, 209, 209, 209, 209,
      9,   9,   9,  11,  11,  11, 306, 307,  13,  13,  13,  13,  13,  13, 308, 309,
     11,  11, 310,  48,  48,  48, 311, 312,  48, 313, 314, 314, 314, 314,  32,  32,
    315, 316, 317, 318, 319, 320, 140, 140, 209, 321, 209, 209, 209, 209, 209, 322,
@@ -4046,7 +3716,7 @@ _hb_ucd_u16[9668] =
    209, 333, 334, 209, 335, 336, 209, 209, 334, 209, 209, 336, 209, 209, 209, 209,
     48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 209, 209, 209, 209,
     48, 337,  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, 338,  48,  48, 229,
+    48,  48,  48,  48,  48,  48,  48,  48, 151, 209, 209, 209, 338,  48,  48, 230,
    339,  48, 340, 140,  13,  13, 341, 342,  13, 343,  48,  48,  48,  48, 344, 345,
     31, 346, 347, 348,  13,  13,  13, 349, 350, 351, 352, 353, 354, 355, 140, 356,
    357,  48, 358, 359,  48,  48,  48, 360, 361,  48,  48, 362, 363, 192,  32, 364,
@@ -4062,547 +3732,623 @@ _hb_ucd_u16[9668] =
     32, 404,  32, 405, 406, 407, 408, 409,  48,  48,  48,  48,  48,  48,  48, 410,
    411,   2,   3,   4,   5, 412, 413, 414,  48, 415,  48, 200, 416, 417, 418, 419,
    420,  48, 172, 421, 204, 204, 140, 140,  48,  48,  48,  48,  48,  48,  48,  71,
-   422, 271, 271, 423, 272, 272, 272, 424, 425, 426, 427, 140, 140, 209, 209, 428,
+   422, 272, 272, 423, 273, 273, 273, 424, 425, 426, 427, 140, 140, 209, 209, 428,
    140, 140, 140, 140, 140, 140, 140, 140,  48, 151,  48,  48,  48, 100, 429, 430,
     48,  48, 431,  48, 432,  48,  48, 433,  48, 434,  48,  48, 435, 436, 140, 140,
      9,   9, 437,  11,  11,  48,  48,  48,  48, 204, 192,   9,   9, 438,  11, 439,
     48,  48, 440,  48,  48,  48, 441, 442, 442, 443, 444, 445,  48,  48,  48, 388,
     48,  48,  48, 313,  48, 199, 440, 140, 446,  27,  27, 447, 140, 140, 140, 140,
    448,  48,  48, 449,  48, 450,  48, 451,  48, 200, 452, 140, 140, 140,  48, 453,
-    48, 454,  48, 455, 140, 140, 140, 140,  48,  48,  48, 456, 271, 457, 271, 271,
+    48, 454,  48, 455,  48, 207, 140, 140,  48,  48,  48, 456, 272, 457, 272, 272,
    458, 459,  48, 460, 461, 462,  48, 463,  48, 464, 140, 140, 465,  48, 466, 467,
     48,  48,  48, 468,  48, 469,  48, 470,  48, 471, 472, 140, 140, 140, 140, 140,
     48,  48,  48,  48, 196, 140, 140, 140,   9,   9,   9, 473,  11,  11,  11, 474,
     48,  48, 475, 192, 476,   9, 477,  11, 478, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 271, 479,  48,  48, 480, 481, 482, 140, 140, 483,
-    48, 464, 484,  48,  62, 485, 140,  48, 486, 140, 140,  48, 487, 140,  48, 313,
-   488,  48,  48, 489, 490, 457, 491, 492, 222,  48,  48, 493, 494,  48, 196, 192,
-   495,  48, 496, 497, 498,  48,  48, 499, 222,  48,  48, 500, 501, 502, 503, 504,
-    48,  97, 505, 506, 507, 140, 140, 140, 508, 509, 510,  48,  48, 511, 512, 192,
-   513,  83,  84, 514, 515, 516, 517, 518, 519,  48,  48, 520, 521, 522, 523, 140,
-    48,  48,  48, 524, 525, 526, 481, 140,  48,  48,  48, 527, 528, 192, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140,  48,  48, 529, 530, 531, 532, 140, 140,
-    48,  48,  48, 533, 534, 192, 535, 140,  48,  48, 536, 537, 192, 538, 539, 140,
-    48, 540, 541, 542, 313, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-    48,  48, 505, 543, 140, 140, 140, 140, 140, 140,   9,   9,  11,  11, 148, 544,
-   545, 546,  48, 547, 548, 192, 140, 140, 140, 140, 549,  48,  48, 550, 551, 140,
-   552,  48,  48, 553, 554, 555,  48,  48, 556, 557, 558,  48,  48,  48,  48, 196,
-   559, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48,  48, 560, 192,
-    84,  48, 529, 561, 562, 148, 175, 563,  48, 564, 565, 566, 140, 140, 140, 140,
-   567,  48,  48, 568, 569, 192, 570,  48, 571, 572, 192, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 573,
-   574, 115,  48, 575, 576, 577, 140, 140, 140, 140, 140, 100, 271, 578, 579, 580,
+   140, 140, 140, 140, 140, 140, 272, 479,  48,  48, 480, 481, 482, 483, 140, 484,
+    48, 464, 485,  48,  62, 486, 140,  48, 487, 140, 140,  48, 488, 140,  48, 313,
+   489,  48,  48, 490, 491, 457, 492, 493, 223,  48,  48, 494, 495,  48, 196, 192,
+   496,  48, 497, 498, 499,  48,  48, 500, 223,  48,  48, 501, 502, 503, 504, 505,
+    48,  97, 506, 507, 508, 140, 140, 140, 509, 510, 511,  48,  48, 512, 513, 192,
+   514,  83,  84, 515, 516, 517, 518, 519, 520,  48,  48, 521, 522, 523, 524, 140,
+    48,  48,  48, 525, 526, 527, 481, 140,  48,  48,  48, 528, 529, 192, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 140,  48,  48, 530, 531, 532, 533, 140, 140,
+    48,  48,  48, 534, 535, 192, 536, 140,  48,  48, 537, 538, 192, 539, 540, 140,
+    48, 541, 542, 543, 313, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+    48,  48, 506, 544, 140, 140, 140, 140, 140, 140,   9,   9,  11,  11, 148, 545,
+   546, 547,  48, 548, 549, 192, 140, 140, 140, 140, 550,  48,  48, 551, 552, 140,
+   553,  48,  48, 554, 555, 556,  48,  48, 557, 558, 559,  48,  48,  48,  48, 196,
+   560, 140, 140, 140, 140, 140, 561, 140, 140, 140, 140, 140,  48,  48, 562, 192,
+    84,  48, 530, 563, 564, 148, 175, 565,  48, 566, 567, 568, 140, 140, 140, 140,
+   569,  48,  48, 570, 571, 192, 572,  48, 573, 574, 192,  48,  48, 575, 192, 140,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 576,
+   577, 115,  48, 578, 579, 580, 140, 140, 140, 140, 140, 100, 272, 581, 582, 583,
     48,  48,  48,  48,  48,  48,  48,  48,  48, 207, 140, 140, 140, 140, 140, 140,
-   272, 272, 272, 272, 272, 272, 581, 582,  48,  48,  48,  48,  48,  48,  48,  48,
+   273, 273, 273, 273, 273, 273, 584, 585,  48,  48,  48,  48,  48,  48,  48,  48,
     48,  48,  48,  48, 388, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140,  48,  48,  48,  48,  48,  48, 583,
-    48,  48,  48, 584, 585, 586,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+   140, 140, 140, 140, 140, 140, 140, 140, 140,  48,  48,  48,  48,  48,  48, 586,
+    48,  48,  48, 587, 588, 589,  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,  71,
     48,  48,  48,  48, 313, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-    48, 587, 588, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-    48,  48,  48, 196,  48, 200, 370,  48,  48,  48,  48, 200, 192,  48, 204, 589,
-    48,  48,  48, 590, 591, 592, 593, 594,  48, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 595,  48, 596, 192, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140,   9,   9,  11,  11, 271, 597, 140, 140, 140, 140, 140, 140,
-    48,  48,  48,  48, 598, 599, 600, 600, 601, 602, 140, 140, 140, 140, 603, 604,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 440,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 199, 140, 605,
-   196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 606,
-    48,  48, 607, 608, 140, 609, 610,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48, 590, 591, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+    48,  48,  48, 196,  48, 200, 370,  48,  48,  48,  48, 200, 192,  48, 204, 592,
+    48,  48,  48, 593, 594, 595, 596, 597,  48, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 598,  48, 599, 192, 140, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140,   9,   9,  11,  11, 272, 600,   9, 601,  11, 602, 140, 140,
+    48,  48,  48,  48, 603, 604, 605, 605, 606, 607, 140, 140, 140, 140, 608, 609,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 199, 140, 610,
+    48, 200, 140, 140, 140, 140, 140, 140,  48,  48,  48,  48,  48,  48,  48, 611,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 612,
+    48,  48, 611, 613, 140, 614, 615,  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,
-    48,  48,  48,  48,  48,  48,  71, 151, 196, 611, 612, 140, 140, 140, 140, 140,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 192,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 322, 140, 140, 140, 140,
-    32,  32, 613,  32, 614, 209, 209, 209, 209, 209, 209, 209, 322, 140, 140, 140,
+    48,  48,  48,  48,  48,  48,  71, 151, 196, 616, 617, 140, 140, 140, 140, 140,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 618,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 619, 209, 427, 209, 620,
+    32,  32, 216,  32, 621, 209, 209, 209, 209, 209, 209, 209, 322, 140, 140, 140,
    209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 323,
-   209, 209, 615, 209, 209, 209, 616, 617, 618, 209, 619, 209, 209, 209, 287, 140,
-   209, 209, 209, 209, 620, 140, 140, 140, 140, 140, 140, 140, 271, 621, 271, 621,
-   209, 209, 209, 209, 209, 338, 271, 461, 140, 140, 140, 140, 140, 140, 140, 140,
-     9, 622,  11, 623, 624, 625, 241,   9, 626, 627, 628, 629, 630,   9, 622,  11,
-   631, 632,  11, 633, 634, 635, 636,   9, 637,  11,   9, 622,  11, 623, 624,  11,
-   241,   9, 626, 636,   9, 637,  11,   9, 622,  11, 638,   9, 639, 640, 641, 642,
-    11, 643,   9, 644, 645, 646, 647,  11, 648,   9, 649,  11, 650, 538, 538, 538,
-    32,  32,  32, 651,  32,  32, 652, 653, 654, 655,  45, 140, 140, 140, 140, 140,
-   656, 657, 658, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   659, 660, 661,  27,  27,  27, 662, 140, 663, 140, 140, 140, 140, 140, 140, 140,
-    48,  48, 151, 664, 665, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 666, 140,  48,  48, 667, 668,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 669, 192,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 587, 670,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 671, 200,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 672, 614, 140, 140,
-     9,   9, 626,  11, 673, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 503, 271, 271, 674, 675, 140, 140, 140, 140,
-   503, 271, 676, 677, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   678,  48, 679, 680, 681, 682, 683, 684, 685, 206, 686, 206, 140, 140, 140, 687,
-   209, 209, 688, 209, 209, 209, 209, 209, 209, 322, 333, 689, 689, 689, 209, 323,
-   690, 209, 209, 209, 209, 209, 209, 209, 209, 209, 691, 140, 140, 140, 692, 209,
-   693, 209, 209, 688, 694, 695, 323, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 696,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 697, 426, 426,
-   209, 209, 209, 209, 209, 209, 209, 698, 209, 209, 209, 209, 209, 176, 688, 427,
-   688, 209, 209, 209, 699, 176, 209, 209, 699, 209, 691, 688, 695, 140, 140, 140,
-   209, 209, 209, 209, 209, 322, 691, 426, 700, 209, 209, 209, 701, 702, 176, 694,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 703, 209, 209, 209, 209, 209, 192,
+   209, 209, 622, 209, 209, 209, 623, 624, 625, 209, 626, 209, 209, 209, 288, 140,
+   209, 209, 209, 209, 627, 140, 140, 140, 140, 140, 140, 140, 272, 628, 272, 628,
+   209, 209, 209, 209, 209, 338, 272, 461, 140, 140, 140, 140, 140, 140, 140, 140,
+     9, 629,  11, 630, 631, 632, 242,   9, 633, 634, 635, 636, 637,   9, 629,  11,
+   638, 639,  11, 640, 641, 642, 643,   9, 644,  11,   9, 629,  11, 630, 631,  11,
+   242,   9, 633, 643,   9, 644,  11,   9, 629,  11, 645,   9, 646, 647, 648, 649,
+    11, 650,   9, 651, 652, 653, 654,  11, 655,   9, 656,  11, 657, 539, 539, 539,
+    32,  32,  32, 658,  32,  32, 659, 660, 661, 662,  45, 140, 140, 140, 140, 140,
+   663, 664, 665, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   666, 667, 668,  27,  27,  27, 669, 140, 670, 140, 140, 140, 140, 140, 140, 140,
+    48,  48, 151, 671, 672, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 673, 140,  48,  48, 674, 675,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 676, 192,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 590, 677,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 200, 678, 679,
+   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 680, 200,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 681, 621, 140, 140,
+     9,   9, 633,  11, 682, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140, 140, 140, 140, 504, 272, 272, 683, 684, 140, 140, 140, 140,
+   504, 272, 685, 686, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   687,  48, 688, 689, 690, 691, 692, 693, 694, 206, 695, 206, 140, 140, 140, 696,
+   209, 209, 697, 209, 209, 209, 209, 209, 209, 322, 333, 698, 698, 698, 209, 323,
+   699, 209, 209, 209, 209, 209, 209, 209, 209, 209, 700, 140, 140, 140, 701, 209,
+   702, 209, 209, 697, 703, 704, 323, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 705,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 706, 426, 426,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 176, 697, 427,
+   697, 209, 209, 209, 707, 176, 209, 209, 707, 209, 700, 697, 704, 708, 140, 140,
+   209, 209, 209, 209, 209, 707, 700, 426, 709, 209, 209, 209, 710, 711, 712, 703,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 713, 209, 209, 209, 209, 209, 714,
     48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 140, 140,
-    48,  48,  48, 207,  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, 481,  48,  48,  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, 100,  48,
     48,  48,  48,  48,  48, 204, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
     48, 204, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
     48,  48,  48,  48,  71,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 140, 140, 140, 140, 140,
-   704, 140, 584, 584, 584, 584, 584, 584, 140, 140, 140, 140, 140, 140, 140, 140,
+    48,  48,  48,  48,  48,  48,  48, 207, 140, 140, 140, 140, 140, 140, 140, 140,
+   715, 140, 587, 587, 587, 587, 587, 587, 140, 140, 140, 140, 140, 140, 140, 140,
     32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32, 140,
-   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 705,
-   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 706,
-     0,   0,   1,   1,   0,   2,   3,   3,   4,   4,   4,   4,   4,   4,   4,   4,
-     4,   4,   4,   4,   4,   5,   0,   6,   7,   7,   7,   8,   9,  10,  11,  12,
-    13,  13,  13,  13,  14,  13,  13,  13,  13,  15,  16,  17,  18,  19,  20,  21,
-    22,  23,  24,  25,  23,  23,  26,  23,  27,  28,  29,  23,  30,  31,  32,  33,
-    34,  35,  36,  37,  38,  23,  23,  39,  40,  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,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,
-    79,  80,  81,  82,  83,  84,  85,  82,  86,  86,  87,  88,  89,  90,  91,  82,
-    92,  92,  92,  92,  92,  93,  94,  95,  96,  96,  96,  96,  96,  96,  96,  96,
-    97,  97,  98,  97,  99, 100, 101,  97, 102,  97, 103, 104, 105, 106, 106, 107,
-   108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 109, 110, 110, 111,
-   112, 113, 114, 115, 116, 116, 117, 118, 119, 120, 120, 121, 120, 122, 108, 123,
-   124, 125, 126, 127, 128, 129, 130, 116, 131, 132, 133, 134, 135, 136, 137,  82,
-   138, 138, 139, 138, 140, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150,
-     4, 151, 152, 153,   4, 154,   7,   7, 155,  11, 156, 157,  11, 158, 159, 160,
-   161,   0,   0, 162, 163,   0, 164, 165,   0, 166, 167,   4, 168,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0, 169, 170,   0,   0,   0,   0,   0,
-   171, 171, 171, 171, 171, 171, 171, 171,   0,   0,   0, 172, 173,   0,   0,   0,
-   174, 174, 174,   4, 175, 175, 175, 176,  93, 177, 178, 179, 180, 181, 181,  13,
-     0,   0, 182,  82, 183, 184, 184, 185, 184, 184, 184, 184, 184, 184, 186, 187,
-   188, 189, 190, 191, 192, 193, 194, 195, 196, 197,  96,  96, 198, 199,   0, 200,
-   201,   0,   0, 202,   0,   0, 203, 204, 194, 194, 205,   0,   0,   0,   0,   0,
-   184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184,   0,   0,
-   206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 207, 206, 208, 209,
-   210, 210, 210, 210, 210, 210, 210, 210, 210, 211,  13,  13,  13, 212, 212, 213,
-     0, 214,   4,   4, 215,   4, 216, 217, 218, 219, 220, 221, 222, 222, 223,  40,
-   224, 225, 226, 227, 228, 228, 229, 230, 231, 232, 233,  92, 234, 234, 235, 236,
-   237, 238, 239, 240, 106, 106, 241, 242,  96,  96,  96,  96,  96, 243, 244, 245,
-    82,  82,  82,  82,  82,  82,  82,  82, 184, 184, 184, 246, 184, 184, 247,  82,
-   248, 249, 250,  23,  23,  23, 251,  23,  23,  23,  23,  23,  23,  23,  23,  23,
-    23, 252,  23,  23, 253,  23, 254, 255, 256, 257, 258, 259,  23,  23,  23, 260,
-   261,   1,   1, 262, 263, 201, 264, 265, 266, 267, 268,  82, 269, 269, 269, 270,
-   271, 272,  11,  11, 273, 274, 187, 275,  82,  82,  82,  82, 276, 277, 278, 279,
-   280, 281, 282, 283, 284, 285, 286,  82, 287, 287, 288, 289, 290, 291, 292, 293,
-   294, 295, 296, 297, 298, 299, 300, 301, 302, 302, 302, 302, 302, 302, 302, 302,
-   302, 303, 304, 305, 306, 307,  82,  82, 308, 309, 310, 311, 312, 313,  82, 314,
-   315, 316,  82,  82, 317, 318, 319, 320, 321, 322, 323, 324, 325,  82, 326, 327,
-   328, 329, 330, 331, 332, 333,  82,  82, 334, 334, 335,  82, 336, 337, 336, 338,
-   339, 340, 341, 342, 343,  82,  82,  82,  82,  82,  82, 344, 345, 346, 347, 348,
-   349, 350, 351, 352, 353, 354, 355, 356, 357, 357, 358, 359, 360, 360, 361, 362,
-   363, 364, 365, 366, 367, 367, 367, 368, 369, 370, 371,  82, 372, 373, 374, 375,
-   376, 377, 378, 379, 380, 381, 382, 383, 384, 384, 385, 386, 387, 387, 388,  82,
-    82,  82,  82,  82, 389, 390, 391,  82, 392, 392, 393, 394, 395, 396, 397, 398,
-   399, 400, 401,  82,  82,  82,  82,  82, 402, 403,  82,  82,  82, 404, 404, 405,
-   406, 407, 408,  82,  82, 409, 410, 411, 412, 412, 413, 414, 414, 415, 416, 417,
-   418,  82,  82,  82,  82,  82, 419, 420, 421, 422, 423, 424, 425, 426,  82,  82,
-   427, 428, 429, 430, 431, 432,  82,  82,  82,  82,  82,  82,  82,  82,  82, 433,
-   434, 435, 436,  82,  82, 437, 438, 439, 440, 440, 440, 440, 440, 440, 440, 440,
-   440, 440, 440, 440, 441,  82,  82,  82, 440, 440, 440, 442, 440, 440, 440, 440,
-   440, 440, 443,  82,  82,  82,  82,  82,  82,  82,  82,  82, 444, 445, 445, 446,
-   447, 447, 447, 447, 447, 447, 447, 447, 447, 447, 448, 447, 447, 447, 447, 447,
-   447, 447, 447, 447, 447, 447, 447, 449, 450, 450, 450, 450, 450, 450, 450, 450,
-   450, 450, 451,  82,  82,  82,  82,  82, 452, 453,  82,  82,  82,  82,  82,  82,
-   212, 212, 212, 212, 212, 212, 212, 212, 212, 454, 455, 456, 457, 458, 459, 460,
-   461, 461, 462, 463, 464,  82,  82,  82,  82,  82, 465, 466,  82,  82,  82,  82,
-    82,  82, 467, 467, 468,  82,  82,  82, 469, 469, 470, 469, 471,  82,  82, 472,
-   473, 473, 473, 473, 473, 473, 473, 473, 473, 473, 473, 473, 473, 473, 473, 474,
-   475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 476, 477,
-   478,  82,  82,  82,  82,  82,  82,  82,  82,  82,  82,  82,  82,  82,  82, 479,
-   480, 191, 191, 191, 191, 191, 191, 191, 191, 481, 482, 483, 484, 484, 484, 484,
-   484, 484, 484, 484, 484, 484, 484, 485, 486, 486, 486, 487, 488, 489,  82,  82,
-     0,   0,   0,   0,   0,   0,   0, 490,   0,   0,   0,   0,   0, 491,  82,  82,
-     7, 492, 493,   0,   0,   0, 489,  82,   0,   0,   0,   0,   0,   0,   0, 494,
-     0, 495,   0, 496, 497, 498,   0, 170,  11,  11, 499,  82,  82,  82, 491, 491,
-     0,   0, 500, 501,  82,  82,  82,  82,   0,   0, 502,   0, 503, 504, 505,   0,
-   506, 507, 508,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 509,   0,   0,
-     0,   0,   0,   0,   0,   0, 510,   0, 511, 511, 511, 511, 511, 511, 511, 511,
-   511, 511, 511, 511, 512, 513,  82,  82, 514, 515,  82,  82,  82,  82,  82,  82,
-   516, 517,  13, 518, 519,  82,  82,  82, 520, 521, 522,  82,  82,  82,  82,  82,
-    82,  82,  82,  82, 523, 524, 525, 526,  82,  82,  82,  82,  82,  82, 527, 528,
-    82,  82,  82,  82,  82,  82, 529, 530,  82,  82,  82,  82,  82,  82,  82, 531,
-   532, 532, 532, 532, 532, 532, 533,  82, 534, 534, 535,  82,  82,  82,  82,  82,
-    82,  82,  82, 536,   0, 537,  82,  82, 261, 182,  82,  82,  82,  82,  82,  82,
-   538, 539, 540, 541, 542, 543,  82, 544,   0, 545,   0,   0, 491, 546, 547, 494,
-     0,   0,   0,   0,   0, 548,  82, 549, 550, 551, 552, 553,  82,  82,  82,  82,
-     0,   0,   0,   0,   0,   0, 554, 555,   0,   0,   0, 556,   0,   0, 490, 557,
-   545,   0, 558,   0, 559, 560, 561,  82,   0,   0, 491, 562, 563,   0, 564, 565,
-     0,   0,   0,   0, 258,   0,   0, 490, 184, 184, 184, 184, 184, 184, 184,  82,
-   184, 247, 184, 184, 184, 184, 184, 184, 566, 184, 184, 184, 184, 184, 184, 184,
-   184, 184, 184, 184, 184, 567, 184, 184, 184, 184, 184, 184, 184, 184, 184, 568,
-   184, 184, 566,  82,  82,  82,  82,  82, 566,  82,  82,  82,  82,  82,  82,  82,
-   184, 184, 569, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 570,  82,  82,
-   571,   0,   0,   0,  82,  82,  82,  82,   7,   7,   7,   7,   7,   7,   7, 572,
-     0,   0,   0,   0,   1,   2,   2,   3,   0,   4,   0,   4,   2,   2,   5,   2,
-     2,   2,   2,   2,   2,   2,   2,   6,   7,   8,   0,   0,   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,  19,  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,  29,  37,  38,  37,  37,
-    37,  37,  37,  37,  37,  39,  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,  31,  31,  31,  50,  51,  31,  52,  31,  31,  31,
-    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, 128, 129, 122, 130,  26, 131, 132, 133, 131,
-   131, 131, 131, 131, 132, 133, 134, 131, 135, 131, 131, 131, 136, 137, 138, 139,
-   137, 137, 140, 141, 138, 142, 143, 137, 144, 137, 145,  26, 146, 147, 147, 147,
-   147, 147, 147, 148, 147, 147, 147, 149,  26,  26,  26,  26, 150, 151, 152, 152,
-   153, 152, 152, 154, 155, 156, 152, 157, 158, 158, 158, 158, 158, 159, 158, 158,
-   158, 160, 159, 158, 158, 158, 158, 159, 158, 158, 158, 161, 158, 161, 162, 163,
-   164, 164, 164, 164, 165, 165, 165, 165, 166, 167, 165, 165, 165, 165, 165, 168,
-   169, 169, 169, 169, 170, 170, 170, 170, 170, 171, 172, 171, 170, 171, 170, 170,
-   170, 170, 171, 172, 171, 170, 172, 170, 170, 170, 171, 170, 170, 170, 170, 173,
-   170, 170, 170, 174, 170, 170, 170, 175, 176, 176, 176, 176, 176, 176, 177, 177,
-   178, 178, 178, 178, 179, 179, 179, 180, 181, 181, 181, 181, 181, 182, 181, 183,
-   184, 184, 185, 186, 187, 187, 188,  26, 189, 189, 190,  26, 191, 192, 193,  26,
-   194, 194, 194, 194, 194, 194, 194, 195, 194, 196, 194, 196, 197, 198, 198, 199,
-   198, 198, 198, 198, 198, 198, 198, 200, 198, 201, 178, 178, 178, 178, 202,  26,
-   203, 203, 203, 204, 203, 205, 203, 205, 206, 203, 207, 207, 207, 208, 209,  26,
-   210, 210, 210, 210, 210, 211, 210, 210, 210, 212, 210, 213, 214, 214, 214, 215,
-   216, 216, 216, 216, 216, 216, 216, 217, 216, 216, 216, 218, 216, 219, 216, 219,
-   216, 220,   9,   9,   9, 221,  26,  26, 222, 222, 222, 222, 222, 223, 222, 222,
-   224, 224, 224, 224, 225, 225, 225, 225, 225, 225, 226, 227, 228, 228, 228, 228,
-   228, 228, 228, 229, 228, 230, 231, 231, 231, 231, 231, 231,  18, 232, 165, 165,
-   165, 165, 165, 233, 224,  26, 234,   9, 235, 236, 237, 238, 239, 240,   2,   2,
-     2,   2,   2, 241, 242, 243,   2, 244,   2,   2,   2, 245,  14,  14, 246, 246,
-   246, 246,  14, 247,  14,  14,  14, 246,  14,  14, 248,  14, 248,  14, 249, 250,
-    14,  14, 251, 252,   0, 253,   0,   0, 254,   0, 255, 256,   0, 257,   2, 258,
-   259,  26,   9,   9,   9,   9, 260,  26, 261, 262,   4,   0,   0, 263,   0,   0,
-     2, 264,   0,   0,   0, 265,  26,  26,   0, 266,  26,  26, 267, 267, 267, 267,
-     0,   0, 268,   0,   0,   0, 269,   0, 270, 270, 270, 270,  17,  17,  17,  17,
-    17,  17, 271, 272, 166, 167, 273, 273, 273, 273, 273, 273, 273, 274, 275, 274,
-   170, 170, 172,  26, 172, 172, 172, 172,   0,   0,   0, 276, 277, 277, 277, 278,
-   277, 277, 277, 277, 277, 277, 279,  26, 277, 277, 280,  26,  26,  26,   0,   0,
-   281,   0,   0,   0, 282, 283,   0, 284, 285, 286, 286, 286, 286, 286, 286, 286,
-   286, 286, 287, 288, 289, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 291,
-   292, 293, 293, 293, 293, 293, 294, 169, 169, 295,   0,   0, 293, 293, 293, 293,
-   276, 296, 290, 290, 169, 169, 169, 295, 169, 169, 169, 297,   0,   0, 290, 290,
-   290, 290, 290, 298, 290, 290, 290,   0, 299, 299, 299, 299, 299, 300, 299, 299,
-   301,  26, 302, 302, 302, 302, 302, 302, 303, 303, 303, 303, 303, 304,  26,  26,
-   305, 305, 305, 305, 305, 305, 305,  26, 306,   2,   2,   2,   2, 307,   2,   2,
-     2, 308, 309, 258,  26,  26, 310,   2, 311, 311, 311, 311, 311, 312,   0, 265,
-   313, 313, 313, 313, 313, 313, 313,  26, 314, 314, 314, 314, 315, 316, 314, 317,
-   318, 318, 318, 318, 318, 319, 320, 320, 320, 320, 321, 322, 169, 169, 169, 323,
-   324, 324, 324, 324, 324, 325, 324, 326, 164, 164, 164, 327, 328, 328, 328, 328,
-   328, 328, 329,  26, 328, 330, 328, 331, 332, 332, 332, 332, 333,  26,  26, 334,
-   335, 335, 336,  26, 337, 337, 337,  26, 172, 172,   2,   2,   2,   2,   2, 338,
-   339, 340, 176, 176, 335, 335, 335, 335, 335, 341, 335, 342, 343,  26, 169, 169,
-   295, 344, 169, 169, 169, 169, 169, 343, 277, 280, 277, 277, 277, 277, 277, 345,
-   346,  26, 347, 348,  25,  25, 349, 350, 351,  25,  31,  31, 352,  26, 353,  31,
-    31,  31,  31, 354,  31,  31, 355,  31,  31, 356,  26,  26,  26,  26,  31,  31,
-     9,   9,   0, 265,   9, 357,   0,   0,   0,   0, 358,   0, 257, 359, 360,  31,
-    31,  31,  31, 361, 362,   0,   0,   0, 363, 290, 289, 290, 290, 290, 290, 364,
-   365, 365, 365, 366, 257, 257,  26, 367, 368, 369, 368, 368, 370, 368, 368, 371,
-   368, 372, 368, 372, 368, 368, 368, 368, 368, 368, 368, 373, 374,   0,   0,   0,
-     0,   0, 375,   0,  14, 252,   0, 376, 377,  26,  26,  26,   0,   0,   0, 378,
-   379, 379, 379, 380, 381, 381, 381, 381, 381, 381, 382,  26, 383,   0,   0, 359,
-   384, 384, 384, 384, 385, 386, 387, 387, 387, 388, 389, 389, 389, 389, 389, 390,
-   391, 391, 391, 392, 393, 393, 393, 393, 394, 393, 395,  26, 396, 396, 396, 396,
-   396, 396, 397, 397, 397, 397, 397, 397, 398, 398, 398, 399, 398, 400, 401, 401,
-   401, 401, 402, 401, 401, 401, 401, 402, 403, 403, 403, 403, 403,  26, 404, 404,
-   404, 404, 404, 404, 405, 406, 407, 408, 407, 408, 409, 407, 410, 407, 410, 411,
-   412, 412, 412, 412, 412, 412, 413,  26, 414, 414, 414, 414, 414, 414, 415,  26,
-   414, 414, 416,  26, 414,  26,  26,  26, 417,   2,   2,   2,   2,   2, 418, 419,
-   420, 421, 422, 422, 422, 422, 423, 424, 425, 425, 426, 425, 427, 427, 427, 427,
-   428, 428, 428, 429, 430, 428,  26,  26, 431, 431, 432, 433, 434, 434, 434, 435,
-   436, 436, 436, 437, 438, 438, 438, 438, 439, 439, 439, 440, 439, 439, 441, 439,
-   439, 439, 439, 439, 442, 443, 444, 445, 446, 446, 447, 448, 446, 449, 446, 449,
-   450, 450, 450, 450, 451, 451, 451, 451, 452, 452, 452, 452, 453, 454, 453,  26,
-   455, 455, 455, 455, 455, 455, 456, 457, 458, 458, 459, 458, 460, 460, 461, 460,
-   462, 462, 463, 464,  26, 465,  26,  26, 466, 466, 466, 466, 466, 467,  26,  26,
-   468, 468, 468, 468, 468, 468, 469,  26, 468, 468, 469, 470, 471, 471, 471, 471,
-   471,  26, 471, 472, 473, 473, 473, 473, 474, 475, 473, 473, 474, 476,  26,  26,
-    31,  31,  31,  50, 477, 477, 477, 477, 477, 478, 479,  26, 480,  26,  26,  26,
-    26,  26,  26, 481, 482, 482, 482, 482, 482,  26, 483, 483, 483, 483, 483, 484,
-    26,  26, 485, 485, 485, 486,  26,  26,  26,  26, 487, 487, 487, 488,  26,  26,
-   489, 489, 490,  26, 491, 491, 491, 491, 491, 492, 493, 491, 491, 491, 492, 494,
-   495, 495, 495, 495, 496, 497, 498, 498, 498, 499, 498, 500, 501, 501, 501, 501,
-   501, 501, 502, 501, 501,  26, 503, 503, 503, 503, 504,  26, 505, 505, 505, 505,
-   506, 137, 507,  26, 508, 508, 509, 508, 508, 508, 508, 508, 510,  26,  26,  26,
-   511, 512, 513, 514, 513, 515, 516, 516, 516, 516, 516, 516, 516, 517, 516, 518,
-   519, 520, 521, 522, 522, 523, 524, 525, 520, 526, 527, 528, 529, 530, 530,  26,
-   531, 532, 531, 531, 531, 531, 533, 531, 534, 535, 533, 536, 537,  26,  26,  26,
-   538, 538, 538, 538, 538, 538, 538, 539, 540,  26,  26,  26, 541, 541, 541, 541,
-   541,  26, 541, 542, 543, 543, 543, 543, 543, 543, 544, 543, 543, 543, 543, 544,
-   545, 545, 545, 545, 546,  26, 545, 547, 198, 548,  26,  26, 549, 549, 549, 549,
-   549, 549, 549, 550, 549, 550, 164, 164, 551,  26,  26,  26, 552, 552, 552, 553,
-   552, 554, 552, 552, 555,  26,  26,  26, 556, 556, 556, 556, 556, 556, 556, 557,
-   558, 558, 558, 558, 558, 558, 559, 560, 561, 562, 563, 564, 564, 564, 565, 566,
-   561,  26, 564, 567, 568, 569, 568, 568, 568, 568, 568, 569, 570,  26,  26,  26,
-   571, 571, 571, 571, 571,  26, 572, 572, 572, 572, 572, 572, 573,  26, 178, 178,
-   574, 574, 574, 574, 574, 574, 574, 575,  53, 576,  26,  26, 577, 577, 577, 577,
-   578,  26, 577, 578, 579, 580, 579, 579, 579, 579, 581, 579, 582,  26, 579, 579,
-   579, 583, 584, 584, 584, 584, 585, 584, 584, 586, 587,  26, 588, 589, 590, 590,
-   590, 590, 588, 591, 590,  26, 590, 592, 593, 594, 595, 595, 595, 596, 597, 598,
-   595, 599,  26,  26, 600, 600, 600, 601, 602, 602, 603, 602, 602, 602, 602, 604,
-   602, 602, 602, 605,  26,  26, 606,  26, 108, 108, 108, 108, 108, 108, 607, 608,
-   609, 609, 609, 609, 609, 609, 609, 610, 609, 611, 612,  26, 613,  26,  26,  26,
-    26,  26, 614, 614, 614, 614, 614, 614, 614, 614, 615,  26, 616, 616, 616, 616,
-   616, 616, 617,  26, 616, 616, 616, 618, 619, 619, 619, 619, 620,  26,  26,  26,
-   621, 621, 621, 621, 621, 621, 621, 622, 305, 305, 305, 623, 624, 624, 624, 625,
-   624, 626, 627, 627, 627, 627, 627, 627, 627, 627, 627, 628, 627, 629, 630, 630,
-   630, 631, 631,  26, 632, 632, 632, 632, 633,  26, 632, 634, 634, 632, 632, 635,
-   632, 632,  26,  26, 636, 636, 636, 636, 636, 636, 636, 637, 638, 638, 638, 638,
-   638, 638, 638, 639, 640, 640, 640, 640, 640, 641, 640, 640, 640, 642, 640, 640,
-   643,  26, 345,  26, 644, 644, 644, 644, 644, 644, 644,  26, 645, 645, 645, 645,
-   645, 645, 646,  26,  26,  26,  26, 647, 644, 648,  26,  26,  26,  26, 649, 650,
-   651, 286, 286, 286, 652,  26, 653,  26,  26,  26, 654,  26, 655,  26, 656, 656,
-   656, 656, 656, 656, 656, 656, 656, 657, 658, 658, 658, 658, 658, 659, 658, 660,
-   658, 661, 658, 662, 359,  26,  26,  26,   0,   0,   0, 265,   0,   0, 359,  26,
-     9, 663,   9,   9, 221,  26,   0,   0,   0,   0, 276,  26, 257, 362,   0,   0,
-   664, 665,   0, 666, 667, 668,   0,   0,   0, 669,   0,   0, 246,  26,  26,  26,
-     0,   0, 257,  26,   0,   0,   0, 259,   0,   0, 254,   0,   0,   0,   0, 254,
-   670, 671,   0, 672, 673,   0,   0,   0, 269, 674, 254, 254,   0,   0,   0, 675,
-   676, 677, 678,   0, 276,   0,   0,   0,   0, 268,   0,   0, 679, 679, 679, 679,
-   679, 680,  26, 681, 682, 679,  26,  26,   2,   2,   2, 346, 683, 419,  26,  26,
-   684, 270, 270, 685, 686, 687,  18,  18,  18, 688,  26,  26,  26, 689,  26,  26,
-   690, 690, 690, 690, 690, 691, 690, 692, 690, 693,  26,  26,  26,  26, 694, 694,
-   694, 695,  26,  26, 696, 696, 696, 696, 696, 696, 696, 697,  26,  26, 698, 698,
-   698, 698, 698, 699,  26,  26, 700, 700, 700, 700, 700, 701, 172, 702, 170, 172,
-   703, 703, 703, 703, 704, 703, 705,  26, 706, 706, 706, 706, 706, 707, 706, 708,
-    26,  26, 362,   0,   0,   0, 376,  26, 709,  31,  31,  31, 710, 711, 712, 713,
-   714, 715, 710, 716, 710, 712, 712, 717,  31, 718,  31, 719, 720, 718,  31, 719,
-    26,  26, 721,  26,   0, 359,   0,   0,   0, 257, 362,   0, 362,   0, 362,   0,
-     0, 276,  26,  26, 722,   0,   0,   0, 723,  26,   0,   0,   0,   0,   0, 359,
-     0, 259, 265,  26, 276,  26,  26,  26,   0,   0,   0, 724,   0, 376,   0, 376,
-     0,   0, 257, 725,   0, 359, 259,  26,   0,  26,   0, 265,   0,  26,   0,   0,
-     0, 276,   0, 359, 265,  26,  26,  26,   0, 276,   0, 376,   0, 726,   0,   0,
-   257, 722,   0, 727,   0, 265,   0, 259, 277, 277, 277, 280, 345,  26, 277, 277,
-   728,  26, 277, 277, 277, 729, 277, 277, 277, 277,  26,  26, 730,  26,  26,  26,
-     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,
+   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 716,
+   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 717,
+     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,  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,  27,  27,  45,  27,  27,  27,  27,  46,  27,
+    47,  47,  47,  47,  47,  48,  49,  47,  50,  51,  52,  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, 108, 109, 110, 111, 108, 112, 113, 114, 115, 116, 117, 118, 119,
+   120, 121, 121, 122, 121, 123, 124, 124, 125, 126, 127, 128, 129, 130, 124, 124,
+   131, 131, 131, 131, 132, 131, 133, 134, 131, 132, 131, 135, 135, 136, 124, 124,
+   137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 138, 138, 139, 138, 138, 140,
+   141, 141, 141, 141, 141, 141, 141, 141, 142, 142, 142, 142, 143, 144, 142, 142,
+   143, 142, 142, 145, 146, 147, 142, 142, 142, 146, 142, 142, 142, 148, 142, 149,
+   142, 150, 151, 151, 151, 151, 151, 152, 153, 153, 153, 153, 153, 153, 153, 153,
+   154, 155, 156, 156, 156, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
+   167, 167, 167, 167, 167, 168, 169, 169, 170, 171, 172, 172, 172, 172, 172, 173,
+   172, 172, 174, 153, 153, 153, 153, 175, 176, 177, 178, 178, 179, 180, 181, 182,
+   183, 183, 184, 183, 185, 186, 167, 167, 187, 188, 189, 189, 189, 190, 189, 191,
+   192, 192, 193,   8,   8, 194, 195, 124, 196, 196, 196, 196, 197, 196, 196, 196,
+   198, 198, 198, 198, 199, 199, 199, 200, 201, 201, 201, 202, 203, 204, 204, 204,
+   205, 138, 138, 206, 207, 208, 209, 210,   4,   4, 211,   4,   4, 212, 213, 214,
+     4,   4,   4, 215,   8,   8,   8,   8,  11, 216,  11,  11, 216, 217,  11, 218,
+    11,  11,  11, 219, 219, 220,  11, 221, 222,   0,   0,   0,   0,   0, 223, 224,
+   225, 226,   0,   0, 227,   8,   8, 228,   0,   0, 229, 230, 231,   0,   4,   4,
+   232,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0, 233, 124, 234, 124,   0,   0, 235, 235, 235, 235, 235, 235, 235, 235,
+     0,   0,   0,   0,   0,   0,   0, 236, 237, 237, 237, 237, 237, 237,   4,   4,
+   238, 238, 238, 238, 238, 238, 238, 239, 138, 138, 139, 240, 240, 240, 241, 242,
+   142, 243, 244, 244, 244, 244,  14,  14,   0,   0,   0,   0,   0, 245, 124, 124,
+   246, 247, 246, 246, 246, 246, 246, 248, 246, 246, 246, 246, 246, 246, 246, 246,
+   246, 246, 246, 246, 246, 249, 124,   0, 250,   0, 251, 252, 253, 254, 254, 254,
+   254, 255, 256, 257, 257, 257, 257, 258, 259, 260, 260, 261, 141, 141, 141, 141,
+   262,   0, 260, 260,   0,   0, 263, 257, 141, 262,   0,   0,   0,   0, 141, 264,
+     0,   0,   0,   0,   0, 257, 257, 265, 257, 257, 257, 257, 257, 266,   0,   0,
+   246, 246, 246, 246,   0,   0,   0,   0, 267, 267, 267, 267, 267, 267, 267, 267,
+   268, 267, 267, 267, 269, 270, 270, 270, 271, 271, 271, 271, 271, 271, 271, 271,
+   271, 271, 272, 124,  14,  14,  14,  14,  14,  14, 273, 273, 273, 273, 273, 274,
+     0,   0, 275,   4,   4,   4,   4,   4, 276,   4,   4,   4,   4, 226, 124, 277,
+   278, 278, 279, 233, 280, 280, 280, 281, 282, 282, 282, 282, 283, 284,  47,  47,
+   285, 285, 286, 287, 287, 288, 141, 289, 290, 290, 290, 290, 291, 292, 137, 293,
+   294, 294, 294, 295, 296, 297, 137, 137, 298, 298, 298, 298, 299, 300, 301, 302,
+   303, 304, 244,   4,   4, 305, 306, 151, 151, 151, 151, 151, 301, 301, 307, 308,
+   141, 141, 309, 141, 310, 141, 141, 311, 124, 124, 124, 124, 124, 124, 124, 124,
+   246, 246, 246, 246, 246, 246, 312, 246, 246, 246, 246, 246, 246, 313, 124, 124,
+   314, 315,  21, 316, 317,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,
+    27,  27,  27, 318,  27,  27,  27,  27,  27,  27,  27,  27,  27, 124, 124,  27,
+     8, 233, 319,   0,   0, 320, 321, 322,  27,  27,  27,  27,  27,  27,  27, 323,
+   324,   0,   1,   2,   1,   2, 325, 256, 257, 326, 141, 262, 327, 328, 329, 330,
+   331, 332, 333, 334, 335, 335, 124, 124, 332, 332, 332, 332, 332, 332, 332, 336,
+   337,   0,   0, 338,  11,  11,  11,  11, 339, 340, 341, 124, 124,   0,   0, 342,
+   343, 344, 345, 345, 345, 346, 347, 348, 349, 349, 350, 351, 352, 353, 353, 354,
+   355, 356, 357, 357, 358, 359, 124, 124, 360, 360, 360, 360, 360, 361, 361, 361,
+   362, 363, 364, 365, 365, 366, 365, 367, 368, 368, 369, 370, 370, 370, 371, 372,
+   372, 373, 374, 375, 376, 376, 376, 377, 378, 378, 378, 378, 378, 378, 378, 378,
+   378, 378, 378, 379, 378, 380, 381, 124, 382,   4,   4, 383, 124, 124, 124, 124,
+   384, 385, 385, 386, 387, 388, 389, 389, 390, 391, 392, 124, 124, 124, 393, 394,
+   395, 396, 397, 398, 399, 400, 124, 124, 401, 401, 402, 403, 402, 404, 402, 402,
+   405, 406, 407, 408, 409, 409, 410, 410, 411, 411, 124, 124, 412, 412, 413, 414,
+   415, 415, 415, 416, 417, 418, 419, 420, 421, 422, 423, 124, 124, 124, 124, 124,
+   424, 424, 424, 424, 425, 124, 124, 124, 426, 426, 426, 427, 426, 426, 426, 428,
+   429, 429, 430, 431, 432, 432, 433, 432, 434, 124, 124, 124, 124, 124, 124, 124,
+   124, 124, 124, 124, 124, 124,  27, 435, 436, 436, 437, 438, 439, 440, 124, 441,
+   442, 442, 443, 444, 444, 445, 124, 446, 447, 124, 124, 448, 449, 124, 450, 451,
+   452, 452, 452, 452, 453, 454, 452, 455, 456, 456, 456, 456, 457, 458, 459, 460,
+   461, 461, 461, 462, 463, 464, 464, 465, 466, 466, 466, 466, 466, 466, 467, 468,
+   469, 470, 469, 469, 471, 124, 124, 124, 472, 473, 474, 475, 475, 475, 476, 477,
+   478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 487, 488, 489, 490, 491, 124,
+   492, 492, 492, 492, 492, 493, 494, 124, 495, 495, 495, 495, 496, 497, 124, 124,
+   498, 498, 498, 499, 498, 500, 124, 124, 501, 501, 501, 501, 502, 503, 504, 124,
+   505, 505, 505, 506, 506, 137, 507, 124, 508, 509, 510, 508, 511, 124, 124, 124,
+   512, 512, 512, 513, 124, 124, 124, 124, 124, 124, 514, 514, 514, 514, 514, 515,
+   516, 517, 518, 519, 520, 521, 124, 124, 124, 124, 522, 523, 523, 522, 524, 124,
+   525, 525, 525, 525, 526, 527, 527, 527, 527, 527, 528, 153, 529, 529, 529, 530,
+   531, 124, 124, 124, 124, 124, 532, 124, 124, 124, 124, 124, 533, 533, 534, 535,
+   536, 537, 537, 538, 539, 537, 540, 541, 541, 542, 543, 544, 124, 124, 124, 124,
+   545, 546, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 555, 556, 557, 124,
+   124, 124, 124, 124, 124, 124, 558, 559, 560, 561, 560, 562, 560, 563, 124, 124,
+   124, 124, 124, 564, 565, 565, 565, 566, 567, 567, 567, 567, 567, 567, 567, 567,
+   567, 568, 124, 124, 124, 124, 124, 124, 567, 567, 567, 567, 567, 567, 569, 570,
+   567, 567, 567, 567, 571, 124, 124, 124, 124, 572, 572, 572, 572, 572, 572, 573,
+   574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 575, 574, 574,
+   574, 574, 574, 574, 574, 574, 574, 576, 577, 577, 577, 577, 577, 577, 577, 577,
+   577, 577, 577, 577, 578, 124, 124, 124, 579, 579, 579, 580, 124, 124, 124, 124,
+   273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 581, 582, 583, 584, 585,
+   585, 585, 585, 586, 587, 588, 589, 590, 591, 591, 591, 591, 592, 593, 594, 595,
+   591, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 596, 596, 596, 597,
+   124, 124, 124, 124, 598, 598, 598, 598, 598, 599, 600, 601, 600, 602, 124, 124,
+   603, 603, 603, 603, 604, 603, 603, 603, 605, 603, 124, 124, 124, 124, 606, 607,
+   608, 608, 608, 608, 608, 608, 608, 608, 609, 609, 609, 609, 609, 609, 609, 609,
+   609, 609, 609, 609, 609, 610, 124, 611, 608, 612, 124, 124, 124, 124, 124, 124,
+   608, 608, 608, 608, 608, 608, 608, 613, 124, 124, 124, 124, 124, 124, 124, 614,
+   615, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
+   254, 254, 616, 617, 124, 618, 619, 620, 620, 620, 620, 620, 620, 620, 620, 620,
+   620, 620, 620, 620, 620, 620, 620, 621, 622, 622, 622, 622, 622, 622, 623, 624,
+   625, 626, 627, 124, 124, 124, 124, 124,   0,   0,   0,   0,   0,   0,   0, 340,
+     0,   0,   0, 628,   0, 629,   0, 629,   8,   8, 194,   8, 630,   0,   0,   0,
+     0,   0,   0,   0, 627, 124, 124, 124,   0,   0,   0,   0,   0,   0,   0, 631,
+     0,   0, 632,   0,   0,   0, 633, 634, 635,   0, 636,   0,   0,   0, 234, 124,
+    11,  11,  11,  11, 637, 124, 124, 124, 124, 124, 124, 124,   0, 627,   0, 627,
+     0,   0,   0,   0,   0, 638,   0, 639,   0,   0,   0,   0,   0, 223,   0,   0,
+     0, 640, 641, 642, 643,   0,   0,   0, 644, 645,   0, 646, 647, 648,   0,   0,
+     0,   0, 649,   0,   0,   0,   0,   0,   0,   0,   0,   0, 650,   0,   0,   0,
+   651, 651, 651, 651, 651, 651, 651, 651, 652, 653, 654, 124, 124, 124, 124, 124,
+     4, 655, 656, 124, 124, 124, 124, 124, 657, 658, 659,  14,  14,  14, 660, 124,
+   661, 124, 124, 124, 124, 124, 124, 124, 662, 662, 663, 664, 665, 124, 124, 124,
+   124, 666, 667, 124, 668, 668, 668, 669, 124, 124, 124, 124, 124, 670, 670, 671,
+   124, 124, 124, 124, 124, 672, 672, 673, 124, 124, 124, 124, 674, 675, 674, 676,
+   124, 124, 124, 124, 124, 124, 677, 678, 679, 679, 679, 679, 679, 679, 679, 679,
+   679, 679, 679, 679, 680, 681, 124, 124, 682, 682, 682, 682, 683, 684, 124, 124,
+   124, 124, 124, 124, 124, 124, 124, 324,   0,   0,   0, 685, 124, 124, 124, 124,
+   324,   0,   0, 245, 124, 124, 124, 124, 686,  27, 687, 688, 689, 690, 691, 692,
+   693, 694, 695, 694, 124, 124, 124, 696,   0,   0, 348,   0,   0,   0,   0,   0,
+     0, 627, 225, 324, 324, 324,   0, 631,   0,   0, 245, 124, 124, 124, 697,   0,
+   698,   0,   0, 348, 639, 227, 631, 124,   0,   0,   0,   0,   0, 699, 340, 340,
+     0,   0,   0,   0,   0, 233, 348, 629, 348,   0,   0,   0, 700, 233,   0,   0,
+   700,   0, 245, 348, 227, 639, 124, 124,   0,   0,   0,   0,   0, 700, 245, 340,
+   701,   0,   0,   0, 702, 703, 704, 639,   0, 320,   0,   0,   0,   0,   0, 234,
+   246, 246, 246, 246, 246, 246, 124, 124, 246, 312, 246, 246, 246, 246, 246, 246,
+   246, 246, 312, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 705, 246,
+   246, 246, 246, 246, 246, 312, 124, 124, 246, 312, 124, 124, 124, 124, 124, 124,
+   246, 246, 246, 246, 706, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 313,
+   707, 124,   0,   0,   0,   0,   0,   0,   8,   8,   8,   8,   8,   8,   8,   8,
+     8,   8,   8,   8,   8,   8,   8,   0,   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,  10,  11,
+    12,  13,  14,  15,   8,   8,   8,   8,  16,   8,   8,   8,  17,  18,  18,  18,
+    19,  19,  19,  19,  19,  20,  19,  19,  21,  22,  22,  22,  22,  22,  22,  22,
+    22,  23,  21,  22,  22,  22,  23,  21,  24,  25,  25,  25,  25,  25,  25,  25,
+    25,  25,  12,  12,  25,  25,  26,  27,  25,  28,  12,  12,  29,  30,  29,  31,
+    29,  29,  32,  32,  29,  29,  29,  29,  31,  29,  33,   7,   7,  34,  29,  29,
+    35,  29,  29,  29,  29,  29,  29,  30,  36,  36,  36,  37,  36,  36,  36,  36,
+    36,  36,  38,  39,  40,  40,  40,  40,  41,  12,  12,  12,  42,  42,  42,  42,
+    42,  42,  43,  44,  45,  45,  45,  45,  45,  45,  45,  46,  45,  45,  45,  47,
+    48,  48,  48,  48,  48,  48,  48,  49,  36,  36,  38,  12,  50,  51,  29,  29,
+    52,  29,  29,  29,  53,  53,  53,  53,  54,  55,  53,  53,  53,  56,  53,  53,
+    57,  58,  57,  59,  59,  57,  57,  57,  57,  57,  60,  57,  61,  62,  63,  57,
+    57,  59,  59,  64,  12,  65,  12,  66,  57,  62,  57,  57,  57,  57,  57,  64,
+    67,  67,  68,  69,  70,  71,  71,  71,  71,  71,  72,  71,  72,  73,  74,  72,
+    68,  69,  70,  74,  75,  12,  67,  76,  12,  77,  71,  71,  71,  68,  12,  12,
+    78,  78,  79,  80,  80,  79,  79,  79,  79,  79,  81,  79,  81,  78,  82,  79,
+    79,  80,  80,  82,  83,  12,  12,  12,  79,  84,  79,  79,  82,  12,  78,  79,
+    85,  85,  86,  87,  87,  86,  86,  86,  86,  86,  88,  86,  88,  85,  89,  86,
+    86,  87,  87,  89,  12,  85,  12,  90,  86,  91,  86,  86,  86,  86,  12,  12,
+    92,  93,  94,  92,  95,  96,  97,  95,  98,  99,  94,  92, 100, 100,  96,  92,
+    94,  92,  95,  96,  99,  98,  12,  12,  12,  92, 100, 100, 100, 100,  94,  12,
+   101, 101, 101, 102, 102, 101, 101, 101, 101, 101, 102, 101, 101, 101, 103, 101,
+   101, 102, 102, 103,  12, 104, 105, 103, 101, 106, 101, 101,  12, 107, 101, 101,
+   108, 108, 108, 109, 109, 108, 108, 108, 108, 108, 109, 108, 108, 110, 111, 108,
+   108, 109, 109, 111,  12, 112,  12, 113, 108, 114, 108, 108, 110,  12,  12,  12,
+   115, 115, 115, 116, 116, 115, 115, 115, 115, 115, 115, 115, 115, 116, 116, 115,
+    12, 115, 115, 115, 115, 117, 115, 115, 118, 118, 119, 119, 119, 120, 121, 119,
+   119, 119, 119, 119, 122, 119, 119, 123, 119, 120, 124, 125, 119, 126, 119, 119,
+    12, 121, 119, 119, 121, 127,  12,  12, 128, 129, 129, 129, 129, 129, 129, 129,
+   129, 129, 130, 131, 129, 129, 129,  12,  12,  12,  12,  12, 132, 133, 134, 135,
+   135, 135, 135, 135, 135, 136, 135, 135, 135, 135, 135, 137, 135, 138, 135, 134,
+   135, 135, 137, 135, 139, 139, 139, 139, 139, 139, 140, 139, 139, 139, 139, 141,
+   140, 139, 139, 139, 139, 139, 139, 142, 139, 143, 144,  12, 145, 145, 145, 145,
+   146, 146, 146, 146, 146, 147,  12, 148, 146, 146, 149, 146, 150, 150, 150, 150,
+   151, 151, 151, 151, 151, 151, 152, 153, 151, 154, 152, 153, 152, 153, 151, 154,
+   152, 153, 151, 151, 151, 154, 151, 151, 151, 151, 154, 155, 151, 151, 151, 156,
+   151, 151, 153,  12, 157, 157, 157, 157, 157, 158, 157, 158, 159, 159, 159, 159,
+   160, 160, 160, 160, 160, 160, 160, 161, 162, 162, 162, 162, 162, 162, 163, 164,
+   162, 162, 165,  12, 166, 166, 166, 166, 166, 167,  12, 168, 169, 169, 169, 169,
+   169, 170,  12,  12, 171, 171, 171, 171, 171,  12,  12,  12, 172, 172, 172, 173,
+   173,  12,  12,  12, 174, 174, 174, 174, 174, 174, 174, 175, 174, 174, 175,  12,
+   176, 177, 178, 178, 178, 178, 179,  12, 178, 178, 178, 178, 178, 178, 180,  12,
+   178, 178, 181,  12, 159, 182,  12,  12, 183, 183, 183, 183, 183, 183, 183, 184,
+   183, 183, 183,  12, 185, 183, 183, 183, 186, 186, 186, 186, 186, 186, 186, 187,
+   186, 188,  12,  12, 189, 189, 189, 189, 189, 189, 189,  12, 189, 189, 190,  12,
+   189, 189, 191, 192, 193, 193, 193, 193, 193, 193, 193, 194, 195, 195, 195, 195,
+   195, 195, 195, 196, 195, 195, 195, 197, 195, 195, 198,  12, 195, 195, 195, 198,
+     7,   7,   7, 199,   7,   7,   7,  12, 200, 200, 200, 200, 200, 200, 200, 201,
+   202, 202, 202, 202, 203, 203, 203, 203, 203,  12,  12, 203, 204, 204, 204, 204,
+   204, 204, 205, 204, 204, 204, 206, 207, 208, 208, 208, 208,  19,  19, 209,  12,
+   146, 146, 210, 211, 202, 202,  12,  12, 212,   7,   7,   7, 213,   7, 214, 215,
+     0, 214, 216,  12,   2, 217, 218,   2,   2,   2,   2, 219, 220, 217, 221,   2,
+     2,   2, 222,   2,   2,   2,   2, 223,   8, 224,   8, 224,   8,   8, 225, 225,
+     8,   8,   8, 224,   8,  15,   8,   8,   8,  10,   8, 226,  10,  15,   8,  14,
+     0,   0,   0, 227,   0, 228,   0,   0, 229,   0,   0, 230,   0,   0,   0, 231,
+     2,   2,   2, 232, 233,  12,  12,  12, 234,  12,  12,  12,   0, 235, 236,   0,
+     4,   0,   0,   0,   0,   0,   0,   4,   2,   2,   5,  12,   0,   0, 233,  12,
+     0,   0, 231,  12, 237, 237, 237, 237,   0, 238,   0,   0, 239, 239, 239, 239,
+    18,  18,  18,  18,  18,  12, 240,  18, 241, 241, 241, 241, 241, 241,  12, 242,
+   243,  12,  12, 242, 151, 154,  12,  12, 151, 154, 151, 154,   0,   0,   0, 233,
+   244, 244, 244, 244, 244, 244, 245, 244, 244,  12,  12,  12, 244, 246,  12,  12,
+     0, 247,   0,   0, 248, 244, 249, 250,   0,   0, 244,   0, 251, 252, 252, 252,
+   252, 252, 252, 252, 252, 253, 254, 255, 256, 257, 257, 257, 257, 257, 257, 257,
+   257, 257, 258, 256,  12, 259, 260, 260, 260, 260, 260, 260, 261, 150, 150, 150,
+   150, 150, 150, 262,   0, 233,  12, 131, 150, 150, 150, 263, 257, 257, 257, 258,
+   257, 257,   0,   0, 264, 264, 264, 264, 264, 264, 264, 265, 264, 266,  12,  12,
+   267, 267, 267, 267, 268, 268, 268, 268, 268, 268, 268,  12, 269, 269, 269, 269,
+   269, 269,  12,  12, 236,   2,   2,   2,   2,   2, 230,   2, 270,   2,   2,   2,
+   271, 271, 271, 271, 271, 271, 271, 272, 273, 273, 273, 273, 273, 273,  12,  12,
+   274, 274, 274, 274, 274, 275,  12, 276, 274, 274, 275,  12, 277, 277, 277, 277,
+   277, 277, 277, 278, 279, 279, 279, 279, 279,  12,  12, 280, 150, 150, 150, 281,
+   282, 282, 282, 282, 282, 282, 282, 283, 282, 282, 284, 285, 145, 145, 145, 286,
+   287, 287, 287, 287, 287, 288,  12,  12, 287, 287, 287, 289, 287, 287, 289, 287,
+   290, 290, 290, 290, 291,  12,  12,  12,  12,  12, 292, 290, 293, 293, 293, 293,
+   293, 294,  12,  12, 155, 154, 155, 154, 155, 154,  12,  12,   2,   2,   3,   2,
+     2, 295, 296,  12, 293, 293, 293, 297, 293, 293, 297,  12, 150,  12,  12,  12,
+   150, 262, 298, 150, 150, 150, 150,  12, 244, 244, 244, 246, 244, 244, 246,  12,
+     2, 299,  12,  12, 300,  22,  12,  24,  25,  26,  25, 301, 302, 303,  25,  25,
+    29,  29,  29, 304,   7,   7,   7, 305, 231,   0,   0,   0,   0, 231,   0,  12,
+    29, 306,  29,  29,  29,  29,  29, 307, 308,   0,   0,   0,   0, 309, 257, 257,
+   257, 257, 257, 310, 311, 150, 311, 150, 311, 150, 311, 281,   0, 231,   0, 231,
+    12,  12, 308, 233, 312, 312, 312, 313, 312, 312, 312, 312, 312, 314, 312, 312,
+   312, 312, 314, 315, 312, 312, 312, 316, 312, 312, 314,  12, 231, 131,   0,   0,
+     0, 131,   0,   0,   8,   8,   8,  14,   0,   0,   0, 317, 318,  12,  12,  12,
+     0,   0,   0, 319, 320, 320, 320, 320, 320, 320, 320, 321, 322, 322, 322, 322,
+   323,  12,  12,  12, 214,   0,   0,   0,   0,   0,   0,  12, 324, 324, 324, 324,
+   324,  12,  12, 325, 326, 326, 326, 326, 326, 326, 327,  12, 328, 328, 328, 328,
+   328, 328, 329,  12, 330, 330, 330, 330, 330, 330, 330, 331, 332, 332, 332, 332,
+   332,  12, 332, 332, 332, 333,  12,  12, 334, 334, 334, 334, 335, 335, 335, 335,
+   336, 336, 336, 336, 336, 336, 336, 337, 336, 336, 337,  12, 338, 338, 338, 338,
+   338,  12, 338, 338, 338, 338, 338,  12, 339, 339, 339, 339, 339, 339,  12,  12,
+   340, 340, 340, 340, 340,  12,  12, 341, 342, 342, 343, 342, 343, 344, 342, 342,
+   344, 342, 342, 342, 344, 342, 344, 345, 346, 346, 346, 346, 346,  12,  12,  12,
+   347, 347, 347, 347, 347, 348,  12,  12, 347, 349,  12,  12, 347, 347,  12,  12,
+     2, 350,   2,   2, 351,   2, 299,  12, 352, 353, 354, 352, 352, 352, 352, 352,
+   352, 355, 356, 357, 358, 358, 358, 358, 358, 359, 358, 358, 360, 360, 360, 360,
+   361, 361, 361, 361, 361, 361, 361, 362,  12, 363, 361, 361, 364, 364, 364, 364,
+   365, 366, 367, 364, 368, 368, 368, 368, 368, 368, 368, 369, 370, 370, 370, 370,
+   370, 370, 371, 372, 373, 373, 373, 373, 373, 373, 374,  12, 375, 375, 375, 375,
+   376, 376, 376, 376, 376, 376,  12, 376, 377, 376, 376, 376, 378, 379,  12, 378,
+   378, 380, 380, 378, 378, 378, 378, 378, 378, 381, 382, 383, 378, 378, 384,  12,
+   385, 385, 385, 385, 386, 386, 386, 386, 387, 387, 387, 387, 387, 388, 389, 387,
+   387, 388,  12,  12, 390, 390, 390, 390, 390, 391, 392, 390, 393, 393, 393, 393,
+   393, 394, 393, 393, 395, 395, 395, 395, 396,  12, 395, 395, 397, 397, 397, 397,
+   398,  12, 399, 400,  12,  12, 399, 397, 401, 401, 401, 401, 401, 401, 402,  12,
+   403, 403, 403, 403, 404,  12,  12,  12, 404,  12, 405, 403, 406, 406, 406, 406,
+   406, 406,  12,  12, 406, 406, 407,  12, 408, 408, 408, 408, 408, 409, 410, 408,
+   408, 409,  12, 411,  29,  29,  29, 412, 413, 413, 413, 413, 413, 413, 414, 415,
+   415,  12,  12,  12, 416,  29,  12,  12,  29,  29, 417,  12,  12,  12, 416,  29,
+   418, 418, 418, 418, 418, 418,  12,  12, 419, 419, 419, 419, 419, 419, 420,  12,
+   421, 421, 421, 421, 421, 421, 422,  12, 423, 423, 423, 423, 423, 423, 423,  12,
+   424, 424, 424, 424, 424, 425,  12,  12, 426, 426, 426, 426, 426, 426, 426, 427,
+   428, 426, 426, 426, 426, 427,  12, 429, 430, 430, 430, 430, 431,  12,  12, 432,
+   433, 433, 433, 433, 433, 433, 434,  12, 433, 433, 435,  12, 436, 436, 436, 436,
+   436, 437, 436, 436, 436, 436,  12,  12, 438, 438, 438, 438, 438, 439,  12,  12,
+   440, 440, 440, 440, 118, 119, 119, 119, 119, 127,  12,  12, 441, 441, 441, 441,
+   442, 441, 441, 441, 443,  12,  12,  12, 444, 445, 446, 447, 444, 444, 444, 447,
+   444, 444, 448,  12, 449, 449, 449, 449, 449, 449, 450,  12, 449, 449, 451,  12,
+   452, 453, 452, 454, 454, 452, 452, 452, 452, 452, 455, 452, 455, 453, 456, 452,
+   452, 454, 454, 457, 458, 459,  12, 453, 452, 460, 452, 458, 452, 458,  12,  12,
+   461, 461, 462, 463, 461, 461, 461, 461, 461, 462, 461, 461, 464, 465, 466, 461,
+   461, 462, 467,  12, 468,  12,  12,  12, 469, 469, 469, 469, 469, 469, 469, 470,
+   471,  12,  12,  12, 472, 472, 472, 472, 472, 472,  12,  12, 472, 472, 473,  12,
+   474, 474, 474, 474, 474, 475, 474, 474, 474, 474, 474, 475, 476, 476, 476, 476,
+   476, 477,  12,  12, 476, 476, 478,  12, 178, 178, 178, 180, 479, 479, 479, 479,
+   479, 479, 480,  12, 145,  12,  12,  12, 481, 481, 481, 481, 481, 481, 482, 483,
+   481, 481, 481,  12, 481, 482,  12,  12, 484, 484, 484, 484, 484, 484, 484,  12,
+   485, 485, 485, 485, 486,  12,  12, 487, 488, 489, 490, 488, 488, 491, 488, 488,
+   488, 488, 488, 488, 488, 492, 493, 488, 488, 489,  12,  12, 488, 488, 494,  12,
+   495, 495, 496, 495, 495, 495, 495, 495, 495, 497,  12,  12, 498, 498, 498, 498,
+   498, 498,  12,  12, 499, 499, 499, 499, 500,  12,  12,  12, 501, 501, 501, 501,
+   501, 501, 502,  12,  53,  53, 503,  12, 440, 440,  12,  12, 504, 504, 504, 504,
+   505,  12,  12,  12, 504, 504, 505,  12, 506, 506, 507, 506, 506, 506, 506, 506,
+   506, 508, 506, 506, 506, 509,  12,  12, 506, 506, 506, 510, 511, 511, 511, 511,
+   512, 511, 511, 511, 511, 511, 513, 511, 511, 514,  12,  12, 515, 516, 517, 515,
+   515, 515, 515, 515, 515, 516, 518, 517, 515, 515,  12,  12, 515, 515, 519,  12,
+   520, 521, 522, 520, 520, 520, 520, 520, 520, 520, 520, 523, 521, 520, 524,  12,
+   520, 520, 525,  12, 526, 526, 526, 526, 526, 526, 526,  12, 526, 526, 527,  12,
+   528, 528, 528, 528, 528, 528, 529,  12, 530, 530, 530, 530, 531, 530, 530, 530,
+   530, 530, 532, 533, 530, 530, 532,  12, 534,  12,  12,  12, 100, 100, 100, 100,
+    96,  12,  12,  98, 535, 535, 535, 535, 535, 535, 536,  12, 535, 535, 535, 537,
+   535, 538,  12,  12, 535,  12,  12,  12, 539, 539, 539, 539, 540,  12,  12,  12,
+   541, 541, 541, 541, 541, 542,  12,  12, 541, 541, 543,  12, 544, 544, 544, 544,
+   544, 545,  12,  12, 546, 546, 546, 546, 546, 546, 547,  12, 269, 269, 548,  12,
+   549, 549, 549, 549, 549, 549, 549, 550, 549, 549, 551, 552, 553, 553, 553, 553,
+   553, 553, 553, 554, 553, 553, 555,  12, 556, 556, 556, 556, 556, 556, 556, 557,
+   556, 557,  12,  12, 558, 558, 558, 558, 558, 559,  12,  12, 558, 558, 560, 558,
+   560, 558, 558, 558, 558, 558,  12, 561, 562, 562, 562, 562, 562, 562, 563,  12,
+   564, 564, 564, 564, 564, 564, 565,  12, 566, 566, 566, 566, 566, 566, 567, 566,
+   566,  12,  12,  12, 568, 568, 568, 568, 568, 568, 569, 570, 568, 568,  12, 570,
+   571, 572,  12,  12, 244, 573,  12,  12, 574, 574, 574, 574, 575, 575, 575, 575,
+   575, 576,  12,  12,  12,  12,  12, 577, 574, 574, 574, 578, 578,  12,  12,  12,
+   257, 579, 257, 580, 581, 252, 252, 252, 582,  12,  12,  12, 583,  12,  12,  12,
+   253, 584,  12,  12,  12, 257,  12,  12, 585, 585, 585, 585, 585, 585, 585,  12,
+   586, 586, 586, 586, 586, 586, 587,  12, 586, 586, 586, 588, 586, 586, 588,  12,
+   586, 586, 589, 586,   0,  12,  12,  12,   0,  12, 238,   0, 317,  12,  12,  12,
+     7, 590,  12,  12,   0, 233,  12,  12,   0, 231, 308,   0,   0, 591, 227,   0,
+     0,   0, 591,   7, 212, 592,   7,   0,   0,   0, 593, 227,   8, 224,  12,  12,
+     0, 231,  12,  12,   0,   0, 317,  12,   0,   0,   0, 228, 594, 595, 308, 228,
+     0,   0, 596, 308,   0, 308,   0,   0,   0, 596, 231, 308,   0, 228,   0, 228,
+     0,   0, 596, 231,   0, 597, 238,   0, 228,   0,   0,   0,   0, 233,   0,   0,
+     0,   0,   0, 238, 598, 598, 598, 598, 598, 598, 598,  12,  12,  12, 599, 598,
+   600, 598, 598, 598,   2,   2,   2, 299,  12, 270, 299,  12, 239, 601, 239, 239,
+   239, 239, 602, 239, 603, 604, 601,  12,  19,  19,  19, 605,  12,  12,  12, 606,
+   607, 607, 607, 607, 607, 607, 607, 608, 607, 607, 607, 609, 607, 607, 609, 610,
+   611, 611, 611, 611, 611, 611, 611, 612, 613, 613, 613, 613, 613, 613, 614, 615,
+   616, 616, 616, 616, 616, 616, 617,  12, 618, 618, 618, 618, 618, 618, 619, 620,
+   621, 621, 621, 621, 621, 621, 621, 622, 621, 623,  12, 624, 151, 154, 151, 625,
+   151, 151, 151, 154, 626, 626, 626, 626, 626, 627, 626, 626, 626, 628,  12,  12,
+   629, 629, 629, 629, 629, 629, 629,  12, 629, 629, 630, 631,   0, 317,  12,  12,
+    29, 632,  29,  29, 633, 634, 632,  29, 412,  29, 635,  12, 636,  51, 635, 632,
+   633, 634, 635, 635, 633, 634, 412,  29, 412,  29, 632, 637,  29,  29, 638,  29,
+    29,  29,  29,  12, 632, 632, 638,  29,  50,  12,  12,  12,  12, 238,   0,   0,
+   639,  12,  12,  12,   0,   0, 317,   0,   0,   0,  12,  12,   0,   0, 231, 238,
+     0, 231, 317, 308,   0,   0,   0, 640,   0,   0, 231, 131, 641,  12,  12,  12,
+   244, 244, 573,  12, 642,  12,  12,  12,   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, 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,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,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,
+  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,
-  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,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,
-  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,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,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,1936,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,1937,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1938,   0,
-  1939,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1940,
+     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,1936,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1937,   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,1943,
-  1944,   0,   0,   0,   0,   0,   0,1945,   0,1946,   0,   0,   0,   0,   0,   0,
-     0,   0,1947,   0,   0,1948,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,1950,   0,1949,1951,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1953,
-  1952,   0,1954,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1955,1956,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1957,   0,   0,   0,
-     0,   0,   0,   0,   0,1958,1961,1959,1965,1960,1962,1964,1963,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1967,1966,1968,   0,
+     0,   0,1938,   0,1939,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1940,   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,1943,1944,   0,   0,   0,   0,   0,   0,1945,   0,1946,   0,   0,
+     0,   0,   0,   0,   0,   0,1947,   0,   0,1948,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1950,   0,1949,
+  1951,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1953,1952,   0,1954,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,1955,1956,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1957,   0,   0,   0,   0,   0,   0,   0,   0,1958,1961,1959,1965,1960,1962,1964,
+  1963,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1967,1966,1968,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1969,1970,1971,1972,1973,1974,1975,   0,   0,   0,
      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,1969,1970,1971,1972,1973,1974,1975,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1976,
-  1977,1978,1980,1979,1981,   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,1976,1977,1978,1980,1979,1981,   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] =
+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,
@@ -4612,42 +4358,37 @@ _hb_ucd_i16[92] =
       0,-2016,-2104,    0,    0,-2106,-2108,-2106,-2250,    0,-2527,    0,
 };
 
-static inline uint_fast8_t
-_hb_ucd_gc (unsigned u)
+static inline uint8_t _hb_ucd_gc (unsigned u)
 {
-  return u<1114110u?_hb_ucd_u8[6472+(((_hb_ucd_u8[816+(((_hb_ucd_u16[((_hb_ucd_u8[272+(((_hb_ucd_u8[u>>1>>3>>4>>4])<<4)+((u>>1>>3>>4)&15u))])<<4)+((u>>1>>3)&15u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+  return u<1114110 ? _hb_ucd_u8[6560u+((_hb_ucd_u8[816u+((_hb_ucd_u16[((_hb_ucd_u8[272u+((_hb_ucd_u8[((((((((u)>>1))>>3))>>4))>>4)])<<4)+((((((((u)>>1))>>3))>>4))&15)])<<4)+((((((u)>>1))>>3))&15)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : 2;
 }
-static inline uint_fast8_t
-_hb_ucd_ccc (unsigned u)
+static inline uint8_t _hb_ucd_ccc (unsigned u)
 {
-  return u<125259u?_hb_ucd_u8[8504+(((_hb_ucd_u8[7936+(((_hb_ucd_u8[7460+(((_hb_ucd_u8[7100+(((_hb_ucd_u8[6854+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
+  return u<125259 ? _hb_ucd_u8[8620u+((_hb_ucd_u8[8036u+((_hb_ucd_u8[7556u+((_hb_ucd_u8[7188u+((_hb_ucd_u8[6942u+((((((((u)>>2))>>2))>>2))>>3)])<<3)+((((((((u)>>2))>>2))>>2))&7)])<<2)+((((((u)>>2))>>2))&3)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)] : 0;
 }
-static inline unsigned
-_hb_ucd_b4 (const uint8_t* a, unsigned i)
+static inline uint8_t _hb_ucd_b4 (const uint8_t* a, unsigned i)
 {
-  return (a[i>>1]>>((i&1u)<<2))&15u;
+  return (a[i>>1]>>((i&1)<<2))&15;
 }
-static inline int_fast16_t
-_hb_ucd_bmg (unsigned u)
+static inline int16_t _hb_ucd_bmg (unsigned u)
 {
-  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9396+(((_hb_ucd_u8[9164+(((_hb_ucd_u8[9068+(((_hb_ucd_b4(9004+_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;
+  return u<65380 ? _hb_ucd_i16[((_hb_ucd_u8[9516u+((_hb_ucd_u8[9284u+((_hb_ucd_u8[9188u+((_hb_ucd_b4(_hb_ucd_u8+9124u,((((((((u)>>1))>>2))>>3))>>3)))<<3)+((((((((u)>>1))>>2))>>3))&7)])<<3)+((((((u)>>1))>>2))&7)])<<2)+((((u)>>1))&3)])<<1)+((u)&1)] : 0;
 }
-static inline uint_fast8_t
-_hb_ucd_sc (unsigned u)
+static inline uint8_t _hb_ucd_sc (unsigned u)
 {
-  return u<918000u?_hb_ucd_u8[10398+(((_hb_ucd_u16[3952+(((_hb_ucd_u16[2624+(((_hb_ucd_u8[9870+(((_hb_ucd_u8[9644+(u>>3>>2>>3>>4)])<<4)+((u>>3>>2>>3)&15u))])<<3)+((u>>3>>2)&7u))])<<2)+((u>>3)&3u))])<<3)+((u)&7u))]:2;
+  return u<918000 ? _hb_ucd_u8[10950u+((_hb_ucd_u16[4648u+((_hb_ucd_u16[2608u+((_hb_ucd_u8[10214u+((_hb_ucd_u8[9764u+((((((((u)>>2))>>2))>>3))>>4)])<<4)+((((((((u)>>2))>>2))>>3))&15)])<<3)+((((((u)>>2))>>2))&7)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)] : 2;
 }
-static inline uint_fast16_t
-_hb_ucd_dm (unsigned u)
+static inline uint16_t _hb_ucd_dm (unsigned u)
 {
-  return u<195102u?_hb_ucd_u16[6244+(((_hb_ucd_u8[16628+(((_hb_ucd_u8[16246+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+  return u<195102 ? _hb_ucd_u16[7480u+((_hb_ucd_u8[13904u+((_hb_ucd_u8[13522u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)] : 0;
 }
 
 
 #else
 
-static const uint8_t
-_hb_ucd_u8[13730] =
+#include 
+
+static const uint8_t _hb_ucd_u8[13937]=
 {
     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
     7,  7,  7,  7,  9, 10,  7,  7,  7,  7,  7, 11, 12, 12, 12, 13,
@@ -4655,7 +4396,7 @@ _hb_ucd_u8[13730] =
     7, 25, 22, 22, 22, 26, 27, 28, 22, 29, 30, 31, 32, 33, 34, 35,
     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, 21, 22, 36,
-    7,  7,  7,  7, 37, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+    7,  7,  7,  7,  7,  7, 37, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
@@ -4708,20 +4449,20 @@ _hb_ucd_u8[13730] =
   111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
   111,111,167,111,111,111,111,111,111,111,111,111,111,111,111,111,
    34, 34, 34, 34,168,169,170, 34,111,111,171,111,172,173,174,175,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,
+   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,119,
    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,176,111,111,111,111,111,111,
-  111,111,111,111,111,111,111,111, 67,177, 67, 67, 67, 67,178, 67,
-   67, 67,179,180,181,131, 65,111,182,183,184,185,186,187,188,189,
-   67, 67, 67, 67,190,191,111,111,111,111,111,111,111,111,192,111,
-  193,194,195,111,111,196,111,111,111,197,111,198,111,111,111, 34,
-   34,199,200,111,111,111,111,111,131,201,202,111, 34,203,111,111,
-   67, 67,204, 67, 67,111, 67,205, 67, 67, 67, 67, 67, 67, 67, 67,
-   67, 67, 67, 67, 67, 67, 67,177,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111, 67,177, 67, 67, 67,178,179, 67,
+   67, 67,180,181,182,131, 65,111,183,184,185,186,187,188,189,190,
+   67, 67, 67, 67,191,192,111,111,111,111,111,111,111,111,193,111,
+  194,195,196,111,111,197,111,111,111,198,111,199,111,200,111, 34,
+   34,201,202,111,111,111,111,111,131,203,204,111, 34,205,111,111,
+   67, 67,206, 67, 67,111, 67,207, 67, 67, 67, 67, 67, 67, 67, 67,
+   67,208, 67, 67, 67, 67, 67,177,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, 34,111,111,111,111,111,111,111,111,
-  206,111,194,194,111,111,111,111,111,111,111,111,111,111,111,111,
+   34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,
+  209,111,195,195,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,
@@ -4735,228 +4476,232 @@ _hb_ucd_u8[13730] =
    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,
+   16, 16, 36, 16, 16, 16, 16, 16, 39, 39, 39, 39, 39, 39, 39, 39,
+   39, 40, 40, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40,
+   39, 39, 41, 40, 40, 40, 41, 41, 40, 40, 40, 40, 40, 40, 40, 40,
+   42, 42, 42, 42, 42, 42, 42, 42, 32, 32, 41, 32, 16, 43, 16, 10,
+   40, 40, 40, 44, 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, 62,  2, 63, 36, 36, 36, 36, 64, 43, 43,
-    7,  7,  7,  7,  7,  2,  2, 36, 65, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 66, 43, 43, 43, 67, 47, 43, 43, 68, 69, 70, 43, 43, 36,
-    7,  7,  7,  7,  7, 36, 71, 72,  2,  2,  2,  2,  2,  2,  2, 73,
-   64, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 65, 36,
-   36, 36, 36, 43, 43, 43, 43, 43,  7,  7,  7,  7,  7, 36, 36, 36,
-   36, 36, 36, 36, 36, 64, 43, 43, 43, 43, 40, 21,  2, 40, 69, 20,
-   36, 36, 36, 43, 43, 69, 43, 43, 43, 43, 69, 43, 69, 43, 43, 43,
-    2,  2,  2,  2,  2,  2,  2,  2, 36, 36, 36, 36, 64, 43, 43,  2,
-   36, 36, 36, 36, 74, 36, 36, 36, 59, 59, 59, 75, 43, 43, 43, 43,
-   36, 36, 36, 36, 76, 43, 43, 43, 43, 75, 43, 43, 43, 43, 43, 43,
-   43, 77, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 77, 65, 78,
-   79, 43, 43, 43, 77, 78, 79, 78, 64, 43, 43, 43, 36, 36, 36, 36,
-   36, 43,  2,  7,  7,  7,  7,  7, 80, 36, 36, 36, 36, 36, 36, 36,
-   64, 78, 81, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 65, 78,
-   79, 43, 43, 77, 78, 78, 79, 36, 36, 36, 36, 82, 78, 78, 36, 36,
-   36, 43, 43,  7,  7,  7,  7,  7, 36, 20, 27, 27, 27, 53, 58, 43,
-   43, 77, 81, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 78,
-   79, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 65, 36, 36, 36,
-   36, 36, 36,  7,  7,  7,  7,  7, 43, 36, 64,  2,  2,  2,  2,  2,
-   79, 43, 43, 43, 77, 78, 79, 43, 60, 20, 20, 20, 83, 43, 43, 43,
-   43, 78, 81, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 65, 79,
-   79, 43, 43, 77, 78, 78, 79, 43, 43, 43, 43, 77, 78, 78, 36, 36,
-   72, 27, 27, 27, 27, 27, 27, 27, 43, 65, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 78, 77, 78, 78, 78, 78, 78, 79, 43,
-   36, 36, 36, 82, 78, 78, 78, 78, 78, 78, 78,  7,  7,  7,  7,  7,
-   27, 84, 61, 61, 53, 61, 61, 61, 77, 78, 65, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 65, 43, 77, 78, 78, 43, 43, 43, 43, 43,
-   43, 43, 43, 43, 36, 36, 36, 36,  7,  7,  7, 85, 27, 27, 27, 84,
-   64, 78, 66, 36, 36, 36, 36, 36, 78, 78, 78, 77, 78, 78, 43, 43,
-   43, 43, 77, 78, 78, 78, 81, 36, 86, 82, 78, 78, 78, 78, 78, 78,
-   43, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 65, 78,
-   79, 43, 43, 78, 78, 78, 79, 71, 61, 61, 36, 82, 27, 27, 27, 87,
-   27, 27, 27, 27, 84, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 77,
-   78, 43, 43, 43, 78, 78, 78, 78,  7, 78,  2,  2,  2,  2,  2,  2,
-   64, 36, 43, 43, 43, 43, 43, 88, 36, 36, 36, 69, 43, 43, 43, 57,
-    7,  7,  7,  7,  7,  2,  2,  2, 64, 36, 43, 43, 43, 43, 65, 36,
-   36, 36, 36, 40, 43, 43, 43, 43,  7,  7,  7,  7,  7,  7, 36, 36,
-   71, 61,  2,  2,  2,  2,  2,  2,  2, 89, 89, 61, 43, 61, 61, 61,
-    7,  7,  7,  7,  7, 27, 27, 27, 27, 27, 47, 47, 47,  4,  4, 78,
-   64, 43, 43, 43, 43, 43, 43, 77, 43, 43, 57, 43, 36, 36, 64, 43,
-   43, 43, 43, 43, 43, 43, 43, 61, 61, 61, 61, 70, 61, 61, 61, 61,
-    2,  2, 89, 61, 21,  2,  2,  2, 36, 36, 36, 36, 36, 82, 79, 43,
-   77, 43, 43, 43, 79, 77, 79, 65, 36, 36, 36, 78, 43, 36, 36, 43,
-   65, 78, 81, 82, 78, 78, 78, 36, 64, 43, 65, 36, 36, 36, 36, 36,
-   36, 77, 79, 77, 78, 78, 79, 82,  7,  7,  7,  7,  7, 78, 79, 61,
-   16, 16, 16, 16, 16, 50, 44, 16, 36, 36, 36, 36, 36, 36, 64, 43,
-    2,  2,  2,  2, 90, 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,
-   91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 71, 66,
-   92, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 93, 94, 94,
-   36, 36, 36, 36, 36, 58,  2, 95, 96, 36, 36, 36, 36, 36, 36, 36,
-   36, 43, 77, 78, 78, 78, 78, 81, 36, 43, 97,  2,  2,  2,  2,  2,
-   36, 43, 43, 43, 43, 43, 43, 43, 36, 36, 43, 79, 43, 43, 43, 78,
-   78, 78, 78, 77, 79, 43, 43, 43, 43, 43,  2, 80,  2, 60, 64, 43,
-    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2, 98,  2, 56, 43, 75,
-   36, 76, 36, 36, 36, 36, 36, 36, 36, 36, 64, 65, 36, 36, 36, 36,
-   36, 36, 36, 36, 64, 36, 36, 36, 43, 77, 78, 79, 77, 78, 78, 78,
-   78, 77, 78, 78, 79, 43, 43, 43, 61, 61,  2,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7, 27, 27, 61, 36, 36, 36, 64, 77, 79, 43,  2,
-   36, 36, 82, 77, 43, 43, 43, 43, 77, 77, 79, 43, 43, 43, 77, 78,
-   78, 79, 43, 43, 43, 43, 43, 43,  2,  2,  2, 80,  2,  2,  2,  2,
-   43, 43, 43, 43, 43, 43, 43, 99, 43, 43, 81, 36, 36, 36, 36, 36,
-   36, 36, 77, 43, 43, 77, 77, 78, 78, 77, 81, 36, 36, 36, 36,  2,
-   89, 61, 61, 61, 61, 47, 43, 43, 43, 43, 61, 61, 61, 61, 21,  2,
-   43, 81, 36, 36, 36, 36, 36, 36, 82, 43, 43, 78, 43, 79, 43, 36,
-   36, 36, 36, 77, 43, 78, 79, 79, 43, 78, 78, 78, 78, 78,  2,  2,
-   36, 36, 78, 78, 78, 78, 43, 43, 43, 43, 78, 43, 43, 57,  2,  2,
-    7,  7,  7,  7,  7,  7, 86, 36, 36, 36, 36, 36, 40, 40, 40,  2,
-   16, 16, 16, 16, 34, 16, 16, 16, 43, 57, 43, 43, 43, 43, 43, 43,
-   77, 43, 43, 43, 65, 36, 64, 36, 36, 36, 65, 82, 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,100, 40, 40,
+   16, 11, 32, 16, 32, 32, 32, 32, 16, 16, 32, 45, 34, 32, 34, 11,
+   32, 46, 42, 42, 47, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16,
+   11, 11, 11, 11, 48,  2,  2,  2, 16, 16, 16, 16, 49, 50, 51, 52,
+   53, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 54,
+   55, 56, 42, 55, 42, 42, 42, 42, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 57,  2,  2,  2,  2,  2,  2, 58, 58, 58,  8,  9, 59,  2, 60,
+   42, 42, 42, 42, 42, 56, 61,  2, 62, 36, 36, 36, 36, 63, 42, 42,
+    7,  7,  7,  7,  7,  2,  2, 36, 64, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 65, 42, 42, 42, 66, 46, 42, 42, 67, 68, 69, 42, 42, 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, 42, 42, 42, 42, 42, 42, 64, 36,
+   36, 36, 36, 42, 42, 42, 42, 42,  7,  7,  7,  7,  7, 36, 36, 36,
+   36, 36, 36, 36, 36, 63, 42, 42, 42, 42, 39, 21,  2, 39, 68, 20,
+   36, 36, 36, 42, 42, 68, 42, 42, 42, 42, 68, 42, 68, 42, 42, 42,
+    2,  2,  2,  2,  2,  2,  2,  2, 36, 36, 36, 36, 63, 42, 42,  2,
+   36, 36, 36, 36, 73, 36, 36, 36, 58, 58, 58, 74, 42, 42, 42, 42,
+   36, 36, 36, 36, 75, 42, 42, 42, 42, 74, 42, 42, 42, 42, 42, 42,
+   42, 76, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 76, 64, 77,
+   78, 42, 42, 42, 76, 77, 78, 77, 63, 42, 42, 42, 36, 36, 36, 36,
+   36, 42,  2,  7,  7,  7,  7,  7, 79, 36, 36, 36, 36, 36, 36, 36,
+   63, 77, 80, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 77,
+   78, 42, 42, 76, 77, 77, 78, 36, 36, 36, 36, 81, 77, 77, 36, 36,
+   36, 42, 42,  7,  7,  7,  7,  7, 36, 20, 27, 27, 27, 52, 57, 42,
+   42, 76, 80, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 42, 77,
+   78, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 64, 36, 36, 36,
+   36, 36, 36,  7,  7,  7,  7,  7, 42, 36, 63,  2,  2,  2,  2,  2,
+   78, 42, 42, 42, 76, 77, 78, 42, 59, 20, 20, 20, 82, 42, 42, 42,
+   42, 77, 80, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 78,
+   78, 42, 42, 76, 77, 77, 78, 42, 42, 42, 42, 76, 77, 77, 36, 36,
+   71, 27, 27, 27, 27, 27, 27, 27, 42, 64, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 77, 76, 77, 77, 77, 77, 77, 78, 42,
+   36, 36, 36, 81, 77, 77, 77, 77, 77, 77, 77,  7,  7,  7,  7,  7,
+   27, 83, 60, 60, 52, 60, 60, 60, 76, 77, 64, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 64, 42, 76, 77, 77, 42, 42, 42, 42, 42,
+   42, 42, 42, 42, 36, 36, 36, 36,  7,  7,  7, 84, 27, 27, 27, 83,
+   63, 77, 65, 36, 36, 36, 36, 36, 77, 77, 77, 76, 77, 77, 42, 42,
+   42, 42, 76, 77, 77, 77, 36, 36, 85, 81, 77, 77, 77, 77, 77, 77,
+   42, 77, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 63, 64, 77,
+   78, 42, 42, 77, 77, 77, 78, 70, 60, 60, 36, 81, 27, 27, 27, 86,
+   27, 27, 27, 27, 83, 36, 36, 36, 36, 36, 36, 36, 36, 42, 42, 76,
+   77, 42, 42, 42, 77, 77, 77, 77,  7, 77,  2,  2,  2,  2,  2,  2,
+   63, 36, 42, 42, 42, 42, 42, 87, 36, 36, 36, 68, 42, 42, 42, 56,
+    7,  7,  7,  7,  7,  2,  2,  2, 63, 36, 42, 42, 42, 42, 64, 36,
+   36, 36, 36, 39, 42, 42, 42, 42,  7,  7,  7,  7,  7,  7, 36, 36,
+   70, 60,  2,  2,  2,  2,  2,  2,  2, 88, 88, 60, 42, 60, 60, 60,
+    7,  7,  7,  7,  7, 27, 27, 27, 27, 27, 46, 46, 46,  4,  4, 77,
+   63, 42, 42, 42, 42, 42, 42, 76, 42, 42, 56, 42, 36, 36, 63, 42,
+   42, 42, 42, 42, 42, 42, 42, 60, 60, 60, 60, 69, 60, 60, 60, 60,
+    2,  2, 88, 60, 21,  2,  2,  2, 36, 36, 36, 36, 36, 81, 78, 42,
+   76, 42, 42, 42, 78, 76, 78, 64, 36, 36, 36, 77, 42, 36, 36, 42,
+   64, 77, 80, 81, 77, 77, 77, 36, 63, 42, 64, 36, 36, 36, 36, 36,
+   36, 76, 78, 76, 77, 77, 78, 81,  7,  7,  7,  7,  7, 77, 78, 60,
+   16, 16, 16, 16, 16, 49, 43, 16, 36, 36, 36, 36, 36, 36, 63, 42,
+    2,  2,  2,  2, 89, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+   60, 60, 60, 60, 60, 60, 60, 60, 11, 11, 11, 11, 16, 16, 16, 16,
+   90, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 65,
+   91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 92, 93, 93,
+   36, 36, 36, 36, 36, 57,  2, 94, 95, 36, 36, 36, 36, 36, 36, 36,
+   36, 42, 76, 77, 77, 77, 77, 80, 36, 42, 96,  2,  2,  2,  2,  2,
+   36, 42, 42, 42, 42, 42, 42, 42, 36, 36, 42, 78, 42, 42, 42, 77,
+   77, 77, 77, 76, 78, 42, 42, 42, 42, 42,  2, 79,  2, 59, 63, 42,
+    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2, 97,  2, 55, 42, 74,
+   36, 75, 36, 36, 36, 36, 36, 36, 36, 36, 63, 64, 36, 36, 36, 36,
+   36, 36, 36, 36, 63, 36, 36, 36, 42, 76, 77, 78, 76, 77, 77, 77,
+   77, 76, 77, 77, 78, 42, 42, 42, 60, 60,  2,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7, 27, 27, 60, 36, 36, 36, 63, 76, 78, 42,  2,
+   36, 36, 81, 76, 42, 42, 42, 42, 76, 76, 78, 42, 42, 42, 76, 77,
+   77, 78, 42, 42, 42, 42, 42, 42,  2,  2,  2, 79,  2,  2,  2,  2,
+   42, 42, 42, 42, 42, 42, 42, 98, 42, 42, 80, 36, 36, 36, 36, 36,
+   36, 36, 76, 42, 42, 76, 76, 77, 77, 76, 80, 36, 36, 36, 36,  2,
+   88, 60, 60, 60, 60, 46, 42, 42, 42, 42, 60, 60, 60, 60, 21,  2,
+   42, 80, 36, 36, 36, 36, 36, 36, 81, 42, 42, 77, 42, 78, 42, 36,
+   36, 36, 36, 76, 42, 77, 78, 78, 42, 77, 77, 77, 77, 77,  2,  2,
+   36, 36, 77, 77, 77, 77, 42, 42, 42, 42, 77, 42, 42, 56,  2,  2,
+    7,  7,  7,  7,  7,  7, 85, 36, 36, 36, 36, 36, 39, 39, 39,  2,
+   16, 16, 16, 16, 34, 16, 16, 16, 42, 56, 42, 42, 42, 42, 42, 42,
+   76, 42, 42, 42, 64, 36, 63, 36, 36, 36, 64, 81, 42, 36, 36, 36,
+   16, 16, 16, 16, 16, 16, 39, 39, 39, 39, 39, 39, 39, 43, 16, 16,
+   16, 16, 16, 16, 43, 16, 16, 16, 16, 16, 16, 16, 16, 99, 39, 39,
    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,101,101,101,101,
-   16, 16, 16, 16, 11, 11,102,103, 41, 16, 16, 16, 11, 11,102, 41,
-   16, 16, 16, 16, 11, 11,104, 41,105,105,105,105,105,106, 59, 59,
-   51, 51, 51,  2,107,108,107,108,  2,  2,  2,  2,109, 59, 59,110,
-    2,  2,  2,  2,111,112,  2,113,114,  2,115,116,  2,  2,  2,  2,
-    2,  9,114,  2,  2,  2,  2,117, 59, 59, 59, 59, 59, 59, 59, 59,
-  118, 40, 27, 27, 27,  8,115,119, 27, 27, 27, 27, 27,  8,115, 94,
-   20, 20, 20, 20, 20, 20, 20, 20, 43, 43, 43, 43, 43, 43,120, 48,
-   99, 48, 99, 43, 43, 43, 43, 43, 61,121, 61,122, 61, 34, 11, 16,
-   11, 32,122, 61, 46, 11, 11, 61, 61, 61,121,121,121, 11, 11,123,
-   11, 11, 35, 36, 39, 61, 16, 11,  8,  8, 46, 16, 16, 26, 61,124,
-   95, 95, 95, 95, 95, 95, 95, 95, 95,125,126, 95,127, 61, 61, 61,
-    8,  8,128, 61, 61,  8, 61, 61,128, 26, 61,128, 61, 61, 61,128,
-   61, 61, 61, 61, 61, 61, 61,  8, 61,128,128, 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,129,130, 61, 61,
-   61, 61, 61, 61, 61, 61,128, 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,115,131,  8,  8,  8,  8,  8,  8,  8,  4,  4,  4,  4,  4,
-    8,115,132,132,132,132,132,132,132,132,132,132,131,  8,  8,  8,
+   16, 16, 16, 16, 34, 11, 11, 11, 16, 16, 16, 16,100,100,100,100,
+   16, 16, 16, 16, 11, 11,101,102, 40, 16, 16, 16, 11, 11,101, 40,
+   16, 16, 16, 16, 11, 11,103, 40,104,104,104,104,104,105, 58, 58,
+   50, 50, 50,  2,106,107,106,107,  2,  2,  2,  2,108, 58, 58,109,
+    2,  2,  2,  2,110,111,  2,112,113,  2,114,115,  2,  2,  2,  2,
+    2,  9,113,  2,  2,  2,  2,116, 58, 58, 58, 58, 58, 58, 58, 58,
+  117, 39, 27, 27, 27,  8,114,118, 27, 27, 27, 27, 27,  8,114, 93,
+   20, 20, 20, 20, 20, 20, 20, 20, 42, 42, 42, 42, 42, 42,119, 47,
+   98, 47, 98, 42, 42, 42, 42, 42, 60,120, 60,121, 60, 34, 11, 16,
+   11, 32,121, 60, 45, 11, 11, 60, 60, 60,120,120,120, 11, 11,122,
+   11, 11, 35, 36,123, 60, 16, 11,  8,  8, 45, 16, 16, 26, 60,124,
+   94, 94, 94, 94, 94, 94, 94, 94, 94,125,126, 94,127, 60, 60, 60,
+    8,  8,128, 60, 60,  8, 60, 60,128, 26, 60,128, 60, 60, 60,128,
+   60, 60, 60, 60, 60, 60, 60,  8, 60,128,128, 60, 60, 60, 60, 60,
+   60, 60,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+   60, 60, 60, 60,  4,  4, 60, 60,  8, 60, 60, 60,129,130, 60, 60,
+   60, 60, 60, 60, 60, 60,128, 60, 60, 60, 60, 60, 60, 26,  8,  8,
+    8,  8, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,  8,  8,
+    8, 60, 60, 60, 60, 60, 60, 60, 27, 27, 27, 27, 27, 27, 60, 60,
+   60, 60, 60, 60, 60, 27, 27, 27, 60, 60, 60, 26, 60, 60, 60, 60,
+   26, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,  8,  8,  8,  8,
+   60, 60, 60, 60, 60, 60, 60, 26, 60, 60, 60, 60,  4,  4,  4,  4,
+    4,  4,  4, 27, 27, 27, 27, 27, 27, 27, 60, 60, 60, 60, 60, 60,
+    8,  8,114,131,  8,  8,  8,  8,  8,  8,  8,  4,  4,  4,  4,  4,
+    8,114,132,132,132,132,132,132,132,132,132,132,131,  8,  8,  8,
     8,  8,  8,  8,  4,  4,  8,  8,  8,  8,  8,  8,  8,  8,  4,  8,
-    8,  8,128, 26,  8,  8,128, 61, 32, 11, 32, 34, 34, 34, 34, 11,
-   32, 32, 34, 16, 16, 16, 40, 11, 32, 32,124, 61, 61,122, 34,133,
-   43, 32, 16, 16, 50,  2, 90,  2, 36, 36, 36, 36, 36, 36, 36, 76,
-    2,  2,  2,  2,  2,  2,  2, 56,  2,107,107,  2,111,112,107,  2,
-    2,  2,  2,  6,  2, 98,107,  2,107,  4,  4,  4,  4,  2,  2, 80,
-    2,  2,  2,  2,  2, 51,  2,  2, 98,134,  2,  2,  2,  2,  2,  2,
-   61,  2,135,132,132,132,136, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-    1,  2,137,138,  4,  4,  4,  4,  4, 61,  4,  4,  4,  4,139, 94,
-  140, 95, 95, 95, 95, 43, 43, 78,141, 40, 40, 61, 95,142, 58, 61,
-   72, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64,143,144, 63,
-   36, 36, 36, 36, 36, 58, 40, 63, 61, 27, 27, 61, 61, 61, 61, 61,
-   27, 27, 27, 27, 27, 61, 61, 61, 61, 61, 61, 61, 27, 27, 27, 27,
-  145, 27, 27, 27, 27, 27, 27, 27, 36, 36, 76, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36,146,  2, 32, 32, 32, 32, 32, 32, 32, 64,
-   48,147, 43, 43, 43, 43, 43, 80, 32, 32, 32, 32, 32, 32, 40, 43,
-   36, 36, 36, 95, 95, 95, 95, 95, 43,  2,  2,  2,  2,  2,  2,  2,
-   41, 41, 41,144, 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,148, 34, 35, 32, 32, 16, 32, 32, 32, 32, 32,
+    8,  8,128, 26,  8,  8,128, 60, 32, 11, 32, 34, 34, 34, 34, 11,
+   32, 32, 34, 16, 16, 16, 39, 11, 32, 32,124, 60, 60,121, 34,133,
+   42, 32, 16, 16, 49,  2, 89,  2, 36, 36, 36, 36, 36, 36, 36, 75,
+    2,  2,  2,  2,  2,  2,  2, 55,  2,106,106,  2,110,111,106,  2,
+    2,  2,  2,  6,  2, 97,106,  2,106,  4,  4,  4,  4,  2,  2, 79,
+    2,  2,  2,  2,  2, 50,  2,  2, 97,134,  2,  2,  2,  2,  2,  2,
+   60,  2,135,132,132,132,136, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+    1,  2,137,138,  4,  4,  4,  4,  4, 60,  4,  4,  4,  4,139, 93,
+  140, 94, 94, 94, 94, 42, 42, 77,141, 39, 39, 60, 94,142, 57, 60,
+   71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 63,143,144, 62,
+   36, 36, 36, 36, 36, 57, 39, 62, 60, 27, 27, 60, 60, 60, 60, 60,
+   27, 27, 27, 27, 27, 60, 60, 60, 60, 60, 60, 60, 27, 27, 27, 27,
+  145, 27, 27, 27, 27, 27, 27, 27, 36, 36, 75, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36,146,  2, 32, 32, 32, 32, 32, 32, 32, 63,
+   47,147, 42, 42, 42, 42, 42, 79, 32, 32, 32, 32, 32, 32, 39, 42,
+   36, 36, 36, 94, 94, 94, 94, 94, 42,  2,  2,  2,  2,  2,  2,  2,
+   40, 40, 40,144, 39, 39, 39, 39, 40, 32, 32, 32, 32, 32, 32, 32,
+   16, 32, 32, 32, 32, 32, 32, 32, 43, 16, 16, 16, 34, 34, 34, 32,
+   32, 32, 32, 32, 41,148, 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,
-   32, 32, 11, 11, 34, 34, 32, 16, 32, 16, 16, 32, 32, 32, 11, 11,
-   11, 40,149, 35, 40, 35, 36, 36, 36, 65, 36, 65, 36, 64, 36, 36,
-   36, 82, 79, 77, 61, 61, 43, 43, 27, 27, 27, 61,150, 61, 61, 61,
-   36, 36,  2,  2,  2,  2,  2,  2, 78, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 78, 78, 78, 78, 78, 78, 78, 78, 43, 43, 43, 43, 43,  2,
-   43, 36, 36, 36,  2, 66, 66, 64, 36, 36, 36, 43, 43, 43, 43,  2,
-   36, 36, 36, 64, 43, 43, 43, 43, 43, 78, 78, 78, 78, 78, 78, 97,
-   36, 64, 78, 43, 43, 78, 43, 78, 97,  2,  2,  2,  2,  2,  2, 80,
-    7,  7,  7,  7,  7,  7,  7,  2, 36, 36, 64, 63, 36, 36, 36, 36,
-   36, 36, 36, 36, 64, 43, 43, 77, 79, 77, 79, 43, 43, 43, 43, 43,
-   36, 64, 36, 36, 36, 36, 77, 78,  7,  7,  7,  7,  7,  7,  2,  2,
-   63, 36, 36, 71, 61, 82, 77, 36, 65, 43, 65, 64, 65, 36, 36, 43,
-   36, 36, 36, 36, 36, 36, 76,  2, 36, 36, 36, 36, 36, 82, 43, 78,
-    2, 76,151, 43, 43, 43, 43, 43, 16, 16, 16, 16, 16,103, 40, 40,
-   16, 16, 16, 16,100, 41, 41, 41, 36, 82, 79, 78, 77, 97, 79, 43,
+   32, 32, 11, 11, 34, 34, 32, 32, 32, 32, 32, 32, 32, 32, 11, 11,
+   48, 39,149, 35, 39, 35, 36, 36, 36, 64, 36, 64, 36, 63, 36, 36,
+   36, 81, 78, 76, 60, 60, 42, 42, 27, 27, 27, 60,150, 60, 60, 60,
+   36, 36,  2,  2,  2,  2,  2,  2, 77, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 77, 77, 77, 77, 77, 77, 77, 77, 42, 42, 42, 42, 42,  2,
+   42, 36, 36, 36,  2, 65, 65, 63, 36, 36, 36, 42, 42, 42, 42,  2,
+   36, 36, 36, 63, 42, 42, 42, 42, 42, 77, 77, 77, 77, 77, 77, 96,
+   36, 63, 77, 42, 42, 77, 42, 77, 96,  2,  2,  2,  2,  2,  2, 79,
+    7,  7,  7,  7,  7,  7,  7,  2, 36, 36, 63, 62, 36, 36, 36, 36,
+   36, 36, 36, 36, 63, 42, 42, 76, 78, 76, 78, 42, 42, 42, 42, 42,
+   36, 63, 36, 36, 36, 36, 76, 77,  7,  7,  7,  7,  7,  7,  2,  2,
+   62, 36, 36, 70, 60, 81, 76, 36, 64, 42, 64, 63, 64, 36, 36, 42,
+   36, 36, 36, 36, 36, 36, 75,  2, 36, 36, 36, 36, 36, 81, 42, 77,
+    2, 75,151, 42, 42, 42, 42, 42, 16, 16, 16, 16, 16,102, 39, 39,
+   16, 16, 16, 16, 99, 40, 40, 40, 36, 81, 78, 77, 76, 96, 78, 42,
   152,152,152,152,152,152,152,152,153,153,153,153,153,153,153,153,
-   16, 16, 16, 16, 16, 16, 35, 65, 36, 36, 36, 36,154, 36, 36, 36,
-   36, 41, 41, 41, 41, 41, 41, 41, 41, 74, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36,132, 36, 36, 36, 36, 36, 36, 36, 71,
-   36, 36, 36, 36, 36, 36,150, 61,  2,  2,  2,135,116,  2,  2,  2,
-    6,155,156,132,132,132,132,132,132,132,116,135,116,  2,113,157,
-    2,  2,  2,  2,139,132,132,116,  2,158,  8,  8, 60,  2,  2,  2,
+   16, 16, 16, 16, 16, 16, 35, 64, 36, 36, 36, 36,154, 36, 36, 36,
+   36, 40, 40, 40, 40, 40, 40, 40, 40, 22, 60, 60, 60, 60, 60, 60,
+   60, 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,132,
+   60, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 60, 60, 60,
+   36, 36, 36, 36, 36, 36,150, 60,  2,  2,  2,135,115,  2,  2,  2,
+    6,155,156,132,132,132,132,132,132,132,115,135,115,  2,112,157,
+    2,  2,  2,  2,139,132,132,115,  2,158,  8,  8, 59,  2,  2,  2,
    36, 36, 36, 36, 36, 36, 36,159,  2,  2,  3,  2,  4,  5,  6,  2,
-   16, 16, 16, 16, 16, 17, 18,115,116,  4,  2, 36, 36, 36, 36, 36,
-   63, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 40,
-   20,160, 53, 20, 26,  8,128, 61, 61, 61, 61, 61,161, 59, 61, 61,
-    2,  2,  2, 90, 27, 27, 27, 27, 27, 27, 27, 84, 61, 61, 61, 61,
-   95, 95,127, 27, 84, 61, 61, 61, 61, 61, 61, 61, 61, 27, 61, 61,
-   61, 61, 61, 61, 61, 61, 47, 43,162,162,162,162,162,162,162,162,
-  163, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 87, 36,
-  138, 36, 36, 36, 36, 95, 95, 95, 36, 36, 36, 36, 36, 36, 36, 58,
-  164, 95, 95, 95, 95, 95, 95, 95, 11, 11, 11, 32, 16, 16, 16, 16,
-   36, 36, 36, 58, 27, 27, 27, 27, 36, 36, 36, 71,145, 27, 27, 27,
+   16, 16, 16, 16, 16, 17, 18,114,115,  4,  2, 36, 36, 36, 36, 36,
+   62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 39,
+   20,160, 52, 20, 26,  8,128, 60, 60, 60, 60, 60,161, 58, 60, 60,
+    2,  2,  2, 89, 27, 27, 27, 27, 27, 27, 27, 83, 60, 60, 60, 60,
+   94, 94,127, 27, 83, 60, 60, 60, 60, 60, 60, 60, 60, 27, 60, 60,
+   60, 60, 60, 60, 60, 60, 46, 42,162,162,162,162,162,162,162,162,
+  163, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 86, 36,
+  138, 36, 36, 36, 36, 94, 94, 94, 36, 36, 36, 36, 36, 36, 36, 57,
+  164, 94, 94, 94, 94, 94, 94, 94, 11, 11, 11, 32, 16, 16, 16, 16,
+   36, 36, 36, 57, 27, 27, 27, 27, 36, 36, 36, 70,145, 27, 27, 27,
    36, 36, 36,165, 27, 27, 27, 27, 36, 36, 36, 36, 36,165, 27, 27,
    36, 36, 36, 27, 27, 27, 27, 30, 36, 36, 36, 36, 36, 36, 27, 36,
-   64, 43, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 43, 43, 43, 43,
+   63, 42, 42, 42, 42, 42, 42, 42, 36, 36, 36, 36, 42, 42, 42, 42,
    36, 36, 36, 36, 36, 36,165, 30, 36, 36, 36, 36, 36, 36,165, 27,
-   36, 36, 36, 36, 72, 36, 36, 36, 36, 36, 64, 43, 43,163, 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,
-    7,  7,  7,  7,  7, 36, 36, 63, 11, 11, 11, 11,166, 43, 43,141,
-   16, 16, 16, 16, 16, 16, 16,  8, 36, 36, 36, 36, 36, 64,167, 51,
-   36, 36, 36, 36, 36, 36, 43, 43, 27, 27, 27, 87, 36, 36, 36, 36,
-  163, 27, 30,  2,  2,  2,  2,  2, 36, 43, 43,  2,  2,  2,  2,  2,
-   36, 36,165, 27, 27, 27, 27, 27, 79, 81, 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, 65, 64, 65, 36, 36, 36, 36, 64,
-   78, 79, 43, 77, 79, 57, 73,  2,  2, 43, 43, 43, 43, 43, 67, 59,
-   36, 36, 36, 64, 43, 43, 79, 43, 43, 43, 43,  7,  7,  7,  7,  7,
-    2,  2, 82, 81, 36, 36, 36, 36, 36, 64,  2, 36, 36, 36, 36, 36,
-   36, 82, 78, 43, 43, 43, 43, 77, 81, 36, 58,  2, 56, 43, 57, 79,
-    7,  7,  7,  7,  7, 58, 58,  2, 90, 27, 27, 27, 27, 27, 27, 27,
-   36, 36, 36, 36, 36, 36, 78, 79, 43, 78, 77, 43,  2,  2,  2, 65,
-   36, 36, 36, 36, 36, 36, 36, 64, 77, 78, 78, 78, 78, 78, 78, 78,
-   36, 36, 36, 82, 78, 78, 81, 36, 36, 78, 78, 43, 43, 43, 43, 43,
-   36, 36, 36, 36, 78, 79, 43, 43, 43, 78, 78, 78, 78, 78, 78, 77,
-   65, 65,  2,  2,  2,  2,  2,  2, 56, 43, 43, 43, 43, 43, 43, 43,
-   36, 36, 82, 78, 43, 43, 43, 43, 78, 43, 77, 65, 36, 58,  2,  2,
-    7,  7,  7,  7,  7,  2,  2, 65, 78, 79, 43, 43, 77, 77, 78, 79,
-   77, 43, 36, 66, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 82,
-   78, 43, 43, 43, 78, 78, 43, 79, 57,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2, 36, 36, 43, 43, 78, 79, 43, 43, 43, 77, 79, 79,
-   57,  2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 79, 78,
-   43, 43, 43, 79, 58,  2,  2,  2, 36, 36, 36, 36, 36, 36, 64, 79,
-   78, 43, 43, 79, 43, 43, 43, 43,  7,  7,  7,  7,  7, 27,  2, 89,
-   43, 43, 43, 43, 79, 57,  2,  2, 27, 27, 27, 27, 27, 27, 27, 87,
-   78, 78, 78, 78, 78, 79, 77, 65, 81, 79,  2,  2,  2,  2,  2,  2,
-   82, 78, 43, 43, 43, 43, 78, 78, 65, 66, 78, 78, 78, 78, 78, 78,
-   78, 78, 78, 78, 78, 78, 78, 78, 64, 43, 43, 43, 43, 65, 36, 36,
-   36, 64, 43, 43, 77, 64, 43, 57,  2,  2,  2, 56, 43, 43, 43, 43,
-   64, 43, 43, 77, 79, 43, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43,
-   43, 43, 43, 77, 43,  2, 66,  2, 58,  2,  2,  2,  2,  2,  2,  2,
-   43, 43, 43, 43, 43, 43, 43, 79,  2, 36, 36, 36, 36, 36, 36, 36,
-   43, 43, 43, 43, 77, 43, 43, 43, 77, 43, 79, 43, 43, 43, 43, 43,
-   43, 43, 43, 64, 43, 43, 43, 43, 36, 36, 36, 36, 36, 78, 78, 78,
-   43, 77, 79, 79, 36, 36, 36, 36, 36, 64, 77, 97,  2,  2,  2,  2,
-   43, 82, 36, 36, 36, 36, 36, 36, 36, 36, 78, 43, 43, 43, 43, 78,
-   77, 57,  2,  2,  2,  2,  2,  2,  7,  7,  7,  7,  7, 43, 43, 43,
-   27, 27, 84, 61, 61, 61, 53, 20,150, 61, 61, 61, 61, 61, 61, 61,
-   61, 61, 61, 61, 61, 61, 61, 21, 65, 36, 36, 64, 43, 43, 43, 43,
-   36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 78, 79, 43,
-   43, 43, 57,  2,  2,  2,  2,  2, 43, 43, 43, 57,  2,  2, 61, 61,
-   40, 40, 89, 61, 61, 61, 61, 61,  7,  7,  7,  7,  7,168, 27, 27,
-   27, 87, 36, 36, 36, 36, 36, 36, 40, 63, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 76,146,  2, 27, 27, 27, 30,  2,  2,  2,  2,
-   82, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 79,
-   43, 68, 40, 40, 40, 40, 40, 40, 40, 80, 43, 43, 43, 43, 43, 43,
-   36, 36, 36, 36, 36, 36, 47, 57, 61, 61,169, 79, 43, 61,169, 78,
-   78,170, 59, 59, 59, 75, 43, 43, 43, 70, 47, 43, 43, 43, 61, 61,
-   61, 61, 61, 61, 61, 43, 43, 61, 61, 43, 70, 61, 61, 61, 61, 61,
+   36, 36, 36, 36, 71, 36, 36, 36, 36, 36, 63, 42, 42,163, 27, 27,
+   36, 36, 36, 36, 57,  2,  2,  2, 36, 36, 36, 36, 27, 27, 27, 27,
+   16, 16, 16, 16, 16, 27, 27, 27, 36, 36, 42, 42, 42, 42, 42, 42,
+    7,  7,  7,  7,  7, 36, 36, 62, 11, 11, 11, 11,166, 42, 42,141,
+   16, 16, 16, 16, 16, 16, 16,  8, 36, 36, 36, 36, 36, 63,167, 50,
+   88, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 42, 42, 42,
+   27, 27, 27, 86, 36, 36, 36, 36,163, 27, 30,  2,  2,  2,  2,  2,
+   36, 42, 42,  2,  2,  2,  2,  2, 36, 36,165, 27, 27, 27, 27, 27,
+   78, 80, 36, 36, 36, 36, 36, 36, 42, 42, 42, 56,  2,  2,  2,  2,
+    2, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,  7,  7,  7,  7,  7,
+   64, 63, 64, 36, 36, 36, 36, 63, 77, 78, 42, 76, 78, 56, 72,  2,
+    2, 42, 42, 42, 42, 42, 66, 58, 36, 36, 36, 63, 42, 42, 78, 42,
+   42, 42, 42,  7,  7,  7,  7,  7,  2,  2, 81, 80, 36, 36, 36, 36,
+   36, 63,  2, 36, 36, 36, 36, 36, 36, 81, 77, 42, 42, 42, 42, 76,
+   80, 36, 57,  2, 55, 42, 56, 78,  7,  7,  7,  7,  7, 57, 57,  2,
+   89, 27, 27, 27, 27, 27, 27, 27, 36, 36, 36, 36, 36, 36, 77, 78,
+   42, 77, 76, 42,  2,  2,  2, 64, 36, 36, 36, 36, 36, 36, 36, 63,
+   76, 77, 77, 77, 77, 77, 77, 77, 36, 36, 36, 81, 77, 77, 80, 36,
+   36, 77, 77, 42, 42, 42, 42, 42, 36, 36, 36, 36, 77, 78, 42, 42,
+   42, 77, 77, 77, 77, 77, 77, 76, 64, 64,  2,  2,  2,  2,  2,  2,
+   55, 42, 42, 42, 42, 42, 42, 42, 36, 36, 81, 77, 42, 42, 42, 42,
+   77, 42, 76, 64, 36, 57,  2,  2,  7,  7,  7,  7,  7,  2,  2, 64,
+   77, 78, 42, 42, 76, 76, 77, 78, 76, 42, 36, 65, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 81, 77, 42, 42, 42, 77, 77, 42, 78,
+   56,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 36, 36, 42, 42,
+   77, 78, 42, 42, 42, 76, 78, 78, 56,  2, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 63, 78, 77, 42, 42, 42, 78, 57,  2,  2,  2,
+   36, 36, 36, 36, 36, 36, 63, 78, 77, 42, 42, 78, 42, 42, 42, 42,
+    7,  7,  7,  7,  7, 27,  2, 88, 42, 42, 42, 42, 78, 56,  2,  2,
+   27, 27, 27, 27, 27, 27, 27, 86, 77, 77, 77, 77, 77, 78, 76, 64,
+   80, 78,  2,  2,  2,  2,  2,  2, 81, 77, 42, 42, 42, 42, 77, 77,
+   64, 65, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+   63, 42, 42, 42, 42, 64, 36, 36, 36, 63, 42, 42, 76, 63, 42, 56,
+    2,  2,  2, 55, 42, 42, 42, 42, 63, 42, 42, 76, 78, 42, 36, 36,
+   36, 36, 36, 36, 36, 42, 42, 42, 42, 42, 42, 76, 42,  2, 65,  2,
+   76, 42, 76, 76, 77, 77, 77, 77, 57,  2,  2,  2,  2,  2,  2,  2,
+   42, 42, 42, 42, 42, 42, 42, 78,  2, 36, 36, 36, 36, 36, 36, 36,
+   42, 42, 42, 42, 76, 42, 42, 42, 76, 42, 78, 42, 42, 42, 42, 42,
+   42, 42, 42, 63, 42, 42, 42, 42, 36, 36, 36, 36, 36, 77, 77, 77,
+   42, 76, 78, 78, 36, 36, 36, 36, 36, 36, 36, 36, 75, 36, 36, 36,
+   36, 63, 76, 96,  2,  2,  2,  2, 42, 81, 36, 36, 36, 36, 36, 36,
+   36, 36, 77, 42, 42, 42, 42, 77, 76, 56,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7, 42, 42, 42, 27, 27, 83, 60, 60, 60, 52, 20,
+  150, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 21,
+   64, 36, 36, 63, 42, 42, 42, 42, 36, 36, 36, 36, 36, 36, 36, 42,
+   42, 42, 42, 42, 42, 77, 78, 42, 42, 42, 56,  2,  2,  2,  2,  2,
+   42, 42, 42, 56,  2,  2, 60, 60, 39, 39, 88, 60, 60, 60, 60, 60,
+    7,  7,  7,  7,  7,168, 27, 27, 27, 86, 36, 36, 36, 36, 36, 36,
+   39, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 75,146,  2,
+   27, 27, 27, 30,  2,  2,  2,  2, 11, 11, 11, 11, 11, 32, 16, 16,
+   81, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 78,
+   42, 67, 39, 39, 39, 39, 39, 39, 39, 79, 42, 42, 42, 42, 42, 42,
+   77, 39, 94, 94, 94, 94, 94, 94, 36, 36, 36, 36, 36, 36, 46, 56,
+    7,  7,  7,  7,  7, 60, 60, 60, 60, 60,169, 78, 42, 60,169, 77,
+   77,170, 58, 58, 58, 74, 42, 42, 42, 69, 46, 42, 42, 42, 60, 60,
+   60, 60, 60, 60, 60, 42, 42, 60, 60, 42, 69, 60, 60, 60, 60, 60,
    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,
@@ -4966,74 +4711,76 @@ _hb_ucd_u8[13730] =
    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, 70, 61, 47, 43, 43, 43, 43, 43, 43, 43, 43, 70, 61,
-   61, 61, 47, 61, 61, 61, 61, 61, 61, 61, 70, 21,  2,  2,  2,  2,
-    2,  2,  2,  2,  2, 56, 43, 43, 16, 16, 16, 16, 16, 39, 16, 16,
-   43, 43, 43, 68, 40, 40, 40, 40,  7,  7,  7,  7,  7,  7,  7, 71,
-    7,  7,  7,  7,  7,  7,  7,171, 36, 36, 36, 36, 36, 76, 43, 43,
-  172,  7,  7,  7,  7,  7,  7, 85, 16, 16, 43, 43, 43, 68, 40, 40,
-   27, 27, 27, 27, 27, 27,145, 27,173, 27, 27, 27, 27, 27, 27, 27,
-   27, 27, 27, 27, 27, 27, 27,145, 27, 27, 27, 27, 27, 27, 84, 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,  1, 21,  6,  7,  7, 12, 12,  7, 21,  7, 12,  1,
-   12,  6,  6, 12, 12, 26,  7, 26, 26,  7, 21,  1, 24,  7,  1, 12,
-    7,  6, 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, 10, 21, 17, 21, 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, 21, 22, 18, 17, 26,  6,  7, 14, 17, 22,
-   26, 14, 17,  6, 14,  6, 12, 24, 24,  6, 26, 15,  6, 21, 11, 21,
-   24,  9,  6,  9, 23, 26,  6, 10,  4,  4,  3,  3,  7, 25, 17, 16,
-   16, 22, 16, 16, 25, 17,  7,  1, 25, 24, 26,  1,  2,  2, 12, 15,
-   21, 14,  7, 15,  9, 12, 12, 17, 13, 15, 26, 10, 10,  1, 13, 23,
-    7, 13, 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,
+   42, 42, 42, 69, 60, 46, 42, 42, 42, 42, 42, 42, 42, 42, 69, 60,
+   60, 60, 46, 60, 60, 60, 60, 60, 60, 60, 69, 21,  2,  2,  2,  2,
+    2,  2,  2,  2,  2, 55, 42, 42, 16, 16, 16, 16, 16,123, 16, 16,
+   42, 42, 42, 67, 39, 39, 39, 39,  7,  7,  7,  7,  7,  7,  7, 70,
+   36, 36, 36, 36, 36, 36, 42, 42,  7,  7,  7,  7,  7,  7,  7,171,
+   36, 36, 36, 36, 36, 75, 42, 42,172,  7,  7,  7,  7,  7,  7, 84,
+   36, 63, 36, 64, 36, 36, 36, 42, 36, 36, 63, 42, 42, 42, 42, 75,
+   16, 16, 42, 42, 42, 67, 39, 39, 27, 27, 27, 27, 27, 27,145, 27,
+  173, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,145,
+   27, 27, 27, 27, 27, 27, 83, 60, 60, 60, 60, 60, 60, 25, 40, 40,
+    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,  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,  1, 21,  6,  7,  7, 12,
+   12,  7, 21,  7, 12,  1, 12,  6,  6, 12, 12, 26,  7, 26, 26,  7,
+   21,  1, 24,  7,  1, 12,  7,  6, 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,
+   10, 21, 17, 21, 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,  7,  5,  5, 26, 14,  9,  5, 14, 14, 15,
+   25, 26, 26, 22, 18, 26, 18, 25, 18, 22,  5, 12, 22, 21, 21, 22,
+   18, 17, 26,  6,  7, 14, 17, 22, 26, 14, 17,  6, 14,  6, 12, 24,
+   24,  6, 26, 15,  6, 21, 11, 21, 24,  9,  6,  9, 23, 26,  6, 10,
+    4,  4,  3,  3,  7, 25, 17, 16, 16, 22, 16, 16, 25, 17,  7,  1,
+   25, 24, 26,  1,  2,  2, 12, 15, 21, 14,  7, 15,  9, 12, 12, 17,
+   13, 15, 26, 10, 10,  1, 13, 23,  7, 13, 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, 17, 18, 19,  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, 34,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 35,  0,  0,  0,
+    0, 36,  0, 37,  0,  0,  0,  0,  0,  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, 34,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0, 35,  0,  0,  0,  0, 36,  0, 37,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0, 38,  0,  0,  0,  0,  0,  0,  0,  0,  0, 39, 40,  0,  0,
-    0,  0,  0,  0, 41, 42, 43,  0, 44,  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, 14, 15, 16, 17,
-   16, 18, 16, 19, 16, 19, 16, 19,  0, 19, 16, 20, 16, 19, 21, 19,
-    0, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,  0, 32,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 33,  0,  0,  0,  0,  0,  0, 34,  0,
-    0, 35,  0,  0, 36,  0, 37,  0,  0,  0, 38, 39, 40, 41, 42, 43,
-   44, 45, 46,  0,  0, 47,  0,  0,  0, 48,  0,  0,  0, 49,  0,  0,
-    0,  0,  0,  0,  0, 50,  0, 51,  0, 52, 53,  0, 54,  0,  0,  0,
-    0,  0,  0, 55, 56, 57,  0,  0,  0,  0, 58,  0,  0, 59, 60, 61,
-   62, 63,  0,  0, 64, 65,  0,  0,  0, 66,  0,  0,  0,  0, 67,  0,
-    0,  0, 68,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0, 69,  0,  0,  0, 70,  0, 71,  0,  0, 72,  0,  0, 73,  0,  0,
-    0,  0,  0,  0,  0,  0, 74, 75,  0,  0,  0,  0, 76, 77,  0, 78,
-   79,  0,  0, 80, 81,  0, 82, 62,  0, 83, 84,  0,  0, 85, 86, 87,
-    0, 88,  0, 89,  0, 90,  0,  0, 51, 91, 51,  0, 92,  0, 93,  0,
-    0,  0, 81,  0,  0,  0, 94, 95,  0, 96, 97, 98, 99,  0,  0,  0,
-    0,  0, 51,  0,  0,  0,  0,100,101,  0,  0,  0,  0,  0,  0,102,
-    0,  0,  0,  0,  0,  0,103,  0,  0,  0,  0,  0,  0,104,105,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,106,  0,  0,107,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,108,109,  0,  0,110,  0,  0,  0,  0,
-    0,  0,111,  0,112,  0,105,  0,  0,  0,  0,  0,113,114,  0,  0,
-    0,  0,  0,  0,  0,115,  0,  0,  0,116,  0,  0,  0,117,  0,118,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 38,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 39, 40,  0,  0,  0,  0,  0,  0, 41, 42, 43, 44,
+   45,  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, 14, 15, 16, 17, 16, 18, 16, 19, 16, 19, 16, 19,
+    0, 19, 16, 20, 16, 19, 21, 19,  0, 22, 23, 24, 25, 26, 27, 28,
+   29, 30, 31,  0, 32,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 33,
+    0,  0,  0,  0,  0,  0, 34,  0,  0, 35,  0,  0, 36,  0, 37,  0,
+    0,  0, 38, 39, 40, 41, 42, 43, 44, 45, 46,  0,  0, 47,  0,  0,
+    0, 48,  0,  0,  0, 49,  0,  0,  0,  0,  0,  0,  0, 50,  0, 51,
+    0, 52, 53,  0, 54,  0,  0,  0,  0,  0,  0, 55, 56, 57,  0,  0,
+    0,  0, 58,  0,  0, 59, 60, 61, 62, 63,  0,  0, 64, 65,  0,  0,
+    0, 66,  0,  0,  0,  0, 67,  0,  0,  0, 68,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0, 69,  0,  0,  0, 70,  0, 71,
+    0,  0, 72,  0,  0, 73,  0,  0,  0,  0,  0,  0,  0,  0, 74, 75,
+    0,  0,  0,  0, 76, 77,  0, 78, 79,  0,  0, 80, 81,  0, 82, 62,
+    0, 83, 84,  0,  0, 85, 86, 87,  0, 88,  0, 89,  0, 90,  0,  0,
+   51, 91, 51,  0, 92,  0, 93,  0,  0,  0, 81,  0,  0,  0, 94, 95,
+    0, 96, 97, 98, 99,  0,  0,  0,  0,  0, 51,  0,  0,  0,  0,100,
+  101,  0,  0,  0,  0,  0,  0,102,  0,  0,  0,  0,  0,  0,103,  0,
+    0,  0,  0,  0,  0,104,105,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,106,  0,  0,107,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,108,
+  109,  0,  0,110,  0,  0,  0,  0,  0,  0,111,  0,112,  0,105,  0,
+    0,  0,  0,  0,113,114,  0,  0,  0,  0,  0,  0,  0,115,  0,  0,
+    0,116,  0,  0,  0,117,  0,  0,  0,  0,  0,  0,  0,118,  0,119,
     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,
@@ -5044,405 +4791,411 @@ _hb_ucd_u8[13730] =
     0, 44,  0,  0,  0, 45, 46,  0,  0,  0, 47,  0,  0,  0,  0,  0,
     0, 48, 49,  0,  0,  0,  0, 50,  0,  0,  0, 51,  0, 52,  0, 53,
     0,  0,  0,  0, 54,  0,  0,  0,  0, 55,  0, 56,  0,  0,  0,  0,
-   57, 58,  0,  0,  0, 59, 60,  0,  0,  0,  0,  0,  0, 61, 52,  0,
-   62, 63,  0,  0, 64,  0,  0,  0, 65, 66,  0,  0,  0, 67,  0, 68,
-   69, 70, 71, 72,  1, 73,  0, 74, 75, 76,  0,  0, 77, 78,  0,  0,
-    0, 79,  0,  0,  1,  1,  0,  0, 80,  0,  0, 81,  0,  0,  0,  0,
-   77, 82,  0, 83,  0,  0,  0,  0,  0, 78, 84,  0, 85,  0, 52,  0,
-    1, 78,  0,  0, 86,  0,  0, 87,  0,  0,  0,  0,  0, 88, 57,  0,
-    0,  0,  0,  0,  0, 89, 90,  0,  0, 84,  0,  0, 33,  0,  0, 91,
-    0,  0,  0,  0, 92,  0,  0,  0,  0, 49,  0,  0, 93,  0,  0,  0,
-    0, 94, 95,  0,  0, 96,  0,  0, 97,  0,  0,  0, 98,  0,  0,  0,
-   99,  0,  0,  0,100,  0,  0,  0,  0,101,102, 93,  0,  0,103,  0,
-    0,  0, 84,  0,  0,104,  0,  0,  0,105,106,  0,  0,107,108,  0,
-    0,  0,  0,  0,  0,109,  0,  0,110,  0,  0,  0,  0,111, 33,  0,
-  112,113,114, 57,  0,  0,115, 35,  0,  0,116,  0,  0,  0,117,  0,
-    0,  0,  0,  0,  0,118,  0,  0,119,  0,  0,  0,  0,120, 88,  0,
-    0,  0,  0,  0, 57,  0,  0,  0,  0, 52,121,  0,  0,  0,  0,122,
-    0,  0,123,  0,  0,  0,  0,121,  0,  0,124,  0,  0,  0,  0,  0,
-   79,  0,  0,  0,  0,125,  0,  0,  0,126,  0,  0,  0,127,  0,128,
-    0,  0,  0,  0,129,130,131,  0,132,  0,133,  0,  0,  0,134,135,
-  136,  0, 77,  0,  0,  0,  0,  0, 35,  0,  0,  0,137,  0,  0,  0,
-  138,  0,  0,  0,139,  0,  0,140,  0,  0,141,  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,  0, 19, 52,  1,  0,  0,
-   38, 14,  4,  1,  1,  1, 53, 21, 43, 52, 54, 21, 35,  1,  0,  0,
-    0, 55,  0,  0,  0, 56, 57, 58,  0,  0,  0,  0,  0, 59,  0, 60,
-    0,  0,  0,  0, 61, 62,  0,  0, 63,  0,  0,  0, 64,  0,  0,  0,
-   65,  0,  0,  0, 66,  0,  0,  0, 67,  0,  0,  0, 68,  0,  0, 69,
-   70,  0, 71, 72, 73, 74, 75, 76,  0,  0,  0, 77,  0,  0,  0, 78,
-   79,  0,  0,  0,  0, 47,  0,  0,  0, 49,  0, 80,  0,  0,  0, 62,
-    0,  0, 63,  0,  0, 81,  0,  0, 82,  0,  0,  0, 83,  0,  0, 19,
-   84,  0, 62,  0,  0,  0,  0, 49,  1, 85,  1, 52, 15, 86, 36, 10,
-   21, 87,  0, 55,  0,  0,  0,  0, 19, 10,  1,  0,  0,  0,  0,  0,
-   88,  0,  0, 89,  0,  0, 88,  0,  0,  0,  0, 78,  0,  0, 87,  9,
-   12,  4, 90,  8, 91, 47,  0, 58, 50,  0, 21,  1, 21, 92, 93,  1,
-    1,  1,  1, 94, 95, 96, 97,  1, 98, 58, 81, 99,100,  4, 58,  0,
-    0,  0,  0,  0,  0, 19, 50,  0,  0,  0,  0,  0,  0, 61,  0,  0,
-  101,102,  0,  0,103,  0,  0,  1,  1, 50,  0,  0,  0, 38,  0, 63,
-    0,  0,  0,  0,  0, 62,  0,  0,104, 68, 61,  0,  0,  0, 78,  0,
-    0,  0,105,106, 58, 38, 81,  0,  0,  0,  0,  0,  0,107,  1, 14,
-    4, 12, 84,  0,  0,  0,  0, 38, 87,  0,  0,  0,  0,108,  0,  0,
-  109, 61,  0,110,  0,  0,  0,  1,  0,  0,  0,  0, 49, 50,  0,  0,
-   19, 58,  0,  0,  0, 51,  0,111, 14, 52,112, 41,  0,  0, 62,  0,
-    0, 61,  0,  0,113,  0, 87,  0,  0,  0, 61, 62,  0,  0, 62,  0,
-   89,  0,  0,113,  0,  0,  0,  0,114,  0,  0,  0, 78, 55,  0, 38,
-    1, 58,  1, 58,  0,  0,  0,  0,  0, 88, 63, 89,  0,  0,115,  0,
-    0,  0, 55,  0,  0,  0,  0,115,  0,  0,  0,  0, 61,  0,  0,  0,
-    0, 79,  0, 61,  0,  0,  0,  0, 56,  0, 89, 80,  0,  0, 79,  0,
-    0,  0,  8, 91,  0,  0,  1, 87,  0,  0,116,  0,  0,  0,  0,  0,
-    0,117,  0,118,119,120,121,  0,104,  4,122, 49, 23,  0,  0,  0,
-   38, 50, 38, 58,  0,  0,  1, 87,  1,  1,  1,  1, 39,  1, 48,105,
-   87,  0,  0,  0,  0,  1,  0,  0,  0,123,  0,  0,  0,112,  4,122,
-    0,  0,  0,  1,124,  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,230,220,220,220,230,230,  0,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,  9,  9,  0,  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,230,230,230,  0,  0,  0,  9,  9,  0,  0,  7,  0,230,  0,
-    1,  1,  1,  0,  0,  0,230,234,214,220,202,230,230,230,230,230,
-  232,228,228,220,218,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,  0,  0,  0,220,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,  0,230,220,  0,  9,  7,  0,  0,  7,
-    9,  0,  0,  0,  9,  7,  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,232,232,220,230,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,
+   57, 58,  0,  0,  0, 59, 60, 61, 62,  0,  0,  0,  0, 63, 52,  0,
+   64, 65,  0,  0, 66,  0,  0,  0, 67, 68,  0,  0,  0, 69,  0, 70,
+   71, 72, 73, 74,  1, 75,  0, 76, 77, 78,  0,  0, 79, 80,  0,  0,
+    0, 81,  0,  0,  1,  1,  0,  0, 82,  0,  0, 83,  0,  0,  0,  0,
+   79, 84,  0, 85,  0,  0,  0,  0,  0, 80, 86,  0, 87,  0, 52,  0,
+    1, 80,  0,  0, 88,  0,  0, 89,  0,  0,  0,  0,  0, 90, 57,  0,
+    0,  0,  0,  0,  0, 91, 92,  0,  0, 86,  0,  0, 33,  0,  0, 93,
+    0,  0,  0,  0, 94,  0,  0,  0,  0, 49,  0,  0, 95,  0,  0,  0,
+    0, 96, 97,  0,  0, 98,  0,  0, 99,  0,  0,  0,100,  0,  0,  0,
+  101,  0,  0,  0,102,  0,  0,  0,  0,103,104, 95,  0,  0,105,  0,
+    0,  0, 86,  0,  0,106,  0,  0,  0,107,108,  0,  0,109,110,  0,
+    0,  0,  0,  0,  0,111,  0,  0,112,  0,  0,  0,  0,113, 33,  0,
+  114,115,116, 57,  0,  0,117, 35,  0,  0,118,  0,  0,  0,119,  0,
+    0,  0,  0,  0,  0,120,  0,  0,121,  0,  0,  0,  0,122, 90,  0,
+    0,  0,  0,  0, 57,  0,  0,  0,  0, 52,123,  0,  0,  0,  0,124,
+    0,  0,125,  0,  0,  0,  0,123,  0,  0,126,  0,  0,  0,  0,  0,
+   81,  0,  0,  0,  0,127,  0,  0,  0,128,  0,  0,  0,129,  0,130,
+    0,  0,  0,  0,131,132,133,  0,134,  0,135,  0,  0,  0,136,137,
+  138,  0, 79,  0,  0,  0,  0,  0, 35,  0,  0,  0,139,  0,  0,  0,
+  140,  0,  0,  0,141,  0,  0,  0,142,143,  0,144,  0,  0,145,  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,  0, 19,
+   52,  1,  0,  0, 38, 14,  4,  1,  1,  1, 53, 21, 43, 52, 54, 21,
+   35,  1,  0,  0,  0, 55,  0,  0,  0, 56, 57, 58,  0,  0,  0,  0,
+    0, 59,  0, 60,  0,  0,  0,  0, 61, 62,  0,  0, 63,  0,  0,  0,
+   64,  0,  0,  0, 65,  0,  0,  0, 66,  0,  0,  0, 67,  0,  0,  0,
+   68,  0,  0, 69, 70,  0, 71, 72, 73, 74, 75, 76,  0,  0,  0, 77,
+    0,  0,  0, 78, 79,  0,  0,  0,  0, 47,  0,  0,  0, 49,  0, 80,
+    0,  0,  0, 62,  0,  0, 63,  0,  0, 81,  0,  0, 82,  0,  0,  0,
+   83,  0,  0, 19, 84,  0, 62,  0,  0,  0,  0, 49,  1, 85,  1, 52,
+   15, 86, 36, 10, 21,  1,  1,  1,  1, 41,  1, 21, 87,  0,  0, 55,
+    0,  0,  0,  0, 19, 10,  1,  0,  0,  0,  0,  0, 88,  0,  0, 89,
+    0,  0, 88,  0,  0,  0,  0, 78,  0,  0, 90,  9, 12,  4, 91,  8,
+   92, 47,  0, 58, 50,  0, 21,  1, 21, 93, 94,  1,  1,  1,  1, 95,
+   96, 97, 98,  1, 99, 58, 81,100,101,  4, 58,  0,  0,  0,  0,  0,
+    0, 19, 50,  0,  0,  0,  0,  0,  0, 61,  0,  0,102,103,  0,  0,
+  104,  0,  0,  1,  1, 50,  0,  0,  0, 38,  0, 63,  0,  0,  0,  0,
+    0, 62,  0,  0,105, 68, 61,  0,  0,  0, 78,  0,  0,  0,106,107,
+   58, 38, 81,  0,  0,  0,  0,  0,  0,108,  1, 14,  4, 12, 84,  0,
+    0,  0,  0, 38, 90,  0,  0,  0,  0,109,  0,  0,110, 61,  0,111,
+    0,  0,  0,  1,  0,  0,  0,  0, 49, 50,  0,  0, 19, 58,  0,  0,
+  112, 51,  0,112, 14, 52,113, 41,  0,  0, 62,  0,  0, 61,  0,  0,
+  114,  0, 90,  0,  0,  0, 61, 62,  0,  0, 62,  0, 89,  0,  0,114,
+    0,  0,  0,  0,115,  0,  0,  0, 78, 55,  0, 38,  1, 58,  1, 58,
+    0,  0,  0,  0,  0, 88, 63, 89,  0,  0,116,  0,  0,  0, 55,  0,
+    0,  0,  0,116,  0,  0,  0,  0, 61,  0,  0,  0,  0, 79,  0, 61,
+    0,  0,  0,  0, 56,  0, 89, 80,  0,  0, 79,  0,  0,  0,  8, 92,
+    0,  0,  1, 90,  0,  0,117,  0,  0,  0,  0,  0,  0,118,  0,119,
+  120,121,122,  0,105,  4,123, 49, 23,  0,  0,  0, 38, 50, 38, 58,
+    0,  0,  1, 90,  1,  1,  1,  1, 39,  1, 48,106, 90,  0,  0,  0,
+    0,  1,  0,  0,  0,124,  0,  0,  0,113, 19, 59,  0, 38,  0, 81,
+    0,  0,  4,123,  0,  0,  0,  1,125,  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,230,220,220,220,230,230,
+    0,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,  9,  9,  0,  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,230,230,230,234,  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,218,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,  0,  0,
+    0,220,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,  0,
+  230,220,  0,  9,  7,  0,  0,  7,  9,  0,  0,  0,  9,  7,  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,232,232,220,230,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,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, 24,  3,  3,  3,  3,  3,  3, 25,  3,  3,  3,  3,  3,
-    3,  3,  3, 26,  3,  3, 27, 28,  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,  0, 56, 57,  0,  0,
-    0,  0,  0, 19, 58, 31,  0,  0,  0,  0,  0,  0,  0, 59, 14,  0,
-    0,  0,  0,  1,  0,  2,  0,  0,  0,  3,  0,  0,  0, 60, 61,  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,  0,  0,  8, 21, 21, 21,  9,  0,  1,  0,  1,  1,  8, 21,
-   21,  9,  0,  4,  5,  8,  9,  1,  0,  0,  0,  1,  2,  3,  3,  4,
-    5,  6,  7,  8,  9, 10, 11, 12, 13, 14,  3,  3,  3,  3,  3,  3,
-    3, 15,  3, 16, 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, 18,  0,  0,  1,  2,  3,
-    4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 17, 17,
-   18, 17, 19, 20, 21, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
-   23, 23, 24, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
-   23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 25, 25, 26, 27,
-   28, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
-   30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31,
-   31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 34, 35, 36, 37, 38, 39,
-   40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 52, 53, 31,
-   31, 31, 31, 54, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 56, 57,
-   31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 58, 31, 31, 31,
-   59, 60, 61, 62, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
-   63, 64, 65, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
-   31, 31, 31, 66, 67, 68, 31, 31, 31, 31, 69, 31, 31, 31, 31, 31,
-   31, 31, 17, 70, 71, 72, 17, 17, 73, 74, 31, 75, 76, 77, 78, 79,
-   80, 31, 81, 82, 17, 83, 17, 17, 17, 17, 31, 31, 23, 23, 23, 23,
-   23, 23, 23, 84, 31, 31, 31, 31, 23, 84, 31, 31, 23, 23, 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, 85,  0,  0,  1,
-    0,  1,  2,  3,  0,  1,  2,  3,  4,  5,  6,  7,  0,  1,  2,  3,
-    4,  4,  4,  4,  4,  4,  5,  6,  7,  8,  9, 10, 11, 11, 12, 11,
-   13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 19, 27,
-   28, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36,
-   37, 37, 38, 38, 39, 40, 41, 41, 42, 42, 42, 43, 44, 44, 45, 46,
-   47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 49, 50, 51, 51, 51, 51,
-   51, 51, 51, 51, 51, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, 51,
-   60, 61, 62, 63, 64, 65, 66,  7, 67, 67, 68, 69, 70, 71, 72, 73,
-   74, 75, 76,  7,  4,  4,  4,  4, 77, 77, 77, 77, 78, 79, 80, 81,
-   82, 83, 84,  0,  0,  0,  0,  0,  0,  0,  0,  0, 85, 85, 85, 85,
-    0,  0,  0,  0, 86, 87, 88, 88, 89, 90, 48, 91,  0,  0, 92, 92,
-   92, 92, 92, 93, 94, 95, 96, 97, 98, 47, 99,100,101,102,  0,103,
-  104,105,  0,  0, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
-   92, 92, 92,  0,106,106,106,106,106,106,106,106,106,106,106,107,
-  108,108,108,108,108, 11,109,110,111,  4,112,  4,113,114,115,116,
-  117,118,119,120,121,122,123,124,125,126, 50,127, 47, 47, 47, 47,
-   47, 47, 47, 47,128,128,128,128,128,128,128,128,128,128,128,128,
-   92, 92, 92, 92, 92, 92, 92, 92,129,130, 19, 19, 19, 19, 19, 19,
-  131, 19, 19, 19,132,133, 19,134,135,136,137,101,138,138,138,138,
-    0, 77,139,140,128,128,141,142,143,144,145,146,147,148,149,150,
-  151,152,153,154,155,155,155,155,155,155,  4,  4,156,157,158,159,
-  160,161,162,163,164,165,166,167,168,169,170,170,171,171,172,172,
-  173,174,174,174, 19, 19,175,176,177,178,179,180,181,181,182,183,
-  184,185,186,187,188,188,189,190,191,192,193,193,194,194,195,195,
-  128,128,196,196,197,198,199,200,201,201,128,128,202,202,203,203,
-  204,204,205,205,206,207,208,209, 28, 28,210,210,211,212,213,213,
-  214,215,216,216,128,128,217,217,218,218,219, 34,220,220,220,220,
-  220,220,220,220,220,220,220,220,220,220,128,128,128,128,128,128,
-  128,128,221,221,222,222,222,222,222,222,222,222,223,223,223,223,
-  223,223,223,223,223,223,128,128,128,128,128,128,128,128,128,128,
-  224,224,128,128,110,110,110,110,110,110,110,110,110,225,226,227,
-  228,228,228,228,128,128,128,128,229,229,128,128,230,230,230,230,
-  231,231,231,232,233,233,233,233,233,233,233,233,233,233,233,233,
-  234,234,234,234,234,234,234,234,233,233,128,128,128,128,128,128,
-  128,128,104,104,235,236,236,236,237,238,239,239,239,239,239,239,
-  128,128,128,128,240,240,241,  0,128,128,128,128,  0,  0,  0,  0,
-    7,242,  0,  0,  0,  0,  0,  0,  0,243,244,  0, 77, 77,  0,  0,
-    0,  0,128,128,245,245,245,245,245,245,245,245,245,245,245,245,
-  128,128,128,128,128,128,128,128,  4,  4,128,128,246, 11, 11, 11,
-  247,247,128,128,128,128,248,249,128,128,128,128,128,128,250,250,
-  128,128,251,251,128,128,128,128,128,128, 48, 48,252,252,252,252,
-  253,253,128,128,  0,  0,  0,  0,  0,  0,128,128, 19, 19, 19, 19,
-  128,128,128,128,254,  0,128,128,  0,  0,  0,  0, 92, 92,128,128,
-  128,128,128,128,  0,  0,128,128,  7,  7,  7,  7,  0,  0,  0,  0,
-    1,  2,  1,  2,  0,  0,  3,  3,  4,  5,  4,  5,  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, 14, 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, 21, 21, 21, 31, 21, 32, 32, 32, 32,
-   32, 33, 34, 32, 35, 35, 35, 35, 36, 36, 36, 36, 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, 45, 44, 44, 44, 44,
-   46, 46, 46, 46, 47, 47, 47, 47, 47, 48, 47, 47, 49, 49, 49, 49,
-   49, 49, 50, 50, 50, 50, 50, 51, 52, 52, 52, 52, 53, 53, 53, 53,
-   53, 53, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 57, 57,
-   57, 57, 58, 57, 59, 59, 60, 61, 62, 62, 63, 63, 64, 64, 64, 64,
-   65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 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, 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,
-   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,
-   90, 90, 90, 90, 91, 91, 91, 91, 91, 91,  4,  4, 92, 92, 92, 92,
-   50, 50, 50, 93, 93, 93, 93, 93, 53, 53, 13, 13, 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,  0,104,104,  0,  0,  0,102,
-   52, 52,  0,  0,  0,  0, 52,106,  0,102,102,107,102,102,102,102,
-  102,108,  0,  0,109,109,109,109,109,110,110,110,111,111,111,111,
-   13, 13,112,112,112,112,112,112,  0,  0,113,  4,114,  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,125,125,125,125,128,128,128,128,
-    4,129, 18, 18, 18, 21, 21, 21, 21, 21, 21,130,  8,  0,131,  0,
-    0,  0,  0, 21, 21, 21, 21,132,  0,  0,  1,  2,  1,  2,133,101,
-  102,134, 52, 52,135,135,135,135, 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,151,
-  151,151,151,151,152,152,152,152,153,153,153,153,154,154,154,154,
-  155,155,156,156,157,157,157,157,157,157,158,158,159,159,160,160,
-  160,160,160,160,161,161,162,162,162,162,162,162,163,163,163,163,
-  163,163,164,164,165,165,165,165,166,166,166,166,167,167,167,167,
-  168,168,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, 21, 21, 21,
-  177,177,177,178,178,178,178,179,179,179,179,180,180,180,181,181,
-  182,182,182,182,183,183,183,183,183,184,184,184,185,185,185,185,
-  185,186,186,186,187,187,187,187,187,187,188, 43,189,189,189,189,
-  190,190,190,191,191,191,191,191,192,192,192,193,192,192,192,192,
-  194,194,194,194,195,195,195,195,196,196,196,196,197,197,197,197,
-  198,198,198,198,198,198, 66, 66,199,199,199,199,199, 49, 49, 49,
-  200,200,200,200,201,201,201,201,202,202,202,202,203,203,203,203,
-  204,204,204,204,205,205,205,205,205,206,206,206,206,206,206, 55,
-  207,207,207,207,208,208,208,208,209,209,209,209,209,209,209,210,
-  210,210,210,210,211,211,211,211,211,211,212,212,212,212,212,212,
-  213,213,213,213,214,214,214,214,110,110,110,110,215,215,215,215,
-  216,216,216,216,217,217,217,217,218,218,218,218,219,219,219,219,
-  220,220,220,221,221,221,221,221,221,222,222,222,223,223,223,223,
-  224,224,224,224,225,225,225,225,226,226,226,226,226,226,227, 94,
-  228,228,228,228,229,229,229,229,230, 99, 99, 99, 99, 99, 99, 99,
-   99, 99,102,231, 99,232,102,233,233,233,233,233,234,234,234,234,
-  234,234,  0,  0,  8,  0,  0,  0,  0,  0,235,236,237,  0,238,  0,
-  239,239,239,239, 91, 91, 91, 13,240,240,240,240,241,241,241,241,
-  242,242,242,242,243,243,243,243,244,244,244,244,245,245,245,245,
-  246,246,246,246,247,  0,  0,  0,  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, 20, 20, 20,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,184,184,184,185,185,185,185,186,186,186,186,
-  187,187,187,187,188,188,188,188,189, 45, 45, 45,190,190,190,190,
-  191,191,191,191,192,192,192,192,193,193,193,193,193,193,194,193,
-  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,216,216,216,217,217,217,217,218,218,218,218,
-  219,219,219,219,220,220,220,220,221,221,221,221,222,222,222,222,
-  223,223,223,223,224,224,224,224,225,225,225,225,226,226,226,226,
-  227,227,227,227,228,229,229,229,230,230,230,230,229,229,229,229,
-  231,106,106,106,232,106,106,106,106,233,109,109,234,234,234,234,
-  235,235,235,235,  0,236, 86,  0,  0,  0,236,  7, 82,138,  7,  0,
-    0,  0,237, 86,238,238,238,238,239,239,239,239,240,240,240,240,
-  241,241,241,241,242,242,242,242,243,243,243,243,244,244,244,244,
-  245,245,245,245,246,  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,161,161,161,161,170,170,170,170,
-  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,165,165,165,165,156,156,156,156,156,156,  3,  3,
-  147,147,147,147,148,148,148,148,158,158,158,158,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,171,171,171,171,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,169,169,169,169,
-  133,133,133,133,134,134,134,134,138,138,138,138,143,143,143,143,
-  145,145,145,145,163,163,163,163, 63, 63, 63, 63,157,157,157,157,
-   80, 80, 80, 80,127,127,127,127,166,166,166,166,115,115,115,115,
-  159,159,159,159,103,103,103,103,119,119,119,119,167,167,167,167,
-  146,146,146,146, 99, 99, 99, 99,136,139, 13, 13,155,155,155,155,
-  136,136,136,136, 17, 15, 15, 15, 17, 17, 15, 15, 15, 17, 17, 17,
-  139,139,139,139,105,105,105,105,  0,  0,  0,  1,  0,  0,  1,  1,
-  131,131,131,131,151,151,151,151,160,160,160,160,152,152,152,152,
-  164,164,164,164,168,168,168,168,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,
+   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, 24,  3,  3,  3,  3,
+    3,  3, 25,  3,  3,  3,  3,  3,  3,  3,  3, 26,  3,  3, 27, 28,
+    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,  0, 56, 57,  0,  0,  0,  0,  0, 19, 58, 31,  0,  0,
+    0,  0,  0,  0,  0, 59, 14,  0,  0,  0,  0,  1,  0,  2,  0,  0,
+    0,  3,  0,  0,  0, 60, 61,  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,  0,  0,  8, 21, 21, 21,
+    9,  0,  1,  0,  1,  1,  8, 21, 21,  9,  0,  4,  5,  8,  9,  1,
+    0,  0, 16, 50, 84,118,136,152,186,187,187,187,187,187,187,187,
+  187,187,187,187,187,187,187,187,187,187,187,187,187,187, 12,  0,
+    1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 13, 13, 13,
+   13, 13, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 15, 16, 17, 18, 18, 18, 18, 18, 18,
+   18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 21, 22,
+   23, 24, 25, 26, 27, 28, 29, 30, 31, 19, 32, 33, 33, 33, 33, 33,
+   34, 19, 19, 19, 19, 19, 19, 35, 19, 36, 37, 38, 38, 38, 38, 38,
+   38, 39, 40, 19, 19, 19, 19, 19, 19, 19, 41, 42, 19, 19, 43, 19,
+   19, 19, 44, 45,  9, 46, 47, 48, 49, 50, 51, 52,  9,  9, 19, 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, 13, 53, 19, 19, 53, 19, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 54, 19, 19, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 55,
+    0,  0,  1,  0,  1,  2,  3,  0,  1,  2,  3,  4,  5,  6,  7,  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, 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, 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,104,105,105,105,  2,106,
+  107,108,109,110,111,112,113,114,115,116,117, 89,118,119,120,121,
+  122,123,124,125,126,127,128,129,130, 87,131,132,133,134, 87,135,
+  136,137,138,139,140,141,142,143,144,145,146, 87,147,148,149,150,
+  150,150,150,150,150,150,150,150,150,150, 87, 87, 87, 87, 87, 87,
+   87, 87, 87, 87, 87, 87,151,152,152,152,152,152,152,152,152,153,
+  153,153,153,153, 87, 87, 87, 87, 87,154, 87, 87, 87, 87, 87,155,
+  155,155,155,156,157,158,158, 87, 87,159, 87,160,161,162,163,164,
+  164,164,164,164,164,164,164,164,164,164,164,164,164,165,165,165,
+  165,164,164, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,166,167,
+  168,169,170,170,170, 87, 87,171,172, 87, 87, 87, 87, 87, 87, 56,
+   56, 56, 56, 56, 56,173, 56, 56, 56,174,175, 51, 56, 56, 87,176,
+  176,176,176,176,176, 87, 87, 87, 87, 87, 87, 87, 87,  2, 87,177,
+    6,178, 87, 87,179, 87, 87, 87,180, 87,181, 87,182, 87, 33,183,
+  183,184, 87, 87, 87, 87, 87, 56, 56, 56, 87, 89, 89, 87, 87, 56,
+   56, 56, 56,185, 87, 56, 56, 62, 62, 62, 62, 62, 87, 87, 87, 62,
+   87, 87, 87, 87, 87, 87, 87, 56, 87,186,186,  0,  1,  2,  2,  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, 21, 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, 21, 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,151,151,
+  151,151,151,152,152,152,152,153,153,153,153,153,153,153,153,154,
+  154,154,154,155,155,156,156,157,157,157,157,157,157,158,158,159,
+  159,160,160,161,161,161,161,162,162,163,163,163,163,163,163,164,
+  164,164,164,164,164,165,165,166,166,166,166,167,167,167,167,168,
+  168,168,168,169,169,170,170,171,171,171,171,171,171,171,171,172,
+  172,172,172,172,172,172,172,173,173,173,173,173,173,173,173,174,
+  174,174,174,175,175,175,175,175,175,175,175,175,175,175,175,176,
+  176,176,176,177, 21, 21, 21,178,178,178,179,179,179,179,180,180,
+  180,180,181,181,181,182,182,183,183,183,183,183,183,183,183,184,
+  184,184,184,184,185,185,185,186,186,186,186,186,187,187,187,188,
+  188,188,188,188,188,189, 43,190,190,190,190,190,190,190,190,191,
+  191,191,192,192,192,192,192,193,193,193,194,193,193,193,193,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,199, 66, 66,200,200,200,200,200, 49, 49, 49,201,
+  201,201,201,201,201,201,201,202,202,202,202,202,202,202,202,203,
+  203,203,203,203,203,203,203,204,204,204,204,204,204,204,204,205,
+  205,205,205,205,205,205,205,206,206,206,206,206,207,207,207,207,
+  207,207, 55,208,208,208,208, 32, 32, 32, 32, 32, 32,188,188,209,
+  209,209,209,209,209,209,209,210,210,210,210,210,210,210,211,211,
+  211,211,211,211,211,211,211,212,212,212,212,212,212,213,213,213,
+  213,213,214,214,214,214,214,215,215,215,215,215,215,215,215,216,
+  216,216,216,216,216,216,216,110,110,110,110, 39, 39, 39, 39,217,
+  217,217,217,217,217,217,217,218,218,218,218,218,218,218,218,219,
+  219,219,219,219,219,219,219,220,220,220,220,220,220,220,220,221,
+  221,221,221,221,221,221,221,112,112,112,112,112,112,112,112,112,
+  112,112,112,222,222,222,223,223,223,223,223,223,224,224,224,225,
+  225,225,225,225,225,225,225,226,226,226,226,226,226,226,226,227,
+  227,227,227,227,227,227,227,227,227,228,228,228,228,228,228,229,
+  229,229,229,229,229,229,229,229,229,229,229,229,229,230, 94,231,
+  231,231,231,231,231,231,231,232,232,232,232,232,232,232,232,102,
+  102,102,102,102,102,102,102,233, 99, 99, 99, 99, 99, 99, 99, 99,
+   99, 99, 99, 99, 99, 99, 99, 99, 99,102,234, 99,235,102,236,236,
+  236,236,236,236,236,236,236,237,237,237,237,237,237,237,237,237,
+  237,  0,  0,  0,  0,  0,  0,  8,  8,  8,  8,  8,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,238,239,240,  0,241,  0,  0,  0,  0,  0,242,
+  242,242,242,242,242,242,242, 91, 91, 91, 13, 13, 13, 13, 13,243,
+  243,243,243,243,243,243,243,244,244,244,244,245,245,245,245,246,
+  246,246,246,246,246,246,246,247,247,247,247,247,247,247,247,248,
+  248,248,248,248,248,248,248,249,249,249,249,249,249,249,249,250,
+  250,250,250,250,250,250,250,251,  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, 20, 20, 20,179,
+  179,179,179,180,180,180,180,181,181,181,181,182,182,182,182,183,
+  183,183,183,184,184,184,184,185,185,185,185,186,186,186,186,187,
+  187,187,187,188,188,188,188,189,189,189,189,190, 45, 45, 45,191,
+  191,191,191,192,192,192,192,193,193,193,193,194,194,194,194,194,
+  194,195,194,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,216,216,216,217,217,217,217,218,218,218,218,219,
+  219,219,219,220,220,220,220,221,221,221,221,222,222,222,222,223,
+  223,223,223,224,224,224,224,225,225,225,225,226,226,226,226,227,
+  227,227,227,228,228,228,228,229,229,229,229,230,230,230,230,231,
+  232,232,232,233,233,233,233,232,232,232,232,234,106,106,106,235,
+  106,106,106,106,236,109,109,237,237,237,237,238,238,238,238,  0,
+  239, 86,  0,  0,  0,239,  7, 82,138,  7,  0,  0,  0,240, 86,241,
+  241,241,241,242,242,242,242,243,243,243,243,244,244,244,244,245,
+  245,245,245,246,246,246,246,247,247,247,247,248,248,248,248,249,
+  249,249,249,250,  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,161,161,161,161,170,170,170,170,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,173,
+  173,173,173, 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,165,165,165,165,156,156,156,156,156,
+  156,  3,  3,147,147,147,147,148,148,148,148,158,158,158,158,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,171,171,171,171,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,169,
+  169,169,169,133,133,133,133,134,134,134,134,138,138,138,138,143,
+  143,143,143,175,175,175,175,145,145,145,145,163,163,163,163, 63,
+   63, 63, 63,157,157,157,157, 80, 80, 80, 80,127,127,127,127,166,
+  166,166,166,115,115,115,115,159,159,159,159,103,103,103,103,119,
+  119,119,119,167,167,167,167,146,146,146,146,172,172,172,172, 99,
+   99, 99, 99,136,139, 13, 13,155,155,155,155,136,136,136,136, 17,
+   15, 15, 15, 17, 17, 15, 15, 15, 17, 17, 17,139,139,139,139,105,
+  105,105,105,  0,  0,  0,  1,  0,  0,  1,  1,131,131,131,131,151,
+  151,151,151,160,160,160,160,152,152,152,152,164,164,164,164,168,
+  168,168,168,174,174,174,174,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,
-   16, 17,  9,  9,  9,  9, 18,  9,  9,  9,  9,  9, 19, 20, 21,  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, 16,
+   17,  9,  9,  9,  9, 18,  9,  9,  9,  9,  9, 19, 20, 21,  9, 22,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9, 23,  9,  9,  9,  9,  9, 24,  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,  9,  9,  9,  9,  9, 24,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  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,  9,  9,  9,
     9,  9,  9,  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,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
@@ -5451,66 +5204,66 @@ _hb_ucd_u8[13730] =
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-   26, 27,  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,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 26,
+   27,  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,  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, 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,  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, 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,  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, 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,  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,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,  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,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,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,162,  0,
-  163,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,164,165,  0,  0,  0,
-    0,  0,  0,  0,166,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,162,  0,163,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,164,165,  0,  0,  0,  0,
+    0,  0,  0,166,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,167,  0,  0,  0,168,169,  0,  0,170,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,171,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,172,  0,  0,
+    0,  0,  0,  0,  0,167,  0,  0,  0,168,169,  0,  0,170,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,171,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,172,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,173,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,173,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,174,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,174,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,175,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,175,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,176,177,  0,  0,  0,  0,178,179,  0,
-    0,  0,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,207,208,209,
-  210,211,212,213,  0,  0,  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,176,177,  0,  0,  0,  0,178,179,  0,  0,
+    0,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,207,208,209,210,
+  211,212,213,  0,  0,  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[5080] =
+static const uint16_t _hb_ucd_u16[5104]=
 {
      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,
@@ -5563,276 +5316,276 @@ _hb_ucd_u16[5080] =
     47,  47,  47, 313,  58, 314, 315, 316,  47,  47,  47,  11,  11, 317, 318,  11,
     11,  11,  11,  11,  47,  47, 319, 160, 320, 320, 320, 320, 320, 320, 320, 320,
    321, 321, 321, 321, 321, 321, 321, 321,  11, 322, 323,  47,  47,  47,  47,  47,
-    47,  47,  47, 324,  31, 325,  47,  47,  47,  47,  47, 326, 146,  47,  47,  47,
-    47,  47,  47,  47, 327, 146, 146, 328,  32, 329,  32, 330, 331, 332, 333,  47,
-    47,  47,  47,  47,  47,  47,  47, 334, 335,   2,   3,   4,   5, 336, 337, 338,
-    47, 339,  47,  47,  47,  47, 340, 341, 342, 145, 145, 343, 220, 220, 220, 344,
-   345, 146, 146, 146, 146, 146, 146, 346, 347, 347, 347, 347, 347, 347, 347, 347,
-    47,  47,  47,  47,  47,  47, 348, 145,  47,  47, 349,  47, 350,  47,  47,  60,
-    47, 351,  47,  47,  47, 352, 220, 220,   9,   9, 147,  11,  11,  47,  47,  47,
-    47,  47, 160,   9,   9, 147,  11,  11,  47,  47,  47,  47,  47,  47, 351,   9,
-     9, 353,  11,  11,  47,  47,  47,  47,  27,  27,  27,  27,  27,  27,  27,  27,
-    47,  47,  47,  47,  47, 354,  47, 355,  47,  47, 356, 145, 145, 145,  47, 357,
-    47, 358,  47, 351,  66,  66,  66,  66,  47,  47,  47, 359, 145, 145, 145, 145,
-   360,  47,  47, 361, 145,  66,  47, 362,  47, 363, 145, 145, 364,  47, 365,  66,
-    47,  47,  47, 366,  47, 367,  47, 367,  47, 366, 144, 145, 145, 145, 145, 145,
-     9,   9,   9,   9,  11,  11,  11, 368,  47,  47, 369, 160, 370,   9, 371,  11,
-   372, 227, 227, 227, 227, 227, 227, 227, 145, 145, 145, 145, 145, 145, 145, 145,
-    47,  47, 373,  47,  47,  47,  47, 374,  47, 363, 375,  47,  60, 376,  66,  47,
-   377,  66,  66,  47, 378, 145,  47,  47, 379,  47,  47, 361, 380, 381, 382, 383,
-   180,  47,  47, 384, 385,  47,  47, 160,  97,  47, 386, 387, 388,  47,  47, 389,
-   180,  47,  47, 390, 391, 392, 393, 145,  47,  47, 394, 395, 360,  32,  32,  32,
-    47,  47, 366,  47,  47, 396, 172, 160,  92,  47,  47, 113, 397, 398, 399,  32,
-    47,  47,  47, 400, 401, 402, 403,  32,  47,  47,  47, 404, 405, 406,  47,  47,
-    47,  47,  47, 407, 408, 160, 160, 160,  47,  47, 409, 410, 411, 412,  32,  32,
-    47,  47,  47, 413, 414, 160,  66,  66,  47,  47, 415, 416, 160, 160, 160, 160,
-    47, 417, 418, 419,  47,  47,  47,  47,  47,  47, 394, 420,  66,  66,  66,  66,
-     9,   9,   9,   9,  11,  11, 128, 421,  47,  47,  47, 422, 423, 160, 160, 160,
-    47,  47,  47,  47,  47, 424, 425, 426, 427,  47,  47, 428, 429, 430,  47,  47,
-   431, 432,  66,  47,  47,  47,  47,  47,  66,  66,  66,  66,  66,  66,  66,  66,
-    47,  47,  47,  47,  47,  47, 433, 160,  47,  47, 409, 434, 433, 128, 145, 435,
-    47, 156, 436, 437,  32,  32,  32,  32,  47,  47,  47, 360, 438, 160,  47,  47,
-   439, 440, 160, 160, 160, 160, 160, 160,  47,  47,  47,  47,  47,  47,  47, 441,
-   442,  47,  47, 443, 444, 445,  32,  32,  47,  47,  47,  47, 145, 446, 447, 448,
-   220, 220, 220, 220, 220, 220, 220,  66,  47,  47,  47,  47,  47,  47,  47, 433,
-    47,  47,  47, 209, 449,  32,  47,  47,  47, 450, 451, 160, 160, 160, 160, 160,
-    47,  47,  47,  47,  47,  47, 306,  47,  47,  47,  47,  47, 160,  47,  47, 452,
-    47,  47,  47, 453, 454, 455, 456,  47,  27,  27,  27,  27, 457,  47, 458, 160,
-     9,   9,   9,   9,   9,   9,  11,  11, 145, 459,  66,  66,  66,  66,  66,  66,
-    47,  47,  47,  47, 396, 460, 426, 426, 461, 462,  27,  27,  27,  27, 463, 426,
-    47, 464, 209, 209, 209, 209, 209, 209, 146, 146, 146, 146, 146, 146, 146, 160,
-    32,  32,  32,  32,  32, 146, 146, 146, 146, 146, 146, 146, 146, 146, 465, 466,
-   467, 146, 468, 146, 146, 146, 146, 146, 146, 146, 146, 146, 469, 146, 146, 146,
-     9, 470,  11, 471, 472,  11, 197,   9, 473, 474,   9, 475,  11,   9, 470,  11,
-   471, 472,  11, 197,   9, 473, 474,   9, 475,  11,   9, 470,  11, 471, 472,  11,
-   197,   9, 473, 474,   9, 475,  11,   9, 470,  11, 197,   9, 476, 477, 478, 479,
-    11, 480,   9, 481, 482, 483, 484,  11, 485,   9, 486,  11, 487, 160, 160, 160,
-    32,  32,  32, 488,  32,  32, 489, 490, 491, 492,  32,  32,  32,  32,  32,  32,
-   493,  11,  11,  11,  11,  11,  11,  11,  32,  32,  32,  27,  27,  27,  27,  27,
-    32,  32,  32,  32,  32,  32,  32,  32,  47,  47,  47, 494, 495, 146, 146, 146,
-    47,  47, 450,  32,  47,  47, 374, 496,  47,  47,  47,  47,  47,  47, 497, 160,
-    47,  47,  47,  47,  47,  47, 450, 498,  47,  47,  47,  47, 356,  32,  32,  32,
-     9,   9, 473,  11, 499, 306,  66,  66, 145, 145, 500, 501, 145, 145, 145, 145,
-   145, 145, 502, 145, 145, 145, 145, 145,  47,  47,  47,  47,  47,  47,  47, 227,
-   503, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 504,
-   209, 209, 209, 209, 209, 209, 209, 209,   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,1936,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1937,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,1938,   0,1939,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,1940,   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,1943,1944,   0,   0,   0,   0,   0,   0,1945,   0,1946,   0,   0,
-     0,   0,   0,   0,   0,   0,1947,   0,   0,1948,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1950,   0,1949,
-  1951,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,1953,1952,   0,1954,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,1955,1956,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-  1957,   0,   0,   0,   0,   0,   0,   0,   0,1958,1961,1959,1965,1960,1962,1964,
-  1963,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-  1967,1966,1968,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,1969,1970,1971,1972,1973,1974,1975,   0,   0,   0,
+    47,  47,  47, 324, 325, 326,  47,  47,  47,  47,  47, 327, 146,  47,  47,  47,
+    47, 328,  47,  47, 329, 146, 146, 330,  32, 331,  32, 332, 333, 334, 335,  47,
+    47,  47,  47,  47,  47,  47,  47, 336, 337,   2,   3,   4,   5, 338, 339, 340,
+    47, 341,  47,  47,  47,  47, 342, 343, 344, 145, 145, 345, 220, 220, 220, 346,
+   347, 146, 146, 146, 146, 146, 146, 348, 349, 349, 349, 349, 349, 349, 349, 349,
+    47,  47,  47,  47,  47,  47, 350, 145,  47,  47, 351,  47, 352,  47,  47,  60,
+    47, 353,  47,  47,  47, 354, 220, 220,   9,   9, 147,  11,  11,  47,  47,  47,
+    47,  47, 160,   9,   9, 147,  11,  11,  47,  47,  47,  47,  47,  47, 353,   9,
+     9, 355,  11,  11,  47,  47,  47,  47,  27,  27,  27,  27,  27,  27,  27,  27,
+    47,  47,  47,  47,  47, 356,  47, 357,  47,  47, 358, 145, 145, 145,  47, 359,
+    47, 360,  47, 353,  47,  47,  47,  47,  47,  47,  47, 361, 145, 145, 145, 145,
+   362,  47,  47, 363, 145,  66,  47, 364,  47, 365, 145, 145, 366,  47, 367,  66,
+    47,  47,  47, 368,  47, 369,  47, 369,  47, 368, 144, 145, 145, 145, 145, 145,
+     9,   9,   9,   9,  11,  11,  11, 370,  47,  47, 371, 160, 372,   9, 373,  11,
+   374, 227, 227, 227, 227, 227, 227, 227, 145, 145, 145, 145, 145, 145, 145, 145,
+    47,  47, 375,  47, 275, 376, 146, 377,  47, 365, 378,  47,  60, 379,  66,  47,
+   380,  66,  66,  47, 381, 145,  47,  47, 382,  47,  47, 363, 383, 384, 385, 386,
+   180,  47,  47, 387, 388,  47,  47, 160,  97,  47, 389, 390, 391,  47,  47, 392,
+   180,  47,  47, 393, 394, 395, 396, 145,  47,  47, 397, 398, 362,  32,  32,  32,
+    47,  47, 368,  47,  47, 399, 172, 160,  92,  47,  47, 113, 400, 401, 402,  32,
+    47,  47,  47, 403, 404, 405, 406,  32,  47,  47,  47, 407, 408, 409,  47,  47,
+    47,  47,  47, 410, 411, 160, 160, 160,  47,  47, 412, 413, 414, 415,  32,  32,
+    47,  47,  47, 416, 417, 160,  66,  66,  47,  47, 418, 419, 160, 160, 160, 160,
+    47, 420, 421, 422,  47,  47,  47,  47,  47,  47, 397, 423,  66,  66,  66,  66,
+     9,   9,   9,   9,  11,  11, 128, 424,  47,  47,  47, 425, 426, 160, 160, 160,
+    47,  47,  47,  47,  47, 427, 428, 429, 430,  47,  47, 431, 432, 433,  47,  47,
+   434, 435,  66,  47,  47,  47,  47,  47,  66,  66,  66,  66,  66,  66, 436, 429,
+    47,  47,  47,  47,  47,  47, 437, 160,  47,  47, 412, 438, 437, 128, 145, 439,
+    47, 156, 440, 441,  32,  32,  32,  32,  47,  47,  47, 362, 442, 160,  47,  47,
+   443, 444, 160,  47,  47, 445, 160, 160,  47,  47,  47,  47,  47,  47,  47, 446,
+   447,  47,  47, 448, 449, 450,  32,  32,  47,  47,  47,  47, 145, 451, 452, 453,
+   220, 220, 220, 220, 220, 220, 220,  66,  47,  47,  47,  47,  47,  47,  47, 437,
+    47,  47,  47, 209, 454,  32,  47,  47,  47, 455, 456, 160, 160, 160, 160, 160,
+    47,  47,  47,  47,  47,  47, 306,  47,  47,  47,  47,  47, 160,  47,  47, 457,
+    47,  47,  47, 458, 459, 460, 461,  47,  27,  27,  27,  27, 462,  47, 463, 160,
+     9,   9,   9,   9,   9,   9,  11,  11, 145, 464,   9, 465,  11,  11,  11,  11,
+    47,  47,  47,  47, 399, 466, 429, 429, 467, 468,  27,  27,  27,  27, 469, 470,
+    47, 471, 209, 209, 209, 209, 209, 209, 146, 146, 146, 146, 146, 146, 146, 472,
+   146, 146, 146, 146, 146, 146, 146, 227,  32,  32,  32,  32,  32, 146, 146, 146,
+   146, 146, 146, 146, 146, 146, 473, 474, 475, 146, 476, 146, 146, 146, 146, 146,
+   146, 146, 146, 146, 477, 146, 146, 146,   9, 478,  11, 479, 480,  11, 197,   9,
+   481, 482,   9, 483,  11,   9, 478,  11, 479, 480,  11, 197,   9, 481, 482,   9,
+   483,  11,   9, 478,  11, 479, 480,  11, 197,   9, 481, 482,   9, 483,  11,   9,
+   478,  11, 197,   9, 484, 485, 486, 487,  11, 488,   9, 489, 490, 491, 492,  11,
+   493,   9, 494,  11, 495, 160, 160, 160,  32,  32,  32, 496,  32,  32, 497, 498,
+   499, 500,  32,  32,  32,  32,  32,  32, 501,  11,  11,  11,  11,  11,  11,  11,
+    32,  32,  32,  27,  27,  27,  27,  27,  32,  32,  32,  32,  32,  32,  32,  32,
+    47,  47,  47, 502, 503, 146, 146, 146,  47,  47, 455,  32,  47,  47, 504, 505,
+    47,  47,  47,  47,  47,  47, 506, 160,  47,  47,  47,  47,  47,  47, 455, 507,
+    47,  47,  47,  47,  47,  47, 508, 509,  47,  47,  47,  47, 358,  32,  32,  32,
+     9,   9, 481,  11, 510, 306,  66,  66, 145, 145, 511, 512, 145, 145, 145, 145,
+   145, 145, 513, 145, 145, 145, 145, 145,  47,  47,  47,  47,  47,  47,  47, 227,
+   514, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 515,
+   146, 146, 146, 146, 146, 227, 227, 227, 209, 209, 209, 209, 209, 209, 209, 209,
      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,1976,1977,1978,1980,1979,1981,   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,
+   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,1936,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1937,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1938,   0,1939,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1940,   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,1943,1944,   0,   0,   0,
+     0,   0,   0,1945,   0,1946,   0,   0,   0,   0,   0,   0,   0,   0,1947,   0,
+     0,1948,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,1950,   0,1949,1951,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1953,1952,   0,1954,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1955,1956,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1957,   0,   0,   0,   0,   0,   0,   0,
+     0,1958,1961,1959,1965,1960,1962,1964,1963,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1967,1966,1968,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1969,1970,
+  1971,1972,1973,1974,1975,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1976,1977,1978,1980,1979,
+  1981,   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] =
+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,
@@ -5842,39 +5595,33 @@ _hb_ucd_i16[92] =
       0,-2016,-2104,    0,    0,-2106,-2108,-2106,-2250,    0,-2527,    0,
 };
 
-static inline uint_fast8_t
-_hb_ucd_gc (unsigned u)
+static inline uint8_t _hb_ucd_gc (unsigned u)
 {
-  return u<1114112u?_hb_ucd_u8[5208+(((_hb_ucd_u8[1168+(((_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;
+  return u<1114112 ? _hb_ucd_u8[5296u+((_hb_ucd_u8[1168u+((_hb_ucd_u16[((_hb_ucd_u8[544u+((_hb_ucd_u8[((((((((u)>>1))>>3))>>3))>>4)])<<4)+((((((((u)>>1))>>3))>>3))&15)])<<3)+((((((u)>>1))>>3))&7)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : 2;
 }
-static inline uint_fast8_t
-_hb_ucd_ccc (unsigned u)
+static inline uint8_t _hb_ucd_ccc (unsigned u)
 {
-  return u<125259u?_hb_ucd_u8[7206+(((_hb_ucd_u8[6638+(((_hb_ucd_u8[6162+(((_hb_ucd_u8[5802+(((_hb_ucd_u8[5556+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
+  return u<125259 ? _hb_ucd_u8[7322u+((_hb_ucd_u8[6738u+((_hb_ucd_u8[6258u+((_hb_ucd_u8[5890u+((_hb_ucd_u8[5644u+((((((((u)>>2))>>2))>>2))>>3)])<<3)+((((((((u)>>2))>>2))>>2))&7)])<<2)+((((((u)>>2))>>2))&3)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)] : 0;
 }
-static inline unsigned
-_hb_ucd_b4 (const uint8_t* a, unsigned i)
+static inline uint8_t _hb_ucd_b4 (const uint8_t* a, unsigned i)
 {
-  return (a[i>>1]>>((i&1u)<<2))&15u;
+  return (a[i>>1]>>((i&1)<<2))&15;
 }
-static inline int_fast16_t
-_hb_ucd_bmg (unsigned u)
+static inline int16_t _hb_ucd_bmg (unsigned u)
 {
-  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[8098+(((_hb_ucd_u8[7866+(((_hb_ucd_u8[7770+(((_hb_ucd_b4(7706+_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;
+  return u<65380 ? _hb_ucd_i16[((_hb_ucd_u8[8218u+((_hb_ucd_u8[7986u+((_hb_ucd_u8[7890u+((_hb_ucd_b4(_hb_ucd_u8+7826u,((((((((u)>>1))>>2))>>3))>>3)))<<3)+((((((((u)>>1))>>2))>>3))&7)])<<3)+((((((u)>>1))>>2))&7)])<<2)+((((u)>>1))&3)])<<1)+((u)&1)] : 0;
 }
-static inline uint_fast8_t
-_hb_ucd_sc (unsigned u)
+static inline uint8_t _hb_ucd_sc (unsigned u)
 {
-  return u<918016u?_hb_ucd_u8[11464+(((_hb_ucd_u8[10472+(((_hb_ucd_u8[9452+(((_hb_ucd_u8[8764+(((_hb_ucd_u8[8460+(((_hb_ucd_u8[8346+(u>>2>>2>>2>>3>>4)])<<4)+((u>>2>>2>>2>>3)&15u))])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
+  return u<918016 ? _hb_ucd_u8[11655u+((_hb_ucd_u8[10647u+((_hb_ucd_u8[9151u+((_hb_ucd_u8[8703u+((_hb_ucd_u8[8495u+((_hb_ucd_b4(_hb_ucd_u8+8466u,((((((((((u)>>2))>>2))>>3))>>3))>>4)))<<4)+((((((((((u)>>2))>>2))>>3))>>3))&15)])<<3)+((((((((u)>>2))>>2))>>3))&7)])<<3)+((((((u)>>2))>>2))&7)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)] : 2;
 }
-static inline uint_fast16_t
-_hb_ucd_dm (unsigned u)
+static inline uint16_t _hb_ucd_dm (unsigned u)
 {
-  return u<195102u?_hb_ucd_u16[1656+(((_hb_ucd_u8[12834+(((_hb_ucd_u8[12452+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+  return u<195102 ? _hb_ucd_u16[1680u+((_hb_ucd_u8[13041u+((_hb_ucd_u8[12659u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)] : 0;
 }
 
-#endif
 
+#endif
 
 #endif /* HB_UCD_TABLE_HH */
 
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 4bc8d64c28f..711dd9b6571 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: 2024-05-01, 21:25:24 GMT
- * # © 2024 Unicode®, Inc.
+ * # Date: 2025-07-25, 17:54:31 GMT
+ * # © 2025 Unicode®, Inc.
  * # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
  * # For terms of use and license, see https://www.unicode.org/terms_of_use.html
  * #
  * # Emoji Data for UTS #51
- * # Used with Emoji Version 16.0 and subsequent minor revisions (if any)
+ * # Version: 17.0
  * #
  * # For documentation and usage, see https://www.unicode.org/reports/tr51
  */
@@ -23,54 +23,62 @@
 
 #include "hb-unicode.hh"
 
-static const uint8_t
-_hb_emoji_u8[464] =
+#include 
+
+static const uint8_t _hb_emoji_u8[624]=
 {
    16, 17, 17, 17, 50, 20, 21, 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,118,152,
-    0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    2,  0,  3,  4,  0,  0,  5,  6,  0,  7,  0,  8,  9, 10, 11, 12,
-    0,  0, 13,  0,  0,  0, 14,  0, 15,  0,  0,  0,  0, 16,  0,  0,
-   17, 17, 18, 19, 20, 17, 17, 21, 17, 17, 22, 17, 23, 17, 24, 25,
-   26, 27, 28, 17, 17, 17,  0,  0, 17, 17, 17, 17, 17, 17, 17, 29,
-    0,  0,  0,  0,  0,  1,  0,  0,  0,  2,  3,  0,  0,  4,  0,  0,
-    5,  6,  0,  0,  7,  8,  0,  0,  8,  0,  9, 10,  0,  0, 11,  0,
-    0, 12, 13, 14, 15, 16, 16, 16, 17, 16, 16, 16, 18, 19, 20, 21,
-   22, 23,  0,  0,  0, 24,  0,  0, 25,  0, 26,  0,  0, 27,  0,  0,
-   28,  0,  0,  0, 16, 16, 16, 16, 29,  9,  0, 30, 31, 32, 16, 33,
-   34, 35, 36, 16, 16, 16, 16, 37, 16, 38, 39, 16, 16, 16, 40,  0,
-    0,  0,  0, 41,  0,  0, 42, 16, 43,  0, 44,  0, 45, 46, 16, 16,
-   47, 48, 49, 16, 16, 16, 16, 38,  0,  0,  0,  0,  0, 66,  0,  0,
-    0,  0,  0, 16,  0,  2,  0,  0,  4,  0,  0,  2,  0,  0,240,  3,
-    0,  6,  0,  0,  0,  0,  0, 12,  0,  1,  0,  0,  0,128,  0,  0,
-    0,254, 15,  7,  4,  0,  0,  0,  0, 12, 64,  0,  1,  0,  0,  0,
-    0,  0,  0,120,191,255,247,255,255,255,255,255, 63,  0,255,255,
-   63,255, 87, 32,  2,  1, 24,  0,144, 80,184,  0,248,  0,  0,  0,
-    0,  0,224,  0,  2,  0,  1,128,  0,  0, 48,  0,224,  0,  0, 24,
-    0,  0, 33,  0,  0,  0,  1, 32,  0,  0,128,  2,  0,224,  0,  0,
-    0,240,  3,192,  0, 64,254,  7,  0,224,255,255, 63,  0,  0,  0,
-  254,255,  0,  4,  0,128,252,247,  0,254,255,255,255,255,255,  7,
-  255,255,255, 63,192,255,255,255,255,255,  0,  0,  0,  0,240,255,
-    0,  0,224,255,  0,240,  0,  0,  0,255,  0,252,  0,255,  0,  0,
-    0,192,255,255,  0,240,255,255,255,255,255,247,191,255,255,255,
+    0,  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,
+    2,  3,  0,  0,  4,  0,  5,  0,  0,  0,  0,  0,  6,  0,  0,  7,
+    0,  0,  0,  8,  0,  0,  9, 10, 11, 12, 13, 14, 15, 16, 17,  0,
+    0,  0,  0,  0, 18,  0,  0,  0,  0,  0,  0,  0, 19, 20,  0,  0,
+   21,  0,  0,  0,  0,  0,  0,  0,  0,  0, 22,  0,  0,  0,  0,  0,
+   23,  0, 24, 25,  0, 26, 27, 28, 29, 30, 31, 31, 32, 31, 33, 34,
+   31, 31, 31, 35, 36, 37, 38, 39, 31, 40, 31, 41,  0,  0,  0, 42,
+   43, 44, 45, 46, 47, 48, 31, 31,  0, 49, 31, 31,  0,  0,  0,  0,
+   31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 36,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 66,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 16,  0,  2,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  4,  0,  0,  2,  0,  0,240,  3,  0,  6,  0,  0,
+    0,  0,  0, 12,  0,  1,  0,  0,  0,128,  0,  0,  0,254, 15,  7,
+    4,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 12, 64,  0,
+    1,  0,  0,  0,  0,  0,  0,120, 31, 64, 50, 33, 77,196,  0,  7,
+    5,255, 15,128,105,  1,  0,200,  0,  0,252, 26,131, 12,  3, 96,
+   48,193, 26,  0,  0,  6,191, 39, 36,191, 84, 32,  2,  1, 24,  0,
+  144, 80,184,  0, 24,  0,  0,  0,  0,  0,224,  0,  2,  0,  1,128,
+    0,  0,  0,  0,  0,  0, 48,  0,224,  0,  0, 24,  0,  0,  0,  0,
+    0,  0, 33,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1, 32,
+    0,  0,128,  2,  0,  0,  0,  0, 16,  0,  0,  0,  0,240,  0,  0,
+    0,  0,240,255,  0,128,  1,  0,  1,128,  1,  0,  0,  0,192,255,
+    0,  0,  0,  0,  0,  0,  3,192,  0, 64,254,  7,  0,192,255,255,
+  255,255,255,255, 63,  0,  0,  0,254,255,  0,  4,  0,128,252,247,
+    0,254,255,255,192,255,255,255,255,255,255,255,255,255,255,255,
+  255,255,255,255,243,255,255,255,255,255,207,206,255,255,255,255,
+  255,255,255,255,255,255,185,  7,255,255,255,255,255,255,255,191,
+  255,255,255,255,255,255,255, 63,  0,126,255,255,255,128,249,  7,
+  128, 60, 97,  0, 48,  1,  6, 16, 28,  0, 14,112, 10,129,  8,252,
+  255,255,  0,  0,  0,  0,  0,  0, 63,248,231,255, 63,250,249,255,
+    0,  0,  0,252,255,255,255,255,  0,240,  0,  0,  0,  0,  0,  0,
+    0,255,  0,252,  0,  0,  0,  0,  0,255,  0,  0,  0,192,  0,240,
+  252,255,  0,254,255,255,255,255,  0,240,255,255,255,255,255,247,
+  191,255,255,255,255,255,255,255,  0,  0,  0,255,  0,192,255,255,
 };
 
-static inline unsigned
-_hb_emoji_b4 (const uint8_t* a, unsigned i)
+static inline uint8_t _hb_emoji_b4 (const uint8_t* a, unsigned i)
 {
-  return (a[i>>1]>>((i&1u)<<2))&15u;
+  return (a[i>>1]>>((i&1)<<2))&15;
 }
-static inline unsigned
-_hb_emoji_b1 (const uint8_t* a, unsigned i)
+static inline uint8_t _hb_emoji_b1 (const uint8_t* a, unsigned i)
 {
-  return (a[i>>3]>>((i&7u)<<0))&1u;
+  return (a[i>>3]>>((i&7)<<0))&1;
 }
-static inline uint_fast8_t
-_hb_emoji_is_Extended_Pictographic (unsigned u)
+static inline uint8_t _hb_emoji_is_Extended_Pictographic (unsigned u)
 {
-  return u<131070u?_hb_emoji_b1(264+_hb_emoji_u8,((_hb_emoji_u8[144+(((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>5>>2>>3))<<3)+((u>>5>>2)&7u))])<<2)+((u>>5)&3u))])<<5)+((u)&31u)):0;
+  return u<131070 ? _hb_emoji_b1(_hb_emoji_u8+224u,((_hb_emoji_u8[64u+((_hb_emoji_b4(_hb_emoji_u8,((((u)>>6))>>4)))<<4)+((((u)>>6))&15)])<<6)+((u)&63)) : 0;
 }
 
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh b/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh
index 924105001d7..9e6f89365fe 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh
@@ -241,6 +241,57 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
     }
   }
 
+  static hb_codepoint_t
+  vertical_char_for (hb_codepoint_t u)
+  {
+    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;
+    }
+
+    return u;
+  }
+
   struct {
 #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_func_t name;
     HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-utf.hh b/src/java.desktop/share/native/libharfbuzz/hb-utf.hh
index 7fd3bf8828b..3891fb331af 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-utf.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-utf.hh
@@ -37,7 +37,7 @@ struct hb_utf8_t
   typedef uint8_t codepoint_t;
   static constexpr unsigned max_len = 4;
 
-  static const codepoint_t *
+  static inline const codepoint_t *
   next (const codepoint_t *text,
         const codepoint_t *end,
         hb_codepoint_t *unicode,
@@ -106,7 +106,7 @@ struct hb_utf8_t
     return text;
   }
 
-  static const codepoint_t *
+  static inline const codepoint_t *
   prev (const codepoint_t *text,
         const codepoint_t *start,
         hb_codepoint_t *unicode,
@@ -185,7 +185,7 @@ struct hb_utf16_xe_t
   typedef TCodepoint codepoint_t;
   static constexpr unsigned max_len = 2;
 
-  static const codepoint_t *
+  static inline const codepoint_t *
   next (const codepoint_t *text,
         const codepoint_t *end,
         hb_codepoint_t *unicode,
@@ -217,7 +217,7 @@ struct hb_utf16_xe_t
     return text;
   }
 
-  static const codepoint_t *
+  static inline const codepoint_t *
   prev (const codepoint_t *text,
         const codepoint_t *start,
         hb_codepoint_t *unicode,
@@ -294,7 +294,7 @@ struct hb_utf32_xe_t
   typedef TCodepoint codepoint_t;
   static constexpr unsigned max_len = 1;
 
-  static const TCodepoint *
+  static inline const TCodepoint *
   next (const TCodepoint *text,
         const TCodepoint *end HB_UNUSED,
         hb_codepoint_t *unicode,
@@ -306,7 +306,7 @@ struct hb_utf32_xe_t
     return text;
   }
 
-  static const TCodepoint *
+  static inline const TCodepoint *
   prev (const TCodepoint *text,
         const TCodepoint *start HB_UNUSED,
         hb_codepoint_t *unicode,
@@ -353,7 +353,7 @@ struct hb_latin1_t
   typedef uint8_t codepoint_t;
   static constexpr unsigned max_len = 1;
 
-  static const codepoint_t *
+  static inline const codepoint_t *
   next (const codepoint_t *text,
         const codepoint_t *end HB_UNUSED,
         hb_codepoint_t *unicode,
@@ -363,7 +363,7 @@ struct hb_latin1_t
     return text;
   }
 
-  static const codepoint_t *
+  static inline const codepoint_t *
   prev (const codepoint_t *text,
         const codepoint_t *start HB_UNUSED,
         hb_codepoint_t *unicode,
@@ -405,7 +405,7 @@ struct hb_ascii_t
   typedef uint8_t codepoint_t;
   static constexpr unsigned max_len = 1;
 
-  static const codepoint_t *
+  static inline const codepoint_t *
   next (const codepoint_t *text,
         const codepoint_t *end HB_UNUSED,
         hb_codepoint_t *unicode,
@@ -417,7 +417,7 @@ struct hb_ascii_t
     return text;
   }
 
-  static const codepoint_t *
+  static inline const codepoint_t *
   prev (const codepoint_t *text,
         const codepoint_t *start HB_UNUSED,
         hb_codepoint_t *unicode,
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-vector.hh b/src/java.desktop/share/native/libharfbuzz/hb-vector.hh
index cd27da96648..b650ca9f066 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-vector.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-vector.hh
@@ -32,6 +32,12 @@
 #include "hb-meta.hh"
 #include "hb-null.hh"
 
+// Change to 1 to force inline vector allocs, to see callsite in malloc-stats tool.
+#if 0
+#define HB_ALWAYS_INLINE_VECTOR_ALLOCS HB_ALWAYS_INLINE
+#else
+#define HB_ALWAYS_INLINE_VECTOR_ALLOCS
+#endif
 
 template 
@@ -45,6 +51,7 @@ struct hb_vector_t
   using c_array_t = typename std::conditional, hb_array_t>::type;
 
   hb_vector_t () = default;
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
   hb_vector_t (std::initializer_list lst) : hb_vector_t ()
   {
     alloc (lst.size (), true);
@@ -57,18 +64,21 @@ struct hb_vector_t
   {
     extend (o);
   }
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
   hb_vector_t (const hb_vector_t &o) : hb_vector_t ()
   {
     alloc_exact (o.length);
     if (unlikely (in_error ())) return;
     copy_array (o.as_array ());
   }
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
   hb_vector_t (array_t o) : hb_vector_t ()
   {
     alloc_exact (o.length);
     if (unlikely (in_error ())) return;
     copy_array (o);
   }
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
   hb_vector_t (c_array_t o) : hb_vector_t ()
   {
     alloc_exact (o.length);
@@ -84,8 +94,29 @@ struct hb_vector_t
   }
   ~hb_vector_t () { fini (); }
 
+  template 
+  void
+  set_storage (Type (&array)[n])
+  { set_storage (array, n); }
+  void
+  set_storage (hb_array_t array)
+  { set_storage (array.arrayZ, array.length); }
+  template 
+  void
+  set_storage (Type *array, unsigned n)
+  {
+    assert (allocated == 0);
+    assert (length == 0);
+
+    arrayZ = array;
+    length = n;
+  }
+
   template 
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
   void extend (const Iterable &o)
   {
     auto iter = hb_iter (o);
@@ -106,12 +137,14 @@ struct hb_vector_t
         push_has_room (*iter++);
     }
   }
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
   void extend (array_t o)
   {
     alloc (length + o.length);
     if (unlikely (in_error ())) return;
     copy_array (o);
   }
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
   void extend (c_array_t o)
   {
     alloc (length + o.length);
@@ -136,10 +169,7 @@ struct hb_vector_t
 
   void fini ()
   {
-    /* We allow a hack to make the vector point to a foreign array
-     * by the user. In that case length/arrayZ are non-zero but
-     * allocated is zero. Don't free anything. */
-    if (allocated)
+    if (is_owned ())
     {
       shrink_vector (0);
       hb_free (arrayZ);
@@ -147,11 +177,13 @@ struct hb_vector_t
     init ();
   }
 
-  void reset ()
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
+  hb_vector_t &reset ()
   {
     if (unlikely (in_error ()))
       reset_error ();
     resize (0);
+    return *this;
   }
 
   friend void swap (hb_vector_t& a, hb_vector_t& b) noexcept
@@ -237,13 +269,16 @@ struct hb_vector_t
   Type * operator  + (unsigned int i) { return arrayZ + i; }
   const Type * operator  + (unsigned int i) const { return arrayZ + i; }
 
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
   Type *push ()
   {
     if (unlikely (!resize (length + 1)))
       return std::addressof (Crap (Type));
     return std::addressof (arrayZ[length - 1]);
   }
-  template  Type *push (Args&&... args)
+  template 
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
+  Type *push (Args&&... args)
   {
     if (unlikely ((int) length >= allocated && !alloc (length + 1)))
       // If push failed to allocate then don't copy v, since this may cause
@@ -253,13 +288,20 @@ struct hb_vector_t
 
     return push_has_room (std::forward (args)...);
   }
-  template  Type *push_has_room (Args&&... args)
+  template 
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
+  Type *push_has_room (Args&&... args)
   {
     /* Emplace. */
     Type *p = std::addressof (arrayZ[length++]);
     return new (p) Type (std::forward (args)...);
   }
 
+  bool is_owned () const
+  {
+    return allocated != 0 && allocated != -1;
+  }
+
   bool in_error () const { return allocated < 0; }
   void set_error ()
   {
@@ -271,27 +313,40 @@ struct hb_vector_t
     assert (allocated < 0);
     allocated = -(allocated + 1);
   }
+  void ensure_error ()
+  {
+    if (!in_error ())
+      set_error ();
+  }
 
-  template 
   Type *
-  realloc_vector (unsigned new_allocated, hb_priority<0>)
+  _realloc (unsigned new_allocated)
   {
     if (!new_allocated)
     {
-      hb_free (arrayZ);
+      if (is_owned ())
+        hb_free (arrayZ);
       return nullptr;
     }
+    if (!allocated && arrayZ)
+    {
+      /* If we have a non-null arrayZ but allocated is 0, then we are
+       * reallocating from a foreign array. */
+      Type *new_array = (Type *) hb_malloc (new_allocated * sizeof (Type));
+      if (unlikely (!new_array))
+        return nullptr;
+      hb_memcpy ((void *) new_array, (const void *) arrayZ, length * sizeof (Type));
+      return new_array;
+    }
     return (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type));
   }
-  template 
   Type *
-  realloc_vector (unsigned new_allocated, hb_priority<0>)
+  _malloc_move (unsigned new_allocated)
   {
     if (!new_allocated)
     {
-      hb_free (arrayZ);
+      if (is_owned ())
+        hb_free (arrayZ);
       return nullptr;
     }
     Type *new_array = (Type *) hb_malloc (new_allocated * sizeof (Type));
@@ -303,22 +358,33 @@ struct hb_vector_t
         new_array[i] = std::move (arrayZ[i]);
         arrayZ[i].~Type ();
       }
-      hb_free (arrayZ);
+      if (is_owned ())
+        hb_free (arrayZ);
     }
     return new_array;
   }
+
+  template 
+  Type *
+  realloc_vector (unsigned new_allocated, hb_priority<0>)
+  {
+    return _realloc (new_allocated);
+  }
+  template 
+  Type *
+  realloc_vector (unsigned new_allocated, hb_priority<0>)
+  {
+    return _malloc_move (new_allocated);
+  }
   /* Specialization for types that can be moved using realloc(). */
   template 
   Type *
   realloc_vector (unsigned new_allocated, hb_priority<1>)
   {
-    if (!new_allocated)
-    {
-      hb_free (arrayZ);
-      return nullptr;
-    }
-    return (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type));
+    return _realloc (new_allocated);
   }
 
   template  other)
   {
-    assert ((int) (length + other.length) <= allocated);
     hb_memcpy ((void *) (arrayZ + length), (const void *) other.arrayZ, other.length * item_size);
     length += other.length;
   }
@@ -362,7 +427,6 @@ struct hb_vector_t
   void
   copy_array (hb_array_t other)
   {
-    assert ((int) (length + other.length) <= allocated);
     hb_memcpy ((void *) (arrayZ + length), (const void *) other.arrayZ, other.length * item_size);
     length += other.length;
   }
@@ -372,7 +436,6 @@ struct hb_vector_t
   void
   copy_array (hb_array_t other)
   {
-    assert ((int) (length + other.length) <= allocated);
     for (unsigned i = 0; i < other.length; i++)
       new (std::addressof (arrayZ[length + i])) Type (other.arrayZ[i]);
     length += other.length;
@@ -385,7 +448,6 @@ struct hb_vector_t
   void
   copy_array (hb_array_t other)
   {
-    assert ((int) (length + other.length) <= allocated);
     for (unsigned i = 0; i < other.length; i++)
     {
       new (std::addressof (arrayZ[length + i])) Type ();
@@ -398,12 +460,12 @@ struct hb_vector_t
   shrink_vector (unsigned size)
   {
     assert (size <= length);
-    if (!std::is_trivially_destructible::value)
+    if (!hb_is_trivially_destructible(Type))
     {
       unsigned count = length - size;
-      Type *p = arrayZ + length - 1;
+      Type *p = arrayZ + length;
       while (count--)
-        p--->~Type ();
+        (--p)->~Type ();
     }
     length = size;
   }
@@ -416,6 +478,7 @@ struct hb_vector_t
   }
 
   /* Allocate for size but don't adjust length. */
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
   bool alloc (unsigned int size, bool exact=false)
   {
     if (unlikely (in_error ()))
@@ -471,17 +534,64 @@ struct hb_vector_t
 
     return true;
   }
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
   bool alloc_exact (unsigned int size)
   {
     return alloc (size, true);
   }
 
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
   void clear ()
   {
     resize (0);
   }
 
-  bool resize (int size_, bool initialize = true, bool exact = false)
+  template 
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
+  bool allocate_from_pool (allocator_t *allocator, unsigned size, unsigned int initialize = true)
+  {
+    if (allocator)
+    {
+      assert (!length && !allocated);
+      arrayZ = (Type *) allocator->alloc (size * sizeof (Type), alignof (Type));
+      if (unlikely (!arrayZ))
+      {
+        set_error ();
+        return false;
+      }
+      if (initialize)
+        grow_vector (size, hb_prioritize);
+      else
+        length = size;
+      return true;
+    }
+    return resize_full ((int) size, initialize, true);
+  }
+
+  template 
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
+  bool duplicate_vector_from_pool (allocator_t *allocator, const hb_vector_t &other)
+  {
+    if (unlikely (!allocate_from_pool (allocator, other.length, false)))
+      return false;
+    length = 0;
+    copy_array (other.as_array ());
+    return true;
+  }
+
+  template 
+  void shrink_back_to_pool (allocator_t *allocator, int size)
+  {
+    unsigned orig_length = length;
+
+    shrink (size, false);
+
+    if (allocator && !is_owned ())
+      allocator->discard (arrayZ + length, (orig_length - length) * sizeof (Type));
+  }
+
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
+  bool resize_full (int size_, bool initialize, bool exact)
   {
     unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
     if (!alloc (size, exact))
@@ -501,9 +611,20 @@ struct hb_vector_t
     length = size;
     return true;
   }
-  bool resize_exact (int size_, bool initialize = true)
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
+  bool resize (int size_)
+  {
+    return resize_full (size_, true, false);
+  }
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
+  bool resize_dirty (int size_)
+  {
+    return resize_full (size_, false, false);
+  }
+  HB_ALWAYS_INLINE_VECTOR_ALLOCS
+  bool resize_exact (int size_)
   {
-    return resize (size_, initialize, true);
+    return resize_full (size_, true, true);
   }
 
   Type pop ()
@@ -544,7 +665,7 @@ struct hb_vector_t
 
     shrink_vector (size);
 
-    if (shrink_memory)
+    if (is_owned () && shrink_memory)
       alloc_exact (size); /* To force shrinking memory if needed. */
   }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-version.h b/src/java.desktop/share/native/libharfbuzz/hb-version.h
index e41286d2d8c..c673d1e3612 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-version.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-version.h
@@ -41,26 +41,26 @@ HB_BEGIN_DECLS
  *
  * The major component of the library version available at compile-time.
  */
-#define HB_VERSION_MAJOR 11
+#define HB_VERSION_MAJOR 12
 /**
  * HB_VERSION_MINOR:
  *
  * The minor component of the library version available at compile-time.
  */
-#define HB_VERSION_MINOR 2
+#define HB_VERSION_MINOR 3
 /**
  * HB_VERSION_MICRO:
  *
  * The micro component of the library version available at compile-time.
  */
-#define HB_VERSION_MICRO 0
+#define HB_VERSION_MICRO 2
 
 /**
  * HB_VERSION_STRING:
  *
  * A string literal containing the library version available at compile-time.
  */
-#define HB_VERSION_STRING "11.2.0"
+#define HB_VERSION_STRING "12.3.2"
 
 /**
  * HB_VERSION_ATLEAST:
diff --git a/src/java.desktop/share/native/libharfbuzz/hb.hh b/src/java.desktop/share/native/libharfbuzz/hb.hh
index 8c430e5770d..7582abaa933 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb.hh
@@ -89,7 +89,6 @@
 #pragma GCC diagnostic error   "-Wstring-conversion"
 #pragma GCC diagnostic error   "-Wswitch-enum"
 #pragma GCC diagnostic error   "-Wtautological-overlap-compare"
-#pragma GCC diagnostic error   "-Wuninitialized"
 #pragma GCC diagnostic error   "-Wunneeded-internal-declaration"
 #pragma GCC diagnostic error   "-Wunused"
 #pragma GCC diagnostic error   "-Wunused-local-typedefs"
@@ -110,11 +109,21 @@
 #pragma GCC diagnostic warning "-Wformat-signedness"
 #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 "-Wpessimizing-move"
 #pragma GCC diagnostic warning "-Wundef"
 #pragma GCC diagnostic warning "-Wunsafe-loop-optimizations"
 #pragma GCC diagnostic warning "-Wunused-but-set-variable"
+#ifdef __clang__
+// The following are too buggy on gcc
+// https://github.com/harfbuzz/harfbuzz/issues/5589
+// https://github.com/harfbuzz/harfbuzz/pull/5367
+#pragma GCC diagnostic warning "-Wmaybe-uninitialized"
+#pragma GCC diagnostic warning "-Wuninitialized"
+#else
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#pragma GCC diagnostic ignored "-Wuninitialized"
+#endif
 #endif
 
 /* Ignored currently, but should be fixed at some point. */
@@ -136,6 +145,7 @@
 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
 #pragma GCC diagnostic ignored "-Wformat-zero-length"
 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#pragma GCC diagnostic ignored "-Wold-style-cast"
 #pragma GCC diagnostic ignored "-Wpacked" // Erratic impl in clang
 #pragma GCC diagnostic ignored "-Wrange-loop-analysis" // https://github.com/harfbuzz/harfbuzz/issues/2834
 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
@@ -239,6 +249,8 @@
 // clang defines it so no need.
 #ifdef __has_builtin
 #define hb_has_builtin __has_builtin
+#elif defined(_MSC_VER)
+#define hb_has_builtin(x) 0
 #else
 #define hb_has_builtin(x) ((defined(__GNUC__) && __GNUC__ >= 5))
 #endif
@@ -314,6 +326,10 @@
 #endif
 #endif
 
+#ifndef HB_HOT
+#define HB_HOT __attribute__((hot))
+#endif
+
 /*
  * Borrowed from https://bugzilla.mozilla.org/show_bug.cgi?id=1215411
  * HB_FALLTHROUGH is an annotation to suppress compiler warnings about switch
@@ -553,4 +569,13 @@ extern "C" void  hb_free_impl(void *ptr);
 #include "hb-vector.hh" // Requires: hb-array hb-null
 #include "hb-object.hh" // Requires: hb-atomic hb-mutex hb-vector
 
+
+/* Our src/test-*.cc use hb_assert(), such that it's not compiled out under NDEBUG.
+ * https://github.com/harfbuzz/harfbuzz/issues/5418 */
+#define hb_always_assert(x) \
+        HB_STMT_START { \
+          if (!(x)) { fprintf(stderr, "Assertion failed: %s, at %s:%d\n", #x, __FILE__, __LINE__); abort(); } \
+        } HB_STMT_END
+
+
 #endif /* HB_HH */
diff --git a/src/java.desktop/share/native/libsplashscreen/giflib/COPYING b/src/java.desktop/share/native/libsplashscreen/giflib/COPYING
index b9c0b501260..92774a3b036 100644
--- a/src/java.desktop/share/native/libsplashscreen/giflib/COPYING
+++ b/src/java.desktop/share/native/libsplashscreen/giflib/COPYING
@@ -1,4 +1,4 @@
-The GIFLIB distribution is Copyright (c) 1997  Eric S. Raymond
+= MIT LICENSE
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/src/java.desktop/share/native/libsplashscreen/giflib/dgif_lib.c b/src/java.desktop/share/native/libsplashscreen/giflib/dgif_lib.c
index 0b2860b4b50..2fa005ed20d 100644
--- a/src/java.desktop/share/native/libsplashscreen/giflib/dgif_lib.c
+++ b/src/java.desktop/share/native/libsplashscreen/giflib/dgif_lib.c
@@ -30,9 +30,9 @@ The functions here and in egif_lib.c are partitioned carefully so that
 if you only require one of read and write capability, only one of these
 two modules will be linked.  Preserve this property!
 
-SPDX-License-Identifier: MIT
-
 *****************************************************************************/
+// SPDX-License-Identifier: MIT
+// SPDX-FileCopyrightText: Copyright (C) Eric S. Raymond 
 
 #include 
 #include 
@@ -55,11 +55,11 @@ SPDX-License-Identifier: MIT
 
 /* avoid extra function call in case we use fread (TVT) */
 static int InternalRead(GifFileType *gif, GifByteType *buf, int len) {
-    // fprintf(stderr, "### Read: %d\n", len);
-    return (((GifFilePrivateType *)gif->Private)->Read
-                ? ((GifFilePrivateType *)gif->Private)->Read(gif, buf, len)
-                : fread(buf, 1, len,
-                        ((GifFilePrivateType *)gif->Private)->File));
+        // fprintf(stderr, "### Read: %d\n", len);
+        return (((GifFilePrivateType *)gif->Private)->Read
+                    ? ((GifFilePrivateType *)gif->Private)->Read(gif, buf, len)
+                    : fread(buf, 1, len,
+                            ((GifFilePrivateType *)gif->Private)->File));
 }
 
 static int DGifGetWord(GifFileType *GifFile, GifWord *Word);
@@ -78,18 +78,18 @@ static int DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf,
  info record.
 ******************************************************************************/
 GifFileType *DGifOpenFileName(const char *FileName, int *Error) {
-    int FileHandle;
-    GifFileType *GifFile;
+        int FileHandle;
+        GifFileType *GifFile;
 
-    if ((FileHandle = open(FileName, O_RDONLY)) == -1) {
-        if (Error != NULL) {
-            *Error = D_GIF_ERR_OPEN_FAILED;
+        if ((FileHandle = open(FileName, O_RDONLY)) == -1) {
+                if (Error != NULL) {
+                        *Error = D_GIF_ERR_OPEN_FAILED;
+                }
+                return NULL;
         }
-        return NULL;
-    }
 
-    GifFile = DGifOpenFileHandle(FileHandle, Error);
-    return GifFile;
+        GifFile = DGifOpenFileHandle(FileHandle, Error);
+        return GifFile;
 }
 
 /******************************************************************************
@@ -98,171 +98,171 @@ GifFileType *DGifOpenFileName(const char *FileName, int *Error) {
  info record.
 ******************************************************************************/
 GifFileType *DGifOpenFileHandle(int FileHandle, int *Error) {
-    char Buf[GIF_STAMP_LEN + 1];
-    GifFileType *GifFile;
-    GifFilePrivateType *Private;
-    FILE *f;
-
-    GifFile = (GifFileType *)malloc(sizeof(GifFileType));
-    if (GifFile == NULL) {
-        if (Error != NULL) {
-            *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
+        char Buf[GIF_STAMP_LEN + 1];
+        GifFileType *GifFile;
+        GifFilePrivateType *Private;
+        FILE *f;
+
+        GifFile = (GifFileType *)malloc(sizeof(GifFileType));
+        if (GifFile == NULL) {
+                if (Error != NULL) {
+                        *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
+                }
+                (void)close(FileHandle);
+                return NULL;
         }
-        (void)close(FileHandle);
-        return NULL;
-    }
 
-    /*@i1@*/ memset(GifFile, '\0', sizeof(GifFileType));
+        /*@i1@*/ memset(GifFile, '\0', sizeof(GifFileType));
 
-    /* Belt and suspenders, in case the null pointer isn't zero */
-    GifFile->SavedImages = NULL;
-    GifFile->SColorMap = NULL;
+        /* Belt and suspenders, in case the null pointer isn't zero */
+        GifFile->SavedImages = NULL;
+        GifFile->SColorMap = NULL;
 
-    Private = (GifFilePrivateType *)calloc(1, sizeof(GifFilePrivateType));
-    if (Private == NULL) {
-        if (Error != NULL) {
-            *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
+        Private = (GifFilePrivateType *)calloc(1, sizeof(GifFilePrivateType));
+        if (Private == NULL) {
+                if (Error != NULL) {
+                        *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
+                }
+                (void)close(FileHandle);
+                free((char *)GifFile);
+                return NULL;
         }
-        (void)close(FileHandle);
-        free((char *)GifFile);
-        return NULL;
-    }
 
-    /*@i1@*/ memset(Private, '\0', sizeof(GifFilePrivateType));
+        /*@i1@*/ memset(Private, '\0', sizeof(GifFilePrivateType));
 
 #ifdef _WIN32
-    _setmode(FileHandle, O_BINARY); /* Make sure it is in binary mode. */
+        _setmode(FileHandle, O_BINARY); /* Make sure it is in binary mode. */
 #endif                                  /* _WIN32 */
 
-    f = fdopen(FileHandle, "rb"); /* Make it into a stream: */
-
-    /*@-mustfreeonly@*/
-    GifFile->Private = (void *)Private;
-    Private->FileHandle = FileHandle;
-    Private->File = f;
-    Private->FileState = FILE_STATE_READ;
-    Private->Read = NULL;     /* don't use alternate input method (TVT) */
-    GifFile->UserData = NULL; /* TVT */
-    /*@=mustfreeonly@*/
-
-    /* Let's see if this is a GIF file: */
-    /* coverity[check_return] */
-    if (InternalRead(GifFile, (unsigned char *)Buf, GIF_STAMP_LEN) !=
-        GIF_STAMP_LEN) {
-        if (Error != NULL) {
-            *Error = D_GIF_ERR_READ_FAILED;
-        }
-        (void)fclose(f);
-        free((char *)Private);
-        free((char *)GifFile);
-        return NULL;
-    }
-
-    /* Check for GIF prefix at start of file */
-    Buf[GIF_STAMP_LEN] = 0;
-    if (strncmp(GIF_STAMP, Buf, GIF_VERSION_POS) != 0) {
-        if (Error != NULL) {
-            *Error = D_GIF_ERR_NOT_GIF_FILE;
-        }
-        (void)fclose(f);
-        free((char *)Private);
-        free((char *)GifFile);
-        return NULL;
-    }
-
-    if (DGifGetScreenDesc(GifFile) == GIF_ERROR) {
-        (void)fclose(f);
-        free((char *)Private);
-        free((char *)GifFile);
-        return NULL;
-    }
-
-    GifFile->Error = 0;
-
-    /* What version of GIF? */
-    Private->gif89 = (Buf[GIF_VERSION_POS + 1] == '9');
-
-    return GifFile;
+        f = fdopen(FileHandle, "rb"); /* Make it into a stream: */
+
+        /*@-mustfreeonly@*/
+        GifFile->Private = (void *)Private;
+        Private->FileHandle = FileHandle;
+        Private->File = f;
+        Private->FileState = FILE_STATE_READ;
+        Private->Read = NULL;     /* don't use alternate input method (TVT) */
+        GifFile->UserData = NULL; /* TVT */
+        /*@=mustfreeonly@*/
+
+        /* Let's see if this is a GIF file: */
+        /* coverity[check_return] */
+        if (InternalRead(GifFile, (unsigned char *)Buf, GIF_STAMP_LEN) !=
+            GIF_STAMP_LEN) {
+                if (Error != NULL) {
+                        *Error = D_GIF_ERR_READ_FAILED;
+                }
+                (void)fclose(f);
+                free((char *)Private);
+                free((char *)GifFile);
+                return NULL;
+        }
+
+        /* Check for GIF prefix at start of file */
+        Buf[GIF_STAMP_LEN] = 0;
+        if (strncmp(GIF_STAMP, Buf, GIF_VERSION_POS) != 0) {
+                if (Error != NULL) {
+                        *Error = D_GIF_ERR_NOT_GIF_FILE;
+                }
+                (void)fclose(f);
+                free((char *)Private);
+                free((char *)GifFile);
+                return NULL;
+        }
+
+        if (DGifGetScreenDesc(GifFile) == GIF_ERROR) {
+                (void)fclose(f);
+                free((char *)Private);
+                free((char *)GifFile);
+                return NULL;
+        }
+
+        GifFile->Error = 0;
+
+        /* What version of GIF? */
+        Private->gif89 = (Buf[GIF_VERSION_POS + 1] == '9');
+
+        return GifFile;
 }
 
 /******************************************************************************
  GifFileType constructor with user supplied input function (TVT)
 ******************************************************************************/
 GifFileType *DGifOpen(void *userData, InputFunc readFunc, int *Error) {
-    char Buf[GIF_STAMP_LEN + 1];
-    GifFileType *GifFile;
-    GifFilePrivateType *Private;
-
-    GifFile = (GifFileType *)malloc(sizeof(GifFileType));
-    if (GifFile == NULL) {
-        if (Error != NULL) {
-            *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
-        }
-        return NULL;
-    }
-
-    memset(GifFile, '\0', sizeof(GifFileType));
-
-    /* Belt and suspenders, in case the null pointer isn't zero */
-    GifFile->SavedImages = NULL;
-    GifFile->SColorMap = NULL;
-
-    Private = (GifFilePrivateType *)calloc(1, sizeof(GifFilePrivateType));
-    if (!Private) {
-        if (Error != NULL) {
-            *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
-        }
-        free((char *)GifFile);
-        return NULL;
-    }
-    /*@i1@*/ memset(Private, '\0', sizeof(GifFilePrivateType));
-
-    GifFile->Private = (void *)Private;
-    Private->FileHandle = 0;
-    Private->File = NULL;
-    Private->FileState = FILE_STATE_READ;
-
-    Private->Read = readFunc;     /* TVT */
-    GifFile->UserData = userData; /* TVT */
-
-    /* Lets see if this is a GIF file: */
-    /* coverity[check_return] */
-    if (InternalRead(GifFile, (unsigned char *)Buf, GIF_STAMP_LEN) !=
-        GIF_STAMP_LEN) {
-        if (Error != NULL) {
-            *Error = D_GIF_ERR_READ_FAILED;
-        }
-        free((char *)Private);
-        free((char *)GifFile);
-        return NULL;
-    }
-
-    /* Check for GIF prefix at start of file */
-    Buf[GIF_STAMP_LEN] = '\0';
-    if (strncmp(GIF_STAMP, Buf, GIF_VERSION_POS) != 0) {
-        if (Error != NULL) {
-            *Error = D_GIF_ERR_NOT_GIF_FILE;
-        }
-        free((char *)Private);
-        free((char *)GifFile);
-        return NULL;
-    }
-
-    if (DGifGetScreenDesc(GifFile) == GIF_ERROR) {
-        free((char *)Private);
-        free((char *)GifFile);
-        if (Error != NULL) {
-            *Error = D_GIF_ERR_NO_SCRN_DSCR;
-        }
-        return NULL;
-    }
-
-    GifFile->Error = 0;
-
-    /* What version of GIF? */
-    Private->gif89 = (Buf[GIF_VERSION_POS + 1] == '9');
-
-    return GifFile;
+        char Buf[GIF_STAMP_LEN + 1];
+        GifFileType *GifFile;
+        GifFilePrivateType *Private;
+
+        GifFile = (GifFileType *)malloc(sizeof(GifFileType));
+        if (GifFile == NULL) {
+                if (Error != NULL) {
+                        *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
+                }
+                return NULL;
+        }
+
+        memset(GifFile, '\0', sizeof(GifFileType));
+
+        /* Belt and suspenders, in case the null pointer isn't zero */
+        GifFile->SavedImages = NULL;
+        GifFile->SColorMap = NULL;
+
+        Private = (GifFilePrivateType *)calloc(1, sizeof(GifFilePrivateType));
+        if (!Private) {
+                if (Error != NULL) {
+                        *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
+                }
+                free((char *)GifFile);
+                return NULL;
+        }
+        /*@i1@*/ memset(Private, '\0', sizeof(GifFilePrivateType));
+
+        GifFile->Private = (void *)Private;
+        Private->FileHandle = 0;
+        Private->File = NULL;
+        Private->FileState = FILE_STATE_READ;
+
+        Private->Read = readFunc;     /* TVT */
+        GifFile->UserData = userData; /* TVT */
+
+        /* Lets see if this is a GIF file: */
+        /* coverity[check_return] */
+        if (InternalRead(GifFile, (unsigned char *)Buf, GIF_STAMP_LEN) !=
+            GIF_STAMP_LEN) {
+                if (Error != NULL) {
+                        *Error = D_GIF_ERR_READ_FAILED;
+                }
+                free((char *)Private);
+                free((char *)GifFile);
+                return NULL;
+        }
+
+        /* Check for GIF prefix at start of file */
+        Buf[GIF_STAMP_LEN] = '\0';
+        if (strncmp(GIF_STAMP, Buf, GIF_VERSION_POS) != 0) {
+                if (Error != NULL) {
+                        *Error = D_GIF_ERR_NOT_GIF_FILE;
+                }
+                free((char *)Private);
+                free((char *)GifFile);
+                return NULL;
+        }
+
+        if (DGifGetScreenDesc(GifFile) == GIF_ERROR) {
+                free((char *)Private);
+                free((char *)GifFile);
+                if (Error != NULL) {
+                        *Error = D_GIF_ERR_NO_SCRN_DSCR;
+                }
+                return NULL;
+        }
+
+        GifFile->Error = 0;
+
+        /* What version of GIF? */
+        Private->gif89 = (Buf[GIF_VERSION_POS + 1] == '9');
+
+        return GifFile;
 }
 
 /******************************************************************************
@@ -270,180 +270,180 @@ GifFileType *DGifOpen(void *userData, InputFunc readFunc, int *Error) {
  this routine is called automatically from DGif file open routines.
 ******************************************************************************/
 int DGifGetScreenDesc(GifFileType *GifFile) {
-    int BitsPerPixel;
-    bool SortFlag;
-    GifByteType Buf[3];
-    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
-
-    if (!IS_READABLE(Private)) {
-        /* This file was NOT open for reading: */
-        GifFile->Error = D_GIF_ERR_NOT_READABLE;
-        return GIF_ERROR;
-    }
-
-    /* Put the screen descriptor into the file: */
-    if (DGifGetWord(GifFile, &GifFile->SWidth) == GIF_ERROR ||
-        DGifGetWord(GifFile, &GifFile->SHeight) == GIF_ERROR) {
-        return GIF_ERROR;
-    }
-
-    if (InternalRead(GifFile, Buf, 3) != 3) {
-        GifFile->Error = D_GIF_ERR_READ_FAILED;
-        GifFreeMapObject(GifFile->SColorMap);
-        GifFile->SColorMap = NULL;
-        return GIF_ERROR;
-    }
-    GifFile->SColorResolution = (((Buf[0] & 0x70) + 1) >> 4) + 1;
-    SortFlag = (Buf[0] & 0x08) != 0;
-    BitsPerPixel = (Buf[0] & 0x07) + 1;
-    GifFile->SBackGroundColor = Buf[1];
-    GifFile->AspectByte = Buf[2];
-    if (Buf[0] & 0x80) { /* Do we have global color map? */
-        int i;
+        int BitsPerPixel;
+        bool SortFlag;
+        GifByteType Buf[3];
+        GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
+
+        if (!IS_READABLE(Private)) {
+                /* This file was NOT open for reading: */
+                GifFile->Error = D_GIF_ERR_NOT_READABLE;
+                return GIF_ERROR;
+        }
 
-        GifFile->SColorMap = GifMakeMapObject(1 << BitsPerPixel, NULL);
-        if (GifFile->SColorMap == NULL) {
-            GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
-            return GIF_ERROR;
+        /* Put the screen descriptor into the file: */
+        if (DGifGetWord(GifFile, &GifFile->SWidth) == GIF_ERROR ||
+            DGifGetWord(GifFile, &GifFile->SHeight) == GIF_ERROR) {
+                return GIF_ERROR;
         }
 
-        /* Get the global color map: */
-        GifFile->SColorMap->SortFlag = SortFlag;
-        for (i = 0; i < GifFile->SColorMap->ColorCount; i++) {
-            /* coverity[check_return] */
-            if (InternalRead(GifFile, Buf, 3) != 3) {
+        if (InternalRead(GifFile, Buf, 3) != 3) {
+                GifFile->Error = D_GIF_ERR_READ_FAILED;
                 GifFreeMapObject(GifFile->SColorMap);
                 GifFile->SColorMap = NULL;
-                GifFile->Error = D_GIF_ERR_READ_FAILED;
                 return GIF_ERROR;
-            }
-            GifFile->SColorMap->Colors[i].Red = Buf[0];
-            GifFile->SColorMap->Colors[i].Green = Buf[1];
-            GifFile->SColorMap->Colors[i].Blue = Buf[2];
         }
-    } else {
-        GifFile->SColorMap = NULL;
-    }
+        GifFile->SColorResolution = (((Buf[0] & 0x70) + 1) >> 4) + 1;
+        SortFlag = (Buf[0] & 0x08) != 0;
+        BitsPerPixel = (Buf[0] & 0x07) + 1;
+        GifFile->SBackGroundColor = Buf[1];
+        GifFile->AspectByte = Buf[2];
+        if (Buf[0] & 0x80) { /* Do we have global color map? */
+                int i;
+
+                GifFile->SColorMap = GifMakeMapObject(1 << BitsPerPixel, NULL);
+                if (GifFile->SColorMap == NULL) {
+                        GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
+                        return GIF_ERROR;
+                }
+
+                /* Get the global color map: */
+                GifFile->SColorMap->SortFlag = SortFlag;
+                for (i = 0; i < GifFile->SColorMap->ColorCount; i++) {
+                        /* coverity[check_return] */
+                        if (InternalRead(GifFile, Buf, 3) != 3) {
+                                GifFreeMapObject(GifFile->SColorMap);
+                                GifFile->SColorMap = NULL;
+                                GifFile->Error = D_GIF_ERR_READ_FAILED;
+                                return GIF_ERROR;
+                        }
+                        GifFile->SColorMap->Colors[i].Red = Buf[0];
+                        GifFile->SColorMap->Colors[i].Green = Buf[1];
+                        GifFile->SColorMap->Colors[i].Blue = Buf[2];
+                }
+        } else {
+                GifFile->SColorMap = NULL;
+        }
 
-    /*
-     * No check here for whether the background color is in range for the
-     * screen color map.  Possibly there should be.
-     */
+        /*
+         * No check here for whether the background color is in range for the
+         * screen color map.  Possibly there should be.
+         */
 
-    return GIF_OK;
+        return GIF_OK;
 }
 
 const char *DGifGetGifVersion(GifFileType *GifFile) {
-    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
+        GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
-    if (Private->gif89) {
-        return GIF89_STAMP;
-    } else {
-        return GIF87_STAMP;
-    }
+        if (Private->gif89) {
+                return GIF89_STAMP;
+        } else {
+                return GIF87_STAMP;
+        }
 }
 
 /******************************************************************************
  This routine should be called before any attempt to read an image.
 ******************************************************************************/
 int DGifGetRecordType(GifFileType *GifFile, GifRecordType *Type) {
-    GifByteType Buf;
-    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
+        GifByteType Buf;
+        GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
-    if (!IS_READABLE(Private)) {
-        /* This file was NOT open for reading: */
-        GifFile->Error = D_GIF_ERR_NOT_READABLE;
-        return GIF_ERROR;
-    }
+        if (!IS_READABLE(Private)) {
+                /* This file was NOT open for reading: */
+                GifFile->Error = D_GIF_ERR_NOT_READABLE;
+                return GIF_ERROR;
+        }
 
-    /* coverity[check_return] */
-    if (InternalRead(GifFile, &Buf, 1) != 1) {
-        GifFile->Error = D_GIF_ERR_READ_FAILED;
-        return GIF_ERROR;
-    }
-
-    // fprintf(stderr, "### DGifGetRecordType: %02x\n", Buf);
-    switch (Buf) {
-    case DESCRIPTOR_INTRODUCER:
-        *Type = IMAGE_DESC_RECORD_TYPE;
-        break;
-    case EXTENSION_INTRODUCER:
-        *Type = EXTENSION_RECORD_TYPE;
-        break;
-    case TERMINATOR_INTRODUCER:
-        *Type = TERMINATE_RECORD_TYPE;
-        break;
-    default:
-        *Type = UNDEFINED_RECORD_TYPE;
-        GifFile->Error = D_GIF_ERR_WRONG_RECORD;
-        return GIF_ERROR;
-    }
+        /* coverity[check_return] */
+        if (InternalRead(GifFile, &Buf, 1) != 1) {
+                GifFile->Error = D_GIF_ERR_READ_FAILED;
+                return GIF_ERROR;
+        }
 
-    return GIF_OK;
+        // fprintf(stderr, "### DGifGetRecordType: %02x\n", Buf);
+        switch (Buf) {
+        case DESCRIPTOR_INTRODUCER:
+                *Type = IMAGE_DESC_RECORD_TYPE;
+                break;
+        case EXTENSION_INTRODUCER:
+                *Type = EXTENSION_RECORD_TYPE;
+                break;
+        case TERMINATOR_INTRODUCER:
+                *Type = TERMINATE_RECORD_TYPE;
+                break;
+        default:
+                *Type = UNDEFINED_RECORD_TYPE;
+                GifFile->Error = D_GIF_ERR_WRONG_RECORD;
+                return GIF_ERROR;
+        }
+
+        return GIF_OK;
 }
 
 int DGifGetImageHeader(GifFileType *GifFile) {
-    unsigned int BitsPerPixel;
-    GifByteType Buf[3];
-    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
+        unsigned int BitsPerPixel;
+        GifByteType Buf[3];
+        GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
-    if (!IS_READABLE(Private)) {
-        /* This file was NOT open for reading: */
-        GifFile->Error = D_GIF_ERR_NOT_READABLE;
-        return GIF_ERROR;
-    }
+        if (!IS_READABLE(Private)) {
+                /* This file was NOT open for reading: */
+                GifFile->Error = D_GIF_ERR_NOT_READABLE;
+                return GIF_ERROR;
+        }
 
-    if (DGifGetWord(GifFile, &GifFile->Image.Left) == GIF_ERROR ||
-        DGifGetWord(GifFile, &GifFile->Image.Top) == GIF_ERROR ||
-        DGifGetWord(GifFile, &GifFile->Image.Width) == GIF_ERROR ||
-        DGifGetWord(GifFile, &GifFile->Image.Height) == GIF_ERROR) {
-        return GIF_ERROR;
-    }
-    if (InternalRead(GifFile, Buf, 1) != 1) {
-        GifFile->Error = D_GIF_ERR_READ_FAILED;
-        GifFreeMapObject(GifFile->Image.ColorMap);
-        GifFile->Image.ColorMap = NULL;
-        return GIF_ERROR;
-    }
-    BitsPerPixel = (Buf[0] & 0x07) + 1;
-    GifFile->Image.Interlace = (Buf[0] & 0x40) ? true : false;
-
-    /* Setup the colormap */
-    if (GifFile->Image.ColorMap) {
-        GifFreeMapObject(GifFile->Image.ColorMap);
-        GifFile->Image.ColorMap = NULL;
-    }
-    /* Does this image have local color map? */
-    if (Buf[0] & 0x80) {
-        unsigned int i;
-
-        GifFile->Image.ColorMap =
-            GifMakeMapObject(1 << BitsPerPixel, NULL);
-        if (GifFile->Image.ColorMap == NULL) {
-            GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
-            return GIF_ERROR;
-        }
-
-        /* Get the image local color map: */
-        for (i = 0; i < GifFile->Image.ColorMap->ColorCount; i++) {
-            /* coverity[check_return] */
-            if (InternalRead(GifFile, Buf, 3) != 3) {
-                GifFreeMapObject(GifFile->Image.ColorMap);
+        if (DGifGetWord(GifFile, &GifFile->Image.Left) == GIF_ERROR ||
+            DGifGetWord(GifFile, &GifFile->Image.Top) == GIF_ERROR ||
+            DGifGetWord(GifFile, &GifFile->Image.Width) == GIF_ERROR ||
+            DGifGetWord(GifFile, &GifFile->Image.Height) == GIF_ERROR) {
+                return GIF_ERROR;
+        }
+        if (InternalRead(GifFile, Buf, 1) != 1) {
                 GifFile->Error = D_GIF_ERR_READ_FAILED;
+                GifFreeMapObject(GifFile->Image.ColorMap);
                 GifFile->Image.ColorMap = NULL;
                 return GIF_ERROR;
-            }
-            GifFile->Image.ColorMap->Colors[i].Red = Buf[0];
-            GifFile->Image.ColorMap->Colors[i].Green = Buf[1];
-            GifFile->Image.ColorMap->Colors[i].Blue = Buf[2];
         }
-    }
+        BitsPerPixel = (Buf[0] & 0x07) + 1;
+        GifFile->Image.Interlace = (Buf[0] & 0x40) ? true : false;
 
-    Private->PixelCount =
-        (long)GifFile->Image.Width * (long)GifFile->Image.Height;
+        /* Setup the colormap */
+        if (GifFile->Image.ColorMap) {
+                GifFreeMapObject(GifFile->Image.ColorMap);
+                GifFile->Image.ColorMap = NULL;
+        }
+        /* Does this image have local color map? */
+        if (Buf[0] & 0x80) {
+                unsigned int i;
+
+                GifFile->Image.ColorMap =
+                    GifMakeMapObject(1 << BitsPerPixel, NULL);
+                if (GifFile->Image.ColorMap == NULL) {
+                        GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
+                        return GIF_ERROR;
+                }
+
+                /* Get the image local color map: */
+                for (i = 0; i < GifFile->Image.ColorMap->ColorCount; i++) {
+                        /* coverity[check_return] */
+                        if (InternalRead(GifFile, Buf, 3) != 3) {
+                                GifFreeMapObject(GifFile->Image.ColorMap);
+                                GifFile->Error = D_GIF_ERR_READ_FAILED;
+                                GifFile->Image.ColorMap = NULL;
+                                return GIF_ERROR;
+                        }
+                        GifFile->Image.ColorMap->Colors[i].Red = Buf[0];
+                        GifFile->Image.ColorMap->Colors[i].Green = Buf[1];
+                        GifFile->Image.ColorMap->Colors[i].Blue = Buf[2];
+                }
+        }
+
+        Private->PixelCount =
+            (long)GifFile->Image.Width * (long)GifFile->Image.Height;
 
-    /* Reset decompress algorithm parameters. */
-    return DGifSetupDecompress(GifFile);
+        /* Reset decompress algorithm parameters. */
+        return DGifSetupDecompress(GifFile);
 }
 
 /******************************************************************************
@@ -451,133 +451,135 @@ int DGifGetImageHeader(GifFileType *GifFile) {
  Note it is assumed the Image desc. header has been read.
 ******************************************************************************/
 int DGifGetImageDesc(GifFileType *GifFile) {
-    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
-    SavedImage *sp;
+        GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
+        SavedImage *sp;
 
-    if (!IS_READABLE(Private)) {
-        /* This file was NOT open for reading: */
-        GifFile->Error = D_GIF_ERR_NOT_READABLE;
-        return GIF_ERROR;
-    }
+        if (!IS_READABLE(Private)) {
+                /* This file was NOT open for reading: */
+                GifFile->Error = D_GIF_ERR_NOT_READABLE;
+                return GIF_ERROR;
+        }
 
-    if (DGifGetImageHeader(GifFile) == GIF_ERROR) {
-        return GIF_ERROR;
-    }
-
-    if (GifFile->SavedImages) {
-        SavedImage *new_saved_images = (SavedImage *)reallocarray(
-            GifFile->SavedImages, (GifFile->ImageCount + 1),
-            sizeof(SavedImage));
-        if (new_saved_images == NULL) {
-            GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
-            return GIF_ERROR;
-        }
-        GifFile->SavedImages = new_saved_images;
-    } else {
-        if ((GifFile->SavedImages =
-                 (SavedImage *)malloc(sizeof(SavedImage))) == NULL) {
-            GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
-            return GIF_ERROR;
-        }
-    }
-
-    sp = &GifFile->SavedImages[GifFile->ImageCount];
-    memcpy(&sp->ImageDesc, &GifFile->Image, sizeof(GifImageDesc));
-    if (GifFile->Image.ColorMap != NULL) {
-        sp->ImageDesc.ColorMap =
-            GifMakeMapObject(GifFile->Image.ColorMap->ColorCount,
-                             GifFile->Image.ColorMap->Colors);
-        if (sp->ImageDesc.ColorMap == NULL) {
-            GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
-            return GIF_ERROR;
-        }
-    }
-    sp->RasterBits = (unsigned char *)NULL;
-    sp->ExtensionBlockCount = 0;
-    sp->ExtensionBlocks = (ExtensionBlock *)NULL;
-
-    GifFile->ImageCount++;
-
-    return GIF_OK;
+        if (DGifGetImageHeader(GifFile) == GIF_ERROR) {
+                return GIF_ERROR;
+        }
+
+        if (GifFile->SavedImages) {
+                SavedImage *new_saved_images = (SavedImage *)reallocarray(
+                    GifFile->SavedImages, (GifFile->ImageCount + 1),
+                    sizeof(SavedImage));
+                if (new_saved_images == NULL) {
+                        GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
+                        return GIF_ERROR;
+                }
+                GifFile->SavedImages = new_saved_images;
+        } else {
+                if ((GifFile->SavedImages =
+                         (SavedImage *)malloc(sizeof(SavedImage))) == NULL) {
+                        GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
+                        return GIF_ERROR;
+                }
+        }
+
+        sp = &GifFile->SavedImages[GifFile->ImageCount];
+        memcpy(&sp->ImageDesc, &GifFile->Image, sizeof(GifImageDesc));
+        if (GifFile->Image.ColorMap != NULL) {
+                sp->ImageDesc.ColorMap =
+                    GifMakeMapObject(GifFile->Image.ColorMap->ColorCount,
+                                     GifFile->Image.ColorMap->Colors);
+                if (sp->ImageDesc.ColorMap == NULL) {
+                        GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
+                        return GIF_ERROR;
+                }
+        }
+        sp->RasterBits = (unsigned char *)NULL;
+        sp->ExtensionBlockCount = 0;
+        sp->ExtensionBlocks = (ExtensionBlock *)NULL;
+
+        GifFile->ImageCount++;
+
+        return GIF_OK;
 }
 
 /******************************************************************************
  Get one full scanned line (Line) of length LineLen from GIF file.
 ******************************************************************************/
 int DGifGetLine(GifFileType *GifFile, GifPixelType *Line, int LineLen) {
-    GifByteType *Dummy;
-    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
+        GifByteType *Dummy;
+        GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
-    if (!IS_READABLE(Private)) {
-        /* This file was NOT open for reading: */
-        GifFile->Error = D_GIF_ERR_NOT_READABLE;
-        return GIF_ERROR;
-    }
-
-    if (!LineLen) {
-        LineLen = GifFile->Image.Width;
-    }
+        if (!IS_READABLE(Private)) {
+                /* This file was NOT open for reading: */
+                GifFile->Error = D_GIF_ERR_NOT_READABLE;
+                return GIF_ERROR;
+        }
 
-    if ((Private->PixelCount -= LineLen) > 0xffff0000UL) {
-        GifFile->Error = D_GIF_ERR_DATA_TOO_BIG;
-        return GIF_ERROR;
-    }
+        if (!LineLen) {
+                LineLen = GifFile->Image.Width;
+        }
 
-    if (DGifDecompressLine(GifFile, Line, LineLen) == GIF_OK) {
-        if (Private->PixelCount == 0) {
-            /* We probably won't be called any more, so let's clean
-             * up everything before we return: need to flush out all
-             * the rest of image until an empty block (size 0)
-             * detected. We use GetCodeNext.
-             */
-            do {
-                if (DGifGetCodeNext(GifFile, &Dummy) ==
-                    GIF_ERROR) {
-                    return GIF_ERROR;
+        if (LineLen < 0 || Private->PixelCount < (unsigned long)LineLen) {
+                GifFile->Error = D_GIF_ERR_DATA_TOO_BIG;
+                return GIF_ERROR;
+        }
+        Private->PixelCount -= LineLen;
+
+        if (DGifDecompressLine(GifFile, Line, LineLen) == GIF_OK) {
+                if (Private->PixelCount == 0) {
+                        /* We probably won't be called any more, so let's clean
+                         * up everything before we return: need to flush out all
+                         * the rest of image until an empty block (size 0)
+                         * detected. We use GetCodeNext.
+                         */
+                        do {
+                                if (DGifGetCodeNext(GifFile, &Dummy) ==
+                                    GIF_ERROR) {
+                                        return GIF_ERROR;
+                                }
+                        } while (Dummy != NULL);
                 }
-            } while (Dummy != NULL);
+                return GIF_OK;
+        } else {
+                return GIF_ERROR;
         }
-        return GIF_OK;
-    } else {
-        return GIF_ERROR;
-    }
 }
 
 /******************************************************************************
  Put one pixel (Pixel) into GIF file.
 ******************************************************************************/
 int DGifGetPixel(GifFileType *GifFile, GifPixelType Pixel) {
-    GifByteType *Dummy;
-    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
+        GifByteType *Dummy;
+        GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
-    if (!IS_READABLE(Private)) {
-        /* This file was NOT open for reading: */
-        GifFile->Error = D_GIF_ERR_NOT_READABLE;
-        return GIF_ERROR;
-    }
-    if (--Private->PixelCount > 0xffff0000UL) {
-        GifFile->Error = D_GIF_ERR_DATA_TOO_BIG;
-        return GIF_ERROR;
-    }
-
-    if (DGifDecompressLine(GifFile, &Pixel, 1) == GIF_OK) {
+        if (!IS_READABLE(Private)) {
+                /* This file was NOT open for reading: */
+                GifFile->Error = D_GIF_ERR_NOT_READABLE;
+                return GIF_ERROR;
+        }
         if (Private->PixelCount == 0) {
-            /* We probably won't be called any more, so let's clean
-             * up everything before we return: need to flush out all
-             * the rest of image until an empty block (size 0)
-             * detected. We use GetCodeNext.
-             */
-            do {
-                if (DGifGetCodeNext(GifFile, &Dummy) ==
-                    GIF_ERROR) {
-                    return GIF_ERROR;
+                GifFile->Error = D_GIF_ERR_DATA_TOO_BIG;
+                return GIF_ERROR;
+        }
+        Private->PixelCount --;
+
+        if (DGifDecompressLine(GifFile, &Pixel, 1) == GIF_OK) {
+                if (Private->PixelCount == 0) {
+                        /* We probably won't be called any more, so let's clean
+                         * up everything before we return: need to flush out all
+                         * the rest of image until an empty block (size 0)
+                         * detected. We use GetCodeNext.
+                         */
+                        do {
+                                if (DGifGetCodeNext(GifFile, &Dummy) ==
+                                    GIF_ERROR) {
+                                        return GIF_ERROR;
+                                }
+                        } while (Dummy != NULL);
                 }
-            } while (Dummy != NULL);
+                return GIF_OK;
+        } else {
+                return GIF_ERROR;
         }
-        return GIF_OK;
-    } else {
-        return GIF_ERROR;
-    }
 }
 
 /******************************************************************************
@@ -589,26 +591,26 @@ int DGifGetPixel(GifFileType *GifFile, GifPixelType Pixel) {
 ******************************************************************************/
 int DGifGetExtension(GifFileType *GifFile, int *ExtCode,
                      GifByteType **Extension) {
-    GifByteType Buf;
-    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
+        GifByteType Buf;
+        GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
-    // fprintf(stderr, "### -> DGifGetExtension:\n");
-    if (!IS_READABLE(Private)) {
-        /* This file was NOT open for reading: */
-        GifFile->Error = D_GIF_ERR_NOT_READABLE;
-        return GIF_ERROR;
-    }
+        // fprintf(stderr, "### -> DGifGetExtension:\n");
+        if (!IS_READABLE(Private)) {
+                /* This file was NOT open for reading: */
+                GifFile->Error = D_GIF_ERR_NOT_READABLE;
+                return GIF_ERROR;
+        }
 
-    /* coverity[check_return] */
-    if (InternalRead(GifFile, &Buf, 1) != 1) {
-        GifFile->Error = D_GIF_ERR_READ_FAILED;
-        return GIF_ERROR;
-    }
-    *ExtCode = Buf;
-    // fprintf(stderr, "### <- DGifGetExtension: %02x, about to call
-    // next\n", Buf);
+        /* coverity[check_return] */
+        if (InternalRead(GifFile, &Buf, 1) != 1) {
+                GifFile->Error = D_GIF_ERR_READ_FAILED;
+                return GIF_ERROR;
+        }
+        *ExtCode = Buf;
+        // fprintf(stderr, "### <- DGifGetExtension: %02x, about to call
+        // next\n", Buf);
 
-    return DGifGetExtensionNext(GifFile, Extension);
+        return DGifGetExtensionNext(GifFile, Extension);
 }
 
 /******************************************************************************
@@ -617,31 +619,31 @@ int DGifGetExtension(GifFileType *GifFile, int *ExtCode,
  The Extension should NOT be freed by the user (not dynamically allocated).
 ******************************************************************************/
 int DGifGetExtensionNext(GifFileType *GifFile, GifByteType **Extension) {
-    GifByteType Buf;
-    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
+        GifByteType Buf;
+        GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
-    // fprintf(stderr, "### -> DGifGetExtensionNext\n");
-    if (InternalRead(GifFile, &Buf, 1) != 1) {
-        GifFile->Error = D_GIF_ERR_READ_FAILED;
-        return GIF_ERROR;
-    }
-    // fprintf(stderr, "### DGifGetExtensionNext sees %d\n", Buf);
-
-    if (Buf > 0) {
-        *Extension = Private->Buf; /* Use private unused buffer. */
-        (*Extension)[0] =
-            Buf; /* Pascal strings notation (pos. 0 is len.). */
-                 /* coverity[tainted_data,check_return] */
-        if (InternalRead(GifFile, &((*Extension)[1]), Buf) != Buf) {
-            GifFile->Error = D_GIF_ERR_READ_FAILED;
-            return GIF_ERROR;
-        }
-    } else {
-        *Extension = NULL;
-    }
-    // fprintf(stderr, "### <- DGifGetExtensionNext: %p\n", Extension);
-
-    return GIF_OK;
+        // fprintf(stderr, "### -> DGifGetExtensionNext\n");
+        if (InternalRead(GifFile, &Buf, 1) != 1) {
+                GifFile->Error = D_GIF_ERR_READ_FAILED;
+                return GIF_ERROR;
+        }
+        // fprintf(stderr, "### DGifGetExtensionNext sees %d\n", Buf);
+
+        if (Buf > 0) {
+                *Extension = Private->Buf; /* Use private unused buffer. */
+                (*Extension)[0] =
+                    Buf; /* Pascal strings notation (pos. 0 is len.). */
+                         /* coverity[tainted_data,check_return] */
+                if (InternalRead(GifFile, &((*Extension)[1]), Buf) != Buf) {
+                        GifFile->Error = D_GIF_ERR_READ_FAILED;
+                        return GIF_ERROR;
+                }
+        } else {
+                *Extension = NULL;
+        }
+        // fprintf(stderr, "### <- DGifGetExtensionNext: %p\n", Extension);
+
+        return GIF_OK;
 }
 
 /******************************************************************************
@@ -651,21 +653,21 @@ int DGifGetExtensionNext(GifFileType *GifFile, GifByteType **Extension) {
 int DGifExtensionToGCB(const size_t GifExtensionLength,
                        const GifByteType *GifExtension,
                        GraphicsControlBlock *GCB) {
-    if (GifExtensionLength != 4) {
-        return GIF_ERROR;
-    }
-
-    GCB->DisposalMode = (GifExtension[0] >> 2) & 0x07;
-    GCB->UserInputFlag = (GifExtension[0] & 0x02) != 0;
-    GCB->DelayTime =
-        UNSIGNED_LITTLE_ENDIAN(GifExtension[1], GifExtension[2]);
-    if (GifExtension[0] & 0x01) {
-        GCB->TransparentColor = (int)GifExtension[3];
-    } else {
-        GCB->TransparentColor = NO_TRANSPARENT_COLOR;
-    }
+        if (GifExtensionLength != 4) {
+                return GIF_ERROR;
+        }
+
+        GCB->DisposalMode = (GifExtension[0] >> 2) & 0x07;
+        GCB->UserInputFlag = (GifExtension[0] & 0x02) != 0;
+        GCB->DelayTime =
+            UNSIGNED_LITTLE_ENDIAN(GifExtension[1], GifExtension[2]);
+        if (GifExtension[0] & 0x01) {
+                GCB->TransparentColor = (int)GifExtension[3];
+        } else {
+                GCB->TransparentColor = NO_TRANSPARENT_COLOR;
+        }
 
-    return GIF_OK;
+        return GIF_OK;
 }
 
 /******************************************************************************
@@ -674,101 +676,101 @@ int DGifExtensionToGCB(const size_t GifExtensionLength,
 
 int DGifSavedExtensionToGCB(GifFileType *GifFile, int ImageIndex,
                             GraphicsControlBlock *GCB) {
-    int i;
+        int i;
 
-    if (ImageIndex < 0 || ImageIndex > GifFile->ImageCount - 1) {
-        return GIF_ERROR;
-    }
+        if (ImageIndex < 0 || ImageIndex > GifFile->ImageCount - 1) {
+                return GIF_ERROR;
+        }
 
-    GCB->DisposalMode = DISPOSAL_UNSPECIFIED;
-    GCB->UserInputFlag = false;
-    GCB->DelayTime = 0;
-    GCB->TransparentColor = NO_TRANSPARENT_COLOR;
+        GCB->DisposalMode = DISPOSAL_UNSPECIFIED;
+        GCB->UserInputFlag = false;
+        GCB->DelayTime = 0;
+        GCB->TransparentColor = NO_TRANSPARENT_COLOR;
 
-    for (i = 0; i < GifFile->SavedImages[ImageIndex].ExtensionBlockCount;
-         i++) {
-        ExtensionBlock *ep =
-            &GifFile->SavedImages[ImageIndex].ExtensionBlocks[i];
-        if (ep->Function == GRAPHICS_EXT_FUNC_CODE) {
-            return DGifExtensionToGCB(ep->ByteCount, ep->Bytes,
-                                      GCB);
+        for (i = 0; i < GifFile->SavedImages[ImageIndex].ExtensionBlockCount;
+             i++) {
+                ExtensionBlock *ep =
+                    &GifFile->SavedImages[ImageIndex].ExtensionBlocks[i];
+                if (ep->Function == GRAPHICS_EXT_FUNC_CODE) {
+                        return DGifExtensionToGCB(ep->ByteCount, ep->Bytes,
+                                                  GCB);
+                }
         }
-    }
 
-    return GIF_ERROR;
+        return GIF_ERROR;
 }
 
 /******************************************************************************
  This routine should be called last, to close the GIF file.
 ******************************************************************************/
 int DGifCloseFile(GifFileType *GifFile, int *ErrorCode) {
-    GifFilePrivateType *Private;
+        GifFilePrivateType *Private;
 
-    if (GifFile == NULL || GifFile->Private == NULL) {
-        return GIF_ERROR;
-    }
+        if (GifFile == NULL || GifFile->Private == NULL) {
+                return GIF_ERROR;
+        }
+
+        if (GifFile->Image.ColorMap) {
+                GifFreeMapObject(GifFile->Image.ColorMap);
+                GifFile->Image.ColorMap = NULL;
+        }
 
-    if (GifFile->Image.ColorMap) {
-        GifFreeMapObject(GifFile->Image.ColorMap);
-        GifFile->Image.ColorMap = NULL;
-    }
+        if (GifFile->SColorMap) {
+                GifFreeMapObject(GifFile->SColorMap);
+                GifFile->SColorMap = NULL;
+        }
 
-    if (GifFile->SColorMap) {
-        GifFreeMapObject(GifFile->SColorMap);
-        GifFile->SColorMap = NULL;
-    }
+        if (GifFile->SavedImages) {
+                GifFreeSavedImages(GifFile);
+                GifFile->SavedImages = NULL;
+        }
 
-    if (GifFile->SavedImages) {
-        GifFreeSavedImages(GifFile);
-        GifFile->SavedImages = NULL;
-    }
+        GifFreeExtensions(&GifFile->ExtensionBlockCount,
+                          &GifFile->ExtensionBlocks);
 
-    GifFreeExtensions(&GifFile->ExtensionBlockCount,
-                      &GifFile->ExtensionBlocks);
+        Private = (GifFilePrivateType *)GifFile->Private;
 
-    Private = (GifFilePrivateType *)GifFile->Private;
+        if (!IS_READABLE(Private)) {
+                /* This file was NOT open for reading: */
+                if (ErrorCode != NULL) {
+                        *ErrorCode = D_GIF_ERR_NOT_READABLE;
+                }
+                free((char *)GifFile->Private);
+                free(GifFile);
+                return GIF_ERROR;
+        }
 
-    if (!IS_READABLE(Private)) {
-        /* This file was NOT open for reading: */
-        if (ErrorCode != NULL) {
-            *ErrorCode = D_GIF_ERR_NOT_READABLE;
+        if (Private->File && (fclose(Private->File) != 0)) {
+                if (ErrorCode != NULL) {
+                        *ErrorCode = D_GIF_ERR_CLOSE_FAILED;
+                }
+                free((char *)GifFile->Private);
+                free(GifFile);
+                return GIF_ERROR;
         }
+
         free((char *)GifFile->Private);
         free(GifFile);
-        return GIF_ERROR;
-    }
-
-    if (Private->File && (fclose(Private->File) != 0)) {
         if (ErrorCode != NULL) {
-            *ErrorCode = D_GIF_ERR_CLOSE_FAILED;
+                *ErrorCode = D_GIF_SUCCEEDED;
         }
-        free((char *)GifFile->Private);
-        free(GifFile);
-        return GIF_ERROR;
-    }
-
-    free((char *)GifFile->Private);
-    free(GifFile);
-    if (ErrorCode != NULL) {
-        *ErrorCode = D_GIF_SUCCEEDED;
-    }
-    return GIF_OK;
+        return GIF_OK;
 }
 
 /******************************************************************************
  Get 2 bytes (word) from the given file:
 ******************************************************************************/
 static int DGifGetWord(GifFileType *GifFile, GifWord *Word) {
-    unsigned char c[2];
+        unsigned char c[2];
 
-    /* coverity[check_return] */
-    if (InternalRead(GifFile, c, 2) != 2) {
-        GifFile->Error = D_GIF_ERR_READ_FAILED;
-        return GIF_ERROR;
-    }
+        /* coverity[check_return] */
+        if (InternalRead(GifFile, c, 2) != 2) {
+                GifFile->Error = D_GIF_ERR_READ_FAILED;
+                return GIF_ERROR;
+        }
 
-    *Word = (GifWord)UNSIGNED_LITTLE_ENDIAN(c[0], c[1]);
-    return GIF_OK;
+        *Word = (GifWord)UNSIGNED_LITTLE_ENDIAN(c[0], c[1]);
+        return GIF_OK;
 }
 
 /******************************************************************************
@@ -779,17 +781,17 @@ static int DGifGetWord(GifFileType *GifFile, GifWord *Word) {
  The block should NOT be freed by the user (not dynamically allocated).
 ******************************************************************************/
 int DGifGetCode(GifFileType *GifFile, int *CodeSize, GifByteType **CodeBlock) {
-    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
+        GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
-    if (!IS_READABLE(Private)) {
-        /* This file was NOT open for reading: */
-        GifFile->Error = D_GIF_ERR_NOT_READABLE;
-        return GIF_ERROR;
-    }
+        if (!IS_READABLE(Private)) {
+                /* This file was NOT open for reading: */
+                GifFile->Error = D_GIF_ERR_NOT_READABLE;
+                return GIF_ERROR;
+        }
 
-    *CodeSize = Private->BitsPerPixel;
+        *CodeSize = Private->BitsPerPixel;
 
-    return DGifGetCodeNext(GifFile, CodeBlock);
+        return DGifGetCodeNext(GifFile, CodeBlock);
 }
 
 /******************************************************************************
@@ -798,78 +800,78 @@ int DGifGetCode(GifFileType *GifFile, int *CodeSize, GifByteType **CodeBlock) {
  The block should NOT be freed by the user (not dynamically allocated).
 ******************************************************************************/
 int DGifGetCodeNext(GifFileType *GifFile, GifByteType **CodeBlock) {
-    GifByteType Buf;
-    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
+        GifByteType Buf;
+        GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
-    /* coverity[tainted_data_argument] */
-    /* coverity[check_return] */
-    if (InternalRead(GifFile, &Buf, 1) != 1) {
-        GifFile->Error = D_GIF_ERR_READ_FAILED;
-        return GIF_ERROR;
-    }
-
-    /* coverity[lower_bounds] */
-    if (Buf > 0) {
-        *CodeBlock = Private->Buf; /* Use private unused buffer. */
-        (*CodeBlock)[0] =
-            Buf; /* Pascal strings notation (pos. 0 is len.). */
-                 /* coverity[tainted_data] */
-        if (InternalRead(GifFile, &((*CodeBlock)[1]), Buf) != Buf) {
-            GifFile->Error = D_GIF_ERR_READ_FAILED;
-            return GIF_ERROR;
-        }
-    } else {
-        *CodeBlock = NULL;
-        Private->Buf[0] = 0; /* Make sure the buffer is empty! */
-        Private->PixelCount =
-            0; /* And local info. indicate image read. */
-    }
+        /* coverity[tainted_data_argument] */
+        /* coverity[check_return] */
+        if (InternalRead(GifFile, &Buf, 1) != 1) {
+                GifFile->Error = D_GIF_ERR_READ_FAILED;
+                return GIF_ERROR;
+        }
+
+        /* coverity[lower_bounds] */
+        if (Buf > 0) {
+                *CodeBlock = Private->Buf; /* Use private unused buffer. */
+                (*CodeBlock)[0] =
+                    Buf; /* Pascal strings notation (pos. 0 is len.). */
+                         /* coverity[tainted_data] */
+                if (InternalRead(GifFile, &((*CodeBlock)[1]), Buf) != Buf) {
+                        GifFile->Error = D_GIF_ERR_READ_FAILED;
+                        return GIF_ERROR;
+                }
+        } else {
+                *CodeBlock = NULL;
+                Private->Buf[0] = 0; /* Make sure the buffer is empty! */
+                Private->PixelCount =
+                    0; /* And local info. indicate image read. */
+        }
 
-    return GIF_OK;
+        return GIF_OK;
 }
 
 /******************************************************************************
  Setup the LZ decompression for this image:
 ******************************************************************************/
 static int DGifSetupDecompress(GifFileType *GifFile) {
-    int i, BitsPerPixel;
-    GifByteType CodeSize;
-    GifPrefixType *Prefix;
-    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
-
-    /* coverity[check_return] */
-    if (InternalRead(GifFile, &CodeSize, 1) <
-        1) { /* Read Code size from file. */
-        GifFile->Error = D_GIF_ERR_READ_FAILED;
-        return GIF_ERROR; /* Failed to read Code size. */
-    }
-    BitsPerPixel = CodeSize;
-
-    /* this can only happen on a severely malformed GIF */
-    if (BitsPerPixel > 8) {
-        GifFile->Error =
-            D_GIF_ERR_READ_FAILED; /* somewhat bogus error code */
-        return GIF_ERROR;          /* Failed to read Code size. */
-    }
-
-    Private->Buf[0] = 0; /* Input Buffer empty. */
-    Private->BitsPerPixel = BitsPerPixel;
-    Private->ClearCode = (1 << BitsPerPixel);
-    Private->EOFCode = Private->ClearCode + 1;
-    Private->RunningCode = Private->EOFCode + 1;
-    Private->RunningBits = BitsPerPixel + 1; /* Number of bits per code. */
-    Private->MaxCode1 = 1 << Private->RunningBits; /* Max. code + 1. */
-    Private->StackPtr = 0; /* No pixels on the pixel stack. */
-    Private->LastCode = NO_SUCH_CODE;
-    Private->CrntShiftState = 0; /* No information in CrntShiftDWord. */
-    Private->CrntShiftDWord = 0;
-
-    Prefix = Private->Prefix;
-    for (i = 0; i <= LZ_MAX_CODE; i++) {
-        Prefix[i] = NO_SUCH_CODE;
-    }
-
-    return GIF_OK;
+        int i, BitsPerPixel;
+        GifByteType CodeSize;
+        GifPrefixType *Prefix;
+        GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
+
+        /* coverity[check_return] */
+        if (InternalRead(GifFile, &CodeSize, 1) <
+            1) { /* Read Code size from file. */
+                GifFile->Error = D_GIF_ERR_READ_FAILED;
+                return GIF_ERROR; /* Failed to read Code size. */
+        }
+        BitsPerPixel = CodeSize;
+
+        /* this can only happen on a severely malformed GIF */
+        if (BitsPerPixel > 8) {
+                GifFile->Error =
+                    D_GIF_ERR_READ_FAILED; /* somewhat bogus error code */
+                return GIF_ERROR;          /* Failed to read Code size. */
+        }
+
+        Private->Buf[0] = 0; /* Input Buffer empty. */
+        Private->BitsPerPixel = BitsPerPixel;
+        Private->ClearCode = (1 << BitsPerPixel);
+        Private->EOFCode = Private->ClearCode + 1;
+        Private->RunningCode = Private->EOFCode + 1;
+        Private->RunningBits = BitsPerPixel + 1; /* Number of bits per code. */
+        Private->MaxCode1 = 1 << Private->RunningBits; /* Max. code + 1. */
+        Private->StackPtr = 0; /* No pixels on the pixel stack. */
+        Private->LastCode = NO_SUCH_CODE;
+        Private->CrntShiftState = 0; /* No information in CrntShiftDWord. */
+        Private->CrntShiftDWord = 0;
+
+        Prefix = Private->Prefix;
+        for (i = 0; i <= LZ_MAX_CODE; i++) {
+                Prefix[i] = NO_SUCH_CODE;
+        }
+
+        return GIF_OK;
 }
 
 /******************************************************************************
@@ -880,147 +882,147 @@ static int DGifSetupDecompress(GifFileType *GifFile) {
 ******************************************************************************/
 static int DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line,
                               int LineLen) {
-    int i = 0;
-    int j, CrntCode, EOFCode, ClearCode, CrntPrefix, LastCode, StackPtr;
-    GifByteType *Stack, *Suffix;
-    GifPrefixType *Prefix;
-    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
-
-    StackPtr = Private->StackPtr;
-    Prefix = Private->Prefix;
-    Suffix = Private->Suffix;
-    Stack = Private->Stack;
-    EOFCode = Private->EOFCode;
-    ClearCode = Private->ClearCode;
-    LastCode = Private->LastCode;
-
-    if (StackPtr > LZ_MAX_CODE) {
-        return GIF_ERROR;
-    }
-
-    if (StackPtr != 0) {
-        /* Let pop the stack off before continueing to read the GIF
-         * file: */
-        while (StackPtr != 0 && i < LineLen) {
-            Line[i++] = Stack[--StackPtr];
-        }
-    }
-
-    while (i < LineLen) { /* Decode LineLen items. */
-        if (DGifDecompressInput(GifFile, &CrntCode) == GIF_ERROR) {
-            return GIF_ERROR;
-        }
-
-        if (CrntCode == EOFCode) {
-            /* Note however that usually we will not be here as we
-             * will stop decoding as soon as we got all the pixel,
-             * or EOF code will not be read at all, and
-             * DGifGetLine/Pixel clean everything.  */
-            GifFile->Error = D_GIF_ERR_EOF_TOO_SOON;
-            return GIF_ERROR;
-        } else if (CrntCode == ClearCode) {
-            /* We need to start over again: */
-            for (j = 0; j <= LZ_MAX_CODE; j++) {
-                Prefix[j] = NO_SUCH_CODE;
-            }
-            Private->RunningCode = Private->EOFCode + 1;
-            Private->RunningBits = Private->BitsPerPixel + 1;
-            Private->MaxCode1 = 1 << Private->RunningBits;
-            LastCode = Private->LastCode = NO_SUCH_CODE;
-        } else {
-            /* Its regular code - if in pixel range simply add it to
-             * output stream, otherwise trace to codes linked list
-             * until the prefix is in pixel range: */
-            if (CrntCode < ClearCode) {
-                /* This is simple - its pixel scalar, so add it
-                 * to output: */
-                Line[i++] = CrntCode;
-            } else {
-                /* Its a code to needed to be traced: trace the
-                 * linked list until the prefix is a pixel,
-                 * while pushing the suffix pixels on our stack.
-                 * If we done, pop the stack in reverse (thats
-                 * what stack is good for!) order to output.  */
-                if (Prefix[CrntCode] == NO_SUCH_CODE) {
-                    CrntPrefix = LastCode;
-
-                    /* Only allowed if CrntCode is exactly
-                     * the running code: In that case
-                     * CrntCode = XXXCode, CrntCode or the
-                     * prefix code is last code and the
-                     * suffix char is exactly the prefix of
-                     * last code! */
-                    if (CrntCode ==
-                        Private->RunningCode - 2) {
-                        Suffix[Private->RunningCode -
-                               2] = Stack[StackPtr++] =
-                            DGifGetPrefixChar(
-                                Prefix, LastCode,
-                                ClearCode);
-                    } else {
-                        Suffix[Private->RunningCode -
-                               2] = Stack[StackPtr++] =
-                            DGifGetPrefixChar(
-                                Prefix, CrntCode,
-                                ClearCode);
-                    }
-                } else {
-                    CrntPrefix = CrntCode;
-                }
+        int i = 0;
+        int j, CrntCode, EOFCode, ClearCode, CrntPrefix, LastCode, StackPtr;
+        GifByteType *Stack, *Suffix;
+        GifPrefixType *Prefix;
+        GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
+
+        StackPtr = Private->StackPtr;
+        Prefix = Private->Prefix;
+        Suffix = Private->Suffix;
+        Stack = Private->Stack;
+        EOFCode = Private->EOFCode;
+        ClearCode = Private->ClearCode;
+        LastCode = Private->LastCode;
+
+        if (StackPtr > LZ_MAX_CODE) {
+                return GIF_ERROR;
+        }
 
-                /* Now (if image is O.K.) we should not get a
-                 * NO_SUCH_CODE during the trace. As we might
-                 * loop forever, in case of defective image, we
-                 * use StackPtr as loop counter and stop before
-                 * overflowing Stack[]. */
-                while (StackPtr < LZ_MAX_CODE &&
-                       CrntPrefix > ClearCode &&
-                       CrntPrefix <= LZ_MAX_CODE) {
-                    Stack[StackPtr++] = Suffix[CrntPrefix];
-                    CrntPrefix = Prefix[CrntPrefix];
-                }
-                if (StackPtr >= LZ_MAX_CODE ||
-                    CrntPrefix > LZ_MAX_CODE) {
-                    GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
-                    return GIF_ERROR;
+        if (StackPtr != 0) {
+                /* Let pop the stack off before continueing to read the GIF
+                 * file: */
+                while (StackPtr != 0 && i < LineLen) {
+                        Line[i++] = Stack[--StackPtr];
                 }
-                /* Push the last character on stack: */
-                Stack[StackPtr++] = CrntPrefix;
+        }
 
-                /* Now lets pop all the stack into output: */
-                while (StackPtr != 0 && i < LineLen) {
-                    Line[i++] = Stack[--StackPtr];
+        while (i < LineLen) { /* Decode LineLen items. */
+                if (DGifDecompressInput(GifFile, &CrntCode) == GIF_ERROR) {
+                        return GIF_ERROR;
                 }
-            }
-            if (LastCode != NO_SUCH_CODE &&
-                Private->RunningCode - 2 < (LZ_MAX_CODE + 1) &&
-                Prefix[Private->RunningCode - 2] == NO_SUCH_CODE) {
-                Prefix[Private->RunningCode - 2] = LastCode;
-
-                if (CrntCode == Private->RunningCode - 2) {
-                    /* Only allowed if CrntCode is exactly
-                     * the running code: In that case
-                     * CrntCode = XXXCode, CrntCode or the
-                     * prefix code is last code and the
-                     * suffix char is exactly the prefix of
-                     * last code! */
-                    Suffix[Private->RunningCode - 2] =
-                        DGifGetPrefixChar(Prefix, LastCode,
-                                          ClearCode);
+
+                if (CrntCode == EOFCode) {
+                        /* Note however that usually we will not be here as we
+                         * will stop decoding as soon as we got all the pixel,
+                         * or EOF code will not be read at all, and
+                         * DGifGetLine/Pixel clean everything.  */
+                        GifFile->Error = D_GIF_ERR_EOF_TOO_SOON;
+                        return GIF_ERROR;
+                } else if (CrntCode == ClearCode) {
+                        /* We need to start over again: */
+                        for (j = 0; j <= LZ_MAX_CODE; j++) {
+                                Prefix[j] = NO_SUCH_CODE;
+                        }
+                        Private->RunningCode = Private->EOFCode + 1;
+                        Private->RunningBits = Private->BitsPerPixel + 1;
+                        Private->MaxCode1 = 1 << Private->RunningBits;
+                        LastCode = Private->LastCode = NO_SUCH_CODE;
                 } else {
-                    Suffix[Private->RunningCode - 2] =
-                        DGifGetPrefixChar(Prefix, CrntCode,
-                                          ClearCode);
+                        /* Its regular code - if in pixel range simply add it to
+                         * output stream, otherwise trace to codes linked list
+                         * until the prefix is in pixel range: */
+                        if (CrntCode < ClearCode) {
+                                /* This is simple - its pixel scalar, so add it
+                                 * to output: */
+                                Line[i++] = CrntCode;
+                        } else {
+                                /* Its a code to needed to be traced: trace the
+                                 * linked list until the prefix is a pixel,
+                                 * while pushing the suffix pixels on our stack.
+                                 * If we done, pop the stack in reverse (thats
+                                 * what stack is good for!) order to output.  */
+                                if (Prefix[CrntCode] == NO_SUCH_CODE) {
+                                        CrntPrefix = LastCode;
+
+                                        /* Only allowed if CrntCode is exactly
+                                         * the running code: In that case
+                                         * CrntCode = XXXCode, CrntCode or the
+                                         * prefix code is last code and the
+                                         * suffix char is exactly the prefix of
+                                         * last code! */
+                                        if (CrntCode ==
+                                            Private->RunningCode - 2) {
+                                                Suffix[Private->RunningCode -
+                                                       2] = Stack[StackPtr++] =
+                                                    DGifGetPrefixChar(
+                                                        Prefix, LastCode,
+                                                        ClearCode);
+                                        } else {
+                                                Suffix[Private->RunningCode -
+                                                       2] = Stack[StackPtr++] =
+                                                    DGifGetPrefixChar(
+                                                        Prefix, CrntCode,
+                                                        ClearCode);
+                                        }
+                                } else {
+                                        CrntPrefix = CrntCode;
+                                }
+
+                                /* Now (if image is O.K.) we should not get a
+                                 * NO_SUCH_CODE during the trace. As we might
+                                 * loop forever, in case of defective image, we
+                                 * use StackPtr as loop counter and stop before
+                                 * overflowing Stack[]. */
+                                while (StackPtr < LZ_MAX_CODE &&
+                                       CrntPrefix > ClearCode &&
+                                       CrntPrefix <= LZ_MAX_CODE) {
+                                        Stack[StackPtr++] = Suffix[CrntPrefix];
+                                        CrntPrefix = Prefix[CrntPrefix];
+                                }
+                                if (StackPtr >= LZ_MAX_CODE ||
+                                    CrntPrefix > LZ_MAX_CODE) {
+                                        GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
+                                        return GIF_ERROR;
+                                }
+                                /* Push the last character on stack: */
+                                Stack[StackPtr++] = CrntPrefix;
+
+                                /* Now lets pop all the stack into output: */
+                                while (StackPtr != 0 && i < LineLen) {
+                                        Line[i++] = Stack[--StackPtr];
+                                }
+                        }
+                        if (LastCode != NO_SUCH_CODE &&
+                            Private->RunningCode - 2 < (LZ_MAX_CODE + 1) &&
+                            Prefix[Private->RunningCode - 2] == NO_SUCH_CODE) {
+                                Prefix[Private->RunningCode - 2] = LastCode;
+
+                                if (CrntCode == Private->RunningCode - 2) {
+                                        /* Only allowed if CrntCode is exactly
+                                         * the running code: In that case
+                                         * CrntCode = XXXCode, CrntCode or the
+                                         * prefix code is last code and the
+                                         * suffix char is exactly the prefix of
+                                         * last code! */
+                                        Suffix[Private->RunningCode - 2] =
+                                            DGifGetPrefixChar(Prefix, LastCode,
+                                                              ClearCode);
+                                } else {
+                                        Suffix[Private->RunningCode - 2] =
+                                            DGifGetPrefixChar(Prefix, CrntCode,
+                                                              ClearCode);
+                                }
+                        }
+                        LastCode = CrntCode;
                 }
-            }
-            LastCode = CrntCode;
         }
-    }
 
-    Private->LastCode = LastCode;
-    Private->StackPtr = StackPtr;
+        Private->LastCode = LastCode;
+        Private->StackPtr = StackPtr;
 
-    return GIF_OK;
+        return GIF_OK;
 }
 
 /******************************************************************************
@@ -1031,15 +1033,15 @@ static int DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line,
 ******************************************************************************/
 static int DGifGetPrefixChar(const GifPrefixType *Prefix, int Code,
                              int ClearCode) {
-    int i = 0;
+        int i = 0;
 
-    while (Code > ClearCode && i++ <= LZ_MAX_CODE) {
-        if (Code > LZ_MAX_CODE) {
-            return NO_SUCH_CODE;
+        while (Code > ClearCode && i++ <= LZ_MAX_CODE) {
+                if (Code > LZ_MAX_CODE) {
+                        return NO_SUCH_CODE;
+                }
+                Code = Prefix[Code];
         }
-        Code = Prefix[Code];
-    }
-    return Code;
+        return Code;
 }
 
 /******************************************************************************
@@ -1047,37 +1049,37 @@ static int DGifGetPrefixChar(const GifPrefixType *Prefix, int Code,
  (12bits), or to -1 if EOF code is returned.
 ******************************************************************************/
 int DGifGetLZCodes(GifFileType *GifFile, int *Code) {
-    GifByteType *CodeBlock;
-    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
-
-    if (!IS_READABLE(Private)) {
-        /* This file was NOT open for reading: */
-        GifFile->Error = D_GIF_ERR_NOT_READABLE;
-        return GIF_ERROR;
-    }
+        GifByteType *CodeBlock;
+        GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
-    if (DGifDecompressInput(GifFile, Code) == GIF_ERROR) {
-        return GIF_ERROR;
-    }
+        if (!IS_READABLE(Private)) {
+                /* This file was NOT open for reading: */
+                GifFile->Error = D_GIF_ERR_NOT_READABLE;
+                return GIF_ERROR;
+        }
 
-    if (*Code == Private->EOFCode) {
-        /* Skip rest of codes (hopefully only NULL terminating block):
-         */
-        do {
-            if (DGifGetCodeNext(GifFile, &CodeBlock) == GIF_ERROR) {
+        if (DGifDecompressInput(GifFile, Code) == GIF_ERROR) {
                 return GIF_ERROR;
-            }
-        } while (CodeBlock != NULL);
+        }
 
-        *Code = -1;
-    } else if (*Code == Private->ClearCode) {
-        /* We need to start over again: */
-        Private->RunningCode = Private->EOFCode + 1;
-        Private->RunningBits = Private->BitsPerPixel + 1;
-        Private->MaxCode1 = 1 << Private->RunningBits;
-    }
+        if (*Code == Private->EOFCode) {
+                /* Skip rest of codes (hopefully only NULL terminating block):
+                 */
+                do {
+                        if (DGifGetCodeNext(GifFile, &CodeBlock) == GIF_ERROR) {
+                                return GIF_ERROR;
+                        }
+                } while (CodeBlock != NULL);
+
+                *Code = -1;
+        } else if (*Code == Private->ClearCode) {
+                /* We need to start over again: */
+                Private->RunningCode = Private->EOFCode + 1;
+                Private->RunningBits = Private->BitsPerPixel + 1;
+                Private->MaxCode1 = 1 << Private->RunningBits;
+        }
 
-    return GIF_OK;
+        return GIF_OK;
 }
 
 /******************************************************************************
@@ -1087,47 +1089,47 @@ int DGifGetLZCodes(GifFileType *GifFile, int *Code) {
  Returns GIF_OK if read successfully.
 ******************************************************************************/
 static int DGifDecompressInput(GifFileType *GifFile, int *Code) {
-    static const unsigned short CodeMasks[] = {
-        0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f,
-        0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff};
+        static const unsigned short CodeMasks[] = {
+            0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f,
+            0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff};
 
-    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
+        GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
-    GifByteType NextByte;
+        GifByteType NextByte;
 
-    /* The image can't contain more than LZ_BITS per code. */
-    if (Private->RunningBits > LZ_BITS) {
-        GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
-        return GIF_ERROR;
-    }
-
-    while (Private->CrntShiftState < Private->RunningBits) {
-        /* Needs to get more bytes from input stream for next code: */
-        if (DGifBufferedInput(GifFile, Private->Buf, &NextByte) ==
-            GIF_ERROR) {
-            return GIF_ERROR;
-        }
-        Private->CrntShiftDWord |= ((unsigned long)NextByte)
-                                   << Private->CrntShiftState;
-        Private->CrntShiftState += 8;
-    }
-    *Code = Private->CrntShiftDWord & CodeMasks[Private->RunningBits];
-
-    Private->CrntShiftDWord >>= Private->RunningBits;
-    Private->CrntShiftState -= Private->RunningBits;
-
-    /* If code cannot fit into RunningBits bits, must raise its size. Note
-     * however that codes above 4095 are used for special signaling.
-     * If we're using LZ_BITS bits already and we're at the max code, just
-     * keep using the table as it is, don't increment Private->RunningCode.
-     */
-    if (Private->RunningCode < LZ_MAX_CODE + 2 &&
-        ++Private->RunningCode > Private->MaxCode1 &&
-        Private->RunningBits < LZ_BITS) {
-        Private->MaxCode1 <<= 1;
-        Private->RunningBits++;
-    }
-    return GIF_OK;
+        /* The image can't contain more than LZ_BITS per code. */
+        if (Private->RunningBits > LZ_BITS) {
+                GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
+                return GIF_ERROR;
+        }
+
+        while (Private->CrntShiftState < Private->RunningBits) {
+                /* Needs to get more bytes from input stream for next code: */
+                if (DGifBufferedInput(GifFile, Private->Buf, &NextByte) ==
+                    GIF_ERROR) {
+                        return GIF_ERROR;
+                }
+                Private->CrntShiftDWord |= ((unsigned long)NextByte)
+                                           << Private->CrntShiftState;
+                Private->CrntShiftState += 8;
+        }
+        *Code = Private->CrntShiftDWord & CodeMasks[Private->RunningBits];
+
+        Private->CrntShiftDWord >>= Private->RunningBits;
+        Private->CrntShiftState -= Private->RunningBits;
+
+        /* If code cannot fit into RunningBits bits, must raise its size. Note
+         * however that codes above 4095 are used for special signaling.
+         * If we're using LZ_BITS bits already and we're at the max code, just
+         * keep using the table as it is, don't increment Private->RunningCode.
+         */
+        if (Private->RunningCode < LZ_MAX_CODE + 2 &&
+            ++Private->RunningCode > Private->MaxCode1 &&
+            Private->RunningBits < LZ_BITS) {
+                Private->MaxCode1 <<= 1;
+                Private->RunningBits++;
+        }
+        return GIF_OK;
 }
 
 /******************************************************************************
@@ -1138,34 +1140,34 @@ static int DGifDecompressInput(GifFileType *GifFile, int *Code) {
 ******************************************************************************/
 static int DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf,
                              GifByteType *NextByte) {
-    if (Buf[0] == 0) {
-        /* Needs to read the next buffer - this one is empty: */
-        /* coverity[check_return] */
-        if (InternalRead(GifFile, Buf, 1) != 1) {
-            GifFile->Error = D_GIF_ERR_READ_FAILED;
-            return GIF_ERROR;
-        }
-        /* There shouldn't be any empty data blocks here as the LZW spec
-         * says the LZW termination code should come first.  Therefore
-         * we shouldn't be inside this routine at that point.
-         */
         if (Buf[0] == 0) {
-            GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
-            return GIF_ERROR;
-        }
-        if (InternalRead(GifFile, &Buf[1], Buf[0]) != Buf[0]) {
-            GifFile->Error = D_GIF_ERR_READ_FAILED;
-            return GIF_ERROR;
-        }
-        *NextByte = Buf[1];
-        Buf[1] = 2; /* We use now the second place as last char read! */
-        Buf[0]--;
-    } else {
-        *NextByte = Buf[Buf[1]++];
-        Buf[0]--;
-    }
-
-    return GIF_OK;
+                /* Needs to read the next buffer - this one is empty: */
+                /* coverity[check_return] */
+                if (InternalRead(GifFile, Buf, 1) != 1) {
+                        GifFile->Error = D_GIF_ERR_READ_FAILED;
+                        return GIF_ERROR;
+                }
+                /* There shouldn't be any empty data blocks here as the LZW spec
+                 * says the LZW termination code should come first.  Therefore
+                 * we shouldn't be inside this routine at that point.
+                 */
+                if (Buf[0] == 0) {
+                        GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
+                        return GIF_ERROR;
+                }
+                if (InternalRead(GifFile, &Buf[1], Buf[0]) != Buf[0]) {
+                        GifFile->Error = D_GIF_ERR_READ_FAILED;
+                        return GIF_ERROR;
+                }
+                *NextByte = Buf[1];
+                Buf[1] = 2; /* We use now the second place as last char read! */
+                Buf[0]--;
+        } else {
+                *NextByte = Buf[Buf[1]++];
+                Buf[0]--;
+        }
+
+        return GIF_OK;
 }
 
 /******************************************************************************
@@ -1175,17 +1177,20 @@ static int DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf,
  SavedImages may point to the spoilt image and null pointer buffers.
 *******************************************************************************/
 void DGifDecreaseImageCounter(GifFileType *GifFile) {
-    GifFile->ImageCount--;
-    if (GifFile->SavedImages[GifFile->ImageCount].RasterBits != NULL) {
-        free(GifFile->SavedImages[GifFile->ImageCount].RasterBits);
-    }
-
-    // Realloc array according to the new image counter.
-    SavedImage *correct_saved_images = (SavedImage *)reallocarray(
-        GifFile->SavedImages, GifFile->ImageCount, sizeof(SavedImage));
-    if (correct_saved_images != NULL) {
-        GifFile->SavedImages = correct_saved_images;
-    }
+        GifFile->ImageCount--;
+        if (GifFile->SavedImages[GifFile->ImageCount].RasterBits != NULL) {
+                free(GifFile->SavedImages[GifFile->ImageCount].RasterBits);
+        }
+        if (GifFile->SavedImages[GifFile->ImageCount].ImageDesc.ColorMap != NULL) {
+                GifFreeMapObject(GifFile->SavedImages[GifFile->ImageCount].ImageDesc.ColorMap);
+        }
+
+        // Realloc array according to the new image counter.
+        SavedImage *correct_saved_images = (SavedImage *)reallocarray(
+            GifFile->SavedImages, GifFile->ImageCount, sizeof(SavedImage));
+        if (correct_saved_images != NULL) {
+                GifFile->SavedImages = correct_saved_images;
+        }
 }
 
 /******************************************************************************
@@ -1194,143 +1199,143 @@ void DGifDecreaseImageCounter(GifFileType *GifFile) {
  first to initialize I/O.  Its inverse is EGifSpew().
 *******************************************************************************/
 int DGifSlurp(GifFileType *GifFile) {
-    size_t ImageSize;
-    GifRecordType RecordType;
-    SavedImage *sp;
-    GifByteType *ExtData;
-    int ExtFunction;
+        size_t ImageSize;
+        GifRecordType RecordType;
+        SavedImage *sp;
+        GifByteType *ExtData;
+        int ExtFunction;
 
-    GifFile->ExtensionBlocks = NULL;
-    GifFile->ExtensionBlockCount = 0;
+        GifFile->ExtensionBlocks = NULL;
+        GifFile->ExtensionBlockCount = 0;
 
-    do {
-        if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
-            return (GIF_ERROR);
-        }
+        do {
+                if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
+                        return (GIF_ERROR);
+                }
 
-        switch (RecordType) {
-        case IMAGE_DESC_RECORD_TYPE:
-            if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
-                return (GIF_ERROR);
-            }
-
-            sp = &GifFile->SavedImages[GifFile->ImageCount - 1];
-            /* Allocate memory for the image */
-            if (sp->ImageDesc.Width <= 0 ||
-                sp->ImageDesc.Height <= 0 ||
-                sp->ImageDesc.Width >
-                    (INT_MAX / sp->ImageDesc.Height)) {
-                DGifDecreaseImageCounter(GifFile);
-                return GIF_ERROR;
-            }
-            ImageSize = sp->ImageDesc.Width * sp->ImageDesc.Height;
+                switch (RecordType) {
+                case IMAGE_DESC_RECORD_TYPE:
+                        if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
+                                return (GIF_ERROR);
+                        }
 
-            if (ImageSize > (SIZE_MAX / sizeof(GifPixelType))) {
-                DGifDecreaseImageCounter(GifFile);
-                return GIF_ERROR;
-            }
-            sp->RasterBits = (unsigned char *)reallocarray(
-                NULL, ImageSize, sizeof(GifPixelType));
+                        sp = &GifFile->SavedImages[GifFile->ImageCount - 1];
+                        /* Allocate memory for the image */
+                        if (sp->ImageDesc.Width <= 0 ||
+                            sp->ImageDesc.Height <= 0 ||
+                            sp->ImageDesc.Width >
+                                (INT_MAX / sp->ImageDesc.Height)) {
+                                DGifDecreaseImageCounter(GifFile);
+                                return GIF_ERROR;
+                        }
+                        ImageSize = sp->ImageDesc.Width * sp->ImageDesc.Height;
 
-            if (sp->RasterBits == NULL) {
-                DGifDecreaseImageCounter(GifFile);
-                return GIF_ERROR;
-            }
+                        if (ImageSize > (SIZE_MAX / sizeof(GifPixelType))) {
+                                DGifDecreaseImageCounter(GifFile);
+                                return GIF_ERROR;
+                        }
+                        sp->RasterBits = (unsigned char *)reallocarray(
+                            NULL, ImageSize, sizeof(GifPixelType));
 
-            if (sp->ImageDesc.Interlace) {
-                int i, j;
-                /*
-                 * The way an interlaced image should be read -
-                 * offsets and jumps...
-                 */
-                static const int InterlacedOffset[] = {0, 4, 2,
-                                                       1};
-                static const int InterlacedJumps[] = {8, 8, 4,
-                                                      2};
-                /* Need to perform 4 passes on the image */
-                for (i = 0; i < 4; i++) {
-                    for (j = InterlacedOffset[i];
-                         j < sp->ImageDesc.Height;
-                         j += InterlacedJumps[i]) {
-                        if (DGifGetLine(
-                                GifFile,
-                                sp->RasterBits +
-                                    j * sp->ImageDesc
-                                            .Width,
-                                sp->ImageDesc.Width) ==
-                            GIF_ERROR) {
-                            DGifDecreaseImageCounter(
-                                GifFile);
-                            return GIF_ERROR;
+                        if (sp->RasterBits == NULL) {
+                                DGifDecreaseImageCounter(GifFile);
+                                return GIF_ERROR;
                         }
-                    }
-                }
-            } else {
-                if (DGifGetLine(GifFile, sp->RasterBits,
-                                ImageSize) == GIF_ERROR) {
-                    DGifDecreaseImageCounter(GifFile);
-                    return GIF_ERROR;
-                }
-            }
 
-            if (GifFile->ExtensionBlocks) {
-                sp->ExtensionBlocks = GifFile->ExtensionBlocks;
-                sp->ExtensionBlockCount =
-                    GifFile->ExtensionBlockCount;
+                        if (sp->ImageDesc.Interlace) {
+                                int i, j;
+                                /*
+                                 * The way an interlaced image should be read -
+                                 * offsets and jumps...
+                                 */
+                                static const int InterlacedOffset[] = {0, 4, 2,
+                                                                       1};
+                                static const int InterlacedJumps[] = {8, 8, 4,
+                                                                      2};
+                                /* Need to perform 4 passes on the image */
+                                for (i = 0; i < 4; i++) {
+                                        for (j = InterlacedOffset[i];
+                                             j < sp->ImageDesc.Height;
+                                             j += InterlacedJumps[i]) {
+                                                if (DGifGetLine(
+                                                        GifFile,
+                                                        sp->RasterBits +
+                                                            j * sp->ImageDesc
+                                                                    .Width,
+                                                        sp->ImageDesc.Width) ==
+                                                    GIF_ERROR) {
+                                                        DGifDecreaseImageCounter(
+                                                            GifFile);
+                                                        return GIF_ERROR;
+                                                }
+                                        }
+                                }
+                        } else {
+                                if (DGifGetLine(GifFile, sp->RasterBits,
+                                                ImageSize) == GIF_ERROR) {
+                                        DGifDecreaseImageCounter(GifFile);
+                                        return GIF_ERROR;
+                                }
+                        }
 
-                GifFile->ExtensionBlocks = NULL;
-                GifFile->ExtensionBlockCount = 0;
-            }
-            break;
+                        if (GifFile->ExtensionBlocks) {
+                                sp->ExtensionBlocks = GifFile->ExtensionBlocks;
+                                sp->ExtensionBlockCount =
+                                    GifFile->ExtensionBlockCount;
 
-        case EXTENSION_RECORD_TYPE:
-            if (DGifGetExtension(GifFile, &ExtFunction, &ExtData) ==
-                GIF_ERROR) {
-                return (GIF_ERROR);
-            }
-            /* Create an extension block with our data */
-            if (ExtData != NULL) {
-                if (GifAddExtensionBlock(
-                        &GifFile->ExtensionBlockCount,
-                        &GifFile->ExtensionBlocks, ExtFunction,
-                        ExtData[0], &ExtData[1]) == GIF_ERROR) {
-                    return (GIF_ERROR);
-                }
-            }
-            for (;;) {
-                if (DGifGetExtensionNext(GifFile, &ExtData) ==
-                    GIF_ERROR) {
-                    return (GIF_ERROR);
-                }
-                if (ExtData == NULL) {
-                    break;
-                }
-                /* Continue the extension block */
-                if (GifAddExtensionBlock(
-                        &GifFile->ExtensionBlockCount,
-                        &GifFile->ExtensionBlocks,
-                        CONTINUE_EXT_FUNC_CODE, ExtData[0],
-                        &ExtData[1]) == GIF_ERROR) {
-                    return (GIF_ERROR);
-                }
-            }
-            break;
+                                GifFile->ExtensionBlocks = NULL;
+                                GifFile->ExtensionBlockCount = 0;
+                        }
+                        break;
+
+                case EXTENSION_RECORD_TYPE:
+                        if (DGifGetExtension(GifFile, &ExtFunction, &ExtData) ==
+                            GIF_ERROR) {
+                                return (GIF_ERROR);
+                        }
+                        /* Create an extension block with our data */
+                        if (ExtData != NULL) {
+                                if (GifAddExtensionBlock(
+                                        &GifFile->ExtensionBlockCount,
+                                        &GifFile->ExtensionBlocks, ExtFunction,
+                                        ExtData[0], &ExtData[1]) == GIF_ERROR) {
+                                        return (GIF_ERROR);
+                                }
+                        }
+                        for (;;) {
+                                if (DGifGetExtensionNext(GifFile, &ExtData) ==
+                                    GIF_ERROR) {
+                                        return (GIF_ERROR);
+                                }
+                                if (ExtData == NULL) {
+                                        break;
+                                }
+                                /* Continue the extension block */
+                                if (GifAddExtensionBlock(
+                                        &GifFile->ExtensionBlockCount,
+                                        &GifFile->ExtensionBlocks,
+                                        CONTINUE_EXT_FUNC_CODE, ExtData[0],
+                                        &ExtData[1]) == GIF_ERROR) {
+                                        return (GIF_ERROR);
+                                }
+                        }
+                        break;
 
-        case TERMINATE_RECORD_TYPE:
-            break;
+                case TERMINATE_RECORD_TYPE:
+                        break;
 
-        default: /* Should be trapped by DGifGetRecordType */
-            break;
-        }
-    } while (RecordType != TERMINATE_RECORD_TYPE);
+                default: /* Should be trapped by DGifGetRecordType */
+                        break;
+                }
+        } while (RecordType != TERMINATE_RECORD_TYPE);
 
-    /* Sanity check for corrupted file */
-    if (GifFile->ImageCount == 0) {
-        GifFile->Error = D_GIF_ERR_NO_IMAG_DSCR;
-        return (GIF_ERROR);
-    }
+        /* Sanity check for corrupted file */
+        if (GifFile->ImageCount == 0) {
+                GifFile->Error = D_GIF_ERR_NO_IMAG_DSCR;
+                return (GIF_ERROR);
+        }
 
-    return (GIF_OK);
+        return (GIF_OK);
 }
 
 /* end */
diff --git a/src/java.desktop/share/native/libsplashscreen/giflib/gif_err.c b/src/java.desktop/share/native/libsplashscreen/giflib/gif_err.c
index 3b6785f7c63..a3cc03b8865 100644
--- a/src/java.desktop/share/native/libsplashscreen/giflib/gif_err.c
+++ b/src/java.desktop/share/native/libsplashscreen/giflib/gif_err.c
@@ -26,9 +26,9 @@
 
 gif_err.c - handle error reporting for the GIF library.
 
-SPDX-License-Identifier: MIT
-
 ****************************************************************************/
+// SPDX-License-Identifier: MIT
+// SPDX-File-Copyright-Txt: (C) Copyright 1989 Gershon Elber
 
 #include 
 
@@ -39,83 +39,83 @@ SPDX-License-Identifier: MIT
  Return a string description of  the last GIF error
 *****************************************************************************/
 const char *GifErrorString(int ErrorCode) {
-    const char *Err;
+        const char *Err;
 
-    switch (ErrorCode) {
-    case E_GIF_ERR_OPEN_FAILED:
-        Err = "Failed to open given file";
-        break;
-    case E_GIF_ERR_WRITE_FAILED:
-        Err = "Failed to write to given file";
-        break;
-    case E_GIF_ERR_HAS_SCRN_DSCR:
-        Err = "Screen descriptor has already been set";
-        break;
-    case E_GIF_ERR_HAS_IMAG_DSCR:
-        Err = "Image descriptor is still active";
-        break;
-    case E_GIF_ERR_NO_COLOR_MAP:
-        Err = "Neither global nor local color map";
-        break;
-    case E_GIF_ERR_DATA_TOO_BIG:
-        Err = "Number of pixels bigger than width * height";
-        break;
-    case E_GIF_ERR_NOT_ENOUGH_MEM:
-        Err = "Failed to allocate required memory";
-        break;
-    case E_GIF_ERR_DISK_IS_FULL:
-        Err = "Write failed (disk full?)";
-        break;
-    case E_GIF_ERR_CLOSE_FAILED:
-        Err = "Failed to close given file";
-        break;
-    case E_GIF_ERR_NOT_WRITEABLE:
-        Err = "Given file was not opened for write";
-        break;
-    case D_GIF_ERR_OPEN_FAILED:
-        Err = "Failed to open given file";
-        break;
-    case D_GIF_ERR_READ_FAILED:
-        Err = "Failed to read from given file";
-        break;
-    case D_GIF_ERR_NOT_GIF_FILE:
-        Err = "Data is not in GIF format";
-        break;
-    case D_GIF_ERR_NO_SCRN_DSCR:
-        Err = "No screen descriptor detected";
-        break;
-    case D_GIF_ERR_NO_IMAG_DSCR:
-        Err = "No Image Descriptor detected";
-        break;
-    case D_GIF_ERR_NO_COLOR_MAP:
-        Err = "Neither global nor local color map";
-        break;
-    case D_GIF_ERR_WRONG_RECORD:
-        Err = "Wrong record type detected";
-        break;
-    case D_GIF_ERR_DATA_TOO_BIG:
-        Err = "Number of pixels bigger than width * height";
-        break;
-    case D_GIF_ERR_NOT_ENOUGH_MEM:
-        Err = "Failed to allocate required memory";
-        break;
-    case D_GIF_ERR_CLOSE_FAILED:
-        Err = "Failed to close given file";
-        break;
-    case D_GIF_ERR_NOT_READABLE:
-        Err = "Given file was not opened for read";
-        break;
-    case D_GIF_ERR_IMAGE_DEFECT:
-        Err = "Image is defective, decoding aborted";
-        break;
-    case D_GIF_ERR_EOF_TOO_SOON:
-        Err = "Image EOF detected before image complete";
-        break;
-    default:
-        Err = NULL;
-        break;
-    }
-    return Err;
+        switch (ErrorCode) {
+        case E_GIF_ERR_OPEN_FAILED:
+                Err = "Failed to open given file";
+                break;
+        case E_GIF_ERR_WRITE_FAILED:
+                Err = "Failed to write to given file";
+                break;
+        case E_GIF_ERR_HAS_SCRN_DSCR:
+                Err = "Screen descriptor has already been set";
+                break;
+        case E_GIF_ERR_HAS_IMAG_DSCR:
+                Err = "Image descriptor is still active";
+                break;
+        case E_GIF_ERR_NO_COLOR_MAP:
+                Err = "Neither global nor local color map";
+                break;
+        case E_GIF_ERR_DATA_TOO_BIG:
+                Err = "Number of pixels bigger than width * height";
+                break;
+        case E_GIF_ERR_NOT_ENOUGH_MEM:
+                Err = "Failed to allocate required memory";
+                break;
+        case E_GIF_ERR_DISK_IS_FULL:
+                Err = "Write failed (disk full?)";
+                break;
+        case E_GIF_ERR_CLOSE_FAILED:
+                Err = "Failed to close given file";
+                break;
+        case E_GIF_ERR_NOT_WRITEABLE:
+                Err = "Given file was not opened for write";
+                break;
+        case D_GIF_ERR_OPEN_FAILED:
+                Err = "Failed to open given file";
+                break;
+        case D_GIF_ERR_READ_FAILED:
+                Err = "Failed to read from given file";
+                break;
+        case D_GIF_ERR_NOT_GIF_FILE:
+                Err = "Data is not in GIF format";
+                break;
+        case D_GIF_ERR_NO_SCRN_DSCR:
+                Err = "No screen descriptor detected";
+                break;
+        case D_GIF_ERR_NO_IMAG_DSCR:
+                Err = "No Image Descriptor detected";
+                break;
+        case D_GIF_ERR_NO_COLOR_MAP:
+                Err = "Neither global nor local color map";
+                break;
+        case D_GIF_ERR_WRONG_RECORD:
+                Err = "Wrong record type detected";
+                break;
+        case D_GIF_ERR_DATA_TOO_BIG:
+                Err = "Number of pixels bigger than width * height";
+                break;
+        case D_GIF_ERR_NOT_ENOUGH_MEM:
+                Err = "Failed to allocate required memory";
+                break;
+        case D_GIF_ERR_CLOSE_FAILED:
+                Err = "Failed to close given file";
+                break;
+        case D_GIF_ERR_NOT_READABLE:
+                Err = "Given file was not opened for read";
+                break;
+        case D_GIF_ERR_IMAGE_DEFECT:
+                Err = "Image is defective, decoding aborted";
+                break;
+        case D_GIF_ERR_EOF_TOO_SOON:
+                Err = "Image EOF detected before image complete";
+                break;
+        default:
+                Err = NULL;
+                break;
+        }
+        return Err;
 }
 
 /* end */
diff --git a/src/java.desktop/share/native/libsplashscreen/giflib/gif_hash.h b/src/java.desktop/share/native/libsplashscreen/giflib/gif_hash.h
index bd00af64161..eb3cba3135f 100644
--- a/src/java.desktop/share/native/libsplashscreen/giflib/gif_hash.h
+++ b/src/java.desktop/share/native/libsplashscreen/giflib/gif_hash.h
@@ -26,9 +26,8 @@
 
 gif_hash.h - magfic constants and declarations for GIF LZW
 
-SPDX-License-Identifier: MIT
-
 ******************************************************************************/
+// SPDX-License-Identifier: MIT
 
 #ifndef _GIF_HASH_H_
 #define _GIF_HASH_H_
@@ -46,7 +45,7 @@ SPDX-License-Identifier: MIT
 
 /* The 32 bits of the long are divided into two parts for the key & code:   */
 /* 1. The code is 12 bits as our compression algorithm is limited to 12bits */
-/* 2. The key is 12 bits Prefix code + 8 bit new char or 20 bits.        */
+/* 2. The key is 12 bits Prefix code + 8 bit new char or 20 bits.           */
 /* The key is the upper 20 bits.  The code is the lower 12. */
 #define HT_GET_KEY(l) (l >> 12)
 #define HT_GET_CODE(l) (l & 0x0FFF)
@@ -54,7 +53,7 @@ SPDX-License-Identifier: MIT
 #define HT_PUT_CODE(l) (l & 0x0FFF)
 
 typedef struct GifHashTableType {
-    uint32_t HTable[HT_SIZE];
+        uint32_t HTable[HT_SIZE];
 } GifHashTableType;
 
 GifHashTableType *_InitHashTable(void);
diff --git a/src/java.desktop/share/native/libsplashscreen/giflib/gif_lib.h b/src/java.desktop/share/native/libsplashscreen/giflib/gif_lib.h
index 74a2e969c0d..64b33beefa7 100644
--- a/src/java.desktop/share/native/libsplashscreen/giflib/gif_lib.h
+++ b/src/java.desktop/share/native/libsplashscreen/giflib/gif_lib.h
@@ -37,8 +37,8 @@ SPDX-License-Identifier: MIT
 extern "C" {
 #endif /* __cplusplus */
 
-#define GIFLIB_MAJOR 5
-#define GIFLIB_MINOR 2
+#define GIFLIB_MAJOR 6
+#define GIFLIB_MINOR 1
 #define GIFLIB_RELEASE 2
 
 #define GIF_ERROR 0
@@ -60,26 +60,26 @@ typedef unsigned int GifPrefixType;
 typedef int GifWord;
 
 typedef struct GifColorType {
-    GifByteType Red, Green, Blue;
+        GifByteType Red, Green, Blue;
 } GifColorType;
 
 typedef struct ColorMapObject {
-    int ColorCount;
-    int BitsPerPixel;
-    bool SortFlag;
-    GifColorType *Colors; /* on malloc(3) heap */
+        int ColorCount;
+        int BitsPerPixel;
+        bool SortFlag;
+        GifColorType *Colors; /* on malloc(3) heap */
 } ColorMapObject;
 
 typedef struct GifImageDesc {
-    GifWord Left, Top, Width, Height; /* Current image dimensions. */
-    bool Interlace;                   /* Sequential/Interlaced lines. */
-    ColorMapObject *ColorMap;         /* The local color map */
+        GifWord Left, Top, Width, Height; /* Current image dimensions. */
+        bool Interlace;                   /* Sequential/Interlaced lines. */
+        ColorMapObject *ColorMap;         /* The local color map */
 } GifImageDesc;
 
 typedef struct ExtensionBlock {
-    int ByteCount;
-    GifByteType *Bytes;            /* on malloc(3) heap */
-    int Function;                  /* The block function code */
+        int ByteCount;
+        GifByteType *Bytes;            /* on malloc(3) heap */
+        int Function;                  /* The block function code */
 #define CONTINUE_EXT_FUNC_CODE 0x00    /* continuation subblock */
 #define COMMENT_EXT_FUNC_CODE 0xfe     /* comment */
 #define GRAPHICS_EXT_FUNC_CODE 0xf9    /* graphics control (GIF89) */
@@ -88,36 +88,36 @@ typedef struct ExtensionBlock {
 } ExtensionBlock;
 
 typedef struct SavedImage {
-    GifImageDesc ImageDesc;
-    GifByteType *RasterBits;         /* on malloc(3) heap */
-    int ExtensionBlockCount;         /* Count of extensions before image */
-    ExtensionBlock *ExtensionBlocks; /* Extensions before image */
+        GifImageDesc ImageDesc;
+        GifByteType *RasterBits;         /* on malloc(3) heap */
+        int ExtensionBlockCount;         /* Count of extensions before image */
+        ExtensionBlock *ExtensionBlocks; /* Extensions before image */
 } SavedImage;
 
 typedef struct GifFileType {
-    GifWord SWidth, SHeight;   /* Size of virtual canvas */
-    GifWord SColorResolution;  /* How many colors can we generate? */
-    GifWord SBackGroundColor;  /* Background color for virtual canvas */
-    GifByteType AspectByte;    /* Used to compute pixel aspect ratio */
-    ColorMapObject *SColorMap; /* Global colormap, NULL if nonexistent. */
-    int ImageCount;            /* Number of current image (both APIs) */
-    GifImageDesc Image;        /* Current image (low-level API) */
-    SavedImage *SavedImages;   /* Image sequence (high-level API) */
-    int ExtensionBlockCount;   /* Count extensions past last image */
-    ExtensionBlock *ExtensionBlocks; /* Extensions past last image */
-    int Error;                       /* Last error condition reported */
-    void *UserData;                  /* hook to attach user data (TVT) */
-    void *Private;                   /* Don't mess with this! */
+        GifWord SWidth, SHeight;   /* Size of virtual canvas */
+        GifWord SColorResolution;  /* How many colors can we generate? */
+        GifWord SBackGroundColor;  /* Background color for virtual canvas */
+        GifByteType AspectByte;    /* Used to compute pixel aspect ratio */
+        ColorMapObject *SColorMap; /* Global colormap, NULL if nonexistent. */
+        int ImageCount;            /* Number of current image (both APIs) */
+        GifImageDesc Image;        /* Current image (low-level API) */
+        SavedImage *SavedImages;   /* Image sequence (high-level API) */
+        int ExtensionBlockCount;   /* Count extensions past last image */
+        ExtensionBlock *ExtensionBlocks; /* Extensions past last image */
+        int Error;                       /* Last error condition reported */
+        void *UserData;                  /* hook to attach user data (TVT) */
+        void *Private;                   /* Don't mess with this! */
 } GifFileType;
 
 #define GIF_ASPECT_RATIO(n) ((n) + 15.0 / 64.0)
 
 typedef enum {
-    UNDEFINED_RECORD_TYPE,
-    SCREEN_DESC_RECORD_TYPE,
-    IMAGE_DESC_RECORD_TYPE, /* Begin with ',' */
-    EXTENSION_RECORD_TYPE,  /* Begin with '!' */
-    TERMINATE_RECORD_TYPE   /* Begin with ';' */
+        UNDEFINED_RECORD_TYPE,
+        SCREEN_DESC_RECORD_TYPE,
+        IMAGE_DESC_RECORD_TYPE, /* Begin with ',' */
+        EXTENSION_RECORD_TYPE,  /* Begin with '!' */
+        TERMINATE_RECORD_TYPE   /* Begin with ';' */
 } GifRecordType;
 
 /* func type to read gif data from arbitrary sources (TVT) */
@@ -133,14 +133,14 @@ typedef int (*OutputFunc)(GifFileType *, const GifByteType *, int);
 ******************************************************************************/
 
 typedef struct GraphicsControlBlock {
-    int DisposalMode;
+        int DisposalMode;
 #define DISPOSAL_UNSPECIFIED 0 /* No disposal specified. */
 #define DISPOSE_DO_NOT 1       /* Leave image in place */
 #define DISPOSE_BACKGROUND 2   /* Set area too background color */
 #define DISPOSE_PREVIOUS 3     /* Restore to previous content */
-    bool UserInputFlag;    /* User confirmation required before disposal */
-    int DelayTime;         /* pre-display delay in 0.01sec units */
-    int TransparentColor;  /* Palette index for transparency, -1 if none */
+        bool UserInputFlag;    /* User confirmation required before disposal */
+        int DelayTime;         /* pre-display delay in 0.01sec units */
+        int TransparentColor;  /* Palette index for transparency, -1 if none */
 #define NO_TRANSPARENT_COLOR -1
 } GraphicsControlBlock;
 
@@ -153,21 +153,21 @@ GifFileType *EGifOpenFileName(const char *GifFileName,
                               const bool GifTestExistence, int *Error);
 GifFileType *EGifOpenFileHandle(const int GifFileHandle, int *Error);
 GifFileType *EGifOpen(void *userPtr, OutputFunc writeFunc, int *Error);
-int EGifSpew(GifFileType *GifFile);
+int EGifSpew(GifFileType *GifFile, int *ErrorCode);
 const char *EGifGetGifVersion(GifFileType *GifFile); /* new in 5.x */
 int EGifCloseFile(GifFileType *GifFile, int *ErrorCode);
 
 #define E_GIF_SUCCEEDED 0
-#define E_GIF_ERR_OPEN_FAILED 1 /* And EGif possible errors. */
-#define E_GIF_ERR_WRITE_FAILED 2
-#define E_GIF_ERR_HAS_SCRN_DSCR 3
-#define E_GIF_ERR_HAS_IMAG_DSCR 4
-#define E_GIF_ERR_NO_COLOR_MAP 5
-#define E_GIF_ERR_DATA_TOO_BIG 6
-#define E_GIF_ERR_NOT_ENOUGH_MEM 7
-#define E_GIF_ERR_DISK_IS_FULL 8
-#define E_GIF_ERR_CLOSE_FAILED 9
-#define E_GIF_ERR_NOT_WRITEABLE 10
+#define E_GIF_ERR_OPEN_FAILED 201 /* And EGif possible errors. */
+#define E_GIF_ERR_WRITE_FAILED 202
+#define E_GIF_ERR_HAS_SCRN_DSCR 203
+#define E_GIF_ERR_HAS_IMAG_DSCR 204
+#define E_GIF_ERR_NO_COLOR_MAP 205
+#define E_GIF_ERR_DATA_TOO_BIG 206
+#define E_GIF_ERR_NOT_ENOUGH_MEM 207
+#define E_GIF_ERR_DISK_IS_FULL 208
+#define E_GIF_ERR_CLOSE_FAILED 209
+#define E_GIF_ERR_NOT_WRITEABLE 210
 
 /* These are legacy.  You probably do not want to call them directly */
 int EGifPutScreenDesc(GifFileType *GifFile, const int GifWidth,
diff --git a/src/java.desktop/share/native/libsplashscreen/giflib/gif_lib_private.h b/src/java.desktop/share/native/libsplashscreen/giflib/gif_lib_private.h
index f905e0d7b48..079d05898b4 100644
--- a/src/java.desktop/share/native/libsplashscreen/giflib/gif_lib_private.h
+++ b/src/java.desktop/share/native/libsplashscreen/giflib/gif_lib_private.h
@@ -60,30 +60,30 @@ SPDX-License-Identifier: MIT
 #define IS_WRITEABLE(Private) (Private->FileState & FILE_STATE_WRITE)
 
 typedef struct GifFilePrivateType {
-    GifWord FileState, FileHandle, /* Where all this data goes to! */
-        BitsPerPixel, /* Bits per pixel (Codes uses at least this + 1). */
-        ClearCode,    /* The CLEAR LZ code. */
-        EOFCode,      /* The EOF LZ code. */
-        RunningCode,  /* The next code algorithm can generate. */
-        RunningBits,  /* The number of bits required to represent
-                         RunningCode. */
-        MaxCode1, /* 1 bigger than max. possible code, in RunningBits bits.
-                   */
-        LastCode, /* The code before the current code. */
-        CrntCode, /* Current algorithm code. */
-        StackPtr, /* For character stack (see below). */
-        CrntShiftState;           /* Number of bits in CrntShiftDWord. */
-    unsigned long CrntShiftDWord; /* For bytes decomposition into codes. */
-    unsigned long PixelCount;     /* Number of pixels in image. */
-    FILE *File;                   /* File as stream. */
-    InputFunc Read;               /* function to read gif input (TVT) */
-    OutputFunc Write;             /* function to write gif output (MRB) */
-    GifByteType Buf[256];         /* Compressed input is buffered here. */
-    GifByteType Stack[LZ_MAX_CODE]; /* Decoded pixels are stacked here. */
-    GifByteType Suffix[LZ_MAX_CODE + 1]; /* So we can trace the codes. */
-    GifPrefixType Prefix[LZ_MAX_CODE + 1];
-    GifHashTableType *HashTable;
-    bool gif89;
+        GifWord FileState, FileHandle, /* Where all this data goes to! */
+            BitsPerPixel, /* Bits per pixel (Codes uses at least this + 1). */
+            ClearCode,    /* The CLEAR LZ code. */
+            EOFCode,      /* The EOF LZ code. */
+            RunningCode,  /* The next code algorithm can generate. */
+            RunningBits,  /* The number of bits required to represent
+                             RunningCode. */
+            MaxCode1, /* 1 bigger than max. possible code, in RunningBits bits.
+                       */
+            LastCode, /* The code before the current code. */
+            CrntCode, /* Current algorithm code. */
+            StackPtr, /* For character stack (see below). */
+            CrntShiftState;           /* Number of bits in CrntShiftDWord. */
+        unsigned long CrntShiftDWord; /* For bytes decomposition into codes. */
+        unsigned long PixelCount;     /* Number of pixels in image. */
+        FILE *File;                   /* File as stream. */
+        InputFunc Read;               /* function to read gif input (TVT) */
+        OutputFunc Write;             /* function to write gif output (MRB) */
+        GifByteType Buf[256];         /* Compressed input is buffered here. */
+        GifByteType Stack[LZ_MAX_CODE]; /* Decoded pixels are stacked here. */
+        GifByteType Suffix[LZ_MAX_CODE + 1]; /* So we can trace the codes. */
+        GifPrefixType Prefix[LZ_MAX_CODE + 1];
+        GifHashTableType *HashTable;
+        bool gif89;
 } GifFilePrivateType;
 
 #ifndef HAVE_REALLOCARRAY
diff --git a/src/java.desktop/share/native/libsplashscreen/giflib/gifalloc.c b/src/java.desktop/share/native/libsplashscreen/giflib/gifalloc.c
index 5aef3044558..25e03914496 100644
--- a/src/java.desktop/share/native/libsplashscreen/giflib/gifalloc.c
+++ b/src/java.desktop/share/native/libsplashscreen/giflib/gifalloc.c
@@ -26,9 +26,9 @@
 
  GIF construction tools
 
-SPDX-License-Identifier: MIT
-
 ****************************************************************************/
+// SPDX-License-Identifier: MIT
+// SPDX-FileCopyrightText: Copyright (C) Eric S. Raymond 
 
 #include 
 #include 
@@ -45,14 +45,14 @@ SPDX-License-Identifier: MIT
 
 /* return smallest bitfield size n will fit in */
 int GifBitSize(int n) {
-    register int i;
+        register int i;
 
-    for (i = 1; i <= 8; i++) {
-        if ((1 << i) >= n) {
-            break;
+        for (i = 1; i <= 8; i++) {
+                if ((1 << i) >= n) {
+                        break;
+                }
         }
-    }
-    return (i);
+        return (i);
 }
 
 /******************************************************************************
@@ -64,64 +64,64 @@ int GifBitSize(int n) {
  * ColorMap if that pointer is non-NULL.
  */
 ColorMapObject *GifMakeMapObject(int ColorCount, const GifColorType *ColorMap) {
-    ColorMapObject *Object;
-
-    /*** FIXME: Our ColorCount has to be a power of two.  Is it necessary to
-     * make the user know that or should we automatically round up instead?
-     */
-    if (ColorCount != (1 << GifBitSize(ColorCount))) {
-        return ((ColorMapObject *)NULL);
-    }
-
-    Object = (ColorMapObject *)malloc(sizeof(ColorMapObject));
-    if (Object == (ColorMapObject *)NULL) {
-        return ((ColorMapObject *)NULL);
-    }
-
-    Object->Colors =
-        (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
-    if (Object->Colors == (GifColorType *)NULL) {
-        free(Object);
-        return ((ColorMapObject *)NULL);
-    }
-
-    Object->ColorCount = ColorCount;
-    Object->BitsPerPixel = GifBitSize(ColorCount);
-    Object->SortFlag = false;
-
-    if (ColorMap != NULL) {
-        memcpy((char *)Object->Colors, (char *)ColorMap,
-               ColorCount * sizeof(GifColorType));
-    }
-
-    return (Object);
+        ColorMapObject *Object;
+
+        /*** FIXME: Our ColorCount has to be a power of two.  Is it necessary to
+         * make the user know that or should we automatically round up instead?
+         */
+        if (ColorCount != (1 << GifBitSize(ColorCount))) {
+                return ((ColorMapObject *)NULL);
+        }
+
+        Object = (ColorMapObject *)malloc(sizeof(ColorMapObject));
+        if (Object == (ColorMapObject *)NULL) {
+                return ((ColorMapObject *)NULL);
+        }
+
+        Object->Colors =
+            (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
+        if (Object->Colors == (GifColorType *)NULL) {
+                free(Object);
+                return ((ColorMapObject *)NULL);
+        }
+
+        Object->ColorCount = ColorCount;
+        Object->BitsPerPixel = GifBitSize(ColorCount);
+        Object->SortFlag = false;
+
+        if (ColorMap != NULL) {
+                memcpy((char *)Object->Colors, (char *)ColorMap,
+                       ColorCount * sizeof(GifColorType));
+        }
+
+        return (Object);
 }
 
 /*******************************************************************************
  Free a color map object
 *******************************************************************************/
 void GifFreeMapObject(ColorMapObject *Object) {
-    if (Object != NULL) {
-        (void)free(Object->Colors);
-        (void)free(Object);
-    }
+        if (Object != NULL) {
+                (void)free(Object->Colors);
+                (void)free(Object);
+        }
 }
 
 #ifdef DEBUG
 void DumpColorMap(ColorMapObject *Object, FILE *fp) {
-    if (Object != NULL) {
-        int i, j, Len = Object->ColorCount;
-
-        for (i = 0; i < Len; i += 4) {
-            for (j = 0; j < 4 && j < Len; j++) {
-                (void)fprintf(fp, "%3d: %02x %02x %02x   ",
-                              i + j, Object->Colors[i + j].Red,
-                              Object->Colors[i + j].Green,
-                              Object->Colors[i + j].Blue);
-            }
-            (void)fprintf(fp, "\n");
+        if (Object != NULL) {
+                int i, j, Len = Object->ColorCount;
+
+                for (i = 0; i < Len; i += 4) {
+                        for (j = 0; j < 4 && j < Len; j++) {
+                                (void)fprintf(fp, "%3d: %02x %02x %02x   ",
+                                              i + j, Object->Colors[i + j].Red,
+                                              Object->Colors[i + j].Green,
+                                              Object->Colors[i + j].Blue);
+                        }
+                        (void)fprintf(fp, "\n");
+                }
         }
-    }
 }
 #endif /* DEBUG */
 
@@ -135,112 +135,112 @@ void DumpColorMap(ColorMapObject *Object, FILE *fp) {
 ColorMapObject *GifUnionColorMap(const ColorMapObject *ColorIn1,
                                  const ColorMapObject *ColorIn2,
                                  GifPixelType ColorTransIn2[]) {
-    int i, j, CrntSlot, RoundUpTo, NewGifBitSize;
-    ColorMapObject *ColorUnion;
-
-    /*
-     * We don't worry about duplicates within either color map; if
-     * the caller wants to resolve those, he can perform unions
-     * with an empty color map.
-     */
-
-    /* Allocate table which will hold the result for sure. */
-    ColorUnion = GifMakeMapObject(
-        MAX(ColorIn1->ColorCount, ColorIn2->ColorCount) * 2, NULL);
-
-    if (ColorUnion == NULL) {
-        return (NULL);
-    }
-
-    /*
-     * Copy ColorIn1 to ColorUnion.
-     */
-    for (i = 0; i < ColorIn1->ColorCount; i++) {
-        ColorUnion->Colors[i] = ColorIn1->Colors[i];
-    }
-    CrntSlot = ColorIn1->ColorCount;
-
-    /*
-     * Potentially obnoxious hack:
-     *
-     * Back CrntSlot down past all contiguous {0, 0, 0} slots at the end
-     * of table 1.  This is very useful if your display is limited to
-     * 16 colors.
-     */
-    while (ColorIn1->Colors[CrntSlot - 1].Red == 0 &&
-           ColorIn1->Colors[CrntSlot - 1].Green == 0 &&
-           ColorIn1->Colors[CrntSlot - 1].Blue == 0) {
-        CrntSlot--;
-    }
-
-    /* Copy ColorIn2 to ColorUnion (use old colors if they exist): */
-    for (i = 0; i < ColorIn2->ColorCount && CrntSlot <= 256; i++) {
-        /* Let's see if this color already exists: */
-        for (j = 0; j < ColorIn1->ColorCount; j++) {
-            if (memcmp(&ColorIn1->Colors[j], &ColorIn2->Colors[i],
-                       sizeof(GifColorType)) == 0) {
-                break;
-            }
-        }
+        int i, j, CrntSlot, RoundUpTo, NewGifBitSize;
+        ColorMapObject *ColorUnion;
 
-        if (j < ColorIn1->ColorCount) {
-            ColorTransIn2[i] = j; /* color exists in Color1 */
-        } else {
-            /* Color is new - copy it to a new slot: */
-            ColorUnion->Colors[CrntSlot] = ColorIn2->Colors[i];
-            ColorTransIn2[i] = CrntSlot++;
-        }
-    }
+        /*
+         * We don't worry about duplicates within either color map; if
+         * the caller wants to resolve those, he can perform unions
+         * with an empty color map.
+         */
 
-    if (CrntSlot > 256) {
-        GifFreeMapObject(ColorUnion);
-        return ((ColorMapObject *)NULL);
-    }
+        /* Allocate table which will hold the result for sure. */
+        ColorUnion = GifMakeMapObject(
+            MAX(ColorIn1->ColorCount, ColorIn2->ColorCount) * 2, NULL);
 
-    NewGifBitSize = GifBitSize(CrntSlot);
-    RoundUpTo = (1 << NewGifBitSize);
+        if (ColorUnion == NULL) {
+                return (NULL);
+        }
 
-    if (RoundUpTo != ColorUnion->ColorCount) {
-        register GifColorType *Map = ColorUnion->Colors;
+        /*
+         * Copy ColorIn1 to ColorUnion.
+         */
+        for (i = 0; i < ColorIn1->ColorCount; i++) {
+                ColorUnion->Colors[i] = ColorIn1->Colors[i];
+        }
+        CrntSlot = ColorIn1->ColorCount;
 
         /*
-         * Zero out slots up to next power of 2.
-         * We know these slots exist because of the way ColorUnion's
-         * start dimension was computed.
+         * Potentially obnoxious hack:
+         *
+         * Back CrntSlot down past all contiguous {0, 0, 0} slots at the end
+         * of table 1.  This is very useful if your display is limited to
+         * 16 colors.
          */
-        for (j = CrntSlot; j < RoundUpTo; j++) {
-            Map[j].Red = Map[j].Green = Map[j].Blue = 0;
+        while (ColorIn1->Colors[CrntSlot - 1].Red == 0 &&
+               ColorIn1->Colors[CrntSlot - 1].Green == 0 &&
+               ColorIn1->Colors[CrntSlot - 1].Blue == 0) {
+                CrntSlot--;
         }
 
-        /* perhaps we can shrink the map? */
-        if (RoundUpTo < ColorUnion->ColorCount) {
-            GifColorType *new_map = (GifColorType *)reallocarray(
-                Map, RoundUpTo, sizeof(GifColorType));
-            if (new_map == NULL) {
+        /* Copy ColorIn2 to ColorUnion (use old colors if they exist): */
+        for (i = 0; i < ColorIn2->ColorCount && CrntSlot <= 256; i++) {
+                /* Let's see if this color already exists: */
+                for (j = 0; j < ColorIn1->ColorCount; j++) {
+                        if (memcmp(&ColorIn1->Colors[j], &ColorIn2->Colors[i],
+                                   sizeof(GifColorType)) == 0) {
+                                break;
+                        }
+                }
+
+                if (j < ColorIn1->ColorCount) {
+                        ColorTransIn2[i] = j; /* color exists in Color1 */
+                } else {
+                        /* Color is new - copy it to a new slot: */
+                        ColorUnion->Colors[CrntSlot] = ColorIn2->Colors[i];
+                        ColorTransIn2[i] = CrntSlot++;
+                }
+        }
+
+        if (CrntSlot > 256) {
                 GifFreeMapObject(ColorUnion);
                 return ((ColorMapObject *)NULL);
-            }
-            ColorUnion->Colors = new_map;
         }
-    }
 
-    ColorUnion->ColorCount = RoundUpTo;
-    ColorUnion->BitsPerPixel = NewGifBitSize;
+        NewGifBitSize = GifBitSize(CrntSlot);
+        RoundUpTo = (1 << NewGifBitSize);
+
+        if (RoundUpTo != ColorUnion->ColorCount) {
+                register GifColorType *Map = ColorUnion->Colors;
+
+                /*
+                 * Zero out slots up to next power of 2.
+                 * We know these slots exist because of the way ColorUnion's
+                 * start dimension was computed.
+                 */
+                for (j = CrntSlot; j < RoundUpTo; j++) {
+                        Map[j].Red = Map[j].Green = Map[j].Blue = 0;
+                }
+
+                /* perhaps we can shrink the map? */
+                if (RoundUpTo < ColorUnion->ColorCount) {
+                        GifColorType *new_map = (GifColorType *)reallocarray(
+                            Map, RoundUpTo, sizeof(GifColorType));
+                        if (new_map == NULL) {
+                                GifFreeMapObject(ColorUnion);
+                                return ((ColorMapObject *)NULL);
+                        }
+                        ColorUnion->Colors = new_map;
+                }
+        }
 
-    return (ColorUnion);
+        ColorUnion->ColorCount = RoundUpTo;
+        ColorUnion->BitsPerPixel = NewGifBitSize;
+
+        return (ColorUnion);
 }
 
 /*******************************************************************************
  Apply a given color translation to the raster bits of an image
 *******************************************************************************/
 void GifApplyTranslation(SavedImage *Image, const GifPixelType Translation[]) {
-    register int i;
-    register int RasterSize =
-        Image->ImageDesc.Height * Image->ImageDesc.Width;
+        register int i;
+        register int RasterSize =
+            Image->ImageDesc.Height * Image->ImageDesc.Width;
 
-    for (i = 0; i < RasterSize; i++) {
-        Image->RasterBits[i] = Translation[Image->RasterBits[i]];
-    }
+        for (i = 0; i < RasterSize; i++) {
+                Image->RasterBits[i] = Translation[Image->RasterBits[i]];
+        }
 }
 
 /******************************************************************************
@@ -249,56 +249,56 @@ void GifApplyTranslation(SavedImage *Image, const GifPixelType Translation[]) {
 int GifAddExtensionBlock(int *ExtensionBlockCount,
                          ExtensionBlock **ExtensionBlocks, int Function,
                          unsigned int Len, unsigned char ExtData[]) {
-    ExtensionBlock *ep;
-
-    if (*ExtensionBlocks == NULL) {
-        *ExtensionBlocks =
-            (ExtensionBlock *)malloc(sizeof(ExtensionBlock));
-    } else {
-        ExtensionBlock *ep_new = (ExtensionBlock *)reallocarray(
-            *ExtensionBlocks, (*ExtensionBlockCount + 1),
-            sizeof(ExtensionBlock));
-        if (ep_new == NULL) {
-            return (GIF_ERROR);
+        ExtensionBlock *ep;
+
+        if (*ExtensionBlocks == NULL) {
+                *ExtensionBlocks =
+                    (ExtensionBlock *)malloc(sizeof(ExtensionBlock));
+        } else {
+                ExtensionBlock *ep_new = (ExtensionBlock *)reallocarray(
+                    *ExtensionBlocks, (*ExtensionBlockCount + 1),
+                    sizeof(ExtensionBlock));
+                if (ep_new == NULL) {
+                        return (GIF_ERROR);
+                }
+                *ExtensionBlocks = ep_new;
         }
-        *ExtensionBlocks = ep_new;
-    }
 
-    if (*ExtensionBlocks == NULL) {
-        return (GIF_ERROR);
-    }
+        if (*ExtensionBlocks == NULL) {
+                return (GIF_ERROR);
+        }
 
-    ep = &(*ExtensionBlocks)[(*ExtensionBlockCount)++];
+        ep = &(*ExtensionBlocks)[(*ExtensionBlockCount)++];
 
-    ep->Function = Function;
-    ep->ByteCount = Len;
-    ep->Bytes = (GifByteType *)malloc(ep->ByteCount);
-    if (ep->Bytes == NULL) {
-        return (GIF_ERROR);
-    }
+        ep->Function = Function;
+        ep->ByteCount = Len;
+        ep->Bytes = (GifByteType *)malloc(ep->ByteCount);
+        if (ep->Bytes == NULL) {
+                return (GIF_ERROR);
+        }
 
-    if (ExtData != NULL) {
-        memcpy(ep->Bytes, ExtData, Len);
-    }
+        if (ExtData != NULL) {
+                memcpy(ep->Bytes, ExtData, Len);
+        }
 
-    return (GIF_OK);
+        return (GIF_OK);
 }
 
 void GifFreeExtensions(int *ExtensionBlockCount,
                        ExtensionBlock **ExtensionBlocks) {
-    ExtensionBlock *ep;
-
-    if (*ExtensionBlocks == NULL) {
-        return;
-    }
-
-    for (ep = *ExtensionBlocks;
-         ep < (*ExtensionBlocks + *ExtensionBlockCount); ep++) {
-        (void)free((char *)ep->Bytes);
-    }
-    (void)free((char *)*ExtensionBlocks);
-    *ExtensionBlocks = NULL;
-    *ExtensionBlockCount = 0;
+        ExtensionBlock *ep;
+
+        if (*ExtensionBlocks == NULL) {
+                return;
+        }
+
+        for (ep = *ExtensionBlocks;
+             ep < (*ExtensionBlocks + *ExtensionBlockCount); ep++) {
+                (void)free((char *)ep->Bytes);
+        }
+        (void)free((char *)*ExtensionBlocks);
+        *ExtensionBlocks = NULL;
+        *ExtensionBlockCount = 0;
 }
 
 /******************************************************************************
@@ -309,37 +309,37 @@ void GifFreeExtensions(int *ExtensionBlockCount,
  * Frees the last image in the GifFile->SavedImages array
  */
 void FreeLastSavedImage(GifFileType *GifFile) {
-    SavedImage *sp;
-
-    if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) {
-        return;
-    }
-
-    /* Remove one SavedImage from the GifFile */
-    GifFile->ImageCount--;
-    sp = &GifFile->SavedImages[GifFile->ImageCount];
-
-    /* Deallocate its Colormap */
-    if (sp->ImageDesc.ColorMap != NULL) {
-        GifFreeMapObject(sp->ImageDesc.ColorMap);
-        sp->ImageDesc.ColorMap = NULL;
-    }
-
-    /* Deallocate the image data */
-    if (sp->RasterBits != NULL) {
-        free((char *)sp->RasterBits);
-    }
-
-    /* Deallocate any extensions */
-    GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
-
-    /*** FIXME: We could realloc the GifFile->SavedImages structure but is
-     * there a point to it? Saves some memory but we'd have to do it every
-     * time.  If this is used in GifFreeSavedImages then it would be
-     * inefficient (The whole array is going to be deallocated.)  If we just
-     * use it when we want to free the last Image it's convenient to do it
-     * here.
-     */
+        SavedImage *sp;
+
+        if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) {
+                return;
+        }
+
+        /* Remove one SavedImage from the GifFile */
+        GifFile->ImageCount--;
+        sp = &GifFile->SavedImages[GifFile->ImageCount];
+
+        /* Deallocate its Colormap */
+        if (sp->ImageDesc.ColorMap != NULL) {
+                GifFreeMapObject(sp->ImageDesc.ColorMap);
+                sp->ImageDesc.ColorMap = NULL;
+        }
+
+        /* Deallocate the image data */
+        if (sp->RasterBits != NULL) {
+                free((char *)sp->RasterBits);
+        }
+
+        /* Deallocate any extensions */
+        GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
+
+        /*** FIXME: We could realloc the GifFile->SavedImages structure but is
+         * there a point to it? Saves some memory but we'd have to do it every
+         * time.  If this is used in GifFreeSavedImages then it would be
+         * inefficient (The whole array is going to be deallocated.)  If we just
+         * use it when we want to free the last Image it's convenient to do it
+         * here.
+         */
 }
 
 /*
@@ -347,103 +347,129 @@ void FreeLastSavedImage(GifFileType *GifFile) {
  */
 SavedImage *GifMakeSavedImage(GifFileType *GifFile,
                               const SavedImage *CopyFrom) {
-    // cppcheck-suppress ctunullpointer
-    if (GifFile->SavedImages == NULL) {
-        GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
-    } else {
-        SavedImage *newSavedImages = (SavedImage *)reallocarray(
-            GifFile->SavedImages, (GifFile->ImageCount + 1),
-            sizeof(SavedImage));
-        if (newSavedImages == NULL) {
-            return ((SavedImage *)NULL);
-        }
-        GifFile->SavedImages = newSavedImages;
-    }
-    if (GifFile->SavedImages == NULL) {
-        return ((SavedImage *)NULL);
-    } else {
-        SavedImage *sp = &GifFile->SavedImages[GifFile->ImageCount++];
-
-        if (CopyFrom != NULL) {
-            memcpy((char *)sp, CopyFrom, sizeof(SavedImage));
-
-            /*
-             * Make our own allocated copies of the heap fields in
-             * the copied record.  This guards against potential
-             * aliasing problems.
-             */
-
-            /* first, the local color map */
-            if (CopyFrom->ImageDesc.ColorMap != NULL) {
-                sp->ImageDesc.ColorMap = GifMakeMapObject(
-                    CopyFrom->ImageDesc.ColorMap->ColorCount,
-                    CopyFrom->ImageDesc.ColorMap->Colors);
-                if (sp->ImageDesc.ColorMap == NULL) {
-                    FreeLastSavedImage(GifFile);
-                    return (SavedImage *)(NULL);
-                }
-            }
-
-            /* next, the raster */
-            sp->RasterBits = (unsigned char *)reallocarray(
-                NULL,
-                (CopyFrom->ImageDesc.Height *
-                 CopyFrom->ImageDesc.Width),
-                sizeof(GifPixelType));
-            if (sp->RasterBits == NULL) {
-                FreeLastSavedImage(GifFile);
-                return (SavedImage *)(NULL);
-            }
-            memcpy(sp->RasterBits, CopyFrom->RasterBits,
-                   sizeof(GifPixelType) *
-                       CopyFrom->ImageDesc.Height *
-                       CopyFrom->ImageDesc.Width);
-
-            /* finally, the extension blocks */
-            if (CopyFrom->ExtensionBlocks != NULL) {
-                sp->ExtensionBlocks =
-                    (ExtensionBlock *)reallocarray(
-                        NULL, CopyFrom->ExtensionBlockCount,
-                        sizeof(ExtensionBlock));
-                if (sp->ExtensionBlocks == NULL) {
-                    FreeLastSavedImage(GifFile);
-                    return (SavedImage *)(NULL);
-                }
-                memcpy(sp->ExtensionBlocks,
-                       CopyFrom->ExtensionBlocks,
-                       sizeof(ExtensionBlock) *
-                           CopyFrom->ExtensionBlockCount);
-            }
+        // cppcheck-suppress ctunullpointer
+        if (GifFile->SavedImages == NULL) {
+                GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
         } else {
-            memset((char *)sp, '\0', sizeof(SavedImage));
+                SavedImage *newSavedImages = (SavedImage *)reallocarray(
+                    GifFile->SavedImages, (GifFile->ImageCount + 1),
+                    sizeof(SavedImage));
+                if (newSavedImages == NULL) {
+                        return ((SavedImage *)NULL);
+                }
+                GifFile->SavedImages = newSavedImages;
         }
+        if (GifFile->SavedImages == NULL) {
+                return ((SavedImage *)NULL);
+        } else {
+                SavedImage *sp = &GifFile->SavedImages[GifFile->ImageCount++];
+
+                if (CopyFrom != NULL) {
+                        memcpy((char *)sp, CopyFrom, sizeof(SavedImage));
+
+                        /*
+                         * Make our own allocated copies of the heap fields in
+                         * the copied record.  This guards against potential
+                         * aliasing problems.
+                         */
+
+                        /* Null out aliased pointers before any allocations
+                         * so that FreeLastSavedImage won't free CopyFrom's
+                         * data if an allocation fails partway through. */
+                        sp->ImageDesc.ColorMap = NULL;
+                        sp->RasterBits = NULL;
+                        sp->ExtensionBlocks = NULL;
+                        sp->ExtensionBlockCount = 0;
+
+                        /* first, the local color map */
+                        if (CopyFrom->ImageDesc.ColorMap != NULL) {
+                                sp->ImageDesc.ColorMap = GifMakeMapObject(
+                                    CopyFrom->ImageDesc.ColorMap->ColorCount,
+                                    CopyFrom->ImageDesc.ColorMap->Colors);
+                                if (sp->ImageDesc.ColorMap == NULL) {
+                                        FreeLastSavedImage(GifFile);
+                                        return (SavedImage *)(NULL);
+                                }
+                        }
+
+                        /* next, the raster */
+                        sp->RasterBits = (unsigned char *)reallocarray(
+                            NULL,
+                            (CopyFrom->ImageDesc.Height *
+                             CopyFrom->ImageDesc.Width),
+                            sizeof(GifPixelType));
+                        if (sp->RasterBits == NULL) {
+                                FreeLastSavedImage(GifFile);
+                                return (SavedImage *)(NULL);
+                        }
+                        memcpy(sp->RasterBits, CopyFrom->RasterBits,
+                               sizeof(GifPixelType) *
+                                   CopyFrom->ImageDesc.Height *
+                                   CopyFrom->ImageDesc.Width);
+
+                        /* finally, the extension blocks */
+                        if (CopyFrom->ExtensionBlocks != NULL) {
+                                int k;
+                                sp->ExtensionBlocks =
+                                    (ExtensionBlock *)calloc(
+                                        CopyFrom->ExtensionBlockCount,
+                                        sizeof(ExtensionBlock));
+                                if (sp->ExtensionBlocks == NULL) {
+                                        FreeLastSavedImage(GifFile);
+                                        return (SavedImage *)(NULL);
+                                }
+                                for (k = 0; k < CopyFrom->ExtensionBlockCount;
+                                     k++) {
+                                        ExtensionBlock *dst =
+                                            &sp->ExtensionBlocks[k];
+                                        ExtensionBlock *src =
+                                            &CopyFrom->ExtensionBlocks[k];
+                                        dst->Function = src->Function;
+                                        dst->ByteCount = src->ByteCount;
+                                        if (src->ByteCount > 0) {
+                                                dst->Bytes =
+                                                    (GifByteType *)malloc(
+                                                        src->ByteCount);
+                                                if (dst->Bytes == NULL) {
+                                                        FreeLastSavedImage(
+                                                            GifFile);
+                                                        return (SavedImage *)(NULL);
+                                                }
+                                                memcpy(dst->Bytes, src->Bytes,
+                                                       src->ByteCount);
+                                        }
+                                }
+                        }
+                } else {
+                        memset((char *)sp, '\0', sizeof(SavedImage));
+                }
 
-        return (sp);
-    }
+                return (sp);
+        }
 }
 
 void GifFreeSavedImages(GifFileType *GifFile) {
-    SavedImage *sp;
+        SavedImage *sp;
 
-    if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) {
-        return;
-    }
-    for (sp = GifFile->SavedImages;
-         sp < GifFile->SavedImages + GifFile->ImageCount; sp++) {
-        if (sp->ImageDesc.ColorMap != NULL) {
-            GifFreeMapObject(sp->ImageDesc.ColorMap);
-            sp->ImageDesc.ColorMap = NULL;
+        if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) {
+                return;
         }
+        for (sp = GifFile->SavedImages;
+             sp < GifFile->SavedImages + GifFile->ImageCount; sp++) {
+                if (sp->ImageDesc.ColorMap != NULL) {
+                        GifFreeMapObject(sp->ImageDesc.ColorMap);
+                        sp->ImageDesc.ColorMap = NULL;
+                }
 
-        if (sp->RasterBits != NULL) {
-            free((char *)sp->RasterBits);
-        }
+                if (sp->RasterBits != NULL) {
+                        free((char *)sp->RasterBits);
+                }
 
-        GifFreeExtensions(&sp->ExtensionBlockCount,
-                          &sp->ExtensionBlocks);
-    }
-    free((char *)GifFile->SavedImages);
-    GifFile->SavedImages = NULL;
+                GifFreeExtensions(&sp->ExtensionBlockCount,
+                                  &sp->ExtensionBlocks);
+        }
+        free((char *)GifFile->SavedImages);
+        GifFile->SavedImages = NULL;
 }
 
 /* end */
diff --git a/src/java.desktop/share/native/libsplashscreen/giflib/openbsd-reallocarray.c b/src/java.desktop/share/native/libsplashscreen/giflib/openbsd-reallocarray.c
index 7420af674c5..57504fceaa9 100644
--- a/src/java.desktop/share/native/libsplashscreen/giflib/openbsd-reallocarray.c
+++ b/src/java.desktop/share/native/libsplashscreen/giflib/openbsd-reallocarray.c
@@ -22,9 +22,8 @@
  * questions.
  */
 
-/*    $OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $    */
 /*
- * Copyright (c) 2008 Otto Moerbeek 
+ * SPDX-FileCopyrightText: Copyright (C) 2008 Otto Moerbeek 
  * SPDX-License-Identifier: MIT
  */
 
@@ -44,55 +43,55 @@
 #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
 
 void *openbsd_reallocarray(void *optr, size_t nmemb, size_t size) {
-    if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
-        nmemb > 0 && SIZE_MAX / nmemb < size) {
-        errno = ENOMEM;
-        return NULL;
-    }
-    /*
-     * Head off variations in realloc behavior on different
-     * platforms (reported by MarkR )
-     *
-     * The behaviour of reallocarray is implementation-defined if
-     * nmemb or size is zero. It can return NULL or non-NULL
-     * depending on the platform.
-     * https://www.securecoding.cert.org/confluence/display/c/MEM04-C.Beware+of+zero-lengthallocations
-     *
-     * Here are some extracts from realloc man pages on different platforms.
-     *
-     * void realloc( void memblock, size_t size );
-     *
-     * Windows:
-     *
-     * If there is not enough available memory to expand the block
-     * to the given size, the original block is left unchanged,
-     * and NULL is returned.  If size is zero, then the block
-     * pointed to by memblock is freed; the return value is NULL,
-     * and memblock is left pointing at a freed block.
-     *
-     * OpenBSD:
-     *
-     * If size or nmemb is equal to 0, a unique pointer to an
-     * access protected, zero sized object is returned. Access via
-     * this pointer will generate a SIGSEGV exception.
-     *
-     * Linux:
-     *
-     * If size was equal to 0, either NULL or a pointer suitable
-     * to be passed to free() is returned.
-     *
-     * OS X:
-     *
-     * If size is zero and ptr is not NULL, a new, minimum sized
-     * object is allocated and the original object is freed.
-     *
-     * It looks like images with zero width or height can trigger
-     * this, and fuzzing behaviour will differ by platform, so
-     * fuzzing on one platform may not detect zero-size allocation
-     * problems on other platforms.
-     */
-    if (size == 0 || nmemb == 0) {
-        return NULL;
-    }
-    return realloc(optr, size * nmemb);
+        if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+            nmemb > 0 && SIZE_MAX / nmemb < size) {
+                errno = ENOMEM;
+                return NULL;
+        }
+        /*
+         * Head off variations in realloc behavior on different
+         * platforms (reported by MarkR )
+         *
+         * The behaviour of reallocarray is implementation-defined if
+         * nmemb or size is zero. It can return NULL or non-NULL
+         * depending on the platform.
+         * https://www.securecoding.cert.org/confluence/display/c/MEM04-C.Beware+of+zero-lengthallocations
+         *
+         * Here are some extracts from realloc man pages on different platforms.
+         *
+         * void realloc( void memblock, size_t size );
+         *
+         * Windows:
+         *
+         * If there is not enough available memory to expand the block
+         * to the given size, the original block is left unchanged,
+         * and NULL is returned.  If size is zero, then the block
+         * pointed to by memblock is freed; the return value is NULL,
+         * and memblock is left pointing at a freed block.
+         *
+         * OpenBSD:
+         *
+         * If size or nmemb is equal to 0, a unique pointer to an
+         * access protected, zero sized object is returned. Access via
+         * this pointer will generate a SIGSEGV exception.
+         *
+         * Linux:
+         *
+         * If size was equal to 0, either NULL or a pointer suitable
+         * to be passed to free() is returned.
+         *
+         * OS X:
+         *
+         * If size is zero and ptr is not NULL, a new, minimum sized
+         * object is allocated and the original object is freed.
+         *
+         * It looks like images with zero width or height can trigger
+         * this, and fuzzing behaviour will differ by platform, so
+         * fuzzing on one platform may not detect zero-size allocation
+         * problems on other platforms.
+         */
+        if (size == 0 || nmemb == 0) {
+                return NULL;
+        }
+        return realloc(optr, size * nmemb);
 }
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
index 3bb1baecd23..ba81df0c0e6 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
@@ -5988,7 +5988,7 @@ Version 1.6.32rc01 [August 18, 2017]
 
 Version 1.6.32rc02 [August 22, 2017]
   Added contrib/oss-fuzz directory which contains files used by the oss-fuzz
-    project (https://github.com/google/oss-fuzz/tree/master/projects/libpng).
+    project .
 
 Version 1.6.32 [August 24, 2017]
   No changes.
@@ -6323,15 +6323,63 @@ Version 1.6.53 [December 5, 2025]
 
 Version 1.6.54 [January 12, 2026]
   Fixed CVE-2026-22695 (medium severity):
-    Heap buffer over-read in `png_image_read_direct_scaled.
+    Heap buffer over-read in `png_image_read_direct_scaled`.
     (Reported and fixed by Petr Simecek.)
   Fixed CVE-2026-22801 (medium severity):
     Integer truncation causing heap buffer over-read in `png_image_write_*`.
   Implemented various improvements in oss-fuzz.
     (Contributed by Philippe Antoine.)
 
+Version 1.6.55 [February 9, 2026]
+  Fixed CVE-2026-25646 (high severity):
+    Heap buffer overflow in `png_set_quantize`.
+    (Reported and fixed by Joshua Inscoe.)
+  Resolved an oss-fuzz build issue involving nalloc.
+    (Contributed by Philippe Antoine.)
+
+Version 1.6.56 [March 25, 2026]
+  Fixed CVE-2026-33416 (high severity):
+    Use-after-free via pointer aliasing in `png_set_tRNS` and `png_set_PLTE`.
+    (Reported by Halil Oktay and Ryo Shimada;
+    fixed by Halil Oktay and Cosmin Truta.)
+  Fixed CVE-2026-33636 (high severity):
+    Out-of-bounds read/write in the palette expansion on ARM Neon.
+    (Reported by Taegu Ha; fixed by Taegu Ha and Cosmin Truta.)
+  Fixed uninitialized reads beyond `num_trans` in `trans_alpha` buffers.
+    (Contributed by Halil Oktay.)
+  Fixed stale `info_ptr->palette` after in-place gamma and background
+    transforms.
+  Fixed wrong channel indices in `png_image_read_and_map` RGB_ALPHA path.
+    (Contributed by Yuelin Wang.)
+  Fixed wrong background color in colormap read.
+    (Contributed by Yuelin Wang.)
+  Fixed dead loop in sPLT write.
+    (Contributed by Yuelin Wang.)
+  Added missing null pointer checks in four public API functions.
+    (Contributed by Yuelin Wang.)
+  Validated shift bit depths in `png_set_shift` to prevent infinite loop.
+    (Contributed by Yuelin Wang.)
+  Avoided undefined behavior in library and tests.
+  Deprecated the hardly-ever-tested POINTER_INDEXING config option.
+  Added negative-stride test coverage for the simplified API.
+  Fixed memory leaks and API misuse in oss-fuzz.
+    (Contributed by Owen Sanzas.)
+  Implemented various fixes and improvements in oss-fuzz.
+    (Contributed by Bob Friesenhahn and Philippe Antoine.)
+  Performed various refactorings and cleanups.
+
+Version 1.6.57 [April 8, 2026]
+  Fixed CVE-2026-34757 (medium severity):
+    Use-after-free in `png_set_PLTE`, `png_set_tRNS` and `png_set_hIST`
+    leading to corrupted chunk data and potential heap information disclosure.
+    Also hardened the append-style setters (`png_set_text`, `png_set_sPLT`,
+    `png_set_unknown_chunks`) against a theoretical variant of the same
+    aliasing pattern.
+    (Reported by Iv4n .)
+  Fixed integer overflow in rowbytes computation in read transforms.
+    (Contributed by Mohammad Seet.)
 
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
 Subscription is required; visit
-https://lists.sourceforge.net/lists/listinfo/png-mng-implement
+
 to subscribe.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/README b/src/java.desktop/share/native/libsplashscreen/libpng/README
index 63d1376edf7..179b8dc8cb4 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/README
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/README
@@ -1,4 +1,4 @@
-README for libpng version 1.6.54
+README for libpng version 1.6.57
 ================================
 
 See the note about version numbers near the top of `png.h`.
@@ -24,14 +24,14 @@ for more things than just PNG files.  You can use zlib as a drop-in
 replacement for `fread()` and `fwrite()`, if you are so inclined.
 
 zlib should be available at the same place that libpng is, or at
-https://zlib.net .
+.
 
 You may also want a copy of the PNG specification.  It is available
 as an RFC, a W3C Recommendation, and an ISO/IEC Standard.  You can find
-these at http://www.libpng.org/pub/png/pngdocs.html .
+these at .
 
-This code is currently being archived at https://libpng.sourceforge.io
-in the download area, and at http://libpng.download/src .
+This code is currently being archived at 
+in the download area, and at .
 
 This release, based in a large way on Glenn's, Guy's and Andreas'
 earlier work, was created and will be supported by myself and the PNG
@@ -39,12 +39,12 @@ development group.
 
 Send comments, corrections and commendations to `png-mng-implement`
 at `lists.sourceforge.net`.  (Subscription is required; visit
-https://lists.sourceforge.net/lists/listinfo/png-mng-implement
+
 to subscribe.)
 
 Send general questions about the PNG specification to `png-mng-misc`
 at `lists.sourceforge.net`.  (Subscription is required; visit
-https://lists.sourceforge.net/lists/listinfo/png-mng-misc
+
 to subscribe.)
 
 Historical notes
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.c b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
index 5636b4a754e..e4e13b0a684 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/png.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
@@ -42,7 +42,7 @@
 #include "pngpriv.h"
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_54 Your_png_h_is_not_version_1_6_54;
+typedef png_libpng_version_1_6_57 Your_png_h_is_not_version_1_6_57;
 
 /* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the
  * corresponding macro definitions.  This causes a compile time failure if
@@ -849,7 +849,7 @@ png_get_copyright(png_const_structrp png_ptr)
    return PNG_STRING_COPYRIGHT
 #else
    return PNG_STRING_NEWLINE \
-      "libpng version 1.6.54" PNG_STRING_NEWLINE \
+      "libpng version 1.6.57" PNG_STRING_NEWLINE \
       "Copyright (c) 2018-2026 Cosmin Truta" PNG_STRING_NEWLINE \
       "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
       PNG_STRING_NEWLINE \
@@ -1199,7 +1199,7 @@ png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ)
       return 1;
 
    /* The reference white is simply the sum of the end-point (X,Y,Z) vectors so
-    * the fillowing calculates (X+Y+Z) of the reference white (media white,
+    * the following calculates (X+Y+Z) of the reference white (media white,
     * encoding white) itself:
     */
    d = dblue;
@@ -1244,9 +1244,9 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
     * (-0.0770) because the PNG spec itself requires the xy values to be
     * unsigned.  whitey is also required to be 5 or more to avoid overflow.
     *
-    * Instead the upper limits have been relaxed to accomodate ACES AP1 where
+    * Instead the upper limits have been relaxed to accommodate ACES AP1 where
     * redz ends up as -600 (-0.006).  ProPhotoRGB was already "in range."
-    * The new limit accomodates the AP0 and AP1 ranges for z but not AP0 redy.
+    * The new limit accommodates the AP0 and AP1 ranges for z but not AP0 redy.
     */
    const png_fixed_point fpLimit = PNG_FP_1+(PNG_FP_1/10);
    if (xy->redx   < 0 || xy->redx > fpLimit) return 1;
@@ -1357,7 +1357,7 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
     *    red-scale + green-scale + blue-scale = 1/white-y = white-scale
     *
     * So now we have a Cramer's rule solution where the determinants are just
-    * 3x3 - far more tractible.  Unfortunately 3x3 determinants still involve
+    * 3x3 - far more tractable.  Unfortunately 3x3 determinants still involve
     * multiplication of three coefficients so we can't guarantee to avoid
     * overflow in the libpng fixed point representation.  Using Cramer's rule in
     * floating point is probably a good choice here, but it's not an option for
@@ -1726,7 +1726,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_const_charp name,
     * into R, G and B channels.
     *
     * Previously it was suggested that an RGB profile on grayscale data could be
-    * handled.  However it it is clear that using an RGB profile in this context
+    * handled.  However it is clear that using an RGB profile in this context
     * must be an error - there is no specification of what it means.  Thus it is
     * almost certainly more correct to ignore the profile.
     */
@@ -2944,7 +2944,7 @@ png_gamma_significant(png_fixed_point gamma_val)
     *
     *    2.2/(2+51/256) == 1.00035524
     *
-    * I.e. vanishly small (<4E-4) but still detectable in 16-bit linear (+/-
+    * I.e. vanishingly small (<4E-4) but still detectable in 16-bit linear (+/-
     * 23).  Note that the Adobe choice seems to be something intended to give an
     * exact number with 8 binary fractional digits - it is the closest to 2.2
     * that is possible a base 2 .8p representation.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.h b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
index ab8876a9626..349e7d07383 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/png.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * libpng version 1.6.54
+ * libpng version 1.6.57
  *
  * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
@@ -43,7 +43,7 @@
  *   libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
  *   libpng versions 0.97, January 1998, through 1.6.35, July 2018:
  *     Glenn Randers-Pehrson
- *   libpng versions 1.6.36, December 2018, through 1.6.54, January 2026:
+ *   libpng versions 1.6.36, December 2018, through 1.6.57, April 2026:
  *     Cosmin Truta
  *   See also "Contributing Authors", below.
  */
@@ -267,7 +267,7 @@
  *    ...
  *    1.5.30                  15    10530  15.so.15.30[.0]
  *    ...
- *    1.6.54                  16    10654  16.so.16.54[.0]
+ *    1.6.57                  16    10657  16.so.16.57[.0]
  *
  *    Henceforth the source version will match the shared-library major and
  *    minor numbers; the shared-library major version number will be used for
@@ -303,7 +303,7 @@
  */
 
 /* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.54"
+#define PNG_LIBPNG_VER_STRING "1.6.57"
 #define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n"
 
 /* The versions of shared library builds should stay in sync, going forward */
@@ -314,7 +314,7 @@
 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
 #define PNG_LIBPNG_VER_MAJOR   1
 #define PNG_LIBPNG_VER_MINOR   6
-#define PNG_LIBPNG_VER_RELEASE 54
+#define PNG_LIBPNG_VER_RELEASE 57
 
 /* This should be zero for a public release, or non-zero for a
  * development version.
@@ -345,7 +345,7 @@
  * From version 1.0.1 it is:
  * XXYYZZ, where XX=major, YY=minor, ZZ=release
  */
-#define PNG_LIBPNG_VER 10654 /* 1.6.54 */
+#define PNG_LIBPNG_VER 10657 /* 1.6.57 */
 
 /* Library configuration: these options cannot be changed after
  * the library has been built.
@@ -455,7 +455,7 @@ extern "C" {
 /* This triggers a compiler error in png.c, if png.c and png.h
  * do not agree upon the version number.
  */
-typedef char *png_libpng_version_1_6_54;
+typedef char *png_libpng_version_1_6_57;
 
 /* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
  *
@@ -2370,7 +2370,7 @@ PNG_EXPORT(162, int, png_get_text,
 #endif
 
 /* Note while png_set_text() will accept a structure whose text,
- * language, and  translated keywords are NULL pointers, the structure
+ * language, and translated keywords are NULL pointers, the structure
  * returned by png_get_text will always contain regular
  * zero-terminated C strings.  They might be empty strings but
  * they will never be NULL pointers.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
index 959c604edbc..1a5bb7b60f8 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * libpng version 1.6.54
+ * libpng version 1.6.57
  *
  * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
index 8fb955f3bd0..09adc3bd27b 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
@@ -31,7 +31,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  */
-/* libpng version 1.6.54 */
+/* libpng version 1.6.57 */
 
 /* Copyright (c) 2018-2026 Cosmin Truta */
 /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
index ee91f58d4ba..086a2f76ee6 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
@@ -986,7 +986,7 @@
  *
  * At present these index values are not exported (not part of the public API)
  * so can be changed at will.  For convenience the names are in lexical sort
- * order but with the critical chunks at the start in the order of occurence in
+ * order but with the critical chunks at the start in the order of occurrence in
  * a PNG.
  *
  * PNG_INFO_ values do not exist for every one of these chunk handles; for
@@ -2115,7 +2115,7 @@ PNG_INTERNAL_FUNCTION(void, png_ascii_from_fixed,
  * not valid it will be the index of a character in the supposed number.
  *
  * The format of a number is defined in the PNG extensions specification
- * and this API is strictly conformant to that spec, not anyone elses!
+ * and this API is strictly conformant to that spec, not anyone else's!
  *
  * The format as a regular expression is:
  *
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
index 79fd9ad6a82..70df18926f5 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
@@ -720,7 +720,7 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr)
       png_read_finish_IDAT(png_ptr);
 
 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
-   /* Report invalid palette index; added at libng-1.5.10 */
+   /* Report invalid palette index; added at libpng-1.5.10 */
    if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
        png_ptr->num_palette_max >= png_ptr->num_palette)
       png_benign_error(png_ptr, "Read palette index exceeding num_palette");
@@ -808,21 +808,19 @@ png_read_destroy(png_structrp png_ptr)
    png_ptr->quantize_index = NULL;
 #endif
 
-   if ((png_ptr->free_me & PNG_FREE_PLTE) != 0)
-   {
-      png_zfree(png_ptr, png_ptr->palette);
-      png_ptr->palette = NULL;
-   }
-   png_ptr->free_me &= ~PNG_FREE_PLTE;
+   /* png_ptr->palette is always independently allocated (not aliased
+    * with info_ptr->palette), so free it unconditionally.
+    */
+   png_free(png_ptr, png_ptr->palette);
+   png_ptr->palette = NULL;
 
 #if defined(PNG_tRNS_SUPPORTED) || \
     defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
-   if ((png_ptr->free_me & PNG_FREE_TRNS) != 0)
-   {
-      png_free(png_ptr, png_ptr->trans_alpha);
-      png_ptr->trans_alpha = NULL;
-   }
-   png_ptr->free_me &= ~PNG_FREE_TRNS;
+   /* png_ptr->trans_alpha is always independently allocated (not aliased
+    * with info_ptr->trans_alpha), so free it unconditionally.
+    */
+   png_free(png_ptr, png_ptr->trans_alpha);
+   png_ptr->trans_alpha = NULL;
 #endif
 
    inflateEnd(&png_ptr->zstream);
@@ -1285,7 +1283,7 @@ png_image_is_not_sRGB(png_const_structrp png_ptr)
     * png_struct::chromaticities always exists since the simplified API
     * requires rgb-to-gray.  The mDCV, cICP and cHRM chunks may all set it to
     * a non-sRGB value, so it needs to be checked but **only** if one of
-    * those chunks occured in the file.
+    * those chunks occurred in the file.
     */
    /* Highest priority: check to be safe. */
    if (png_has_chunk(png_ptr, cICP) || png_has_chunk(png_ptr, mDCV))
@@ -2625,7 +2623,7 @@ png_image_read_colormap(png_voidp argument)
                   {
                      r = back_r;
                      g = back_g;
-                     b = back_g;
+                     b = back_b;
                   }
 
                   /* Compare the newly-created color-map entry with the one the
@@ -2903,9 +2901,9 @@ png_image_read_and_map(png_voidp argument)
          {
             png_bytep inrow = png_voidcast(png_bytep, display->local_row);
             png_bytep outrow = first_row + y * row_step;
-            png_const_bytep end_row = outrow + width;
+            png_const_bytep row_end = outrow + width;
 
-            /* Read read the libpng data into the temporary buffer. */
+            /* Read the libpng data into the temporary buffer. */
             png_read_row(png_ptr, inrow, NULL);
 
             /* Now process the row according to the processing option, note
@@ -2916,7 +2914,7 @@ png_image_read_and_map(png_voidp argument)
             switch (proc)
             {
                case PNG_CMAP_GA:
-                  for (; outrow < end_row; outrow += stepx)
+                  for (; outrow < row_end; outrow += stepx)
                   {
                      /* The data is always in the PNG order */
                      unsigned int gray = *inrow++;
@@ -2945,7 +2943,7 @@ png_image_read_and_map(png_voidp argument)
                   break;
 
                case PNG_CMAP_TRANS:
-                  for (; outrow < end_row; outrow += stepx)
+                  for (; outrow < row_end; outrow += stepx)
                   {
                      png_byte gray = *inrow++;
                      png_byte alpha = *inrow++;
@@ -2962,7 +2960,7 @@ png_image_read_and_map(png_voidp argument)
                   break;
 
                case PNG_CMAP_RGB:
-                  for (; outrow < end_row; outrow += stepx)
+                  for (; outrow < row_end; outrow += stepx)
                   {
                      *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]);
                      inrow += 3;
@@ -2970,7 +2968,7 @@ png_image_read_and_map(png_voidp argument)
                   break;
 
                case PNG_CMAP_RGB_ALPHA:
-                  for (; outrow < end_row; outrow += stepx)
+                  for (; outrow < row_end; outrow += stepx)
                   {
                      unsigned int alpha = inrow[3];
 
@@ -3007,10 +3005,10 @@ png_image_read_and_map(png_voidp argument)
                          */
                         if (inrow[0] & 0x80) back_i += 9; /* red */
                         if (inrow[0] & 0x40) back_i += 9;
-                        if (inrow[0] & 0x80) back_i += 3; /* green */
-                        if (inrow[0] & 0x40) back_i += 3;
-                        if (inrow[0] & 0x80) back_i += 1; /* blue */
-                        if (inrow[0] & 0x40) back_i += 1;
+                        if (inrow[1] & 0x80) back_i += 3; /* green */
+                        if (inrow[1] & 0x40) back_i += 3;
+                        if (inrow[2] & 0x80) back_i += 1; /* blue */
+                        if (inrow[2] & 0x40) back_i += 1;
 
                         *outrow = (png_byte)back_i;
                      }
@@ -3277,18 +3275,18 @@ png_image_read_composite(png_voidp argument)
          {
             png_bytep inrow = png_voidcast(png_bytep, display->local_row);
             png_bytep outrow;
-            png_const_bytep end_row;
+            png_const_bytep row_end;
 
             /* Read the row, which is packed: */
             png_read_row(png_ptr, inrow, NULL);
 
             outrow = png_voidcast(png_bytep, display->first_row);
             outrow += y * row_step;
-            end_row = outrow + width * channels;
+            row_end = outrow + width * channels;
 
             /* Now do the composition on each pixel in this row. */
             outrow += startx;
-            for (; outrow < end_row; outrow += stepx)
+            for (; outrow < row_end; outrow += stepx)
             {
                png_byte alpha = inrow[channels];
 
@@ -3461,14 +3459,14 @@ png_image_read_background(png_voidp argument)
                      png_bytep inrow = png_voidcast(png_bytep,
                          display->local_row);
                      png_bytep outrow = first_row + y * row_step;
-                     png_const_bytep end_row = outrow + width;
+                     png_const_bytep row_end = outrow + width;
 
                      /* Read the row, which is packed: */
                      png_read_row(png_ptr, inrow, NULL);
 
                      /* Now do the composition on each pixel in this row. */
                      outrow += startx;
-                     for (; outrow < end_row; outrow += stepx)
+                     for (; outrow < row_end; outrow += stepx)
                      {
                         png_byte alpha = inrow[1];
 
@@ -3506,14 +3504,14 @@ png_image_read_background(png_voidp argument)
                      png_bytep inrow = png_voidcast(png_bytep,
                          display->local_row);
                      png_bytep outrow = first_row + y * row_step;
-                     png_const_bytep end_row = outrow + width;
+                     png_const_bytep row_end = outrow + width;
 
                      /* Read the row, which is packed: */
                      png_read_row(png_ptr, inrow, NULL);
 
                      /* Now do the composition on each pixel in this row. */
                      outrow += startx;
-                     for (; outrow < end_row; outrow += stepx)
+                     for (; outrow < row_end; outrow += stepx)
                      {
                         png_byte alpha = inrow[1];
 
@@ -3596,7 +3594,7 @@ png_image_read_background(png_voidp argument)
                {
                   png_const_uint_16p inrow;
                   png_uint_16p outrow = first_row + y * row_step;
-                  png_uint_16p end_row = outrow + width * outchannels;
+                  png_uint_16p row_end = outrow + width * outchannels;
 
                   /* Read the row, which is packed: */
                   png_read_row(png_ptr, png_voidcast(png_bytep,
@@ -3606,7 +3604,7 @@ png_image_read_background(png_voidp argument)
                   /* Now do the pre-multiplication on each pixel in this row.
                    */
                   outrow += startx;
-                  for (; outrow < end_row; outrow += stepx)
+                  for (; outrow < row_end; outrow += stepx)
                   {
                      png_uint_32 component = inrow[0];
                      png_uint_16 alpha = inrow[1];
@@ -4142,7 +4140,7 @@ png_image_finish_read(png_imagep image, png_const_colorp background,
             row_stride = (png_int_32)/*SAFE*/png_row_stride;
 
          if (row_stride < 0)
-            check = (png_uint_32)(-row_stride);
+            check = -(png_uint_32)row_stride;
 
          else
             check = (png_uint_32)row_stride;
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
index 7680fe64828..838c8460f91 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2025 Cosmin Truta
+ * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -259,7 +259,7 @@ png_set_strip_alpha(png_structrp png_ptr)
  *
  * Terminology (assuming power law, "gamma", encodings):
  *    "screen" gamma: a power law imposed by the output device when digital
- *    samples are converted to visible light output.  The EOTF - volage to
+ *    samples are converted to visible light output.  The EOTF - voltage to
  *    luminance on output.
  *
  *    "file" gamma: a power law used to encode luminance levels from the input
@@ -524,6 +524,9 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
    if (png_rtran_ok(png_ptr, 0) == 0)
       return;
 
+   if (palette == NULL)
+      return;
+
    png_ptr->transformations |= PNG_QUANTIZE;
 
    if (full_quantize == 0)
@@ -737,8 +740,8 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
                          break;
 
                      t->next = hash[d];
-                     t->left = (png_byte)i;
-                     t->right = (png_byte)j;
+                     t->left = png_ptr->palette_to_index[i];
+                     t->right = png_ptr->palette_to_index[j];
                      hash[d] = t;
                   }
                }
@@ -840,7 +843,13 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
    }
    if (png_ptr->palette == NULL)
    {
-      png_ptr->palette = palette;
+      /* Allocate an owned copy rather than aliasing the caller's pointer,
+       * so that png_read_destroy can free png_ptr->palette unconditionally.
+       */
+      png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
+          PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
+      memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
+          (sizeof (png_color)));
    }
    png_ptr->num_palette = (png_uint_16)num_palette;
 
@@ -1393,7 +1402,7 @@ png_resolve_file_gamma(png_const_structrp png_ptr)
    if (file_gamma != 0)
       return file_gamma;
 
-   /* If png_reciprocal oveflows it returns 0 which indicates to the caller that
+   /* If png_reciprocal overflows, it returns 0, indicating to the caller that
     * there is no usable file gamma.  (The checks added to png_set_gamma and
     * png_set_alpha_mode should prevent a screen_gamma which would overflow.)
     */
@@ -2090,6 +2099,21 @@ png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr)
 {
    png_debug(1, "in png_read_transform_info");
 
+   if (png_ptr->transformations != 0)
+   {
+      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+          info_ptr->palette != NULL && png_ptr->palette != NULL)
+      {
+         /* Sync info_ptr->palette with png_ptr->palette.
+          * The function png_init_read_transformations may have modified
+          * png_ptr->palette in place (e.g. for gamma correction or for
+          * background compositing).
+          */
+         memcpy(info_ptr->palette, png_ptr->palette,
+             PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)));
+      }
+   }
+
 #ifdef PNG_READ_EXPAND_SUPPORTED
    if ((png_ptr->transformations & PNG_EXPAND) != 0)
    {
@@ -2384,7 +2408,7 @@ png_do_unpack(png_row_infop row_info, png_bytep row)
       }
       row_info->bit_depth = 8;
       row_info->pixel_depth = (png_byte)(8 * row_info->channels);
-      row_info->rowbytes = row_width * row_info->channels;
+      row_info->rowbytes = (size_t)row_width * row_info->channels;
    }
 }
 #endif
@@ -2586,7 +2610,7 @@ png_do_scale_16_to_8(png_row_infop row_info, png_bytep row)
 
       row_info->bit_depth = 8;
       row_info->pixel_depth = (png_byte)(8 * row_info->channels);
-      row_info->rowbytes = row_info->width * row_info->channels;
+      row_info->rowbytes = (size_t)row_info->width * row_info->channels;
    }
 }
 #endif
@@ -2614,7 +2638,7 @@ png_do_chop(png_row_infop row_info, png_bytep row)
 
       row_info->bit_depth = 8;
       row_info->pixel_depth = (png_byte)(8 * row_info->channels);
-      row_info->rowbytes = row_info->width * row_info->channels;
+      row_info->rowbytes = (size_t)row_info->width * row_info->channels;
    }
 }
 #endif
@@ -2850,7 +2874,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             *(--dp) = lo_filler;
             row_info->channels = 2;
             row_info->pixel_depth = 16;
-            row_info->rowbytes = row_width * 2;
+            row_info->rowbytes = (size_t)row_width * 2;
          }
 
          else
@@ -2865,7 +2889,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             }
             row_info->channels = 2;
             row_info->pixel_depth = 16;
-            row_info->rowbytes = row_width * 2;
+            row_info->rowbytes = (size_t)row_width * 2;
          }
       }
 
@@ -2888,7 +2912,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             *(--dp) = hi_filler;
             row_info->channels = 2;
             row_info->pixel_depth = 32;
-            row_info->rowbytes = row_width * 4;
+            row_info->rowbytes = (size_t)row_width * 4;
          }
 
          else
@@ -2905,7 +2929,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             }
             row_info->channels = 2;
             row_info->pixel_depth = 32;
-            row_info->rowbytes = row_width * 4;
+            row_info->rowbytes = (size_t)row_width * 4;
          }
       }
 #endif
@@ -2929,7 +2953,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             *(--dp) = lo_filler;
             row_info->channels = 4;
             row_info->pixel_depth = 32;
-            row_info->rowbytes = row_width * 4;
+            row_info->rowbytes = (size_t)row_width * 4;
          }
 
          else
@@ -2946,7 +2970,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             }
             row_info->channels = 4;
             row_info->pixel_depth = 32;
-            row_info->rowbytes = row_width * 4;
+            row_info->rowbytes = (size_t)row_width * 4;
          }
       }
 
@@ -2973,7 +2997,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             *(--dp) = hi_filler;
             row_info->channels = 4;
             row_info->pixel_depth = 64;
-            row_info->rowbytes = row_width * 8;
+            row_info->rowbytes = (size_t)row_width * 8;
          }
 
          else
@@ -2995,7 +3019,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
 
             row_info->channels = 4;
             row_info->pixel_depth = 64;
-            row_info->rowbytes = row_width * 8;
+            row_info->rowbytes = (size_t)row_width * 8;
          }
       }
 #endif
@@ -4489,7 +4513,7 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info,
                }
                row_info->bit_depth = 8;
                row_info->pixel_depth = 32;
-               row_info->rowbytes = row_width * 4;
+               row_info->rowbytes = (size_t)row_width * 4;
                row_info->color_type = 6;
                row_info->channels = 4;
             }
@@ -4497,7 +4521,7 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info,
             else
             {
                sp = row + (size_t)row_width - 1;
-               dp = row + (size_t)(row_width * 3) - 1;
+               dp = row + (size_t)row_width * 3 - 1;
                i = 0;
 #ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE
                i = png_do_expand_palette_rgb8_neon(png_ptr, row_info, row,
@@ -4516,7 +4540,7 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info,
 
                row_info->bit_depth = 8;
                row_info->pixel_depth = 24;
-               row_info->rowbytes = row_width * 3;
+               row_info->rowbytes = (size_t)row_width * 3;
                row_info->color_type = 2;
                row_info->channels = 3;
             }
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
index 01bb0c8bedc..4712dfd418a 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
@@ -465,7 +465,7 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner)
     * be gained by using this when it is known *if* the zlib stream itself does
     * not record the number; however, this is an illusion: the original writer
     * of the PNG may have selected a lower window size, and we really must
-    * follow that because, for systems with with limited capabilities, we
+    * follow that because, for systems with limited capabilities, we
     * would otherwise reject the application's attempts to use a smaller window
     * size (zlib doesn't have an interface to say "this or lower"!).
     *
@@ -1035,7 +1035,7 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
     * in the case of an 8-bit display with a decoder which controls the palette.
     *
     * The alternative here is to ignore the error and store the palette anyway;
-    * destroying the tRNS will definately cause problems.
+    * destroying the tRNS will definitely cause problems.
     *
     * NOTE: the case of PNG_COLOR_TYPE_PALETTE need not be considered because
     * the png_handle_ routines for the three 'after PLTE' chunks tRNS, bKGD and
@@ -1082,19 +1082,6 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
       /* A valid PLTE chunk has been read */
       png_ptr->mode |= PNG_HAVE_PLTE;
 
-      /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to
-       * its own copy of the palette.  This has the side effect that when
-       * png_start_row is called (this happens after any call to
-       * png_read_update_info) the info_ptr palette gets changed.  This is
-       * extremely unexpected and confusing.
-       *
-       * REVIEW: there have been consistent bugs in the past about gamma and
-       * similar transforms to colour mapped images being useless because the
-       * modified palette cannot be accessed because of the above.
-       *
-       * CONSIDER: Fix this by not sharing the palette in this way.  But does
-       * this completely fix the problem?
-       */
       png_set_PLTE(png_ptr, info_ptr, palette, num);
       return handled_ok;
    }
@@ -1296,7 +1283,7 @@ png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 
    /* png_set_cHRM may complain about some of the values but this doesn't matter
     * because it was a cHRM and it did have vaguely (if, perhaps, ridiculous)
-    * values.  Ridiculousity will be checked if the values are used later.
+    * values.  Ridiculosity will be checked if the values are used later.
     */
    png_set_cHRM_fixed(png_ptr, info_ptr, xy.whitex, xy.whitey, xy.redx, xy.redy,
          xy.greenx, xy.greeny, xy.bluex, xy.bluey);
@@ -1593,7 +1580,8 @@ static png_handle_result_code /* PRIVATE */
 png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 /* Note: this does not properly handle chunks that are > 64K under DOS */
 {
-   png_bytep entry_start, buffer;
+   png_bytep buffer;
+   png_bytep entry_start;
    png_sPLT_t new_palette;
    png_sPLT_entryp pp;
    png_uint_32 data_length;
@@ -1800,10 +1788,6 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
       return handled_error;
    }
 
-   /* TODO: this is a horrible side effect in the palette case because the
-    * png_struct ends up with a pointer to the tRNS buffer owned by the
-    * png_info.  Fix this.
-    */
    png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
        &(png_ptr->trans_color));
    return handled_ok;
@@ -2062,7 +2046,7 @@ png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
       return handled_error;
 
    /* PNGv3: the code used to check the byte order mark at the start for MM or
-    * II, however PNGv3 states that the the first 4 bytes should be checked.
+    * II, however PNGv3 states that the first 4 bytes should be checked.
     * The caller ensures that there are four bytes available.
     */
    {
@@ -2184,9 +2168,13 @@ png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 static png_handle_result_code /* PRIVATE */
 png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
+   png_bytep buffer;
+   png_bytep buf;
+   png_bytep endptr;
    png_int_32 X0, X1;
-   png_byte type, nparams;
-   png_bytep buffer, buf, units, endptr;
+   png_byte type;
+   png_byte nparams;
+   png_byte *units;
    png_charpp params;
    int i;
 
@@ -3040,7 +3028,7 @@ static const struct
    png_uint_32 max_length :12; /* Length min, max in bytes */
    png_uint_32 min_length :8;
       /* Length errors on critical chunks have special handling to preserve the
-       * existing behaviour in libpng 1.6.  Anciallary chunks are checked below
+       * existing behaviour in libpng 1.6.  Ancillary chunks are checked below
        * and produce a 'benign' error.
        */
    png_uint_32 pos_before :4; /* PNG_HAVE_ values chunk must precede */
@@ -3048,7 +3036,7 @@ static const struct
       /* NOTE: PLTE, tRNS and bKGD require special handling which depends on
        * the colour type of the base image.
        */
-   png_uint_32 multiple   :1; /* Multiple occurences permitted */
+   png_uint_32 multiple   :1; /* Multiple occurrences permitted */
       /* This is enabled for PLTE because PLTE may, in practice, be optional */
 }
 read_chunks[PNG_INDEX_unknown] =
@@ -3082,7 +3070,7 @@ read_chunks[PNG_INDEX_unknown] =
 #  define CDIHDR      13U,   13U,  hIHDR,     0,        0
 #  define CDPLTE  NoCheck,    0U,      0, hIHDR,        1
       /* PLTE errors are only critical for colour-map images, consequently the
-       * hander does all the checks.
+       * handler does all the checks.
        */
 #  define CDIDAT  NoCheck,    0U,  aIDAT, hIHDR,        1
 #  define CDIEND  NoCheck,    0U,      0, aIDAT,        0
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
index 0b2844f1864..29082a6be08 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2025 Cosmin Truta
+ * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -362,7 +362,8 @@ png_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr,
    png_debug1(1, "in %s storage function", "eXIf");
 
    if (png_ptr == NULL || info_ptr == NULL ||
-       (png_ptr->mode & PNG_WROTE_eXIf) != 0)
+       (png_ptr->mode & PNG_WROTE_eXIf) != 0 ||
+       exif == NULL)
       return;
 
    new_exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr, num_exif));
@@ -413,11 +414,12 @@ void PNGAPI
 png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
     png_const_uint_16p hist)
 {
+   png_uint_16 safe_hist[PNG_MAX_PALETTE_LENGTH];
    int i;
 
    png_debug1(1, "in %s storage function", "hIST");
 
-   if (png_ptr == NULL || info_ptr == NULL)
+   if (png_ptr == NULL || info_ptr == NULL || hist == NULL)
       return;
 
    if (info_ptr->num_palette == 0 || info_ptr->num_palette
@@ -429,6 +431,13 @@ png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
       return;
    }
 
+   /* Snapshot the caller's hist before freeing, in case it points to
+    * info_ptr->hist (getter-to-setter aliasing).
+    */
+   memcpy(safe_hist, hist, (unsigned int)info_ptr->num_palette *
+       (sizeof (png_uint_16)));
+   hist = safe_hist;
+
    png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);
 
    /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in
@@ -770,7 +779,7 @@ void PNGAPI
 png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
     png_const_colorp palette, int num_palette)
 {
-
+   png_color safe_palette[PNG_MAX_PALETTE_LENGTH];
    png_uint_32 max_palette_length;
 
    png_debug1(1, "in %s storage function", "PLTE");
@@ -804,28 +813,47 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
       png_error(png_ptr, "Invalid palette");
    }
 
-   /* It may not actually be necessary to set png_ptr->palette here;
-    * we do it for backward compatibility with the way the png_handle_tRNS
-    * function used to do the allocation.
-    *
-    * 1.6.0: the above statement appears to be incorrect; something has to set
-    * the palette inside png_struct on read.
+   /* Snapshot the caller's palette before freeing, in case it points to
+    * info_ptr->palette (getter-to-setter aliasing).
     */
+   if (num_palette > 0)
+      memcpy(safe_palette, palette, (unsigned int)num_palette *
+          (sizeof (png_color)));
+
+   palette = safe_palette;
+
    png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
 
    /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
     * of num_palette entries, in case of an invalid PNG file or incorrect
     * call to png_set_PLTE() with too-large sample values.
+    *
+    * Allocate independent buffers for info_ptr and png_ptr so that the
+    * lifetime of png_ptr->palette is decoupled from the lifetime of
+    * info_ptr->palette.  Previously, these two pointers were aliased,
+    * which caused a use-after-free vulnerability if png_free_data freed
+    * info_ptr->palette while png_ptr->palette was still in use by the
+    * row transform functions (e.g. png_do_expand_palette).
+    *
+    * Both buffers are allocated with png_calloc to zero-fill, because
+    * the ARM NEON palette riffle reads all 256 entries unconditionally,
+    * regardless of num_palette.
     */
+   png_free(png_ptr, png_ptr->palette);
    png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
        PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
+   info_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
+       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
+   png_ptr->num_palette = info_ptr->num_palette = (png_uint_16)num_palette;
 
    if (num_palette > 0)
+   {
+      memcpy(info_ptr->palette, palette, (unsigned int)num_palette *
+          (sizeof (png_color)));
       memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
           (sizeof (png_color)));
+   }
 
-   info_ptr->palette = png_ptr->palette;
-   info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;
    info_ptr->free_me |= PNG_FREE_PLTE;
    info_ptr->valid |= PNG_INFO_PLTE;
 }
@@ -955,6 +983,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
     png_const_textp text_ptr, int num_text)
 {
    int i;
+   png_textp old_text = NULL;
 
    png_debug1(1, "in text storage function, chunk typeid = 0x%lx",
       png_ptr == NULL ? 0xabadca11UL : (unsigned long)png_ptr->chunk_name);
@@ -1002,7 +1031,10 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
          return 1;
       }
 
-      png_free(png_ptr, info_ptr->text);
+      /* Defer freeing the old array until after the copy loop below,
+       * in case text_ptr aliases info_ptr->text (getter-to-setter).
+       */
+      old_text = info_ptr->text;
 
       info_ptr->text = new_text;
       info_ptr->free_me |= PNG_FREE_TEXT;
@@ -1087,6 +1119,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
       {
          png_chunk_report(png_ptr, "text chunk: out of memory",
              PNG_CHUNK_WRITE_ERROR);
+         png_free(png_ptr, old_text);
 
          return 1;
       }
@@ -1140,6 +1173,8 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
       png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
    }
 
+   png_free(png_ptr, old_text);
+
    return 0;
 }
 #endif
@@ -1183,28 +1218,50 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
 
    if (trans_alpha != NULL)
    {
-       /* It may not actually be necessary to set png_ptr->trans_alpha here;
-        * we do it for backward compatibility with the way the png_handle_tRNS
-        * function used to do the allocation.
-        *
-        * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively
-        * relies on png_set_tRNS storing the information in png_struct
-        * (otherwise it won't be there for the code in pngrtran.c).
+       /* Snapshot the caller's trans_alpha before freeing, in case it
+        * points to info_ptr->trans_alpha (getter-to-setter aliasing).
         */
+       png_byte safe_trans[PNG_MAX_PALETTE_LENGTH];
+
+       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
+          memcpy(safe_trans, trans_alpha, (size_t)num_trans);
+
+       trans_alpha = safe_trans;
 
        png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
 
        if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
        {
-         /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */
+          /* Allocate info_ptr's copy of the transparency data.
+           * Initialize all entries to fully opaque (0xff), then overwrite
+           * the first num_trans entries with the actual values.
+           */
           info_ptr->trans_alpha = png_voidcast(png_bytep,
               png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
+          memset(info_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH);
           memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
-
           info_ptr->free_me |= PNG_FREE_TRNS;
           info_ptr->valid |= PNG_INFO_tRNS;
+
+          /* Allocate an independent copy for png_struct, so that the
+           * lifetime of png_ptr->trans_alpha is decoupled from the
+           * lifetime of info_ptr->trans_alpha.  Previously these two
+           * pointers were aliased, which caused a use-after-free if
+           * png_free_data freed info_ptr->trans_alpha while
+           * png_ptr->trans_alpha was still in use by the row transform
+           * functions (e.g. png_do_expand_palette).
+           */
+          png_free(png_ptr, png_ptr->trans_alpha);
+          png_ptr->trans_alpha = png_voidcast(png_bytep,
+              png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
+          memset(png_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH);
+          memcpy(png_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
+       }
+       else
+       {
+          png_free(png_ptr, png_ptr->trans_alpha);
+          png_ptr->trans_alpha = NULL;
        }
-       png_ptr->trans_alpha = info_ptr->trans_alpha;
    }
 
    if (trans_color != NULL)
@@ -1255,6 +1312,7 @@ png_set_sPLT(png_const_structrp png_ptr,
  */
 {
    png_sPLT_tp np;
+   png_sPLT_tp old_spalettes;
 
    png_debug1(1, "in %s storage function", "sPLT");
 
@@ -1275,7 +1333,10 @@ png_set_sPLT(png_const_structrp png_ptr,
       return;
    }
 
-   png_free(png_ptr, info_ptr->splt_palettes);
+   /* Defer freeing the old array until after the copy loop below,
+    * in case entries aliases info_ptr->splt_palettes (getter-to-setter).
+    */
+   old_spalettes = info_ptr->splt_palettes;
 
    info_ptr->splt_palettes = np;
    info_ptr->free_me |= PNG_FREE_SPLT;
@@ -1339,6 +1400,8 @@ png_set_sPLT(png_const_structrp png_ptr,
    }
    while (--nentries);
 
+   png_free(png_ptr, old_spalettes);
+
    if (nentries > 0)
       png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR);
 }
@@ -1387,6 +1450,7 @@ png_set_unknown_chunks(png_const_structrp png_ptr,
     png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)
 {
    png_unknown_chunkp np;
+   png_unknown_chunkp old_unknowns;
 
    if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||
        unknowns == NULL)
@@ -1433,7 +1497,10 @@ png_set_unknown_chunks(png_const_structrp png_ptr,
       return;
    }
 
-   png_free(png_ptr, info_ptr->unknown_chunks);
+   /* Defer freeing the old array until after the copy loop below,
+    * in case unknowns aliases info_ptr->unknown_chunks (getter-to-setter).
+    */
+   old_unknowns = info_ptr->unknown_chunks;
 
    info_ptr->unknown_chunks = np; /* safe because it is initialized */
    info_ptr->free_me |= PNG_FREE_UNKN;
@@ -1479,6 +1546,8 @@ png_set_unknown_chunks(png_const_structrp png_ptr,
       ++np;
       ++(info_ptr->unknown_chunks_num);
    }
+
+   png_free(png_ptr, old_unknowns);
 }
 
 void PNGAPI
@@ -1902,7 +1971,7 @@ png_set_benign_errors(png_structrp png_ptr, int allowed)
 #endif /* BENIGN_ERRORS */
 
 #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
-   /* Whether to report invalid palette index; added at libng-1.5.10.
+   /* Whether to report invalid palette index; added at libpng-1.5.10.
     * It is possible for an indexed (color-type==3) PNG file to contain
     * pixels with invalid (out-of-range) indexes if the PLTE chunk has
     * fewer entries than the image's bit-depth would allow. We recover
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h
index 8edb4bc393a..f02365e8d8e 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2025 Cosmin Truta
+ * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -135,7 +135,7 @@ typedef enum
  * TODO: C23: convert these macros to C23 inlines (which are static).
  */
 #define png_chunk_flag_from_index(i) (0x80000000U >> (31 - (i)))
-   /* The flag coresponding to the given png_index enum value.  This is defined
+   /* The flag corresponding to the given png_index enum value.  This is defined
     * for png_unknown as well (until it reaches the value 32) but this should
     * not be relied on.
     */
@@ -144,7 +144,7 @@ typedef enum
    (((png_ptr)->chunks & png_chunk_flag_from_index(i)) != 0)
    /* The chunk has been recorded in png_struct */
 
-#define png_file_add_chunk(pnt_ptr, i)\
+#define png_file_add_chunk(png_ptr, i)\
    ((void)((png_ptr)->chunks |= png_chunk_flag_from_index(i)))
    /* Record the chunk in the png_struct */
 
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c
index b9f6cb5d437..86ff2812e23 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -113,9 +113,38 @@ png_set_shift(png_structrp png_ptr, png_const_color_8p true_bits)
 {
    png_debug(1, "in png_set_shift");
 
-   if (png_ptr == NULL)
+   if (png_ptr == NULL || true_bits == NULL)
       return;
 
+   /* Check the shift values before passing them on to png_do_shift. */
+   {
+      png_byte bit_depth = png_ptr->bit_depth;
+      int invalid = 0;
+
+      if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
+      {
+         if (true_bits->red == 0 || true_bits->red > bit_depth ||
+             true_bits->green == 0 || true_bits->green > bit_depth ||
+             true_bits->blue == 0 || true_bits->blue > bit_depth)
+            invalid = 1;
+      }
+      else
+      {
+         if (true_bits->gray == 0 || true_bits->gray > bit_depth)
+            invalid = 1;
+      }
+
+      if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0 &&
+          (true_bits->alpha == 0 || true_bits->alpha > bit_depth))
+         invalid = 1;
+
+      if (invalid)
+      {
+         png_app_error(png_ptr, "png_set_shift: invalid shift values");
+         return;
+      }
+   }
+
    png_ptr->transformations |= PNG_SHIFT;
    png_ptr->shift = *true_bits;
 }
@@ -486,10 +515,9 @@ png_do_packswap(png_row_infop row_info, png_bytep row)
 
    if (row_info->bit_depth < 8)
    {
+      png_const_bytep table;
       png_bytep rp;
-      png_const_bytep end, table;
-
-      end = row + row_info->rowbytes;
+      png_bytep row_end = row + row_info->rowbytes;
 
       if (row_info->bit_depth == 1)
          table = onebppswaptable;
@@ -503,7 +531,7 @@ png_do_packswap(png_row_infop row_info, png_bytep row)
       else
          return;
 
-      for (rp = row; rp < end; rp++)
+      for (rp = row; rp < row_end; rp++)
          *rp = table[*rp];
    }
 }
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java
index f14c377759f..1e6618fd144 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -53,17 +53,27 @@
 import java.util.function.IntBinaryOperator;
 
 /**
- * Implements SSL using two SubscriberWrappers.
+ * Implements SSL using two {@link SubscriberWrapper}s.
  *
- * 

Constructor takes two Flow.Subscribers: one that receives the network - * data (after it has been encrypted by SSLFlowDelegate) data, and one that - * receives the application data (before it has been encrypted by SSLFlowDelegate). + *

Constructor takes two {@linkplain Flow.Subscriber subscribers} - {@code downReader} + * and {@code downWriter}. {@code downReader} receives the application data (after it has + * been decrypted by SSLFlowDelegate). {@code downWriter} receives the network data (after it has + * been encrypted by SSLFlowDelegate). * - *

Methods upstreamReader() and upstreamWriter() return the corresponding - * Flow.Subscribers containing Flows for the encrypted/decrypted upstream data. - * See diagram below. + *

Method {@link #upstreamWriter()} returns a {@linkplain Subscriber subscriber} which should + * be subscribed with a {@linkplain Flow.Publisher publisher} which publishes application data + * that can then be encrypted into network data by this SSLFlowDelegate and handed off to the + * {@code downWriter}. * - *

How Flow.Subscribers are used in this class, and where they come from: + *

Method {@link #upstreamReader()} returns a {@link Subscriber subscriber} which should be + * subscribed with a {@linkplain Flow.Publisher publisher} which publishes encrypted network data + * that can then be decrypted into application data by this SSLFlowDelegate and handed off to the + * {@code downReader}. + * + *

Errors are reported to the {@code downReader} subscriber. + * + *

The diagram below illustrates how the Flow.Subscribers are used in this class, and where + * they come from: *

  * {@code
  *
@@ -72,17 +82,21 @@
  * --------->  data flow direction
  *
  *
- *                         +------------------+
- *        upstreamWriter   |                  | downWriter
- *        ---------------> |                  | ------------>
- *  obtained from this     |                  | supplied to constructor
- *                         | SSLFlowDelegate  |
- *        downReader       |                  | upstreamReader
- *        <--------------- |                  | <--------------
- * supplied to constructor |                  | obtained from this
- *                         +------------------+
- *
- * Errors are reported to the downReader Flow.Subscriber
+ *                  |                                   ^
+ *  upstreamWriter  |                                   | downReader
+ *  obtained from   |                                   | supplied to
+ * upstreamWriter() |                                   | constructor
+ *                  v                                   |
+ *      +-----------------------------------------------------------+
+ *      *                                            decrypts       *
+ *      *                       SSLFlowDelegate                     *
+ *      *        encrypts                                           *
+ *      +-----------------------------------------------------------+
+ *                  |                                   ^
+ *    downWriter    |                                   | upstreamReader
+ *    supplied to   |                                   | obtained from
+ *    constructor   |                                   | upstreamReader()
+ *                  v                                   |
  *
  * }
  * 
@@ -254,7 +268,7 @@ final class Reader extends SubscriberWrapper implements FlowTube.TubeSubscriber final SequentialScheduler scheduler; volatile ByteBuffer readBuf; - volatile boolean completing; + boolean completing; final Object readBufferLock = new Object(); final Logger debugr = Utils.getDebugLogger(this::dbgString, Utils.DEBUG); @@ -282,6 +296,11 @@ protected SchedulingAction enterScheduling() { return enterReadScheduling(); } + @Override + public boolean closing() { + return closeNotifyReceived(); + } + public final String dbgString() { return "SSL Reader(" + tubeName + ")"; } @@ -318,14 +337,19 @@ private void reallocReadBuf() { @Override protected long upstreamWindowUpdate(long currentWindow, long downstreamQsize) { - if (readBuf.remaining() > TARGET_BUFSIZE) { - if (debugr.on()) - debugr.log("readBuf has more than TARGET_BUFSIZE: %d", - readBuf.remaining()); - return 0; - } else { - return super.upstreamWindowUpdate(currentWindow, downstreamQsize); + if (needsMoreData()) { + // run the scheduler to see if more data should be requested + if (debugr.on()) { + int remaining = readBuf.remaining(); + if (remaining > TARGET_BUFSIZE) { + // just some logging to check how much we have in the read buffer + debugr.log("readBuf has more than TARGET_BUFSIZE: %d", + remaining); + } + } + scheduler.runOrSchedule(); } + return 0; // we will request more from the scheduler loop (processData). } // readBuf is kept ready for reading outside of this method @@ -368,6 +392,32 @@ void stop() { // we had before calling unwrap() again. volatile int minBytesRequired; + // We might need to request more data if: + // - we have a subscription from upstream + // - and we don't have enough data to decrypt in the read buffer + // - *and* - either we're handshaking, and more data is required (NEED_UNWRAP), + // - or we have demand from downstream, but we have nothing decrypted + // to forward downstream. + boolean needsMoreData() { + if (upstreamSubscription != null && readBuf.remaining() <= minBytesRequired && + (engine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP + || !downstreamSubscription.demand.isFulfilled() && hasNoOutputData())) { + return true; + } + return false; + } + + // If the readBuf has not enough data, and we either need to + // unwrap (handshaking) or we have demand from downstream, + // then request more data + void requestMoreDataIfNeeded() { + if (needsMoreData()) { + // request more will only request more if our + // demand from upstream is fulfilled + requestMore(); + } + } + // work function where it all happens final void processData() { try { @@ -426,7 +476,7 @@ else if (this.completing) { } } // request more data and return. - requestMore(); + requestMoreDataIfNeeded(); return; } if (complete && result.status() == Status.CLOSED) { @@ -434,12 +484,13 @@ else if (this.completing) { outgoing(Utils.EMPTY_BB_LIST, true); // complete ALPN if not yet completed setALPN(); + requestMoreDataIfNeeded(); return; } if (result.handshaking()) { handshaking = true; if (debugr.on()) debugr.log("handshaking"); - if (doHandshake(result, READER)) continue; // need unwrap + if (doHandshake(result.handshakeStatus(), READER)) continue; // need unwrap else break; // doHandshake will have triggered the write scheduler if necessary } else { if (trySetALPN()) { @@ -451,8 +502,10 @@ else if (this.completing) { handleError(ex); return; } - if (handshaking && !complete) + if (handshaking && !complete) { + requestMoreDataIfNeeded(); return; + } } if (!complete) { synchronized (readBufferLock) { @@ -466,6 +519,8 @@ else if (this.completing) { // activity. setALPN(); outgoing(Utils.EMPTY_BB_LIST, true); + } else { + requestMoreDataIfNeeded(); } } catch (Throwable ex) { errorCommon(ex); @@ -475,6 +530,7 @@ else if (this.completing) { private volatile Status lastUnwrapStatus; EngineResult unwrapBuffer(ByteBuffer src) throws IOException { + assert Thread.holdsLock(readBufferLock); ByteBuffer dst = getAppBuffer(); int len = src.remaining(); while (true) { @@ -498,6 +554,8 @@ EngineResult unwrapBuffer(ByteBuffer src) throws IOException { break; case CLOSED: assert dst.position() == 0; + src.position(src.limit()); + completing = true; return doClosure(new EngineResult(sslResult)); case BUFFER_UNDERFLOW: // handled implicitly by compaction/reallocation of readBuf @@ -758,7 +816,7 @@ private void processData() { boolean handshaking = false; if (result.handshaking()) { if (debugw.on()) debugw.log("handshaking"); - doHandshake(result, WRITER); // ok to ignore return + doHandshake(result.handshakeStatus(), WRITER); // ok to ignore return handshaking = true; } else { if (trySetALPN()) { @@ -1015,14 +1073,14 @@ private void resumeActivity() { return (current & HANDSHAKING); }; - private boolean doHandshake(EngineResult r, int caller) { + private boolean doHandshake(HandshakeStatus handshakeStatus, int caller) { // unconditionally sets the HANDSHAKING bit, while preserving task bits handshakeState.getAndAccumulate(0, (current, unused) -> HANDSHAKING | (current & TASK_BITS)); if (stateList != null && debug.on()) { - stateList.add(r.handshakeStatus().toString()); + stateList.add(handshakeStatus.toString()); stateList.add(Integer.toString(caller)); } - switch (r.handshakeStatus()) { + switch (handshakeStatus) { case NEED_TASK: int s = handshakeState.accumulateAndGet(0, REQUEST_OR_DO_TASKS); if ((s & REQUESTING_TASKS) > 0) { // someone else is or will do tasks @@ -1050,7 +1108,7 @@ private boolean doHandshake(EngineResult r, int caller) { break; default: throw new InternalError("Unexpected handshake status:" - + r.handshakeStatus()); + + handshakeStatus); } return true; } @@ -1107,30 +1165,20 @@ boolean trySetALPN() { return false; } - // FIXME: acknowledge a received CLOSE request from peer EngineResult doClosure(EngineResult r) throws IOException { if (debug.on()) debug.log("doClosure(%s): %s [isOutboundDone: %s, isInboundDone: %s]", r.result, engine.getHandshakeStatus(), engine.isOutboundDone(), engine.isInboundDone()); + if (debug.on()) debug.log("doClosure: close_notify received"); + close_notify_received = true; + engine.closeOutbound(); if (engine.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) { // we have received TLS close_notify and need to send // an acknowledgement back. We're calling doHandshake // to finish the close handshake. - if (engine.isInboundDone() && !engine.isOutboundDone()) { - if (debug.on()) debug.log("doClosure: close_notify received"); - close_notify_received = true; - if (!writer.scheduler.isStopped()) { - doHandshake(r, READER); - } else { - // We have received closed notify, but we - // won't be able to send the acknowledgement. - // Nothing more will come from the socket either, - // so mark the reader as completed. - synchronized (reader.readBufferLock) { - reader.completing = true; - } - } + if (!writer.scheduler.isStopped()) { + doHandshake(HandshakeStatus.NEED_WRAP, READER); } } return r; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java index 2383b6516b1..9b3998333ed 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +26,7 @@ package jdk.internal.net.http.common; import java.io.Closeable; -import java.lang.System.Logger.Level; import java.nio.ByteBuffer; -import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.concurrent.CompletableFuture; @@ -318,11 +316,33 @@ private void run1() { downstreamSubscriber.onNext(b); datasent = true; } - if (datasent) upstreamWindowUpdate(); + + // If we have sent some decrypted data downstream, + // or if: + // - there's nothing more available to send downstream + // - and we still have some demand from downstream + // - and upstream is not completed yet + // - and our demand from upstream has reached 0, + // then check whether we should request more data from + // upstream + if (datasent || outputQ.isEmpty() + && !downstreamSubscription.demand.isFulfilled() + && !upstreamCompleted + && upstreamWindow.get() == 0) { + upstreamWindowUpdate(); + } checkCompletion(); } } + final int outputQueueSize() { + return outputQ.size(); + } + + final boolean hasNoOutputData() { + return outputQ.isEmpty(); + } + void upstreamWindowUpdate() { long downstreamQueueSize = outputQ.size(); long upstreamWindowSize = upstreamWindow.get(); @@ -341,7 +361,7 @@ public void onSubscribe(Flow.Subscription subscription) { throw new IllegalStateException("Single shot publisher"); } this.upstreamSubscription = subscription; - upstreamRequest(upstreamWindowUpdate(0, 0)); + upstreamRequest(initialUpstreamDemand()); if (debug.on()) debug.log("calling downstreamSubscriber::onSubscribe on %s", downstreamSubscriber); @@ -356,7 +376,6 @@ public void onNext(List item) { if (prev <= 0) throw new IllegalStateException("invalid onNext call"); incomingCaller(item, false); - upstreamWindowUpdate(); } private void upstreamRequest(long n) { @@ -365,6 +384,16 @@ private void upstreamRequest(long n) { upstreamSubscription.request(n); } + /** + * Initial demand that should be requested + * from upstream when we get the upstream subscription + * from {@link #onSubscribe(Flow.Subscription)}. + * @return The initial demand to request from upstream. + */ + protected long initialUpstreamDemand() { + return 1; + } + protected void requestMore() { if (upstreamWindow.get() == 0) { upstreamRequest(1); @@ -428,7 +457,7 @@ public void addData(ByteBuffer l) { } void checkCompletion() { - if (downstreamCompleted || !upstreamCompleted) { + if (downstreamCompleted || (!upstreamCompleted && !completionAcknowledged)) { return; } if (!outputQ.isEmpty()) { diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java index 914e7cb2907..99cdf6934ff 100644 --- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java +++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java @@ -95,7 +95,7 @@ public KeyImpl(KerberosPrincipal principal, this.keyBytes = key.getBytes(); this.keyType = key.getEType(); } catch (KrbException e) { - throw new IllegalArgumentException(e.getMessage()); + throw new IllegalArgumentException("key creation error", e); } } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesDkCrypto.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesDkCrypto.java index 54b9edffe4d..f04f28ae134 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesDkCrypto.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesDkCrypto.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,8 @@ import sun.security.krb5.internal.crypto.KeyUsage; import java.util.Arrays; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * This class provides the implementation of AES Encryption for Kerberos * as defined RFC 3962. @@ -104,10 +106,8 @@ public byte[] stringToKey(char[] password, String salt, byte[] s2kparams) byte[] saltUtf8 = null; try { - saltUtf8 = salt.getBytes("UTF-8"); + saltUtf8 = salt.getBytes(UTF_8); return stringToKey(password, saltUtf8, s2kparams); - } catch (Exception e) { - return null; } finally { if (saltUtf8 != null) { Arrays.fill(saltUtf8, (byte)0); @@ -118,14 +118,7 @@ public byte[] stringToKey(char[] password, String salt, byte[] s2kparams) private byte[] stringToKey(char[] secret, byte[] salt, byte[] params) throws GeneralSecurityException { - int iter_count = DEFAULT_ITERATION_COUNT; - if (params != null) { - if (params.length != 4) { - throw new RuntimeException("Invalid parameter to stringToKey"); - } - iter_count = readBigEndian(params, 0, 4); - } - + int iter_count = DkCrypto.iterationCount(params, DEFAULT_ITERATION_COUNT); byte[] tmpKey = randomToKey(PBKDF2(secret, salt, iter_count, getKeySeedLength())); byte[] result = dk(tmpKey, KERBEROS_CONSTANT); @@ -485,17 +478,4 @@ private static byte[] PBKDF2(char[] secret, byte[] salt, return result; } - - public static final int readBigEndian(byte[] data, int pos, int size) { - int retVal = 0; - int shifter = (size-1)*8; - while (size > 0) { - retVal += (data[pos] & 0xff) << shifter; - shifter -= 8; - pos++; - size--; - } - return retVal; - } - } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesSha2DkCrypto.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesSha2DkCrypto.java index f46e1850946..5af0517f883 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesSha2DkCrypto.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesSha2DkCrypto.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ import sun.security.krb5.internal.crypto.KeyUsage; import java.util.Arrays; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * This class provides the implementation of AES Encryption with * HMAC-SHA2 for Kerberos 5 @@ -107,10 +109,8 @@ public byte[] stringToKey(char[] password, String salt, byte[] s2kparams) byte[] saltUtf8 = null; try { - saltUtf8 = salt.getBytes("UTF-8"); + saltUtf8 = salt.getBytes(UTF_8); return stringToKey(password, saltUtf8, s2kparams); - } catch (Exception e) { - return null; } finally { if (saltUtf8 != null) { Arrays.fill(saltUtf8, (byte)0); @@ -122,14 +122,7 @@ public byte[] stringToKey(char[] password, String salt, byte[] s2kparams) private byte[] stringToKey(char[] secret, byte[] salt, byte[] params) throws GeneralSecurityException { - int iter_count = DEFAULT_ITERATION_COUNT; - if (params != null) { - if (params.length != 4) { - throw new RuntimeException("Invalid parameter to stringToKey"); - } - iter_count = readBigEndian(params, 0, 4); - } - + int iter_count = DkCrypto.iterationCount(params, DEFAULT_ITERATION_COUNT); byte[] saltp = new byte[26 + 1 + salt.length]; if (keyLength == 128) { System.arraycopy(ETYPE_NAME_128, 0, saltp, 0, 26); @@ -525,17 +518,4 @@ private static byte[] PBKDF2(char[] secret, byte[] salt, return result; } - - public static final int readBigEndian(byte[] data, int pos, int size) { - int retVal = 0; - int shifter = (size-1)*8; - while (size > 0) { - retVal += (data[pos] & 0xff) << shifter; - shifter -= 8; - pos++; - size--; - } - return retVal; - } - } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/ArcFourCrypto.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/ArcFourCrypto.java index cb9912df6c2..a6fbefc464b 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/ArcFourCrypto.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/ArcFourCrypto.java @@ -90,8 +90,6 @@ private byte[] stringToKey(char[] secret, byte[] opaque) MessageDigest md = sun.security.provider.MD4.getInstance(); md.update(passwd); digest = md.digest(); - } catch (Exception e) { - return null; } finally { if (passwd != null) { Arrays.fill(passwd, (byte)0); diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java index abdbaed3a16..a72023fd9b8 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. */ /* @@ -31,8 +31,8 @@ package sun.security.krb5.internal.crypto.dk; import javax.crypto.Cipher; -import javax.crypto.Mac; import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.io.ByteArrayInputStream; @@ -695,4 +695,41 @@ static byte[] charToUtf16(char[] chars) { bb.get(answer, 0, len); return answer; } + + static int iterationCount(byte[] params, int defaultValue) + throws InvalidAlgorithmParameterException { + if (params == null) { + return defaultValue; + } + if (params.length != 4) { + throw new InvalidAlgorithmParameterException("Invalid params"); + } + if (params[0] != 0 || ((params[1] & 0xff) >= 80)) { + // IC should be less than 80 * 2^16. This is roughly + // the same as PKCS12KeyStore's 5_000_000 limit. + throw new InvalidAlgorithmParameterException( + "Incoming iteration count is too big"); + } + int iter_count = readBigEndian(params, 0, 4); + if (!ALLOW_WEAK_PBKDF2_ITERATION_COUNT && iter_count < defaultValue) { + throw new InvalidAlgorithmParameterException( + "Incoming iteration count is too small"); + } + return iter_count; + } + + public static final int readBigEndian(byte[] data, int pos, int size) { + int retVal = 0; + int shifter = (size-1)*8; + while (size > 0) { + retVal += (data[pos] & 0xff) << shifter; + shifter -= 8; + pos++; + size--; + } + return retVal; + } + + // Only used by test + public static boolean ALLOW_WEAK_PBKDF2_ITERATION_COUNT = false; } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ktab/KeyTab.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ktab/KeyTab.java index 87cdb528cdf..b9bcdee605a 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ktab/KeyTab.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ktab/KeyTab.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -371,12 +371,33 @@ public void addEntry(PrincipalName service, char[] psswd, addEntry(service, service.getSalt(), psswd, kvno, append); } - // Called by KDC test + /** + * Adds a new entry in the key table. + * @param service the service which will have a new entry in the key table. + * @param salt specified non default salt, cannot be null + * @param psswd the password which generates the key. + * @param kvno the kvno to use, -1 means automatic increasing + * @param append false if entries with old kvno would be removed. + * Note: if kvno is not -1, entries with the same kvno are always removed + */ public void addEntry(PrincipalName service, String salt, char[] psswd, int kvno, boolean append) throws KrbException { EncryptionKey[] encKeys = EncryptionKey.acquireSecretKeys( - psswd, salt); + psswd, salt); + addEntry(service, encKeys, kvno, append); + } + + /** + * Adds a new entry in the key table. + * @param service the service which will have a new entry in the key table. + * @param encKeys the keys to be added + * @param kvno the kvno to use, -1 means automatic increasing + * @param append false if entries with old kvno would be removed. + * Note: if kvno is not -1, entries with the same kvno are always removed + */ + public void addEntry(PrincipalName service, EncryptionKey[] encKeys, + int kvno, boolean append) throws KrbException { // There should be only one maximum KVNO value for all etypes, so that // all added keys can have the same KVNO. diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java index 0724520f3f8..07f5455ecf5 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java @@ -30,6 +30,7 @@ import javax.xml.xpath.XPathFunctionResolver; import javax.xml.xpath.XPathVariableResolver; import jdk.xml.internal.JdkXmlFeatures; +import jdk.xml.internal.XMLSecurityManager; import org.w3c.dom.Document; import org.xml.sax.InputSource; @@ -46,7 +47,8 @@ public class XPathExpressionImpl extends XPathImplUtil implements XPathExpressio * from the context. */ protected XPathExpressionImpl() { - this(null, null, null, null, false, new JdkXmlFeatures(false)); + this(null, null, null, null, false, new JdkXmlFeatures(true), + new XMLSecurityManager(true)); }; protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, @@ -54,13 +56,14 @@ protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, XPathFunctionResolver functionResolver, XPathVariableResolver variableResolver) { this(xpath, prefixResolver, functionResolver, variableResolver, - false, new JdkXmlFeatures(false)); + false, new JdkXmlFeatures(true), + new XMLSecurityManager(true)); }; protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, JAXPPrefixResolver prefixResolver,XPathFunctionResolver functionResolver, XPathVariableResolver variableResolver, boolean featureSecureProcessing, - JdkXmlFeatures featureManager) { + JdkXmlFeatures featureManager, XMLSecurityManager xmlSecMgr) { this.xpath = xpath; this.prefixResolver = prefixResolver; this.functionResolver = functionResolver; @@ -69,6 +72,7 @@ protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, this.overrideDefaultParser = featureManager.getFeature( JdkXmlFeatures.XmlFeature.JDK_OVERRIDE_PARSER); this.featureManager = featureManager; + this.xmlSecMgr = xmlSecMgr; }; public void setXPath (com.sun.org.apache.xpath.internal.XPath xpath) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java index bddc73811ee..f9307122f3c 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java @@ -47,7 +47,7 @@ * New methods: evaluateExpression * Refactored to share code with XPathExpressionImpl. * - * @LastModified: Jan 2022 + * @LastModified: Nov 2025 */ public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath { @@ -168,7 +168,8 @@ public XPathExpression compile(String expression) // Can have errorListener XPathExpressionImpl ximpl = new XPathExpressionImpl (xpath, prefixResolver, functionResolver, variableResolver, - featureSecureProcessing, featureManager); + featureSecureProcessing, featureManager, + xmlSecMgr); return ximpl; } catch (TransformerException te) { throw new XPathExpressionException (te) ; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java index 6b33783306f..15bbc9eb964 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java @@ -48,6 +48,9 @@ protected static class GCTestRunner extends TestRunner { public GCTestRunner(Test test, String[] args) { super(test, args); + // GC tests often run at the brink of OOME, make sure + // LocalRandom is loaded, initialized, and has enough memory. + LocalRandom.init(); } private GCParams getGCParams(String[] args) { diff --git a/test/jdk/java/awt/Frame/GetBoundsResizeTest.java b/test/jdk/java/awt/Frame/GetBoundsResizeTest.java index d3c2ffb0bad..73d8bd8ab85 100644 --- a/test/jdk/java/awt/Frame/GetBoundsResizeTest.java +++ b/test/jdk/java/awt/Frame/GetBoundsResizeTest.java @@ -38,16 +38,15 @@ */ public class GetBoundsResizeTest { - private static final String INSTRUCTIONS = """ - 0. There is a test window with a "Press" button, - Its original bounds should be printed in the text area below. - 1. Resize the test window using the upper left corner. - 2. Press the button to print the result of getBounds() to the text area. - 3. Previously, a window could report an incorrect position on the - screen after resizing the window in this way. - If getBounds() prints the appropriate values for the window, - click Pass, otherwise click Fail. - """; + private static final String INSTRUCTIONS = + "0. There is a test window with a \"Press\" button,\n" + + " Its original bounds should be printed in the text area below.\n" + + "1. Resize the test window using the upper left corner.\n" + + "2. Press the button to print the result of getBounds() to the text area.\n" + + "3. Previously, a window could report an incorrect position on the\n" + + " screen after resizing the window in this way.\n" + + " If getBounds() prints the appropriate values for the window,\n" + + " click Pass, otherwise click Fail."; private static JTextArea textArea; private static Frame frame; @@ -92,6 +91,6 @@ private static Frame getFrame() { } private static void logFrameBounds(String format) { - textArea.append(format.formatted(frame.getBounds())); + textArea.append(String.format(format, frame.getBounds())); } } diff --git a/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_1.java b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_1.java index 808bb598cec..944bd368833 100644 --- a/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_1.java +++ b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_1.java @@ -39,23 +39,22 @@ public class AddRemoveMenuBarTest_1 { - private static final String INSTRUCTIONS = """ - An initially empty frame should appear. - - Click anywhere in the frame to add a menu bar at the top of the frame. - - Click again to replace the menu bar with another menu bar. - - Each menu bar has one (empty) menu, labelled with the - number of the menu bar appearing. - - After a menubar is added, the frame should not be resized nor repositioned - on the screen; - - it should have the same size and position. - - Upon test completion, click Pass or Fail appropriately. - """; + private static final String INSTRUCTIONS = + "An initially empty frame should appear.\n" + + "\n" + + "Click anywhere in the frame to add a menu bar at the top of the frame.\n" + + "\n" + + "Click again to replace the menu bar with another menu bar.\n" + + "\n" + + "Each menu bar has one (empty) menu, labelled with the\n" + + "number of the menu bar appearing.\n" + + "\n" + + "After a menubar is added, the frame should not be resized nor repositioned\n" + + "on the screen;\n" + + "\n" + + "it should have the same size and position.\n" + + "\n" + + "Upon test completion, click Pass or Fail appropriately."; public static void main(String[] args) throws Exception { PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() diff --git a/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_2.java b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_2.java index c0c98a5ca95..3a465ae1b35 100644 --- a/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_2.java +++ b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_2.java @@ -39,19 +39,18 @@ */ public class AddRemoveMenuBarTest_2 { - private static final String INSTRUCTIONS = """ - A frame with a menu bar appears. - - Click anywhere in the frame to replace the menu bar with - another one. - - Each menu bar has one (empty) menu, 'foo'. - - After the menu bar replacement, the containing frame - should not be resized nor repositioned on the screen. - - Upon test completion, click Pass or Fail appropriately. - """; + private static final String INSTRUCTIONS = + "A frame with a menu bar appears.\n" + + "\n" + + "Click anywhere in the frame to replace the menu bar with\n" + + "another one.\n" + + "\n" + + "Each menu bar has one (empty) menu, 'foo'.\n" + + "\n" + + "After the menu bar replacement, the containing frame\n" + + "should not be resized nor repositioned on the screen.\n" + + "\n" + + "Upon test completion, click Pass or Fail appropriately."; public static void main(String[] args) throws Exception { PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() diff --git a/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_3.java b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_3.java index a01ddd9925b..1dc92382111 100644 --- a/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_3.java +++ b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_3.java @@ -46,35 +46,34 @@ */ public class AddRemoveMenuBarTest_3 { - private static final String INSTRUCTIONS = """ - A frame at (100,100) contains two (2) rows of three (3) text - fields each, and under this, a checkbox labelled 'Use menubar'. - - The first row's text fields pertain to the x coordinates and - the second row's text fields pertain to the y coordinates. - - The first column, 'request', is an input only field for frame - location. (press enter to apply). - - The second column, 'reported', is an output only - field reporting frame location. - - The third column, 'inset', is an output only field reporting - the frame's inset values. - - You can click the 'Use menubar' checkbox to alternately add - and remove a menu bar containing an (empty) 'Help' menu. - - After a menubar is added or removed, the frame should not - have been resized nor repositioned on the screen and the - y inset should accurately reflect the presence or absence - of the menubar within the inset. - - The insets always include the window manager's title and border - decorations, if any. - - Upon test completion, click Pass or Fail appropriately. - """; + private static final String INSTRUCTIONS = + "A frame at (100,100) contains two (2) rows of three (3) text\n" + + "fields each, and under this, a checkbox labelled 'Use menubar'.\n" + + "\n" + + "The first row's text fields pertain to the x coordinates and\n" + + "the second row's text fields pertain to the y coordinates.\n" + + "\n" + + "The first column, 'request', is an input only field for frame\n" + + "location. (press enter to apply).\n" + + "\n" + + "The second column, 'reported', is an output only\n" + + "field reporting frame location.\n" + + "\n" + + "The third column, 'inset', is an output only field reporting\n" + + "the frame's inset values.\n" + + "\n" + + "You can click the 'Use menubar' checkbox to alternately add\n" + + "and remove a menu bar containing an (empty) 'Help' menu.\n" + + "\n" + + "After a menubar is added or removed, the frame should not\n" + + "have been resized nor repositioned on the screen and the\n" + + "y inset should accurately reflect the presence or absence\n" + + "of the menubar within the inset.\n" + + "\n" + + "The insets always include the window manager's title and border\n" + + "decorations, if any.\n" + + "\n" + + "Upon test completion, click Pass or Fail appropriately."; public static void main(String[] args) throws Exception { PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() .title("AddRemoveMenuBarTest_3 Instructions") diff --git a/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_4.java b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_4.java index 571fce7fba5..4c40ecda030 100644 --- a/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_4.java +++ b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_4.java @@ -41,24 +41,23 @@ public class AddRemoveMenuBarTest_4 { - private static final String INSTRUCTIONS = """ - There is a frame with a menubar and a single button. - - The button is labelled 'Add new MenuBar'. - - If you click the button, the menubar is replaced with another menubar. - This can be done repeatedly. - - The -th menubar contains one menu, 'TestMenu', - with two items, 'one ' and 'two '. - - Click again to replace the menu bar with another menu bar. - - After a menubar has been replaced with another menubar, - the frame should not be resized nor repositioned on the screen. - - Upon test completion, click Pass or Fail appropriately. - """; + private static final String INSTRUCTIONS = + "There is a frame with a menubar and a single button.\n" + + "\n" + + "The button is labelled 'Add new MenuBar'.\n" + + "\n" + + "If you click the button, the menubar is replaced with another menubar.\n" + + "This can be done repeatedly.\n" + + "\n" + + "The -th menubar contains one menu, 'TestMenu',\n" + + "with two items, 'one ' and 'two '.\n" + + "\n" + + "Click again to replace the menu bar with another menu bar.\n" + + "\n" + + "After a menubar has been replaced with another menubar,\n" + + "the frame should not be resized nor repositioned on the screen.\n" + + "\n" + + "Upon test completion, click Pass or Fail appropriately."; public static void main(String[] args) throws Exception { PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() diff --git a/test/jdk/java/net/httpclient/HttpSlowServerTest.java b/test/jdk/java/net/httpclient/HttpSlowServerTest.java new file mode 100644 index 00000000000..298f3222933 --- /dev/null +++ b/test/jdk/java/net/httpclient/HttpSlowServerTest.java @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsServer; +import jdk.test.lib.net.SimpleSSLContext; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.SocketAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +/** + * @test + * @summary This test verifies that the HttpClient works correctly when connected to a + * slow server. + * @library /test/lib http2/server + * @build jdk.test.lib.net.SimpleSSLContext HttpServerAdapters DigestEchoServer HttpSlowServerTest + * @modules java.net.http/jdk.internal.net.http.common + * java.net.http/jdk.internal.net.http.frame + * java.net.http/jdk.internal.net.http.hpack + * java.logging + * java.base/sun.net.www.http + * java.base/sun.net.www + * java.base/sun.net + * @run main/othervm -Dtest.requiresHost=true + * -Djdk.httpclient.HttpClient.log=headers + * -Djdk.internal.httpclient.debug=false + * HttpSlowServerTest + * + */ +public class HttpSlowServerTest implements HttpServerAdapters { + static final List data = List.of( + "Lorem ipsum", + "dolor sit amet", + "consectetur adipiscing elit, sed do eiusmod tempor", + "quis nostrud exercitation ullamco", + "laboris nisi", + "ut", + "aliquip ex ea commodo consequat.", + "Duis aute irure dolor in reprehenderit in voluptate velit esse", + "cillum dolore eu fugiat nulla pariatur.", + "Excepteur sint occaecat cupidatat non proident." + ); + + static final SSLContext context; + static { + try { + context = new SimpleSSLContext().get(); + SSLContext.setDefault(context); + } catch (Exception x) { + throw new ExceptionInInitializerError(x); + } + } + + final AtomicLong requestCounter = new AtomicLong(); + final AtomicLong responseCounter = new AtomicLong(); + HttpTestServer http1Server; + HttpTestServer http2Server; + HttpTestServer https1Server; + HttpTestServer https2Server; + DigestEchoServer.TunnelingProxy proxy; + + URI http1URI; + URI https1URI; + URI http2URI; + URI https2URI; + InetSocketAddress proxyAddress; + ProxySelector proxySelector; + HttpClient client; + List> futures = new CopyOnWriteArrayList<>(); + Set pending = new CopyOnWriteArraySet<>(); + + final ExecutorService executor = new ThreadPoolExecutor(12, 60, 10, + TimeUnit.SECONDS, new LinkedBlockingQueue<>()); // Shared by HTTP/1.1 servers + final ExecutorService clientexec = new ThreadPoolExecutor(6, 12, 1, + TimeUnit.SECONDS, new LinkedBlockingQueue<>()); // Used by the client + + public HttpClient newHttpClient(ProxySelector ps) { + HttpClient.Builder builder = HttpClient + .newBuilder() + .sslContext(context) + .executor(clientexec) + .proxy(ps); + return builder.build(); + } + + public void setUp() throws Exception { + try { + InetSocketAddress sa = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + + // HTTP/1.1 + HttpServer server1 = HttpServer.create(sa, 0); + server1.setExecutor(executor); + http1Server = HttpTestServer.of(server1); + http1Server.addHandler(new HttpTestSlowHandler(), "/HttpSlowServerTest/http1/"); + http1Server.start(); + http1URI = new URI("http://" + http1Server.serverAuthority() + "/HttpSlowServerTest/http1/"); + + + // HTTPS/1.1 + HttpsServer sserver1 = HttpsServer.create(sa, 100); + sserver1.setExecutor(executor); + sserver1.setHttpsConfigurator(new HttpsConfigurator(context)); + https1Server = HttpTestServer.of(sserver1); + https1Server.addHandler(new HttpTestSlowHandler(), "/HttpSlowServerTest/https1/"); + https1Server.start(); + https1URI = new URI("https://" + https1Server.serverAuthority() + "/HttpSlowServerTest/https1/"); + + // HTTP/2.0 + http2Server = HttpTestServer.of( + new Http2TestServer("localhost", false, 0)); + http2Server.addHandler(new HttpTestSlowHandler(), "/HttpSlowServerTest/http2/"); + http2Server.start(); + http2URI = new URI("http://" + http2Server.serverAuthority() + "/HttpSlowServerTest/http2/"); + + // HTTPS/2.0 + https2Server = HttpTestServer.of( + new Http2TestServer("localhost", true, 0)); + https2Server.addHandler(new HttpTestSlowHandler(), "/HttpSlowServerTest/https2/"); + https2Server.start(); + https2URI = new URI("https://" + https2Server.serverAuthority() + "/HttpSlowServerTest/https2/"); + + proxy = DigestEchoServer.createHttpsProxyTunnel( + DigestEchoServer.HttpAuthSchemeType.NONE); + proxyAddress = proxy.getProxyAddress(); + proxySelector = new HttpProxySelector(proxyAddress); + client = newHttpClient(proxySelector); + System.out.println("Setup: done"); + } catch (Exception x) { + tearDown(); throw x; + } catch (Error e) { + tearDown(); throw e; + } + } + + public static void main(String[] args) throws Exception { + HttpSlowServerTest test = new HttpSlowServerTest(); + test.setUp(); + long start = System.nanoTime(); + try { + test.run(args); + } finally { + try { + long elapsed = System.nanoTime() - start; + System.out.println("*** Elapsed: " + Duration.ofNanos(elapsed)); + } finally { + test.tearDown(); + } + } + } + + public void run(String... args) throws Exception { + List serverURIs = List.of(http1URI, http2URI, https1URI, https2URI); + for (int i=0; i<20; i++) { + for (URI base : serverURIs) { + if (base.getScheme().equalsIgnoreCase("https")) { + URI proxy = i % 1 == 0 ? base.resolve(URI.create("proxy/foo?n="+requestCounter.incrementAndGet())) + : base.resolve(URI.create("direct/foo?n="+requestCounter.incrementAndGet())); + test(proxy); + } + } + for (URI base : serverURIs) { + URI direct = base.resolve(URI.create("direct/foo?n="+requestCounter.incrementAndGet())); + test(direct); + } + } + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); + } + + public void test(URI uri) throws Exception { + System.out.println("Testing with " + uri); + pending.add(uri); + HttpRequest request = HttpRequest.newBuilder(uri).build(); + CompletableFuture> resp = + client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) + .whenComplete((r, t) -> this.requestCompleted(request, r, t)); + futures.add(resp); + } + + private void requestCompleted(HttpRequest request, HttpResponse r, Throwable t) { + responseCounter.incrementAndGet(); + pending.remove(request.uri()); + System.out.println(request + " -> " + (t == null ? r : t) + + " [still pending: " + (requestCounter.get() - responseCounter.get()) +"]"); + if (pending.size() < 5 && requestCounter.get() > 100) { + pending.forEach(u -> System.out.println("\tpending: " + u)); + } + } + + public void tearDown() { + proxy = stop(proxy, DigestEchoServer.TunnelingProxy::stop); + http1Server = stop(http1Server, HttpTestServer::stop); + https1Server = stop(https1Server, HttpTestServer::stop); + http2Server = stop(http2Server, HttpTestServer::stop); + https2Server = stop(https2Server, HttpTestServer::stop); + client = null; + try { + executor.awaitTermination(2000, TimeUnit.MILLISECONDS); + } catch (Throwable x) { + } finally { + executor.shutdownNow(); + } + try { + clientexec.awaitTermination(2000, TimeUnit.MILLISECONDS); + } catch (Throwable x) { + } finally { + clientexec.shutdownNow(); + } + System.out.println("Teardown: done"); + } + + private interface Stoppable { public void stop(T service) throws Exception; } + + static T stop(T service, Stoppable stop) { + try { if (service != null) stop.stop(service); } catch (Throwable x) { }; + return null; + } + + static class HttpProxySelector extends ProxySelector { + private static final List NO_PROXY = List.of(Proxy.NO_PROXY); + private final List proxyList; + HttpProxySelector(InetSocketAddress proxyAddress) { + proxyList = List.of(new Proxy(Proxy.Type.HTTP, proxyAddress)); + } + + @Override + public List select(URI uri) { + // our proxy only supports tunneling + if (uri.getScheme().equalsIgnoreCase("https")) { + if (uri.getPath().contains("/proxy/")) { + return proxyList; + } + } + return NO_PROXY; + } + + @Override + public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { + System.err.println("Connection to proxy failed: " + ioe); + System.err.println("Proxy: " + sa); + System.err.println("\tURI: " + uri); + ioe.printStackTrace(); + } + } + + public static class HttpTestSlowHandler implements HttpTestHandler { + static final AtomicLong respCounter = new AtomicLong(); + @Override + public void handle(HttpTestExchange t) throws IOException { + try (InputStream is = t.getRequestBody(); + OutputStream os = t.getResponseBody()) { + byte[] bytes = is.readAllBytes(); + assert bytes.length == 0; + URI u = t.getRequestURI(); + long responseID = Long.parseLong(u.getQuery().substring(2)); + System.out.println("Server " + t.getRequestURI() + " sending response " + responseID); + t.sendResponseHeaders(200, -1); + for (String part : data) { + bytes = part.getBytes(StandardCharsets.UTF_8); + os.write(bytes); + os.flush(); + System.out.println("\tresp:" + responseID + ": wrote " + bytes.length + " bytes"); + // wait... + try { Thread.sleep(300); } catch (InterruptedException x) {}; + } + System.out.println("\tresp:" + responseID + ": done"); + } + } + } + +} diff --git a/test/jdk/java/net/httpclient/LargeHandshakeTest.java b/test/jdk/java/net/httpclient/LargeHandshakeTest.java new file mode 100644 index 00000000000..b03cdb36498 --- /dev/null +++ b/test/jdk/java/net/httpclient/LargeHandshakeTest.java @@ -0,0 +1,1200 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsServer; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.SocketAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.time.Duration; +import java.util.Base64; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +/** + * @test + * @bug 8231449 + * @summary This test verifies that the HttpClient works correctly when the server + * sends a large certificate. This test will not pass without + * the fix for JDK-8231449. To regenerate the certificate, modify the + * COMMAND constant as you need, possibly changing the start date + * and validity of the certificate in the command, then run the test. + * The test will run with the old certificate, but will print the new command. + * Copy paste the new command printed by this test into a terminal. + * Then modify the at run line to pass the file generated by that command + * as first argument, and copy paste the new values of the COMMAND and + * BASE64_CERT constant printed by the test into the test. + * Then restore the original at run line and test again. + * @library /test/lib http2/server + * @build jdk.test.lib.net.SimpleSSLContext HttpServerAdapters DigestEchoServer LargeHandshakeTest + * @modules java.net.http/jdk.internal.net.http.common + * java.net.http/jdk.internal.net.http.frame + * java.net.http/jdk.internal.net.http.hpack + * java.logging + * java.base/sun.net.www.http + * java.base/sun.net.www + * java.base/sun.net + * @run main/othervm -Dtest.requiresHost=true + * -Djdk.httpclient.HttpClient.log=headers + * -Djdk.internal.httpclient.debug=true + * LargeHandshakeTest + * + */ +public class LargeHandshakeTest implements HttpServerAdapters { + + // Use this command to regenerate the keystore file whose content is + // base 64 encoded into this file (close your eyes): + private static final String COMMAND = + "keytool -genkeypair -keyalg RSA -startdate 2019/09/30 -valid" + + "ity 13000 -keysize 1024 -dname \"C=Duke, ST=CA-State, L=CA-Ci" + + "ty, O=CA-Org\" -deststoretype PKCS12 -alias server -keystore " + + "temp0.jks -storepass passphrase -ext san:critical=dns:localh" + + "ost,ip:127.0.0.1,ip:0:0:0:0:0:0:0:1,uri:http://www.example.c" + + "om/1.2.3.6.1.4.1.11129.666.666.666.999/041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100,uri:http://www.example.com/1.2.3.6.1.4.1.111" + + "29.666.666.666.999.2/041287234567896776987654327821000412872" + + "345678967769876543278210004128723456789677698765432782100041" + + "287234567896776987654327821000412872345678967769876543278210" + + "004128723456789677698765432782100041287234567896776987654327" + + "821000412872345678967769876543278210004128723456789677698765" + + "432782100041287234567896776987654327821000412872345678967769" + + "876543278210004128723456789677698765432782100041287234567896" + + "776987654327821000412872345678967769876543278210004128723456" + + "789677698765432782100041287234567896776987654327821000412872" + + "345678967769876543278210004128723456789677698765432782100041" + + "287234567896776987654327821000412872345678967769876543278210" + + "004128723456789677698765432782100041287234567896776987654327" + + "821000412872345678967769876543278210004128723456789677698765" + + "432782100041287234567896776987654327821000412872345678967769" + + "876543278210004128723456789677698765432782100041287234567896" + + "776987654327821000412872345678967769876543278210004128723456" + + "789677698765432782100041287234567896776987654327821000412872" + + "345678967769876543278210004128723456789677698765432782100041" + + "287234567896776987654327821000412872345678967769876543278210" + + "004128723456789677698765432782100041287234567896776987654327" + + "821000412872345678967769876543278210004128723456789677698765" + + "432782100041287234567896776987654327821000412872345678967769" + + "876543278210004128723456789677698765432782100041287234567896" + + "776987654327821000412872345678967769876543278210004128723456" + + "789677698765432782100041287234567896776987654327821000412872" + + "345678967769876543278210004128723456789677698765432782100,ur" + + "i:http://www.example.com/1.2.3.6.1.4.1.11129.666.666.666.999" + + ".2/041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "27821000412872345678967769876543278210001,uri:http://www.exa" + + "mple.com/1.2.3.6.1.4.1.11129.666.666.666.999.2/0412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "5678967769876543278210002,uri:http://www.example.com/1.2.3.6" + + ".1.4.1.11129.666.666.666.999.2/04128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210003,uri:http://www.example.com/1.2.3.6.1.4.1.11129.666" + + ".666.666.999.2/041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "96776987654327821000412872345678967769876543278210004,uri:ht" + + "tp://www.example.com/1.2.3.6.1.4.1.11129.666.666.666.999.2/0" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "1000412872345678967769876543278210005,uri:http://www.example" + + ".com/1.2.3.6.1.4.1.11129.666.666.666.999.2/04128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210006,uri:http://www.example.com/1.2.3.6.1.4" + + ".1.11129.666.666.666.999.2/041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "10007,uri:http://www.example.com/1.2.3.6.1.4.1.11129.666.666" + + ".666.999.2/0412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "6987654327821000412872345678967769876543278210008,uri:http:/" + + "/www.example.com/1.2.3.6.1.4.1.11129.666.666.666.999.2/04128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210009,uri:http://www.example.com" + + "/1.2.3.6.1.4.1.11129.666.666.666.999.2/041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "698765432782100041287234567896776987654327821000412872345678" + + "967769876543278210004128723456789677698765432782100041287234" + + "567896776987654327821000412872345678967769876543278210004128" + + "723456789677698765432782100041287234567896776987654327821000" + + "412872345678967769876543278210004128723456789677698765432782" + + "100041287234567896776987654327821000412872345678967769876543" + + "278210004128723456789677698765432782100041287234567896776987" + + "654327821000412872345678967769876543278210004128723456789677" + + "6987654327821000A"; + + // This is a Base64 encoded keystore containing our certificate. + // The keystore itself was produced with the command above, then its content + // base 64 encoded into the string below. The helper function to produce + // and format the string below are included in this file. + private static final String BASE64_CERT = + "MIJR0AIBAzCCUYoGCSqGSIb3DQEHAaCCUXsEglF3MIJRczCCAyAGCSqGSIb3" + + "DQEHAaCCAxEEggMNMIIDCTCCAwUGCyqGSIb3DQEMCgECoIICsjCCAq4wKAYK" + + "KoZIhvcNAQwBAzAaBBSx1wdTxGqb9z4exOHVZNswvFL+oQICBAAEggKA7JdM" + + "91kkP9QkG/igw2p+prxeEOQSmyScKMLtln81eKvT9zpvNjtT+hjABcH2QY8u" + + "1Z3Ji48Umoaxi38Fk58/VazFM6wpL47VVNJ2EeTdj8sFoo8ExCH8EHJNNaVK" + + "VNTG0YWOMa/HOPttl5wtD6pReGNOrVYVOnI2aY6zTqwI0sZS4uPczfb21vyI" + + "NyF4B0Z9WGl77PRoGwrSeoLspISBTq6/JE8UhMWtuz7xnXw04DGp4DeIOO9n" + + "E8+VBRKOELPqNaQ+VEgnwPNtPzjohi4Cwaf84c6vokAl1S/V6GzS0Al1mSGH" + + "syAaszDYWcXXp2JpSXVAztySWZErwHE49/P42taXdhJvOSfqYb6FHpdrCXST" + + "TPo+ULCGxQ83EGfnb/qaqAYZrS//+lzzqw18OY0JcF1i+cGHY8ofJK+bYr7x" + + "ZyC8pLut84pEWNTp1V7SQcMif2Gd2SO2Y+ua4isjfMLNeNE/4puCV1vYsyiz" + + "C9Gnp0Jywv13ioaC24Qy68uVQ81TvwizN3j7FxPCQOEEjXpfJ+5x2q0pUfqp" + + "Roy7ow3Z+d+/fpMIcgyMqWidzLBChRkx4Ugnh7rYBfY1ghchlu8WIIhiR/8p" + + "EBX5WQHyEtwrXOFiWxT+QwXWjbs9dQSUoCU1i2zwCFW9R8FkY2yb98QxF74z" + + "0TpyW+w6cGPUNUd2T143PL4eGt4rGUBUMewe2ENSgZCDstvtiNPfccW8f9tq" + + "G49pHBZt1ZIadM/DbCk1cqDD3u2/e7c57mInFkBBJKjl2K7GK9EYsiey+3Fk" + + "NvkxbaF+89OTqEDPP4E97EeHkk/MFe0bQ/a/aXZrTPSN7mNgusWBQyztnYex" + + "BRr8sPRhNDFAMBsGCSqGSIb3DQEJFDEOHgwAcwBlAHIAdgBlAHIwIQYJKoZI" + + "hvcNAQkVMRQEElRpbWUgMTU2OTk1MzczODEyNzCCTksGCSqGSIb3DQEHBqCC" + + "Tjwwgk44AgEAMIJOMQYJKoZIhvcNAQcBMCgGCiqGSIb3DQEMAQYwGgQUBIoZ" + + "0r5Kc2cs6fHseA1vKWpQi30CAgQAgIJN+Lch8gN0kyMcpdNDM2iAfBHd/kXZ" + + "4ye8lmGvvV0Yy9dd4Q6zmOmkPjWcusyh/vJdya8OG8Fxc/nQmyhB441qtJR5" + + "dwIQe/7lft2gDg2sBD0osPvEHesvFVr0+2cy22sdBXS4ihdtVTciPV+4v0EU" + + "AK6Lcib57Ml7MI6VhBGpWLkaZXv/25CqXGaiY85dSXPHMugvfJn8JoNxe+tN" + + "PDEAy5ar5bnSD9Xl8GyQwHFwQ1P+gEjwg0+hC6OQA6Eg0jBFhIL+dCf6FJwz" + + "J2HekpKXcyCTNTx0HB8AW3u4gVjao0B7oNr0GZprpPgYp4dl04Tar6fmb9MN" + + "w4MWkcySjX0wCNjpvE0bWlUx55jlN+25SWNEafmbzRNECW1hT6Xl3HLLNQQv" + + "8fIgkd2200+Ppwk+cG2dYMrl0MpHPxOo2l+nLNDI+a84v6R2Mqf3qVNfcRxZ" + + "Xmw0kJ1JNUKhd0Dy6FKB7tY1Gwc4rfQQgdUXTlnB96rUrSK2o91QZZ9rN3PD" + + "SbbQRzSBSPMDen+W5878kwd1BkDH1ao7qOHoGYYiYxczkMVncOtOIdg8VScU" + + "t/N1NS9Yrzlj0aAYwX5EYmYzFMiyXr+El/7VnrLHBiaYwJaYVw7a1HgkSXxb" + + "er/vgM639AIhT5ab9NFF+ib+7qwbWPzggIBtfm1bXiRPE6Ue0+aQ9g4vYSR7" + + "QNusu/2Kwyrd6cwqJnQnG53wiSXh3hs7dvNRYpM16iF1dTeud0FSpQx1tMFi" + + "Wp9cGwtUSzvLw1+5Mvz7igLTNAPyTMFNAYFR7JZgRjg1035Y7Xo4aXNMVtGp" + + "BCa+/eJzE33CHH2+kuSa13N6qHA2Ek33aR4Vi7P/QOI1aghsR6tL62ctoq4c" + + "FmRwvReYGdFK08+B2auPHOEPdGaPefydmPNnFLDguH6d2NYIH8cgzpjz48Gf" + + "i5UQfh/UJAxricLjuV2eor7gZCCaC9MfnLlHnDH5MYUQgDsGBTRxh6rpZxVo" + + "PFUm1DQCFdDHgmvVz+GAuiVzUu0TrUAxBeycl9lrDshgZj2jd9FU7XcMFwzC" + + "dMsWJaA8EC8u31vnpWWqK8C03pdXTbWOEJdIDMXKOzd2ZxjGPnBSNXNRsGzi" + + "RdEspHElrfGwHA5Vpsj4Q6tMZ8tZ+gSSmBrKP6xNUDNwi1bPayJw/dAKaC+D" + + "vp5sx/+nZcxSF/ig8ZM6aA3escS1GBNBWFrx2vEASHNpHZsTIOTuOM4e584/" + + "NJpNlRfaTzJ3i9/XoufnHbT5pmpZgxlZckYto3h6lL8R0bXthICRrI37Oh6s" + + "yfO7zhMiGoNdaFAnXTsMzA+Uwr1gesHWE9Rbd+jrkcGgL4Zst/A/c64F58qt" + + "J2RzA3xJCGQ6AXB3SlDHLObuYZ48TH4v2nJ4S8RTs/ant/T9DTRJyhQMa9+P" + + "QC8Ny1ejFOK71Oqjz7J2jGpoBm3gDRZDYeBa6ZiMeJf8Q+bkpbEgUQbdiXhn" + + "dpN7acdJTSHnO5/3Y4G1T6kLNzKc1+NYiYwH9Y6KIMa9IaocOA4wCHEFog7Z" + + "Ac6vFv6r9/cnXEIe9/t5gYLL7X/gU6HMqZFjM0QjRru/Sy9vYfpytqrnOf/q" + + "eOTJ9gRdIn7jNVTrgrE3ZgNvxYapaDMyFG/ixZV0cblsVJ6JO4MArOQq6q9/" + + "LWGtYYEDclyLNxUTYf0gHmVRhYV8rlyMKXtDu0aBOOn13dRxKKVN5pG+LrKe" + + "V+FZ3tDhYiFBxI/gkAiegSQlvknJlbEuanCWFq7sHOZ3C76L5G4qtRv7tHAs" + + "8rtqzhYnddxIkTcj4tkVYsFxkj1afSuLSSoYqc0jYZUXHkL+5U0ZRxhJbo6b" + + "/QVtiGXbS9i1em3+Yr47jHRH7f5Crlc2EdEzZaIm8tCw5G3CddXhhCpQTT3r" + + "Mjwep5/w2ai8qbGC1xo6AV7ZyQS535UbIhOYMPO7vd3oUBmQXyutSxx8Wedx" + + "HbIlBdZ44JlRWELdL6Ejo7PwhG0F3Zd3+FtasM13teYlbDWdFeoTF+inrXCG" + + "BCSqoUDYLAAxRK7oYKSDqfrcRioHO4AkeaF8x5YZpRSM73yawZaWeLVq1NKb" + + "DdeSJEjqDs5Ve6cA/jSLDtlJqudspFamzkdUWa4L1Tc15JY2YD8urNz/qXUK" + + "E74H2MtQWjrQ8Yjz7y+3yUTYd8Clp1dBKV2haIr+sCTnFtUXaQ9LZF5S+enU" + + "mOf7OmdFObwvV1f43HDuDSiFZpE+w57YmAgSIfWelKnGvvn1lBBWBomyVBKo" + + "69seibaSyUXyuq8q3525ZKpHIcic7doYOYgqU94HBQOwkwTtoiX3tKX4EgDa" + + "9AjYD4LHITkwgKzsQAe+3ASKq3SPFXi/UbYuZNXdkXgh7kqL6PZPD6ayIxOW" + + "f8E95fZRXPyNbKf5U9pp9hVKeuOPKbEYKsQNG0ZiephMmV3S6JjSqLo+qTU+" + + "QyGH3vhwlhda9cmxrpKCy0KM8AHyWoS4L5TAiJXp6moCttP0v8P/RRFtBePl" + + "53nyLwZ5SyXv4ifVayJyyeDXn08In9MINLRyjvNF2gHbHI7XbeQKqB3yIBC9" + + "sKpyShX6UKb1Dnd3Z19rT4a7QUkqfcodX9cU7tV6ncRuP5ZJRLHQQi9w/2DI" + + "Leu8Y43jJ/CWYo8Fb8IXHrWA/hwNT28Yr3OcZUIDFdbdxenTKyhMlDOQ87aU" + + "VXBCnq96jEAzY0NY3PZj+CBvts2wlCJJDhBCVTXM9OusZjH2/B6phWO7ybMq" + + "15QqYyypNM62oBlu82psklHRREO1D23MaOyoXSHYVFxvLMKxhstK3wd59cst" + + "8V/uvzzrURJu85X1X0cQJaKB+OjvBT8n8e9jzjATOTiGH2ULLSro2wc7Ne1r" + + "bEK4qHeuSwlvulvcqB7wK84PItmVOW+g9VuXA9QGGHxzybbs+/QaMqJzdN6C" + + "oS1Az5UmvZbdnSAuXtW8xiKJ+ELAGCjOcdkzQaAbd8Tq5hUXAgYeNQnoDjJz" + + "+a8CTk1IaGkeHlg7MrV98AuIQjUB16IU6gE4MH6ueOIZhF3PB2Fp0dGPXL6O" + + "KzIiC3jM7rIuTmOstI/t+XB3+BYxKvLuQhbV5n8sUBsGFFGBKoxIZawKG1Pk" + + "3Dny2rzcB2JkcOO8r6f0dA5V4PKIrhmVeQJyHgY+/fF+JMZxfjYmaSrwu/1R" + + "JnlDfDCIwNon7smi8QwXbEvRehI5a883yI07COM1paHBKNddlw4sfkfbIrNx" + + "LQJLb0mHgqvHAblivBmMuaiZaK0MVOgZTe4bYuYdRSN8/ueZDHOo7lyfXGzc" + + "8FEThaiGp5m/uWYJgG2FIRxM6by9PhusaTZgJ8DmjRLF5yDuR14gau6zj7GZ" + + "TMXGDIDTRWTKTP0/DYF+EEnuWJb2JrrxMnWH8X7xXhrRA6Ku3nqVEwy8eUnR" + + "WtLAQkApLOEhsp3wQyLRbaydcD1Si9s5JICy/m5Sv2NXseKbmAHDphTYuSGr" + + "Gjk5ryTEaaiULVvi7mv1HqDq3fli/PAzMIcsK0yaF9rQv7JjtsOtZtr77+zs" + + "vM8CSY835WpqTtjGDC+HWHulEADgS4ShpIrn3zgyEd1jrRY6rR5ZDuioc7sE" + + "2A/8w6I5KkmcXMu/jKoLjotdUvvGMMAIhqCZD8sD+F2jpNcCV3/7NpwaJSk+" + + "61rfPxzQRKu1jn/9TV7e5PyWQMkPOMbTMlA9jJPi5WEXNanIFTJBYgI6vmYc" + + "156uLrlXh4F5gpLN42JyhddSbV4dXXLt8an9X4dMAJmdgBmzFldFPU7I88Xm" + + "nuy3Rkqs2p4eb44b4oe9xdIyUw3fkfdoYzRx96X2Tvlx67BvbprglcdoiBce" + + "UitoMsN5tI9+o4/wp6SCU1nv97Yl/kGR6xyY/5irK3wVr2DsrRSF/WuycPFV" + + "3EOZLCoh/Y+9yH2dLlslarL2ZVIe701NTp/fN1GCQoCI2elSwXZAiJ446Fyv" + + "F5x8UTIbAZKiJfL8F09XVnNSRIp78rcNUUeFKehewGJ/I6WtD/SyGc7uTCKi" + + "EqXAwoQN+4GcncLQ2eqFFqR1aZLEcJKU79EpKu08rFTl0X9NaA7Qd0nXAiNF" + + "EUz1Xo33ReE9l67+QLXYK17UIqxkFQnawydZKt1T7HeRpTKEQzo9/wLk+IYD" + + "m5y8DXHK/d/kPySyLW4+srw3HRIe2Cuz9nNhPTUKtVC9CPt9NT9guhOhDGRA" + + "XBkF08Snjpn7wG6G1cE2gwU3W4oQIvCAwpdsJ8leg0fbosc1UD1QHR+3CxIU" + + "0yoPm19LygYjIyTg55bGBID0GV+DAHKUVHIUkBpaPM0PcSxsJgFv1seuQSJy" + + "dRUcKGzPg+xJhVvHuuAnnlBibjzrl/DBLCPgOl2kybpsv1sLJdTLEkwkv/yf" + + "83PdSz+uPha5hv7AGfxEaaUwbnktHultVbjO+IKBNqgjz763XgUAKbtfxW4u" + + "VLBESpZiVe/gzgNV7j+6+vHWsOC8GBMjJwHGAFfTyjYv9BmrxkQyabZ8wCb/" + + "5NPvaHBH+qkWVVWBaLZuOkgG9dmQI/oEcO2H9IDtve3OEXGuP2zG3xkk7h8W" + + "RwcHoz/anAbEHA1wmPYn/NFn2FZW3KxdyD0/URj4DaZqMYCJMCN8TkbLBxQk" + + "ZS+8VCcXMALybXUD9OLX/jUHaPqO70e9+o4cD+O/JfxKkTj5A2WD2345b8nK" + + "Lill7lJ5JlYekkGG4LQf92FbH0ytLSVB+A4oc7/nxI5ciWy5vDmaG+3HS5W2" + + "mGxnpLApVJZhhiJRB5fjfgRiuVbcGNWFQtgH2imMorrE0FzONSQfepLtBSQM" + + "Ec8NWgmEa5O0RIYLMblXisxt7jB0k8NqgiSm3dmNmR7GhbBt+mg95uCXWmB7" + + "nbcUaTWUw4Lb1EwVB/MmUEBjer/JYDADWz+NS/0VcAgBbjk7vrjAdgXkgiRB" + + "l9qBDioO73qjmjeTiCjoLsuEreXPu9WTaZDuyKO1uxHoesZE0AcWjcZgKVY+" + + "1Eqz3awCUxQTH+/1HsVxONmbYzJgMZ3f9Kuk7dxwFc0jgIw0LfFNnBDW3wY6" + + "nrdtm7vEuR0gfYU83oqXQqAMQGwMZXKXtibS7yPL+rinLwcoWYkZaIaI6LTb" + + "3DthepCtsYfIpaErOHMVOqxDUb4n5e0EUJiy7gw9JQjDX+VzpxAnt2Kc6/fl" + + "kon4xadP5oyNx3YU+jIywk8p/NMhDfia0fFvl2BHRcgFXHyOa8IPNmRb0CgO" + + "78Zbt3NG2+cFUx1WwOuCohfoYt/STUnxDXpOCrxYk2CD09Vm+2xC+7+VLfex" + + "UnKzKH0tWLNyzA5XKSHyLe6lJCO+mvgdp2vrO7i053YVfqfqWSL9rhR0tH5w" + + "NO8uUd1/ozkIjb74PSft0txTP25/c4/MEWy2JIg+HMM+2fmanJi4xJsuxBfq" + + "2p/7AYfmsp05TfoSLieWDBNx3lrADGUnuPf/o8Zo2tgn8ek4ig706kqzZy9W" + + "p1PaYNK6p/MLI86Sv6OLHf6fR0u6IsGPqMcYx9J7U5SCemntLvucfWRAqRn4" + + "5htDzdTFrtO2nXLNDxk20DQtol7yyBg3ngVX8XDhKReGdV/Z9kEeJhgzbxLT" + + "fbjoGQD5twirxYyV+eRqQZM7fu71Srg6lz7najEyH9pbQjpEPForDy5Briry" + + "nplWImdWd+KwG0N35+H48kpxAU09sOUGURzsUPdwTANQUnrWWMo5+UIjxXtR" + + "cDMuQmj8vlYH8iH0bKgexZMb7cRciRUF3az3lo24FA6l7e4SkyFErGJITGFN" + + "IHO7wDz9h4rLikjGkz4G1d04XQCxrpHSrW9fj808up1LSoaye5ijutJihEHu" + + "hkiFLi1nwuhd4ZrAZD+0VkTde9GAi9xPa8Cx+lh4JMB5mghk8uTjv7G4KqzE" + + "Wlpos30CMyCc5cBGqkCVLKt64+KgUyt0FnU6tbZve7i1/oYyUaWx7BCk6o9f" + + "9PuQM2bOwqhjRtpBR7q9Zb9H+qytAM8psLV6Sh9K0cK5Ug4BBEAtCK+JHBHG" + + "U3zkhu2FXlm0Mnp5xiaTvPwPWe0P/mrD4Fhgn2pbPvyJXTPgWV107zafKuLW" + + "34/+ML8oog69/oUOSAw4vaJx8PWguMRoQIsS6ATT2RhUVn/t21fJK9j6eF/B" + + "YG5IIEavyybQMILx86+SI5sLi9j+Xqd5bPLWnZTataP+voMTzyyYqAi6ybEl" + + "4QkWM0c8t141t7FULXHMTrKhdZDocb9plz3sfYk6cEqlOphvmhbZbT88iWJe" + + "ndBHJxY0SL0NQ7Yl6fg/DHt4goXSIWGL5IamBM8CZnVwyCHz7laP15Zsc92H" + + "DqWgbojeMxiPSVnFqxFzL/6TBBTQYuNl6+CgCOPIe88FwhZvfwzXVnQHb91i" + + "58t7pwXCURscYFK7iyxi7QTrofT0QM4upsI3zBqOO0X2SOW5H6Dx3uukNP2r" + + "Ud0AbXWHglnooaMNl/XRfYyb6VYg28r7qcfsSKlWuRenNf/ejaLl6GeO/ef9" + + "VI+ia0qv7S2Hi6xgdw3/NTqltehTyZylC7LtKr/TVRFdGLsFKtGvT/KGMYt4" + + "eUYR1zz61CVxAjjGAg+NlpTG8P50xralMthUppA7P6X4j4cDrD3E74HYg9Zv" + + "4PLAh6MOymj0YbW+/QjbO13DeSXxYX5/EGk78+sBOVSzvigI9NLvWHZMFylp" + + "mi5m3Wh7cQojpkeKXSw0XRd8lSeMN6lrzkMknniWfZZhK3idGCH3kHd7IGzC" + + "X67K3gf+8syXOIpoDfUJHVpfvKZCw5XN2huYNGKP8KqELMoDatmEoB4hoVq/" + + "VIssuwanWj3vDOxp7bYRUXID9dfTrgq5A5+1RuzrJVpmK+maTGypBDvemJhw" + + "OSP62Oa+1ryH3+e1yqWDbWJrDts1S1wqMRRG5LKP16e3ZUYo33Gir/qott4b" + + "J3PSvZn50KLnkyt1apUGE3pIyytvencsCca26qm+EGLYJXu+njUHIU+s4z5Y" + + "xxrR4xcqc4CKXKK5+z34YCkdGM8JME8fCinDgrsixnYCjyv367LrQ+/YRvtF" + + "6gF2XrCyPNTtRisqHg8Ug3CSKMPYJBXO2uu8/9dxF+r8LGv0pbVoPUBJpPiL" + + "+tnxY0ggyOiU2zsUfb3QcuHONXU/2qv9FxUzBZDUDVuhXeCgNDtfv5QN7R2S" + + "VoWWQDcQP5Vop61TXUhLnNaU6LwaXsVIIi9hbv4k7LV3tOxgjtyddymxch0x" + + "4mR6XCXVwPx3yVIEwju7ANKsDxR+yT7crRYpPstka9lY8Y73w5MIgz2LVk65" + + "xJ13puMbAGnCuSEuQgRdPHyt9JDp8KfvQ0/FegDE1axheKVAfCKgCuAudIxZ" + + "UGXjPXLh4hMp+o87hw0Mkr0tfmKBd3KzRkjZm854ksnURKPODIjEqhHcW4t3" + + "gRQ3cYiMqcv0cDd7cDw/4dFsfJs11aXSF674f1lhOjYqB2Xa7EMDQxJC2zw9" + + "6HPVKHmGGSNAv/UiJHjcQuJslGVq1SisnSWgpMND5+QnxHDBww1p7DqXpDQJ" + + "boHjZKPM/gi9N4GD6iHGbF4l8Mx1YzuzoAbqqg/6v+fmYQRUgzGnNRHW781F" + + "R6J6R6JwNOVTaSvlDFzQukHdwpyqcR4OM6XkaxNK3SMRWye4O1/U+12FhPYx" + + "5pPHMId8d8voJIIMPYRjFIkZAWpYbavjtV5x4xUWu/Ch6SeZ6uQu5h3WbFVe" + + "buXjnOQbVIixTh8qo1WXXKiG9DUYHowgz2XWC45izfOnt1xwWj1He0IQoYWg" + + "WkePdJPKfS5igRdzjwEp29RlLoqXj9TsICzYhWY626A3UjnTSOAg8Av2iWxx" + + "j+3I3zA5I34udiSf/4iyrWZHeaLP3S4wIDrTTNzOh18NvspyLJrjoRokXwoJ" + + "g5BnQan1rHl4p2e7oNLPhc9ewKF0QWdi2rJZDY6qO7sa6jt2C57g8jAYhAFS" + + "2cXjJNQAPCgoodeKTnJ/1R6Ykk+byXzeDc1NuHPHiNbtGu54Hz5Xd3P8hYJ3" + + "VBYvhkF90Rq7LvBBXyVTy8tL0I0N9BdCQrnd94HPm+fMj/nwc0pqCi9b68ex" + + "Gcr8YM3vSg9xRHEBXsWjL16oKchvwavauC2Uap/OEizdkQUKBZlzDazbXTN6" + + "dZpCyFcB+Ox/zgltv3jxum19WdgjyIddqBIyiKxFtC3XunK5yvmr/fFZV8X3" + + "vxbxV6y0QPqJDM2ctb/ndiYaGn60EJQjxETGIanp5szgKFBYs1p1mjyov5p6" + + "p76yEvTm+Ba+LX4ngM1AddqyfbPYscxtIyhUsqDqQ7vSNHQezTBcz63OclbJ" + + "G2SyQFZfZKIgUXiZt+ZC3BwKRBGQZUE+UIV9WjrIvhtZN7A1qdo42c0S/skz" + + "lHMKR75/PxVVXRaArCRytERwdLOvlyBE1xl3rxnxErTQHViP0xEzOfOpQ2M2" + + "Ds9TcXkm66ZRnJBuk+fp4m8iiz7IfRlrI8y4AUuI9LEaFOKkh0HH7sjSWzs5" + + "7uGe0eBZsLpzWoDd2Uacht9+xLcnn8tQQ32H0KHkZjm1UGtbSyUSvvoC8SQk" + + "U8QstWumKzrzf3/GYuW43N4TIBUvl7GWcpmpevuAicl6SVeDjyaSGp1n/OUM" + + "FH6e6kSgyDvrs/V/pQran+Dymby9DPV7fUWNo51rFdqvLhktICGGWRuUXjvA" + + "eOOk4JhsD4MSlKysuGfbcUhFnkhjFkctA63HEAPAKNLoQze2tRwG+tZhJuAp" + + "Q+3YEHce9DEVo/13eYVKRu4yFqD0G+KAkwcXHcFwH4b8ByTJ6K4BboRIpGAI" + + "sCWN2r4Yx6sH7hDgDH/ywTs3xTI+JBDGk4+15EXUSVA41bCKEsT3BiksVE7b" + + "Uo2eXPFkG7ikOuyMr5xfWtIN5v3tg/lE8K45LtWgOT2mZeEZVEVmgozGwR55" + + "OqZvFeqdZbV1l57N2vSf3YkJFU8CRwd6uDZ96C/Fax7aL4biwSragaXrYu04" + + "XqqWIJVYOZQnHHHTGSH+C8+NEZJiAEH2ILRlqa8VCTGPTVd96+tVriytRGFE" + + "wG2xl4jYviismG73MqzuCq6iwx+HaWTiGSlXzMfhKL0DE3rhPmWrKIjdR+Ub" + + "Lp1C/L2mM/y+DEMoj59/l+SwMaijQY6oUpOtVGS+Pm2C03JFNSFZyYo+HHAC" + + "OkBnWMUKCGWMWOejGaC4vtBxZsHn7Q5ij+9diNfxyLEWc08L/muJG46bzlHY" + + "+t6W/j4UdYuizHNm1og+DD17Kbxk7fjRsQr1ARKeDkw0RgVZrnMzfsVeNfP/" + + "tQVCeOlsgTa8x3j5eQsR7aJi1taen0BQATTprJmN0428+g3Sgh+4eLslkGfi" + + "9c5Ftpq6vM9bxE5w8PxjPdQdGQZdcNkDHEreAmGf8Tb/r0ODx9wMdYNRqbq0" + + "Uo2Y09Q9zm91bPC75IGGrLvzc1X0MXqQmQ0YsRFq7T8j9wZqS6+bveA/Svd8" + + "pwfzfR7GWDCd1lwzuP9QezVrYYcozCquJNMFgCu5hcCJUb0RdC8EBsxArcP4" + + "iEM5+R62j5eOOBMikMgLpRsTQCFxBgFLiqv1sLBe1xxPIjQhtx2FJvuxd6PS" + + "zOVdplRe8WbbN1XZUW5UQJH3fnD8OLpAlWS6xas3Qk0ZCl0jNqUYANUmnuJx" + + "SysQeI4HRF0pvthikuZBzpS6gkxDf+CyNbJa8DZrwc+cZje11KWkthn+DMdG" + + "sODZI4Z/wUGBRB9S4QQSaHUajYbJ/wfiYopt884ophtyjW14oBs67hmX/nZy" + + "cYxmJnEaqcoJvSDzVDnK7YVwV6dV5pmvFe20fWuk9nAdtWbUyk1dXwZrtx7y" + + "Yw6N93sAtlA+a0xwKDWK30PUU0DXuVnaw5pejrHznj1gM+zCycZ0jAQkq5Nv" + + "I3VkSo6+mDhD7VfR16p5+cPgjabFb1yJYjit44H+852Tr1bzekpO8qdDw0un" + + "AOjou03PaJURRqI7E4oHPA9kRIPEHzqJyIxVJrly8hSMbbVaviZOLSzbxrvI" + + "J8qWlIenjvtD2m86tDZ/0V7QEek5bjlpr9wY8sEGtBhuWdRukWhHLm2RlmPY" + + "2pqodKPSiDxAy1mDQiOEMAhHOfrABDKroLsVOBa+zZyR+MzUcBZk4mhXZUmo" + + "dTaMjxYykxeOqnnlapKaz7qwFswwRrXP7n/Pa9XTxKpJms2s2pJZdKhZlAvp" + + "E7KNlmCV8ag2hhDF300Wu+J7syVrNffpqnn4jT8bdgL8orfAXT3dgTzwplni" + + "Fa2C5FQlaeGSG/7yM7qUXChppyAOA0aa3Ujbet9tf2PiS4+dsLjV1ynanz72" + + "zC0bbfzdhZBMY/mYEq6GBAH8lHpAWaoVda66iIoBjNk6+qtv/ShnEFmRawLy" + + "3KWyNeVw4gJjvejp+4Ch2I0zNssPrqcF6ne3k/FxB67eng7kqkFZRfC5xbLq" + + "NVG28rtlDCVVWkcbyPgo3cMaym5ZEj6Hf8E+Z84PuFhQBw7gJao781M0ddV2" + + "RIypj36LsxzzhpSPfmM+GHBtLzvryNqxlzViaHcsPBoh75XL9tQSPVzT6436" + + "5c6dzaW7lkak2TiPoWucxZvjh1PVqoijWvHv/YGav9ffjJef9TfREsBQG+ym" + + "Sw7Z4l7RZaWjfr76sO/K5FKlUmw91k8LyFeRtZ8gBIrGdV1j1DsHktHuH8/K" + + "v/lHolVp0QPI7vyrXRcZd7ccJv05dm5mj+CNw7JHvAHeIps1goDamOCROexB" + + "ksW7YqAuzex8xajTKtaESP3D1kZYz9BZ16sM5LWNjPNdcLygVHMBV7oAVepj" + + "tOd6BYY4xfFDSWT6UFcz0v1GgdsQaszcQdCoRL1XrCatRKjSvQDN6QGXUc22" + + "Cy/JqD3HHc7cqL8y2WELIPZcLNyDFe3P5Psvkcs/hysQPs3XGhfbWrvSarmF" + + "AlwFT5hJEy+pXeb7x+jNjOxaj0vq/k1gyXm1y/pWPZvB//MjLA8tU6mQCyUC" + + "U9wjAtrieJRAdZc4pqqO7Ha1Iq50vtdLu0I2mNn6M9/b2IUfwqziE+rBdXH5" + + "Wj2n3+TQed5xzpJIqG7iJQbOEY4byZgVmSQCJHjWBU1yaK+gkTGunPbv56+P" + + "PNYZ5uUJPWCrWSkmRow4Z8B/Gi1IMKkAsEsv6i6HwomZZoj9tZGpXL27ZKxC" + + "fZMnyIN3QMXrtCb+RHcRSTWlgraLfVMZvjtYh2Kxwb1wB/Lv6ClHT/A69uYZ" + + "QNSDQCCxSOaAOQoACjh2bj38g08nA/rGXUYft9LTEKIkqUSf4fMTc3WzTaqN" + + "MzZ+iXnNMPDYWSWnVOZ21HpkOoOID0zRbk2jBy1B0xW9kcS86ekhkBXhKYxw" + + "x+J1k3WqsMVnsVqPWWTRU/G5OCfgsVXfYElFlrmM3f3jiMADkdBsfEqrpPt3" + + "0QsVHp4T8Q6WzkOV8D5lIGdLKsF++8LSjwLjhERWXdwooq+6KoLPm3cm9Tiu" + + "LMjtfIfVYfaw09zXmKqOkVONEsZDLHTztqmNWNJJB1Ay5iL7QPvSjKQS9WIQ" + + "TJOARZD0k+qUW/9a3QHaeg3O9aqYFMxf7QO4FCHf1TIMNnr5LGoUIxC3n7Ki" + + "cB9MlAunuFud8DiiB8/+3QgslIVknChjQiCeZPFsJIszUvPooQJsRDcGXADH" + + "kXInEcaqT9EsHYnWwDtmZ7gQd+NgT3IqvlRJRZ6KXmyuphamZKieRkOIplHV" + + "muUq1T60+6tBHld2033XYtS0qY81/fOY8WbvjCxUjF5xu/So1tmW0tqr0l3y" + + "GGp8jyNE6vL8/gJgobfXTVgnZhPB86D17FNWwEWHG/dBis7gmo0mkZRh9+gk" + + "PLAl8E3UFqWmTLknSqqcI6ajgkyI3nmphyLc5H2l2mUYRI+bCiOunlWGGzMq" + + "Qj2oSuGdOYX/hNn7MfAYmb1WNwpopBJYHA3VKIKCH4YDLz8h5LF9v1iHpZT3" + + "IiHf1WEwC7JpI3Q1S09sJMjSih5dctNkmoCG56gJ0ZjmJvYhWy+A9/Nyd9qp" + + "oj0E6j0hf6p8dovu1eE2BqKRydCa0T2i+bPnNnB21KU2MLgV5NGw4tyIfUoR" + + "Ui8QSHDynL1Ob1BUbKuqT5p0Ybqths/oWeBN032wA8DOblale/gyz0fXWWTh" + + "VqD5ktw5SGRJTmA/tJfhK7kFfMdk+9Fsvw/yV735NAcTorVbOPJoEWSsq7k5" + + "vY1qreQO6tRd6Gx8aeHW0st8w0Cyf3UpLi8x+NcX53WJaYBhXXJtYZlEnZ3W" + + "do1Ekrs6TWrnRzSUk1uD3Ku47Gpd02hOTfN0T5lUUjaoqRLuvwyYmQiU47Ww" + + "Wnb5ftTAoljtH2P4LXQZyqYWca+BgHdSjlaadtJ7hG88zgSHomwu/QVSVRSJ" + + "zqW+0ekjRr45/9gKNmaDdFwZ41HBgly98x4Z1LzcimtylmgTpAmowJRCBSV5" + + "uad7WgR5Pw2LKWx8YnPAD9aJ78DfSA4LqkULHOfVfqM1CIDO92Makz1gL6bM" + + "6jEpuNkQHE1FifU31Dof4JeoGC+w6V6UjtmUrilKgq98UPAHHU8Bs3ADfXIH" + + "w5Gz/LEjwmUL5pEeFft2PMzf9HkgKcuCFrg8by4PgIv4wMiE6gXZCMfE+Mzd" + + "fulMuy1opZB6LdObgrv8uzhfsplRaVl4utuTGqg3ZE7PyZ+a2nVTBDj3Blx9" + + "88gBN6wjC7MnTRR7C3PlVfX0ApBjmX84Eu9AF7R0zc+XlqsguJK7KKWq9BFL" + + "xXETLlygW2oux+30km40WiZC70wZJuG/Y8NzPwZd3JiJ5/cVWySyppfBD5cY" + + "k6as7/9oXDj5OfXilXXJNnzMSp9Q9h0P0do3qteAp3um6ixvnE/unKtCDua1" + + "KuYbV9ThI+RedYYkYdyKSgBiFxfUtMmYw1E3tqjxm4vNlGJijmBM4HbEmR3S" + + "okiE+52LKS4SiNRNfp6Hbnghld56n/Bpjv3jsMlwES7415uKmAfm7pRQrB6I" + + "6MhGGYhpATf+q3iImH5nSkYt6OCyBjjII17Dkrs+Au/wOk9xhY81j2lua4hC" + + "VAWiv8lXTznHxcHl0e9w7lr2rqdl74byKD0ey+GT15C/oRYGM2LNTwNK/K4I" + + "hh629dJF+od59sUGg3fJ4qPM4cK0M81VxE86TvZP6Nmbah9L+uqVrnA4IT6O" + + "BmiJub1LG0awl59Khw/Nvc1wxje0dr6cuHQuXM2CIYKfaIyjs1snuCpO0KgQ" + + "Tkz7DpQSe9RUo6aC2870GuvKlTLWkI0WI/oRLU0sjgssUXraZQ/8XeC9pS2X" + + "d5FlZX+gA1OM2x6v/DQLzDeN18R6i6UeQZSgDMv5PeCM+1amS+wVznR+2pzx" + + "KNlyPta/4XYWhX/2GB5lwHtYlKDOnI8+0gWU4Lp+mrfKSYdpvnAg4SKRwL8V" + + "h344eiwCCpdDDOuqN02dJs4H552sy1SFwMvBnsJCRtQUCq6SPiJ+lrVTPsQZ" + + "snJcwOKQHNGHkWs2rTPU7nrhbXaRUCcTcPKknAg3wdORtT54ASE73dkufPUS" + + "8hgbDJB8EwD+nKy0Y2y1KdsCCHjoHqtXOwaCoPHecBud71ontPj0XCZ54drN" + + "U4coNXGJjUtKhRPMC45US6AJRYu37P4crc043eO8D+E9MgE9cm8zCF1aRJe5" + + "lP2uQLvGXvg2qdbrQP/ebQNZ3QJ2LUT1km3ApZXRi0ht0a9SzWsRo5CSQY2k" + + "g8K6YbslkxCT/AvYEGWjEHx2kBj96lSTYYz7nXkJHzLX5kbgXWAHavzWN04L" + + "Hqf6pbzbbiNpJ7SpG1SUxZE9xU34BP2msOD4aOUPBJCfd3pE+5Nrnwudk3r1" + + "Lwp9YBlbbI2md/A6z0H5qKrWYyViiFbfmUKZ/BrSt8+g8Z0MY26V+7wQCmZu" + + "JbyOQkLbPG3YghMUK/T//1NbEsgVK43Bh5mvMZgLOWFOHf360y1RBNtJgcpF" + + "/Ckig/TSA25XC4l3MQ0bSEdszSjUkRlKk6WARrZ62EpCV5mNP6XMJOPRpNRl" + + "DHvumo89/PKxn9/0GqLSGqkC+yHxOhxqF/3pe9wduSuEamM2FFySftqO0BKU" + + "uvYDGs2USoeZCO4xXELDn93caAYRCUIEzFYU6dT9JGEEgapq6UrmiS2Hi6/X" + + "zYcs41tJtI143kOJ6NKq/YzvZTNnyOiTmXuKJwE5R4VdtkZ2PBD8MZvqMpk9" + + "reFXpubJBL9z7ZqvvchZ2AHsnKWCOQ/rG+rRXTuWMDF5hHIhr8NOy6Sp8X1k" + + "DC49CFKkSv23OxhLQLfRBQHcKQ5IH0sJTtbHviBq+vB9OV8dz3qpLvAbTB89" + + "tPrKfy7jsfPaFEJUy9bjJsk8gg70WLR32OucUO5AStWk39b2C6PEGewzp+Pe" + + "uy/SWBly28gN3Em4RsHUptWkyiOrw7sQhwalJV60rwqROCfSb01jLfAcBgDl" + + "1yZ08YSKsMvRGUCRID22eDBxl8fFeNHyfPWZrsGegLiWpG4SEhdz9MuayNCW" + + "+K/rq5wXnvgmVeDx9rgeCSuEc2+iGgyirvVcwINSPoJIejyfLP8A+dNQrS8b" + + "6n6ZWKEpiK+4K6gQJArgbdU/2QdzHmDH+b4ITnrhqA2SVH5kjdglYMWBZ45/" + + "/Q5LwMEdqv/P48eWWxN8XMoIkVf+FtqeHwfr48AZhINxbQROlqBS7hCNYj44" + + "BLipDiGmeGI3pYeWsoZqu7hCRMPb42ziwSGFdvv4Q2HFWdgDYvirxqh2SbgF" + + "aznvDQxq4Zzk+TiJbHgphDZJR+DEHYX5n9HbgLWOp2kYWKWT0BPwzS1w++vK" + + "+pMEmbn3C5d7OEBIJ9TTD/jZXB3KP9tUICFFaFXUrk2752fBfO9kA5xxbxDk" + + "ISUvhwBgiNGxet1T5SoRKPb61Zz3NY0SLr+GD5KfH4mJSF6tOUZ2iAP81uUs" + + "fwPIxqHh83mMS5PW/DAEeJT2FFcBMVaXdj6Xc1hvIGGXYjc3NQLxII5vbQVR" + + "3UGhRFSJEi0urSXTFUDMan2AO24mM+jnNRCOxOIAx98qj6DKTfkcBZidH9tG" + + "nJAOlISyY49hJvSk57tjc0oiSq8ojE9bxQQ007mc+XnKP9/5dXrTa/zUhCZi" + + "DIeqvdOZ1ugRt1garJv+BS0kRrMpahYxkqUJijkSE6U+4+5V3ssWhWu+3VM/" + + "LpKK/sKXImOzcBbcdvzPd1/2yUp+ZCzDRB9qeOmdhZtEgKHp3b2Xw7211jfP" + + "ZWG3ydrVCduI2m2Vo4Lb+4NddZj3yN6xeurZw/JZIuzBcmOg6viEu+Be38GP" + + "VWz4DV3lAK/2eVPGUMVIVXthJCFLKaT10psSNqFYWi92OxhOIu0End71Gb1H" + + "tupvmdPZWCQbhaW8l2RvYMZuJFKpH+reSP6FrgqmrxXGf+2EXzz6PdbeLmnB" + + "UB9QcTdu8tsIuUvzh2Axvrxmqi5rigefuQqwvSgl4KPC2mFI3cKrVJ3kB4Nz" + + "gMIpgW1FzVkiVQSHMTno/bm1LxzGv5Bcjx48NbL183kkAb3kYGNfZHEE7EIN" + + "/3EgK1RUUF0YC9EAYt5U/hnNOofK5rNTjYPepexhY5/4Ve5msVrtn3C2Nlp7" + + "gpnGtHvcm2yoPuWo5ASHh+wGZWwkUMz19x7176l2GczPSajuK6CT2i3xnZ8Q" + + "VGQALJ3Tg83Lqg7LfUhQIFYr6yPttZAjuETlWXxIa2IDsxj6Jz9WBzQHr8TE" + + "1NY9XmTY2eenwpmNOVHrwn3ADzW6OyDHfjv6IY+INC9CAnGSf1EMiwUPNOpr" + + "oYhGfRzTgLLJQTPTWwkn4rmds8eLVdp1gF4uK9fEdY17nJFe39I2Tui4yhwD" + + "Ue39/dGYG16nNTqYj/yt07oilo8PKAKczLLN20Le0aYmOBMGWx+5gWGiPQGk" + + "Jmq0LCHO5rHf7L1j53+efwedTj1Z+qv20IQINJcUvgUX4XfJewiUoLU9Nf8P" + + "jOTIzyR7lNWV75kK0JZJz1jww94GjuCq6F/qXwAM3P+X1VThbLKd+drT3YmP" + + "WVOeOYWPOXUrU3OowSzMGIE5sq7rQY5WwZWpE8O5lUJ6fZwx+MjKVnAYdzAJ" + + "rRxH7eBJOFwn/IGlgJDUdvOHy2bXX9kcVP/ShWuflU1e0y158UTGQNiIRjN2" + + "E19RBBgTru0eB0DZ/yke4BhkeIo5u0Rg91asZHp2RHONDyTppR8wSO7aMKRZ" + + "BQYEv87BIO+B06YsohMfWa7GwD4jFd3XAm12aXIukDo8sMJ6f/C70NwyNsNB" + + "wvjMvl+8E4jK1s5qgagPwECIdl6RBtf0m/CDm3FS1jD8ghJnvbHG7aZnafm3" + + "jTPJcAUDP0+GGtK4aFvqC6yvbUPotlWYyPDhMaOOFSwuFUqn9tzlY3NPlo4x" + + "28rietj+sZjSd+fdUiPP5q7T/VR/SsnzIWTgWOUyEGVeJczUpSdqNO3MJoY+" + + "5MV6+KRkRAbULuVC+N6whOfPW4aihfNVLEBkUfkpo9f0by7fpVU6eJTaqv4T" + + "Z3qW1t80ZVUXN6qRnjG2t7UmTqP2rTXurYseWBYZceo59zfQQSMo5cirpLbh" + + "SlCrVXP/CbUM+OMoiudWha/RZw4fdximFlo6R+TxMoWdWOAMc1kfyL5q7tZk" + + "kJfAj7r3Y4XBcNeQ9bqKKdBzJxUNRvU2Be47fEfbVpKqDWFlxeOrj6tRqjKK" + + "YUt7zjZpYGFqG3YzTfXZVSQ6Qwmxu/QM6vFVjbOpsScYal7Io1qLnDBSUmRb" + + "v/gong0EpsUNvjQ40B8jmNUNsTnRF8memZC7k2cKLnah5RXyuLFvN4cZFSar" + + "LPhBgDBWRgtEzeShPtQiYzJCelbelDoFBz/KfavE4MLRYgXf6/AE3U7CAwDq" + + "splXWaEuCGw7Snwpchk4gCXSiFjVDj2ao2WMA6y/zot6a27ppekkvQRFCtkL" + + "SXNkgJ/F0mvgp3mQBOvo7Yd4NPJV++tRFf4tHWbb8VIopwGynZlnlxXyil0c" + + "P1tRMXjBWDHFY5GYv48XTon13fw/GORM7XMTbv30KXQvTGpLk24IEjIG5iD1" + + "MrqQaAgkWkzBFPwnZpKIenpGmO0G06uW0+c3eJRbfkUaVlsDCnB+3+qZNYSw" + + "ugJsWuMUo/brItbV3Yrt2012ocymZSqOGtUewz+VSOopAHG+uIZi2L9h3/kj" + + "cJr4b5QSsmFoRCAR5j7TSkVpsfTK6YH43FbXxOHamseOOE18TY5BLb/tIlU+" + + "i8p59WnYo5sDy20o/sDM9N8L0Ks4Vma6DIdwYm0YGRzLBR9N5i+HjcprWz4x" + + "FxBHMVMalm7metqsOihfb7aj/iu36uZ9eAEJNZra2vUz3F2oFwlK0aJwznMT" + + "+k06Rqd2xZOKZxWqbVeWMb8EPiAvjwtAbmoXzTf7AZPChwAtb/fkd8QhKAHt" + + "Ge1akmgoY/puFLMJnFECvmy8dlzVfsAX7JhBlVRkeEDofUDCnkh7brT9qqrR" + + "gj92kv+jO5PS2svsFJa+3bB6tuKLe+AHnuvaB1aAdf4aPxFGwHAS2a5ANqJ4" + + "CskScf9J9kCm6KwO+CmhdcjlZFMs8S8CV7XVpNrlwWDV0CdwEmZMvIuIvUB8" + + "Ic58/kCZ8A7OwUVzMEtmJPuLBDVNrS2jLTb3CKjWw5EO9H15J5FseeTz4jWj" + + "7PfjV95NT/n0IqhN/1CsozW6Ko2LDrzH9AjD267p/cF62Hc0a7XI+FMF+d0v" + + "myz/L8RjdZzwiq/Xg+gYWLT8uAv48yazhy+3h95Ttf8IP8E1pSAEvyiuKUcA" + + "liw8aOjVpYaBJU3SZEy/T4QAyY1wmiyaReHXZ+ayWHB+HIiCNdNXj5koUOUc" + + "LVKQBdvgjvMMLIUlUCJB+armPQ63GNp5bBfI1lhvjrs/He1HfgKYf8H6kWwf" + + "BrBSYVno6HkRNKutUpc2nrXCHRqmJtuzB7uabtGFQEZbxP6OHY01k+tLPHUz" + + "EJ/tUGZ7mUfZp1m+PwbXlSjRMYJhLJPsNbczNkuFdfIAfAN8YlUjaeHQWAuJ" + + "KaA5iwxIqENVCZR48WUI4s/1uXO3VNa+UoSGI5N9FLgfsf/m/3Er8djDf/VH" + + "kW6nG3u8maC6xuTmHh2w0QSsLhjqkjuIBoY7T2Ye+phZYhcjLTuRkoJxNGXv" + + "foVPuNghwAHm2Jw1QN0LjWQp0aggReKLBIAb5sTLYLQltGHDNj6ime+gQmk2" + + "2kb2QlCP2sOP2zs2/D7CuUWHVeeA5hcJc2eWEWv/I5s6cYysTM13dleBwIu0" + + "+0Lyz34cvXrC+9agwHa+uAdO9KYfuk8PjRmVPY5rgL5ux7QbhgA5Ou/1GFm7" + + "66fbdqYHNN48Dof8WeNQTZE1qlHl2ftAKyFk9vH+2T/1knJVHpEo2Dh5KywQ" + + "M41C0Gla+cIj+Wpit9hVYyF+VMC4MYbJDDQ/f5VCuSMXJIFZ7wwV5EkCLZV4" + + "qlDC37hMec645uyutF+SAFAyyiOufGnyR/spllpPXf8pF/HXvtwkPCyN/IKE" + + "vp9YOKtXdGfQ0NksPRP6f/nfy8X49Nmr7N4oexlVB/2hfym9ApWw3zVMhWpr" + + "sk9EWMkVzNccL084P0UBYDRwVmaU0OJHU1zDs5MS/joegbwjO1gA2FJcFdoE" + + "vbbLWCDJGVkZWvfgPr28xxSZAhYuFO5zJ+Sn+36NXPsAwQlbyMWp7y5R/JBH" + + "zHrQmpEp6uyyyYqOFA4QIWW4RhBW30gABmq+Dc9qqEUyVjRd+8RXf1Qvin7F" + + "tD0cTAOl2UISjI7Z7JexkSFBcS1uEEgG2SkGYycFa3TapP2PXEdL77pN+FJ3" + + "tuefmxbW4UaQq5xDr59BmhJ6bZ887I6vwi1t5Q2rqTNRxZjePkCqhtZSV0E7" + + "JfWxMEPxxzJz5e4/PMMdMUeN2lG45WAbdJuWYsuC7gb3gVmtCkSyTJcF0Xos" + + "Uh/jsWbVPsDWOle55iWepn7i0HBUQONI0iv/BLFTbU1+19frmpB6MEmV+t+P" + + "cUeiVWy2uoRXXJiZgZ6uWAPtSedlFNO3DGCl6a/POkU0OBvW5UpVlpVAJ2qt" + + "qXbBz3OYJ5eOS9xqRpdvqtkzIB7eXO+2Icxq281+M6Ug5PFRgyLpk20RXkyR" + + "PEqmjBnTkR8Ku2B2F4SvQJsKK3dxjGdxwYr9+3ReS69grg4/4WtbD4iVf/lE" + + "G/UrIyW4nCL3/k0y2LL/pdbCPsoT3kSLvtNxKF7sFnLxvxvPxGMvYpnGyE9s" + + "UeOtPY5LsIjRX3eMuT+msI8fPrlOcZ2ejz5FRYvvChBxB6o9w9ybZlxx0SUh" + + "1yqqW+hjCY0bfzaOxEVs8ZfGKgfS16AVN0sArOBdS+FhK3zKSAubqx4IfZ0y" + + "luFVMPAGUUo558vyGZNhmW6U1FJczZWz+yFOZMcH9Y21GRkE+JKnBIEY+cuM" + + "RolrU0Tzj3USUC8xazB6ipNZNKepCCzcRy+B8ulGVeaZHFzVLe+yt1zPvFOJ" + + "BQOoGDe9ZDsqo1QJHxTh7eaEWr8hMfLs5bDanrN8mBjhom+1Ni7RQEg7qtbf" + + "kWd6RdB5gDEZDeFNP/16n1dFf1M/lLYfKWUuYLXueOX4s3dFFAxyKqy9NXVk" + + "X7/s+d9XTQfIax6Zh3SH5YF47yddlysYZu/HjhaO31yq1+hBLQgeBEl91vnT" + + "Qg6DlMnh36Vpsfc36UqKo/97LMioJq+4vViL2CqMlTboeepvgOMjdm0VfPn1" + + "cN0ithvdPi0pOPjArFjhcsdF2I9qQpQCPfC9n4xpaz1E1PQpek5x/LqueH8F" + + "UgiOGoUZWSdRaFjXu9KPP77mayqTT8SnCx0flb0E92mEpI4P4zq58/nOnVWN" + + "uGcOZ7AqZRwIfIHJSMlXgaHQGg8YDoDXJKgp28fZZzESjzEzKlE4zwQyyAFe" + + "jQSXjRexLS9YqWpWaIFaVaNy6b3zIohOjLMWATB+OeuR48JfUKIsaBUz+HdA" + + "Y33pgtJsb4tmC99SeS1sBfZAw3hUYWUE3y24+u6lRdw6AX3SvfhC5Vc8qVt7" + + "+GFWGlOH9MdHYcoNxPpB3N0HqQYZk5uGgcTgHneJ3oq9QLRzURvzjEupTzI/" + + "z36YZRA9vm+TgWoCrhUH2/52vJhKgjOY4usDvJFfEUWHv61fOAxzy8wLgu5v" + + "NXBX8ABR1txwpN08BCs1I3aoODlTz/T/WwPNfGptkP1sQ4PgHxJdCQsvi5WM" + + "L2sBq/ZmIf2SVNQaRI7MkeS0z3NdnqxzY+8wTVjQVZG0zbpNpg1G9fEk6Rkk" + + "wV0vHEGXnZJ3DXTzMexg6NSyE3GXMJHa9J2fP4lMuKc89XtGaA+CU28RgbkE" + + "Zs+Mlbu0YNvk7JABJ/UHxf8UNJY9YG5BdUvJbElrbajWnllEaRauDzjnvjkZ" + + "U4Uw4fdHmzpu0PUuM9Wm5UusD5lZfj0Xng+XO4Kea9RheukO7CCf01jZuFlu" + + "Xgbi1tbOkkVA0AvWbnp2Dv59O75kaaVq4kBJB1SxUFb2DTvHTA2b8NYEfeis" + + "eVIiKNW9fDMJbbmwySQftx0SRcrKbCloN8q7RAzmewiyVBtCI8a5CNw3qtEO" + + "RjZYDPmLXaFU+uc83/dIMh3jnJcbZyUvt/X1NMsrF+sSonKepfVhq4mtO5XM" + + "lQGTY5Wyl6ytdlMbK/vwp4MsZXFsAzP85AOpEI9cHUnlYM/Q8YTMeLZt60hD" + + "Mqq9SU0USmvqbhteriLTuTczrsaebhXHsPbdcq1zopsOtA03q2hyQPebYWP5" + + "x79K6lUVxOar3JvnguVfyOrDBPRXDphI1Ew5g8dlGP5OoOhGWT4/S4OEIa0K" + + "32dRruB7A/F31osJeK8J2pvoosZzLpxh7nyU3Jyc0c8uuQqj+1NiGvERfV9W" + + "a2UkCOHaLwmNRb43ifkYIW9R66mL3Mu+hWo3aXfDriYxZHG61blhFYNDxkUf" + + "qx3BlDmcjbWae8v6G/JI7mEK0XKRI5Z4NgheSSY7VBnj4nQRRht5efUq1TWt" + + "OpK4Ws29BRhSfgd7DtpVS9zSW48JCfxGTuNHHbXzSWrLSAU0OX42ycv74gm0" + + "Nv7XeLzs5Bp79Vkc/YZRxGa65h5AfQzKf001czPofnw58fHa6WUqD5m2pEBC" + + "0fC/YSIpV7wJfUBuj/JlWGiwAkWpkQihq7mW8GcxUTk2nLLrBbWr4X8QBdXZ" + + "s9dA11UTul6nVzGnFDrWRbHgcAmU4bxSEsMYL31tGg/jMKPx6blN/M3I+KKN" + + "U+9y1Arn/36z471rKz6Xgo5bP4qbRxLArWnmV4BpB14hL0JeQJaqJtFuNIxw" + + "+y04cXQjdHxmjluTC5F4hViPS5rY5+AM4C7IqR8fjmC/pLNhWQsnz3/rH2Ax" + + "3zPs0E3vdeZl3JRMUeWqRYLQuF/Q38u08/8PthUhYyT978xWJ6+t9rrC2iS0" + + "QbRNvmqE1TuROy3JcLz8ig4Ryo6thY7tKnKuRFmbBQHWk+43yU5hUqw2H3hX" + + "roIYd9NqTeImqfesegSnRpSBnOnFQLRkI8KZOIQeyYzKOWVJQw16xwSX+PdU" + + "4hc6pA6+pIm5k5KO/UzJGmWpzpH1HyHuSIjhLi/zRGBHOXPZHLtTHjQO0fZs" + + "WH1QcmVrrrRvHhTXzKqKsQRfKtkgjQRCJtNIB5tQjWfwNgW4Lu0psB3x0sSL" + + "GnKm+BKjgE7HMApctusBLXNwplxsp8PYyZOiQeL+6v+iUCDLDLI5Tv6XIONW" + + "GzxU6SAAcVhJ14gy+95ptYSdc9YioUHvAgcletAy7oWdnpIliUfmlOELyvZF" + + "kpixQDAyNSVUUWxGsad4dwYRv+Q57WMWkDQB/WfkBfqK6EO0DQg0FvJSQ2Ij" + + "Fj7O4vOPDyXt/ir1QUxfELactILEpBTf0UUgIJAjcnAI0waPu9fN/619eo7V" + + "VH8Wpk3HUU9LjOIIDC7BAPPTE2xDa3kAG9VGweIXpL6YyW4JnAVSkou1pZWt" + + "CW05eMRe0HkDpEJb4iz/UHn2KII4ZjJaFUgSWgNDRiHRvMoW4tIImHuI4+Y7" + + "rokPlAlmO8yEnsLyBVgiPr51Sq9RWPCL1y3bryOfUoGFc/cozQ1csN02Mncz" + + "YeSbbwt0toufO1ex/gfsiteqRgZvSIn91yMsFl7lzEi3kyJIhW7hBrPDfAHm" + + "TZ5Czrcs1z0+JKfU1PXcuaRm/Bw+OY/1v8Z+YYKIynupdgnLCY8LfruNzk5S" + + "e/mT0UwgtoJE+TvceiYGTw+Rkf0a4jZiTEcs3lF/IRvIOnd/+5m1eeWtGJp+" + + "z6rlPrlRWjrhl4Ufqxob6U5jjY1/7zAMV6Ge7RgkNJiRy0Brb5+phAHpkajC" + + "I/q4m/qBBm+gqRrfmFvPfo1CeijfMelIXMh3+p628kWGpIAypU3ocEcVcXXG" + + "B+K/n2zyfbBQtMQ+MEUurRbn4G90gyRaHKgf3SuQSM53c+OVfJGXhR4Gtki9" + + "NF3kCMt3wiGXi+c25NEs07LZ+xWfLeK0/0IrAHCmG8IcoO6T8pujgZUEyIHv" + + "9Za/9vrvP72UlQ4+z6yUg0RNwlHgWN2nF0xnTQZXySXaoAaqwGA8HetCbx7s" + + "ePd+VFl1/gApyxeGhWFTf0d3YiBLRCqvdFCsKrC/ni7aIGgbpuvjxmHiTAKa" + + "Jaick9xE7a13b2pY557OVq6ExqRiC3c28z4YuKXfJf6IIeBug1HY9yEnjU37" + + "eqNJL/XbyImo55ARAH61MwL1RSqu7uWJDui4GKCOKC+piqOwLDjSx8AyRVN8" + + "zbsTxKtN0N0AUBqstlxgrfbV3/BCqKSQHCaqlg0Nrzk0T53RZEHyNv16qtr2" + + "iF45GMDj3k/lP/NLU4DQX3R0zx1dQirSfUr0PJGxZdwnfHFzSZ7o5YaAnqdW" + + "j8t4DGsu5wdktDOfqRsXrX3eKmeps5ycRBKTUgPhoccH+PFtMXYjkTH49aW4" + + "hKgnJd5I49A5o/Vdd5Z3zNFF7eSUsMFA6pYxXOy4/wQYpu8vqmYBs5p/WBM3" + + "wJkp0iLaEsEvJGSRNjbyuhV+N16GamJVIQVk0X2HvzKVtL1cHHN2f9BkFbFC" + + "R2iW/I0ZFz/OECDOnlS1Ea/jGXuEIOB2+4O/Fki7kQ1opkc5pB5ehMMCetXP" + + "cPJrEyyQJXsG0ZiCmr9RtGoEKG6lfvNxFWBtXHjXrFXjZ/KRZi7BS6ZPIRb+" + + "YER6V8tyLNkL86xTjkm1oq9+opihDSf2+dve/u3YFooowsleeNynMVEyEPo2" + + "yOLB8FO/l60qpSOSrepG6kS37ifjrv1piMyqLxz9EWP33jG0ajCEj1hAoke2" + + "5uLFL0xaYT5Hbb3SPD6E5Kwm3GrP53VMGpzxFb3WirP2iW1pSLH5ZwBSiiJa" + + "awGW/1JAZ/AemOroG1jpFXYG30euz9cj1ha97GagqGgaklIQGbGejqj1lu7/" + + "H8Uu47sdFxrQTbs0enJEr7iZdOWHb/Gk1u6X2+1d1+2ifn5k4dd2QrKi4lKZ" + + "TnzU6InfbE6wl7kblSGnvxG5CdMs6vfcs1VQHbahPxyZ1ci7h3Yda6MV1xNv" + + "8gru+cCbr/x6v0L0L0rjSg2ZwFq+UCexc8t7ONv6y6KhjbUgGmy15GthHqYQ" + + "/wFMIeobeq7yd04vUMhsvSxfXL54RECwu0Wz9OXfPU8yGdLiUqGDlVM/lrCF" + + "H7zdSU+XKqOoxA/Wb8zayXZehYRQqnDVlJzA39Sp4KtPQdIapZ42ViJ8SWXI" + + "sgtztW588KRMxjtMxpIj5eKucFr9bqfYsaYU74t3JQUIeWrKMEGlftBrT5Tn" + + "BIPhOlTSMWe3pWOkJP76uUm/mqrz/LirLgzKrMpsw32eUSQsizWwXnC2a9pf" + + "VQcqDIQBgIRxI6bp4U4IQIhCezOhZe+02pt/R6el4fvDyhGh2sjcUyt50XHa" + + "tobMMkNVoQTWm1UUJpRB5n0CbtXDRkB54kL7IYlhsZVBYQqDMihNbTvcGfUE" + + "tz+Yw405OdLawX5VpV4azSeXxncq4LlHgE23JKIpZjnQ/ueb8c/6EUyfn1u7" + + "4+lGsqIK87fwPrGP6tgozyo8e+uzYl2wIKjL3p1ypi9IJodtMtQJT4Aw/Nyk" + + "d+fB2zS7h54vyh9XJBqXBlyBJTDoevGxACfCZMOagdR4kmysiWUEqcaPSslx" + + "9is9VTALHRpN7LeKyTnPnMzFb1otJ+tYncqtvaP0I8hRgtWHsbiBqpjDUZxF" + + "nOXaXzbuYdEV2rzcQ9msOCqejRctklNVGwrFdqEKUeOV4QwwGJv6wb6rRYaB" + + "qXB0/8CEkoNYOC/VU668RDOkwTFd12w/9TOgr88DHX0dN0OHLKa7/xzNji1k" + + "OVkQcT+Bcrqr2pUWkic30U+YU7mJSC49tssKTROJ6SM6m25jou/0YuuYTge0" + + "S/bn+Th6Y7YJ79eqvmG2OneqcCwE+SzpehGo/LeROeBH5w3rGTcl2qcxvRf1" + + "SyyJ5aGlh6fseWgcO1NW2oLr+ih6JCpDf4vRcYjdaZysmzB9y5kLOY3rPQbI" + + "OxqaO1KshMb3fGJIcK53lZBqHQfqQ7CgeYotq2OGUmKzr2BVmkah+YIMUrRE" + + "xVGSlMzJyDABEE5cTBvcmq8MJvTdFeQrOHkAHJ4Y10v0rb01hGkvJbSUq5a9" + + "B7f7ulZPnYpWmJZ8iDPs2eETUH/fm/a+B1i2kb7QCs50zGfp6grwmwMb7fd2" + + "DEOkjXS6VEOfnzS4jlNhBfGRD0GORIjRCI2arB1hjQvthLU14Q03ZetymTXE" + + "dMml0i+t7wNhESkAMwvfqkPrG72sg32w8yCKh9zE7YATcElTAobdxR9aU8ei" + + "ulXgMb/PnC15/SZTvGzK4E5FGjRbRYx0ZJsQYpdzx4D0L/Yx0BEODfIdbXDV" + + "kSRMtltmWx+88xlqzN28I43ezoe/8rU7WzQvJLs/9N7Ud9JS6H2pHJxqGYQs" + + "3Sk32tnWjIk57PXk/++6IwsGonmalUSP53cILKDerkkj8LkOtbCSdmQu5uTb" + + "dXdxM6Yo6nHStyJyHZUz52qDbZruVnBLS2HXjG0LOBNSU80jbkNzJ9+uSr81" + + "bsHaUlIsq7Wksrv1pfNIz8ieisEJnk3FE6nitwh6w5RYF7Kl21a1vEPQUipZ" + + "hfPBLGel0lBmBb36va4ge0nketjV01j4lBStIg5c6c+V00gwsu3/Aj+EaMy8" + + "jDW1nle5f1wG6KQxAqLo78BIOojlyQjR1rAbPS+rvxTjirQ60LEPeyEnljmG" + + "xVnGGliSrnlRuI5KAkQxLCUEQTTFy3Dj+1NAUkx4Xoi7ARsfvj0L7T36wq0Y" + + "+aFViAoYfBXqNqf5vLbXo8hcKIkfvUf5b90ivNPnQx/nUH6LsSaDAUEpR3CR" + + "8c3iNn7BURwoIjtAz3NfEgsQRYbyQIb4hgCODp2tnhl+GK1bKvkgnbRoxyCJ" + + "XsK6Ka9lLK6TGP2AG7zdJIBBvWF4yCsNdF06qYuN32L0t4OOP6cRMowDchoY" + + "vwXr9KWAvAc4Kq3KnwwUDPTISLp33n9LFItdgZNZeMjZ3hi7mSisMB4lK0lX" + + "L4T3G/GNH+sYKgS17BRU1Dw/Bmt9LGOmQIFLsKErqIV+cXsBLlNiuC5lzl5Q" + + "W3DTNJhErd3vaecEAJJlTfSjSQ9PLy7nDLv/RjzVKNgXSerqfuiM05McEm40" + + "g6jQDRalN1alU8Cz3GLRjsfNGdYTsh/jPD4+ZiEqnCJo7VMxs+kb38etoTlz" + + "Zs3hoJKH3euds2uSSGn1yPYb7J4QkG0toLIydkwAvMMdIhwQ1VN6bU8cYGax" + + "FtmaugxN+n+00lb2Rbpdp+yVchdeNx1Yal30XPugP7x1OrVAZw5InTNCU9zQ" + + "Fx8ria6g4+t1GgwBqmPi1noSHHG3bThI74oBTsg3L4esRW27OMrTTzYVNemt" + + "dvJXN8yedTY2rVqwbKJO7bGR2VcDDn8ZgoaPBIvQuLSRBIdbUSIeKuLiuHbK" + + "IbkwtZTyz7LvrE1SZ0oDpMf19pb9fZPi3v7yQpFLx0oqqSYdhrJyOfhNVZXU" + + "dc4vbE0qez8MX9PNmyMtt4yktA+FC+2FM4P9jjdvaIfdm2Q7NhxjffvuwBJW" + + "SIoHBSEmxfxZgGCo29pOy2TZt/VpU8zpGpRBaqx0F9L2YzRJgwgOTYbkhF4w" + + "w1w03jCk3UWEg1Eq6kr6ZOEY3Us8DLTnx1RGKeGEpJ/vqtKzX1+KJS1t4E5G" + + "3eqa7WUqcyNqII/9ShMZqdfmXj1llgfuD+31HjDXXVO8RFY2zG/OneMkJJP2" + + "WfCs+IyN0I1+u/UJVMVW1d9y09nbrjruXSjvI2NwALB8NgtTHYbu3aLi0c02" + + "ijIB19xcNdSjwsmpR87lp9VFqIGEPVcYb+E11OODliUPNRPig6kPcbzGGq4b" + + "2CmbVVjPURU0U5cXJv0jqxGl8C7AsDIaJkXwGvQlp0t2wL/Wl66mAqBCQmJO" + + "Uw3A7/NbqGbhky8r4XMBBk0bOBn2jUIXyfJG696QPR27NrMshZRFG8fKmRfm" + + "4inNQQtcu6uUOKcoppeghWHBkK134LCFJakVrgmo0QeUXvdlR79imF9iyFDc" + + "Z6Fayr5Mh0RiDS0DtI4E4k17OVTjPYenflXCSk5VDCN8kM8d34wQEX2lahR2" + + "oWTBvJAFrvMqBL3zjnzjnNavoVaMlJy/Ezjrr+vNraCbNSY69Icflfb0xUEa" + + "RsdADuCKDVXoAavcUKw9aXBTolmHvquBBnUsyi630i2mONUg7ylqJCvCTCGk" + + "EDq48TofcRnuafZt38iwv5PRmRkhnMSGLR3L5AxjCAnSAUvqKPytH4QQ7+PJ" + + "NHc5qetzZdz+jRkCdCnC5YonOWyzi5I20U3Cdl7pL7Ev5INyk8knQLY2a88f" + + "9cUiV5kwPTAhMAkGBSsOAwIaBQAEFM74e0Rbt2IGCAn48XjvdAcaIl6cBBSY" + + "pFDCs7BGKfo6O4hW9fB0/2HXqwICBAA="; + + // You can use this method to print the java code for the BASE64_CERT + // constant. It will open the keystore file provided as argument and + // it will Base64 encode its content - then print the code that you can + // cut and paste back in this test. + private static final String encodeKeyStoreToBase64(String keystorePath) throws IOException { + // e.g.: keystorePath="temp0.jks" + try (FileInputStream fis = new FileInputStream(keystorePath)) { + byte[] bytes = fis.readAllBytes(); + String encoded = Base64.getEncoder().encodeToString(bytes); + format("BASE64_CERT", encoded); + return encoded; + } + } + + private static void format(String name, String value) { + System.out.println("private static final String " + name + " ="); + int start = 0, end = 60; + while (start < value.length() - 1 && end < value.length()) { + System.out.print(" \""); + System.out.print(value.substring(start, end) + .replace("\"", "\\\"")); + System.out.println("\" +"); + start = end; + end += 60; + } + if (end > value.length()) end = value.length(); + System.out.print(" \""); + System.out.print(value.substring(start, end)); + System.out.println("\";"); + } + + private static SSLContext createSSLContext(InputStream i) { + try { + char[] passphrase = "passphrase".toCharArray(); + KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(i, passphrase); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX"); + kmf.init(ks, passphrase); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); + tmf.init(ks); + + SSLContext ssl = SSLContext.getInstance("TLS"); + ssl.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + return ssl; + } catch (KeyManagementException | KeyStoreException | + UnrecoverableKeyException | CertificateException | + NoSuchAlgorithmException e) { + throw new RuntimeException(e.getMessage()); + } catch (IOException io) { + throw new UncheckedIOException(io); + } + } + + static final byte[] DATA; + + static { + DATA = new byte[1024]; + int len = 'z' - 'a'; + for (int i = 0; i < DATA.length; i++) { + DATA[i] = (byte) ('a' + (i % len)); + } + } + + final SSLContext context; + final AtomicLong requestCounter = new AtomicLong(); + final AtomicLong responseCounter = new AtomicLong(); + HttpTestServer http1Server; + HttpTestServer http2Server; + HttpTestServer https1Server; + HttpTestServer https2Server; + DigestEchoServer.TunnelingProxy proxy; + + URI http1URI; + URI https1URI; + URI http2URI; + URI https2URI; + InetSocketAddress proxyAddress; + ProxySelector proxySelector; + HttpClient client; + List> futures = new CopyOnWriteArrayList<>(); + Set pending = new CopyOnWriteArraySet<>(); + + final ExecutorService executor = new ThreadPoolExecutor(12, 60, 10, + TimeUnit.SECONDS, new LinkedBlockingQueue<>()); + final ExecutorService clientexec = new ThreadPoolExecutor(6, 12, 1, + TimeUnit.SECONDS, new LinkedBlockingQueue<>()); + + LargeHandshakeTest(String cert) { + byte[] decoded = Base64.getDecoder().decode(BASE64_CERT); + context = createSSLContext(new ByteArrayInputStream(decoded)); + SSLContext.setDefault(context); + } + + public HttpClient newHttpClient(ProxySelector ps) { + HttpClient.Builder builder = HttpClient + .newBuilder() + .sslContext(context) + .executor(clientexec) + .proxy(ps); + return builder.build(); + } + + public void setUp() throws Exception { + try { + InetSocketAddress sa = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + + // HTTP/1.1 + HttpServer server1 = HttpServer.create(sa, 0); + server1.setExecutor(executor); + http1Server = HttpTestServer.of(server1); + http1Server.addHandler(new HttpTestLargeHandler(), "/LargeHandshakeTest/http1/"); + http1Server.start(); + http1URI = new URI("http://" + http1Server.serverAuthority() + "/LargeHandshakeTest/http1/"); + + + // HTTPS/1.1 + HttpsServer sserver1 = HttpsServer.create(sa, 100); + sserver1.setExecutor(executor); + sserver1.setHttpsConfigurator(new HttpsConfigurator(context)); + https1Server = HttpTestServer.of(sserver1); + https1Server.addHandler(new HttpTestLargeHandler(), "/LargeHandshakeTest/https1/"); + https1Server.start(); + https1URI = new URI("https://" + https1Server.serverAuthority() + "/LargeHandshakeTest/https1/"); + + // HTTP/2.0 + http2Server = HttpTestServer.of( + new Http2TestServer("localhost", false, 0)); + http2Server.addHandler(new HttpTestLargeHandler(), "/LargeHandshakeTest/http2/"); + http2Server.start(); + http2URI = new URI("http://" + http2Server.serverAuthority() + "/LargeHandshakeTest/http2/"); + + // HTTPS/2.0 + https2Server = HttpTestServer.of( + new Http2TestServer("localhost", true, 0)); + https2Server.addHandler(new HttpTestLargeHandler(), "/LargeHandshakeTest/https2/"); + https2Server.start(); + https2URI = new URI("https://" + https2Server.serverAuthority() + "/LargeHandshakeTest/https2/"); + + proxy = DigestEchoServer.createHttpsProxyTunnel( + DigestEchoServer.HttpAuthSchemeType.NONE); + proxyAddress = proxy.getProxyAddress(); + proxySelector = new HttpProxySelector(proxyAddress); + client = newHttpClient(proxySelector); + System.out.println("Setup: done"); + } catch (Exception x) { + tearDown(); + throw x; + } catch (Error e) { + tearDown(); + throw e; + } + } + + public static void main(String[] args) throws Exception { + System.out.print("The certificate used in this test was generated " + + "with the following command:\n\t"); + System.out.println(COMMAND); + String cert; + if (args.length == 1) { + String storeFile = args[0]; + System.out.println("Parsing jks file: " + storeFile); + format("COMMAND", COMMAND); + cert = encodeKeyStoreToBase64(storeFile); + } else { + cert = BASE64_CERT; + } + LargeHandshakeTest test = new LargeHandshakeTest(cert); + + test.setUp(); + long start = System.nanoTime(); + try { + test.run(args); + } finally { + try { + long elapsed = System.nanoTime() - start; + System.out.println("*** Elapsed: " + Duration.ofNanos(elapsed)); + } finally { + test.tearDown(); + } + } + } + + public void run(String... args) throws Exception { + List serverURIs = List.of(http1URI, http2URI, https1URI, https2URI); + for (int i = 0; i < 5; i++) { + for (URI base : serverURIs) { + if (base.getScheme().equalsIgnoreCase("https")) { + URI proxy = i % 1 == 0 ? base.resolve(URI.create("proxy/foo?n=" + requestCounter.incrementAndGet())) + : base.resolve(URI.create("direct/foo?n=" + requestCounter.incrementAndGet())); + test(proxy); + } + } + for (URI base : serverURIs) { + URI direct = base.resolve(URI.create("direct/foo?n=" + requestCounter.incrementAndGet())); + test(direct); + } + } + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); + } + + public void test(URI uri) throws Exception { + System.out.println("Testing with " + uri); + pending.add(uri); + HttpRequest request = HttpRequest.newBuilder(uri).build(); + CompletableFuture> resp = + client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) + .whenComplete((r, t) -> this.requestCompleted(request, r, t)); + futures.add(resp); + } + + private void requestCompleted(HttpRequest request, HttpResponse r, Throwable t) { + responseCounter.incrementAndGet(); + pending.remove(request.uri()); + System.out.println(request + " -> " + (t == null ? r : t) + + " [still pending: " + (requestCounter.get() - responseCounter.get()) + "]"); + if (pending.size() < 10 && requestCounter.get() > 10) { + pending.forEach(u -> System.out.println("\tpending: " + u)); + } + } + + public void tearDown() { + proxy = stop(proxy, DigestEchoServer.TunnelingProxy::stop); + http1Server = stop(http1Server, HttpTestServer::stop); + https1Server = stop(https1Server, HttpTestServer::stop); + http2Server = stop(http2Server, HttpTestServer::stop); + https2Server = stop(https2Server, HttpTestServer::stop); + client = null; + try { + executor.awaitTermination(2000, TimeUnit.MILLISECONDS); + } catch (Throwable x) { + } finally { + executor.shutdownNow(); + } + try { + clientexec.awaitTermination(2000, TimeUnit.MILLISECONDS); + } catch (Throwable x) { + } finally { + clientexec.shutdownNow(); + } + System.out.println("Teardown: done"); + } + + private interface Stoppable { + public void stop(T service) throws Exception; + } + + static T stop(T service, Stoppable stop) { + try { + if (service != null) stop.stop(service); + } catch (Throwable x) { + } + ; + return null; + } + + static class HttpProxySelector extends ProxySelector { + private static final List NO_PROXY = List.of(Proxy.NO_PROXY); + private final List proxyList; + + HttpProxySelector(InetSocketAddress proxyAddress) { + proxyList = List.of(new Proxy(Proxy.Type.HTTP, proxyAddress)); + } + + @Override + public List select(URI uri) { + // our proxy only supports tunneling + if (uri.getScheme().equalsIgnoreCase("https")) { + if (uri.getPath().contains("/proxy/")) { + return proxyList; + } + } + return NO_PROXY; + } + + @Override + public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { + System.err.println("Connection to proxy failed: " + ioe); + System.err.println("Proxy: " + sa); + System.err.println("\tURI: " + uri); + ioe.printStackTrace(); + } + } + + public static class HttpTestLargeHandler implements HttpTestHandler { + @Override + public void handle(HttpTestExchange t) throws IOException { + try (InputStream is = t.getRequestBody(); + OutputStream os = t.getResponseBody()) { + byte[] bytes = is.readAllBytes(); + assert bytes.length == 0; + URI u = t.getRequestURI(); + long responseID = Long.parseLong(u.getQuery().substring(2)); + System.out.println("Server " + t.getRequestURI() + " sending response " + responseID); + t.sendResponseHeaders(200, DATA.length * 3); + for (int i = 0; i < 3; i++) { + os.write(DATA); + } + System.out.println("\tresp:" + responseID + ": done"); + } + } + } +} diff --git a/test/jdk/java/net/httpclient/LargeResponseTest.java b/test/jdk/java/net/httpclient/LargeResponseTest.java new file mode 100644 index 00000000000..6dd7ca3479f --- /dev/null +++ b/test/jdk/java/net/httpclient/LargeResponseTest.java @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsServer; +import jdk.test.lib.net.SimpleSSLContext; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.SocketAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +/** + * @test + * @bug 8231449 + * @summary This test verifies that the HttpClient works correctly when the server + * sends large amount of data. Note that this test will pass even without + * the fix for JDK-8231449, which is unfortunate. + * @library /test/lib http2/server + * @build jdk.test.lib.net.SimpleSSLContext HttpServerAdapters DigestEchoServer LargeResponseTest + * @modules java.net.http/jdk.internal.net.http.common + * java.net.http/jdk.internal.net.http.frame + * java.net.http/jdk.internal.net.http.hpack + * java.logging + * java.base/sun.net.www.http + * java.base/sun.net.www + * java.base/sun.net + * @run main/othervm -Dtest.requiresHost=true + * -Djdk.httpclient.HttpClient.log=headers + * -Djdk.internal.httpclient.debug=true + * LargeResponseTest + * + */ +public class LargeResponseTest implements HttpServerAdapters { + static final byte[] DATA; + static { + DATA = new byte[64 * 1024]; + int len = 'z' - 'a'; + for (int i=0; i < DATA.length; i++) { + DATA[i] = (byte) ('a' + (i % len)); + } + } + + static final SSLContext context; + static { + try { + context = new SimpleSSLContext().get(); + SSLContext.setDefault(context); + } catch (Exception x) { + throw new ExceptionInInitializerError(x); + } + } + + final AtomicLong requestCounter = new AtomicLong(); + final AtomicLong responseCounter = new AtomicLong(); + HttpTestServer http1Server; + HttpTestServer http2Server; + HttpTestServer https1Server; + HttpTestServer https2Server; + DigestEchoServer.TunnelingProxy proxy; + + URI http1URI; + URI https1URI; + URI http2URI; + URI https2URI; + InetSocketAddress proxyAddress; + ProxySelector proxySelector; + HttpClient client; + List> futures = new CopyOnWriteArrayList<>(); + Set pending = new CopyOnWriteArraySet<>(); + + final ExecutorService executor = new ThreadPoolExecutor(12, 60, 10, + TimeUnit.SECONDS, new LinkedBlockingQueue<>()); + final ExecutorService clientexec = new ThreadPoolExecutor(6, 12, 1, + TimeUnit.SECONDS, new LinkedBlockingQueue<>()); + + public HttpClient newHttpClient(ProxySelector ps) { + HttpClient.Builder builder = HttpClient + .newBuilder() + .sslContext(context) + .executor(clientexec) + .proxy(ps); + return builder.build(); + } + + public void setUp() throws Exception { + try { + InetSocketAddress sa = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + + // HTTP/1.1 + HttpServer server1 = HttpServer.create(sa, 0); + server1.setExecutor(executor); + http1Server = HttpTestServer.of(server1); + http1Server.addHandler(new HttpTestLargeHandler(), "/LargeResponseTest/http1/"); + http1Server.start(); + http1URI = new URI("http://" + http1Server.serverAuthority() + "/LargeResponseTest/http1/"); + + + // HTTPS/1.1 + HttpsServer sserver1 = HttpsServer.create(sa, 100); + sserver1.setExecutor(executor); + sserver1.setHttpsConfigurator(new HttpsConfigurator(context)); + https1Server = HttpTestServer.of(sserver1); + https1Server.addHandler(new HttpTestLargeHandler(), "/LargeResponseTest/https1/"); + https1Server.start(); + https1URI = new URI("https://" + https1Server.serverAuthority() + "/LargeResponseTest/https1/"); + + // HTTP/2.0 + http2Server = HttpTestServer.of( + new Http2TestServer("localhost", false, 0)); + http2Server.addHandler(new HttpTestLargeHandler(), "/LargeResponseTest/http2/"); + http2Server.start(); + http2URI = new URI("http://" + http2Server.serverAuthority() + "/LargeResponseTest/http2/"); + + // HTTPS/2.0 + https2Server = HttpTestServer.of( + new Http2TestServer("localhost", true, 0)); + https2Server.addHandler(new HttpTestLargeHandler(), "/LargeResponseTest/https2/"); + https2Server.start(); + https2URI = new URI("https://" + https2Server.serverAuthority() + "/LargeResponseTest/https2/"); + + proxy = DigestEchoServer.createHttpsProxyTunnel( + DigestEchoServer.HttpAuthSchemeType.NONE); + proxyAddress = proxy.getProxyAddress(); + proxySelector = new HttpProxySelector(proxyAddress); + client = newHttpClient(proxySelector); + System.out.println("Setup: done"); + } catch (Exception x) { + tearDown(); throw x; + } catch (Error e) { + tearDown(); throw e; + } + } + + public static void main(String[] args) throws Exception { + LargeResponseTest test = new LargeResponseTest(); + test.setUp(); + long start = System.nanoTime(); + try { + test.run(args); + } finally { + try { + long elapsed = System.nanoTime() - start; + System.out.println("*** Elapsed: " + Duration.ofNanos(elapsed)); + } finally { + test.tearDown(); + } + } + } + + public void run(String... args) throws Exception { + List serverURIs = List.of(http1URI, http2URI, https1URI, https2URI); + for (int i=0; i<5; i++) { + for (URI base : serverURIs) { + if (base.getScheme().equalsIgnoreCase("https")) { + URI proxy = i % 1 == 0 ? base.resolve(URI.create("proxy/foo?n="+requestCounter.incrementAndGet())) + : base.resolve(URI.create("direct/foo?n="+requestCounter.incrementAndGet())); + test(proxy); + } + } + for (URI base : serverURIs) { + URI direct = base.resolve(URI.create("direct/foo?n="+requestCounter.incrementAndGet())); + test(direct); + } + } + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); + } + + public void test(URI uri) throws Exception { + System.out.println("Testing with " + uri); + pending.add(uri); + HttpRequest request = HttpRequest.newBuilder(uri).build(); + CompletableFuture> resp = + client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) + .whenComplete((r, t) -> this.requestCompleted(request, r, t)); + futures.add(resp); + } + + private void requestCompleted(HttpRequest request, HttpResponse r, Throwable t) { + responseCounter.incrementAndGet(); + pending.remove(request.uri()); + System.out.println(request + " -> " + (t == null ? r : t) + + " [still pending: " + (requestCounter.get() - responseCounter.get()) +"]"); + if (pending.size() < 10 && requestCounter.get() > 10) { + pending.forEach(u -> System.out.println("\tpending: " + u)); + } + } + + public void tearDown() { + proxy = stop(proxy, DigestEchoServer.TunnelingProxy::stop); + http1Server = stop(http1Server, HttpTestServer::stop); + https1Server = stop(https1Server, HttpTestServer::stop); + http2Server = stop(http2Server, HttpTestServer::stop); + https2Server = stop(https2Server, HttpTestServer::stop); + client = null; + try { + executor.awaitTermination(2000, TimeUnit.MILLISECONDS); + } catch (Throwable x) { + } finally { + executor.shutdownNow(); + } + try { + clientexec.awaitTermination(2000, TimeUnit.MILLISECONDS); + } catch (Throwable x) { + } finally { + clientexec.shutdownNow(); + } + System.out.println("Teardown: done"); + } + + private interface Stoppable { public void stop(T service) throws Exception; } + + static T stop(T service, Stoppable stop) { + try { if (service != null) stop.stop(service); } catch (Throwable x) { }; + return null; + } + + static class HttpProxySelector extends ProxySelector { + private static final List NO_PROXY = List.of(Proxy.NO_PROXY); + private final List proxyList; + HttpProxySelector(InetSocketAddress proxyAddress) { + proxyList = List.of(new Proxy(Proxy.Type.HTTP, proxyAddress)); + } + + @Override + public List select(URI uri) { + // our proxy only supports tunneling + if (uri.getScheme().equalsIgnoreCase("https")) { + if (uri.getPath().contains("/proxy/")) { + return proxyList; + } + } + return NO_PROXY; + } + + @Override + public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { + System.err.println("Connection to proxy failed: " + ioe); + System.err.println("Proxy: " + sa); + System.err.println("\tURI: " + uri); + ioe.printStackTrace(); + } + } + + public static class HttpTestLargeHandler implements HttpTestHandler { + @Override + public void handle(HttpTestExchange t) throws IOException { + try (InputStream is = t.getRequestBody(); + OutputStream os = t.getResponseBody()) { + byte[] bytes = is.readAllBytes(); + assert bytes.length == 0; + URI u = t.getRequestURI(); + long responseID = Long.parseLong(u.getQuery().substring(2)); + System.out.println("Server " + t.getRequestURI() + " sending response " + responseID); + t.sendResponseHeaders(200, DATA.length * 3); + for (int i=0; i<3; i++) { + os.write(DATA); + } + System.out.println("\tresp:" + responseID + ": done"); + } + } + } + +} diff --git a/test/jdk/java/net/httpclient/whitebox/SSLFlowDelegateTestDriver.java b/test/jdk/java/net/httpclient/whitebox/SSLFlowDelegateTestDriver.java new file mode 100644 index 00000000000..083a291751f --- /dev/null +++ b/test/jdk/java/net/httpclient/whitebox/SSLFlowDelegateTestDriver.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * 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 8308144 + * @summary tests that the SSLFlowDelegate doesn't accumulate application data when the + * downReader doesn't request any + * @modules java.net.http/jdk.internal.net.http + * @run testng/othervm -Djdk.internal.httpclient.debug=true + * -Djavax.net.debug=ssl:handshake + * java.net.http/jdk.internal.net.http.SSLFlowDelegateTest + */ diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLFlowDelegateTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLFlowDelegateTest.java new file mode 100644 index 00000000000..45af27a96a8 --- /dev/null +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLFlowDelegateTest.java @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.internal.net.http; + +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Flow; +import java.util.concurrent.Flow.Subscriber; +import java.util.concurrent.SubmissionPublisher; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; + +import jdk.internal.net.http.common.Logger; +import jdk.internal.net.http.common.SSLFlowDelegate; +import jdk.internal.net.http.common.SubscriberWrapper; +import jdk.internal.net.http.common.Utils; +import org.testng.Assert; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +// jtreg test definition for this test resides in SSLFlowDelegateTestDriver.java +public class SSLFlowDelegateTest { + private static final String ALPN = "foobar"; + private static final String debugTag = SSLFlowDelegateTest.class.getSimpleName(); + private static final Random random = new Random(); + private static final byte DATA_BYTE = (byte) random.nextInt(); + + private ExecutorService executor; + private SSLContext sslContext; + private SSLParameters sslParams; + private SSLServerSocket sslServerSocket; + private SSLEngine clientEngine; + private CompletableFuture testCompletion; + + @BeforeTest + public void beforeTest() throws Exception { + this.executor = Executors.newCachedThreadPool(); + this.sslContext = new jdk.internal.net.http.SimpleSSLContext().get(); + this.testCompletion = new CompletableFuture<>(); + + final SSLParameters sp = new SSLParameters(); + sp.setApplicationProtocols(new String[]{ALPN}); + this.sslParams = sp; + + this.sslServerSocket = startServer(this.sslContext); + println(debugTag, "Server started at " + this.sslServerSocket.getInetAddress() + ":" + + this.sslServerSocket.getLocalPort()); + + this.clientEngine = createClientEngine(this.sslContext); + } + + @AfterTest + public void afterTest() throws Exception { + if (this.sslServerSocket != null) { + println(debugTag, "Closing server socket " + this.sslServerSocket); + this.sslServerSocket.close(); + } + if (this.executor != null) { + println(debugTag, "Shutting down the executor " + this.executor); + this.executor.shutdownNow(); + } + } + + private static void println(final String debugTag, final String msg) { + println(debugTag, msg, null); + } + + private static void println(final String debugTag, final String msg, final Throwable t) { + final Logger logger = Utils.getDebugLogger(() -> debugTag); + logger.log(msg); + if (t != null) { + t.printStackTrace(); + } + } + + private SSLServerSocket createSSLServerSocket( + final SSLContext ctx, final InetSocketAddress bindAddr) throws IOException { + final SSLServerSocketFactory fac = ctx.getServerSocketFactory(); + final SSLServerSocket sslServerSocket = (SSLServerSocket) fac.createServerSocket(); + sslServerSocket.setReuseAddress(false); + sslServerSocket.setSSLParameters(this.sslParams); + sslServerSocket.bind(bindAddr); + return sslServerSocket; + } + + private SSLServerSocket startServer(final SSLContext ctx) throws Exception { + final SSLServerSocket sslServerSocket = createSSLServerSocket(ctx, + new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); + final Runnable serverResponsePusher = new ServerResponsePusher(sslServerSocket, + this.testCompletion); + final Thread serverThread = new Thread(serverResponsePusher, "serverResponsePusher"); + // start the thread which will accept() a socket connection and send data over it + serverThread.start(); + return sslServerSocket; + } + + private SSLEngine createClientEngine(final SSLContext ctx) { + final SSLEngine clientEngine = ctx.createSSLEngine(); + clientEngine.setSSLParameters(this.sslParams); + clientEngine.setUseClientMode(true); + return clientEngine; + } + + /** + * Constructs a {@code SSLFlowDelegate} with a {@code downReader} which only requests one + * item and then never requests any more. After that one item has been received by the + * {@code downReader}, this test feeds the + * {@linkplain SSLFlowDelegate#upstreamReader() upstreamReader} with (network SSL) data in + * such a manner that while + * {@link SSLEngine#unwrap(ByteBuffer, ByteBuffer) unwrapping} it in the internal implementation + * of {@code SSLFlowDelegate}, it will often trigger {@code BUFFER_UNDERFLOW} state. + * This test then verifies that the {@code SSLFlowDelegate} when it reaches such a state will + * not keep asking for more (network SSL) data and decrypting it to application data and + * accumulating it (since the {@code downReader} won't be using any of this accumulated data). + */ + @Test + public void testUnsolicitedBytes() throws Exception { + // initiate a connection to the server + try (final Socket socket = new Socket(sslServerSocket.getInetAddress(), + sslServerSocket.getLocalPort())) { + println(debugTag, "connected to server, local socket: " + socket); + // this future is completed when the AppResponseReceiver subscriber receives + // the sole item that is requests for (through just one subscription.request(1)) + final CompletableFuture soleExpectedAppData = new CompletableFuture<>(); + // the "testCompletion" CompletableFuture represents that future that's used + // in various places in this test. If the "testCompletion" completes before + // the "soleExpectedAppData" completes (typically due to some exception), + // then we complete the "soleExpectedAppData" too. + this.testCompletion.whenComplete((r, t) -> { + if (soleExpectedAppData.isDone()) { + return; + } + if (t == null) { + soleExpectedAppData.complete(-1L); // -1 indicates no item received + return; + } + soleExpectedAppData.completeExceptionally(t); + }); + // the "downReader" Subscriber which is passed to the constructor of SSLFlowDelegate. + // This subscriber receives the (decrypted) application data. This subscriber requests + // only one item (no restriction on how many bytes are received in this one item). + final AppResponseReceiver appResponseReceiver = new AppResponseReceiver( + this.testCompletion, soleExpectedAppData); + // the "downWriter" Subscriber which is passed to the constructor of the + // SSLFlowDelegate. + // This subscriber receives the (encrypted) network data and just writes it out to the + // connected socket's OutputStream. Makes no restrictions on how much items (and thus + // bytes) it receives and just keeps writing as and when it receives the data. + final SocketWriter networkDataWriter = new SocketWriter(socket, this.testCompletion); + // construct the SSLFlowDelegate + final SSLFlowDelegate sslFlowDelegate = new SSLFlowDelegate(clientEngine, executor, + appResponseReceiver, networkDataWriter); + // the SocketReader runs in a thread and it keeps reading data from the connected + // socket's InputStream. This data keeps coming from the ServerResponsePusher which too + // is running in a thread of its own and is writing it out over the connected socket's + // OutputStream. The SocketReader and ServerResponsePusher are convenience constructs + // which use the simple APIs (InputStream/OutputStream) provided by SSLServerSocket + // and (SSL)Socket to generate SSL network data. This generated data is then fed to + // the relevant subscribers of SSLFlowDelegate. The SocketReader and the + // ServerResponsePusher play no other role than just generating this SSL network data. + final SocketReader socketReader = new SocketReader(socket, executor, + sslFlowDelegate.upstreamReader(), this.testCompletion); + // start reading from the socket in separate thread + new Thread(socketReader, "socketReader").start(); + + // we use this publisher only to trigger the SSL handshake and the publisher itself + // doesn't publish any data i.e. there is no application client "request" data needed + // in this test + final Flow.Publisher> publisher = new ZeroDataPublisher<>(); + println(debugTag, "Subscribing the upstreamWriter() to trigger SSL handshake"); + // now connect all the pieces. + // this call to subscribe the upstreamWriter() triggers the SSL handshake (doesn't + // matter if our zero app data publisher publishes no app data; SSL handshake + // doesn't require app data). see SSLFlowDelegate$Writer.onSubscribe() where + // it triggers the SSL handshake when this subscription happens + publisher.subscribe(sslFlowDelegate.upstreamWriter()); + println(debugTag, "Waiting for handshake to complete"); + final String negotiatedALPN = sslFlowDelegate.alpn().join(); + println(debugTag, "handshake completed, with negotiated ALPN: " + negotiatedALPN); + Assert.assertEquals(negotiatedALPN, ALPN, "unexpected ALPN negotiated"); + try { + // now wait for the initial (and the only) chunk of application data to be + // received by the AppResponseReceiver + println(debugTag, "waiting for the sole expected chunk of application data to" + + " become available to " + appResponseReceiver); + final long numAppDataBytesReceived = soleExpectedAppData.join(); + println(debugTag, "Received " + numAppDataBytesReceived + " app data bytes," + + " no more app data expected"); + // at this point, we have received the only expected item in the downReader + // i.e. the AppResponseReceiver. We no longer expect the SSLFlowDelegate to be + // accumulating any decrypted application data (because the downReader hasn't + // requested any). + // We will now let the SocketReader and the ServerResponsePusher threads to keep + // generating and feeding the SSL network data to the SSLFlowDelegate subscribers, + // until they are "done" (either normally or exceptionally). Those threads decide + // when to stop generating the SSL network data. + this.testCompletion.join(); + } catch (CompletionException ce) { + // fail with a Assert.fail instead of throwing an exception, thus providing a + // better failure report + failTest(ce); + } + println(debugTag, "now checking if any unsolicited bytes accumulated"); + // SSL network data generation has completed, now check if the SSLFlowDelegate + // decrypted and accumulated any application data when it shouldn't have. + assertNoUnsolicitedBytes(sslFlowDelegate); + println(debugTag, "testing completed successfully, no unsolicited bytes accumulated"); + } + } + + private void failTest(final CompletionException ce) { + final Throwable cause = ce.getCause(); + Assert.fail(cause.getMessage() == null ? "test failed" : cause.getMessage(), cause); + } + + // uses reflection to get hold of the SSLFlowDelegate.reader.outputQ member field, + // which is a ConcurrentLinkedQueue holding the decrypted application data that + // is supposed to be sent to the downReader subscriber of the SSLFlowDelegate. + // Asserts that this outputQ has 0 bytes of data accumulated + private void assertNoUnsolicitedBytes(final SSLFlowDelegate sslFlowDelegate) throws Exception { + final Field readerField = SSLFlowDelegate.class.getDeclaredField("reader"); + readerField.setAccessible(true); + + final Field readerOutputQField = SubscriberWrapper.class.getDeclaredField("outputQ"); + readerOutputQField.setAccessible(true); + + final Object reader = readerField.get(sslFlowDelegate); + final ConcurrentLinkedQueue> outputQ = + ConcurrentLinkedQueue.class.cast(readerOutputQField.get(reader)); + long numUnsolicitated = 0; + List accumulations; + while ((accumulations = outputQ.poll()) != null) { + println(debugTag, "found some items in outputQ"); + for (final ByteBuffer buf : accumulations) { + if (!buf.hasRemaining()) { + continue; + } + try { + numUnsolicitated = Math.addExact(numUnsolicitated, buf.remaining()); + } catch (ArithmeticException ame) { + numUnsolicitated = Long.MAX_VALUE; + break; + } + } + println(debugTag, "num unsolicited bytes so far = " + numUnsolicitated); + } + Assert.assertEquals(numUnsolicitated, 0, + "SSLFlowDelegate has accumulated " + numUnsolicitated + " unsolicited bytes"); + } + + // A publisher which accepts only one subscriber and doesn't ever publish any data + private static final class ZeroDataPublisher implements Flow.Publisher { + private final AtomicBoolean hasSubscriber = new AtomicBoolean(); + + @Override + public void subscribe(final Subscriber subscriber) { + if (!hasSubscriber.compareAndSet(false, true)) { + // we allow only one subscriber + throw new IllegalStateException("Cannot subscribe more than once"); + } + subscriber.onSubscribe(new Flow.Subscription() { + @Override + public void request(long n) { + // no-op, we don't publish any data + } + + @Override + public void cancel() { + // no-op + } + }); + } + } + + // a Subscriber which subscribers for encrypted SSL network data that it will then + // write to a connected (SSL) Socket's OutputStream + private static final class SocketWriter implements Subscriber> { + private static final String debugTag = SocketWriter.class.getSimpleName(); + + private final Socket socket; + private final CompletableFuture completion; + private volatile Flow.Subscription subscription; + private final AtomicLong numBytesWritten = new AtomicLong(); + + private SocketWriter(final Socket socket, final CompletableFuture completion) { + this.socket = socket; + this.completion = completion; + } + + @Override + public void onSubscribe(final Flow.Subscription subscription) { + this.subscription = subscription; + println(debugTag, "onSubscribe invoked, requesting for data to write to socket"); + subscription.request(1); + } + + @Override + public void onNext(final List bufs) { + try { + final OutputStream os = + new BufferedOutputStream(this.socket.getOutputStream()); + + // these buffers contain encrypted SSL network data that we receive + // from the SSLFlowDelegate. We just write them out to the + // Socket's OutputStream. + for (final ByteBuffer buf : bufs) { + int len = buf.remaining(); + int written = writeToStream(os, buf); + assert len == written; + this.numBytesWritten.addAndGet(len); + assert !buf.hasRemaining() + : "buffer has " + buf.remaining() + " bytes left"; + this.subscription.request(1); // willing to write out more data when available + } + } catch (Throwable e) { + println(debugTag, "failed: " + e, e); + completion.completeExceptionally(e); + } + } + + @Override + public void onError(final Throwable throwable) { + println(debugTag, "error: " + throwable, throwable); + completion.completeExceptionally(throwable); + } + + @Override + public void onComplete() { + println(debugTag, "onComplete(), total bytes written: " + this.numBytesWritten.get()); + } + + private int writeToStream(final OutputStream os, final ByteBuffer buf) throws IOException { + final byte[] b = buf.array(); + final int offset = buf.arrayOffset() + buf.position(); + final int n = buf.limit() - buf.position(); + os.write(b, offset, n); + buf.position(buf.limit()); + os.flush(); + return n; + } + } + + // a background task that keeps reading encrypted SSL network data from a connected + // (SSL) Socket and publishes this data to the SSLFlowDelegate's upstreamReader() subscriber. + // Very importantly, irrespective of how many bytes of data this SocketReader reads + // of the Socket's InputStream in one read() operation, it publishes this data to the + // upstreamReader() subscriber in very small chunks, so that when the upstreamReader() + // subscriber receives it and starts unwrapping that SSL network data, it often + // encounters a BUFFER_UNDERFLOW state. + private static final class SocketReader implements Runnable { + private static final String debugTag = SocketReader.class.getSimpleName(); + + // the size of data that will be published to the upstreamReader() subscriber. + // small enough; no other meaning to this value + private static final int VERY_SMALL_DATA_SIZE = 123; + + private final Socket socket; + private final SubmissionPublisher> publisher; + private final CompletableFuture completion; + + private SocketReader(final Socket socket, final Executor executor, + final Subscriber> incomingNetworkDataSubscriber, + final CompletableFuture completion) { + this.socket = socket; + this.completion = completion; + this.publisher = new SubmissionPublisher<>(executor, Flow.defaultBufferSize(), + (s, t) -> completion.completeExceptionally(t)); + this.publisher.subscribe(incomingNetworkDataSubscriber); + } + + @Override + public void run() { + try { + // reads off the SSLSocket the data from the "server" + final InputStream is = socket.getInputStream(); + long numBytesRead = 0; + long numBytesPublished = 0; + while (true) { + final byte[] buf = new byte[10240]; // this size doesn't matter + final int n = is.read(buf); + if (n == -1) { + println(debugTag, "got EOF, now closing resources; total read " + + numBytesRead + " bytes, total published " + numBytesPublished + + " bytes"); + closeAndComplete(is); + return; + } + println(debugTag, "read " + n + " bytes from socket"); + numBytesRead = Math.addExact(numBytesRead, n); + int remaining = n; + int index = 0; + while (remaining > 0) { + final int chunkSize = Math.min(remaining, VERY_SMALL_DATA_SIZE); + final byte[] chunk = Arrays.copyOfRange(buf, index, index + chunkSize); + index += chunkSize; + remaining -= chunkSize; + final int lagOrDrops = publisher.offer( + List.of(ByteBuffer.wrap(chunk)), 2, TimeUnit.SECONDS, null); + if (lagOrDrops < 0) { + println(debugTag, "dropped a chunk, re-offering"); + // dropped, we now re-attempt once more and if that too is dropped, + // we stop + final int newLagOrDrops = publisher.offer( + List.of(ByteBuffer.wrap(chunk)), 2, TimeUnit.SECONDS, null); + if (newLagOrDrops < 0) { + println(debugTag, "dropped the re-offered chunk; closing resources," + + " total bytes read: " + numBytesRead + + " total bytes published: " + numBytesPublished); + closeAndComplete(is); + return; + } + } + numBytesPublished += chunkSize; + println(debugTag, "published " + numBytesPublished + " bytes of total " + + numBytesRead + " bytes read"); + } + } + } catch (Throwable e) { + println(debugTag, "failed: " + e, e); + completion.completeExceptionally(e); + } + } + + private void closeAndComplete(final InputStream is) { + publisher.close(); + completion.complete(null); + Utils.close(is); + } + } + + // a background task which accepts one socket connection on a SSLServerSocket and keeps + // writing (application) data to the OutputStream of that socket. + private static final class ServerResponsePusher implements Runnable { + private static final String debugTag = ServerResponsePusher.class.getSimpleName(); + private final SSLServerSocket sslServerSocket; + private final CompletableFuture completion; + + private ServerResponsePusher(final SSLServerSocket sslServerSocket, + final CompletableFuture completion) { + this.sslServerSocket = sslServerSocket; + this.completion = completion; + } + + @Override + public void run() { + try { + // accept a connection + try (final Socket socket = this.sslServerSocket.accept()) { + println(debugTag, "Accepted connection from " + socket); + try (final OutputStream os = socket.getOutputStream()) { + final byte[] resp = new byte[10240]; // this size doesn't matter + Arrays.fill(resp, DATA_BYTE); + long numWritten = 0; + // reasonable number of times to generate enough network data + final int numTimes = 50; + for (int i = 0; i < numTimes; i++) { + println(debugTag, "writing " + resp.length + " bytes, " + + numWritten + " written so far"); + os.write(resp); + numWritten += resp.length; + os.flush(); + } + println(debugTag, "stopped writing, total bytes written: " + numWritten); + } + } + } catch (Throwable e) { + println(debugTag, "error: " + e, e); + this.completion.completeExceptionally(e); + } + } + } + + // the "downReader" Subscriber which is passed to the constructor of SSLFlowDelegate. + // This subscriber receives the (decrypted) application data. This subscriber requests + // only one item (no restriction on how many bytes are received in this one item). + private static final class AppResponseReceiver implements Subscriber> { + private static final String debugTag = AppResponseReceiver.class.getSimpleName(); + + private final byte[] expectedData = new byte[1024]; // no significance of the size + + private final AtomicLong numBytesReceived; + private volatile Flow.Subscription subscription; + private final CompletableFuture completion; + private final CompletableFuture soleExpectedAppData; + private boolean receivedOneItem; + + private AppResponseReceiver(final CompletableFuture completion, + final CompletableFuture soleExpectedAppData) { + this.numBytesReceived = new AtomicLong(0); + this.soleExpectedAppData = soleExpectedAppData; + this.completion = completion; + Arrays.fill(expectedData, DATA_BYTE); + } + + @Override + public void onSubscribe(Flow.Subscription subscription) { + println(debugTag, "onSubscribe invoked"); + this.subscription = subscription; + subscription.request(1); // the sole item request this subscriber will make + } + + @Override + public void onNext(final List buffers) { + if (receivedOneItem) { + // don't throw an exception since that will go against the Subscriber's + // specification, instead complete the future exceptionally + completion.completeExceptionally(new AssertionError("onNext() called more than" + + " once, even though no request was made")); + return; + } + receivedOneItem = true; + // these buffers contain (decrypted) application data that the SSLFlowDelegate has + // forwarded to this subscriber + for (final ByteBuffer buf : buffers) { + final int numBytes = buf.remaining(); + // verify the content of the received application data + while (buf.hasRemaining()) { + final int size = Math.min(buf.remaining(), expectedData.length); + final byte[] actual = new byte[size]; + buf.get(actual); + // this is just convenience/performance optimization - instead of checking + // one byte at a time, we compare multiple bytes + final int index = Arrays.mismatch(expectedData, 0, size, actual, 0, size); + if (index != -1) { + final String errMsg = "Unexpected byte received: " + actual[index]; + println(debugTag, "Cancelling subscription due to error: " + errMsg); + subscription.cancel(); + completion.completeExceptionally(new AssertionError(errMsg)); + return; + } + } + numBytesReceived.addAndGet(numBytes); + } + println(debugTag, "Received " + numBytesReceived.get() + " bytes," + + " will not request any more data"); + soleExpectedAppData.complete(numBytesReceived.get()); + } + + @Override + public void onError(final Throwable throwable) { + completion.completeExceptionally(throwable); + } + + @Override + public void onComplete() { + final long n = numBytesReceived.get(); + println(debugTag, "Completed: received " + n + " bytes"); + } + } +} diff --git a/test/jdk/java/rmi/server/RemoteServer/AddrInUse.java b/test/jdk/java/rmi/server/RemoteServer/AddrInUse.java index 34e343b6193..86ac5b0313b 100644 --- a/test/jdk/java/rmi/server/RemoteServer/AddrInUse.java +++ b/test/jdk/java/rmi/server/RemoteServer/AddrInUse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ /* @test * @bug 4111507 * @summary retryServerSocket should not retry on BindException - * @author Ann Wollrath * * @run main/othervm AddrInUse */ @@ -33,75 +32,54 @@ import java.rmi.registry.LocateRegistry; import java.rmi.server.ExportException; -public class AddrInUse implements Runnable { +public class AddrInUse { - private static int port = -1; - private static final long TIMEOUT = 10000; - - private boolean exportSucceeded = false; - private Throwable exportException = null; - - public void run() { - - /* - * Attempt to create (i.e. export) a registry on the port that - * has already been bound, and record the result. - */ - try { - LocateRegistry.createRegistry(port); - synchronized (this) { - exportSucceeded = true; - notifyAll(); - } - } catch (Throwable t) { - synchronized (this) { - exportException = t; - notifyAll(); - } - } - } + private static volatile Throwable registryExportFailure = null; public static void main(String[] args) throws Exception { - System.err.println("\nRegression test for bug 4111507\n"); - /* * Bind a server socket to a port. */ - ServerSocket server = new ServerSocket(0); - port = server.getLocalPort(); - System.err.println("Created a ServerSocket on port " + port + "..."); - - /* - * Start a thread that creates a registry on the same port, - * and analyze the result. - */ - System.err.println("create a registry on the same port..."); - System.err.println("(should cause an ExportException)"); - AddrInUse obj = new AddrInUse(); - synchronized (obj) { - (new Thread(obj, "AddrInUse")).start(); + try (ServerSocket server = new ServerSocket(0)) { + int port = server.getLocalPort(); + System.err.println("Created a ServerSocket on port " + port + "..."); /* - * Don't wait forever (original bug is that the export - * hangs). + * Start a thread that creates a registry on the same port, + * and analyze the result. */ - obj.wait(TIMEOUT); + System.err.println("create a registry on the same port..."); + System.err.println("(should cause an ExportException)"); - if (obj.exportSucceeded) { - throw new RuntimeException( - "TEST FAILED: export on already-bound port succeeded"); - } else if (obj.exportException != null) { - obj.exportException.printStackTrace(); - if (obj.exportException instanceof ExportException) { - System.err.println("TEST PASSED"); - } else { - throw new RuntimeException( - "TEST FAILED: unexpected exception occurred", - obj.exportException); + Thread exportRegistryThread = new Thread(() -> { + /* + * Attempt to create (i.e. export) a registry on the port that + * has already been bound, and record the result. + */ + try { + LocateRegistry.createRegistry(port); + } catch (Throwable t) { + registryExportFailure = t; } - } else { - throw new RuntimeException("TEST FAILED: export timed out"); + }, "ExportRegistry-Thread"); + + exportRegistryThread.start(); + + /* + * Wait for the LocateRegistry.createRegistry() call to complete or + * if it blocks forever (due to the original bug), then let jtreg fail + * the test with a timeout + */ + exportRegistryThread.join(); + if (registryExportFailure == null) { + throw new RuntimeException( + "TEST FAILED: export on already-bound port succeeded"); + } + if (!(registryExportFailure instanceof ExportException)) { + throw new RuntimeException( + "TEST FAILED: unexpected exception occurred", registryExportFailure); } + System.err.println("TEST PASSED, received expected exception: " + registryExportFailure); } } } diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION index 750d9fae2b1..2f72d7dbcb2 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION +++ b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION @@ -1 +1 @@ -tzdata2025b +tzdata2026a diff --git a/test/jdk/javax/net/ssl/ALPN/MyX509ExtendedKeyManager.java b/test/jdk/javax/net/ssl/ALPN/MyX509ExtendedKeyManager.java deleted file mode 100644 index ecd7dcfc4eb..00000000000 --- a/test/jdk/javax/net/ssl/ALPN/MyX509ExtendedKeyManager.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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.net.Socket; -import java.security.Principal; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.X509ExtendedKeyManager; - -public class MyX509ExtendedKeyManager extends X509ExtendedKeyManager { - - static final String ERROR = "ERROR"; - X509ExtendedKeyManager akm; - String expectedAP; - boolean doCheck = true; - - MyX509ExtendedKeyManager(X509ExtendedKeyManager akm) { - this.akm = akm; - } - - public MyX509ExtendedKeyManager( - X509ExtendedKeyManager akm, String expectedAP, boolean doCheck) { - this.akm = akm; - this.expectedAP = expectedAP; - this.doCheck = doCheck; - - } - - @Override - public String[] getClientAliases(String keyType, Principal[] issuers) { - return akm.getClientAliases(keyType, issuers); - } - - @Override - public String chooseClientAlias(String[] keyType, Principal[] issuers, - Socket socket) { - String nap = ((SSLSocket) socket).getHandshakeApplicationProtocol(); - checkALPN(nap); - - return akm.chooseClientAlias(keyType, issuers, socket); - } - - @Override - public String[] getServerAliases(String keyType, Principal[] issuers) { - return akm.getServerAliases(keyType, issuers); - } - - @Override - public String chooseServerAlias(String keyType, Principal[] issuers, - Socket socket) { - String nap = ((SSLSocket) socket).getHandshakeApplicationProtocol(); - checkALPN(nap); - - return akm.chooseServerAlias(keyType, issuers, socket); - } - - @Override - public X509Certificate[] getCertificateChain(String alias) { - return akm.getCertificateChain(alias); - } - - @Override - public PrivateKey getPrivateKey(String alias) { - return akm.getPrivateKey(alias); - } - - @Override - public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, - SSLEngine engine) { - String nap = engine.getHandshakeApplicationProtocol(); - checkALPN(nap); - - return akm.chooseEngineClientAlias(keyType, issuers, engine); - } - - @Override - public String chooseEngineServerAlias(String keyType, Principal[] issuers, - SSLEngine engine) { - String nap = engine.getHandshakeApplicationProtocol(); - checkALPN(nap); - - return akm.chooseEngineServerAlias(keyType, issuers, engine); - } - - private void checkALPN(String ap) { - - if (!doCheck) { - System.out.println("Skipping KeyManager checks " + - "because a callback has been registered"); - return; - } - - if (ERROR.equals(expectedAP)) { - throw new RuntimeException("Should not reach here"); - } - - System.out.println("Expected ALPN value: " + expectedAP - + " Got: " + ap); - - if (ap == null) { - throw new RuntimeException( - "ALPN should be negotiated, but null was received"); - } - if (expectedAP.equals("NONE")) { - if (!ap.isEmpty()) { - throw new RuntimeException("Expected no ALPN value"); - } else { - System.out.println("No ALPN value negotiated, as expected"); - } - } else if (!expectedAP.equals(ap)) { - throw new RuntimeException(expectedAP - + " ALPN value not available on negotiated connection"); - } - - } -} diff --git a/test/jdk/javax/net/ssl/ALPN/SSLEngineAlpnTest.java b/test/jdk/javax/net/ssl/ALPN/SSLEngineAlpnTest.java index adeb1a7dfc4..275615c2127 100644 --- a/test/jdk/javax/net/ssl/ALPN/SSLEngineAlpnTest.java +++ b/test/jdk/javax/net/ssl/ALPN/SSLEngineAlpnTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ * @test * @bug 8051498 8145849 8170282 * @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension - * @compile MyX509ExtendedKeyManager.java + * @library /javax/net/ssl/templates /test/lib + * @build jdk.test.lib.Utils * * @run main/othervm SSLEngineAlpnTest h2 UNUSED h2 h2 * @run main/othervm SSLEngineAlpnTest h2 UNUSED h2,http/1.1 h2 @@ -125,12 +126,9 @@ */ import javax.net.ssl.*; import javax.net.ssl.SSLEngineResult.*; -import java.io.*; -import java.security.*; -import java.nio.*; import java.util.Arrays; -public class SSLEngineAlpnTest { +public class SSLEngineAlpnTest extends SSLEngineTemplate { /* * Enables logging of the SSLEngine operations. @@ -148,41 +146,8 @@ public class SSLEngineAlpnTest { */ private static final boolean debug = false; - private static boolean hasServerAPs; // whether server APs are present private static boolean hasCallback; // whether a callback is present - private final SSLContext sslc; - - private SSLEngine clientEngine; // client Engine - private ByteBuffer clientOut; // write side of clientEngine - private ByteBuffer clientIn; // read side of clientEngine - - private SSLEngine serverEngine; // server Engine - private ByteBuffer serverOut; // write side of serverEngine - private ByteBuffer serverIn; // read side of serverEngine - - /* - * For data transport, this example uses local ByteBuffers. This - * isn't really useful, but the purpose of this example is to show - * SSLEngine concepts, not how to do network transport. - */ - private ByteBuffer cTOs; // "reliable" transport client->server - private ByteBuffer sTOc; // "reliable" transport server->client - - /* - * The following is to set up the keystores. - */ - private static final String pathToStores = "../etc"; - private static final String keyStoreFile = "keystore"; - private static final String trustStoreFile = "truststore"; - private static final String passwd = "passphrase"; - - private static final String keyFilename - = System.getProperty("test.src", ".") + "/" + pathToStores - + "/" + keyStoreFile; - private static final String trustFilename - = System.getProperty("test.src", ".") + "/" + pathToStores - + "/" + trustStoreFile; /* * Main entry point for this test. @@ -199,10 +164,9 @@ public static void main(String args[]) throws Exception { throw new Exception("Invalid number of test parameters"); } - hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used? hasCallback = !args[1].equals("UNUSED"); // is callback being used? - SSLEngineAlpnTest test = new SSLEngineAlpnTest(args[3]); + SSLEngineAlpnTest test = new SSLEngineAlpnTest(); try { test.runTest(convert(args[0]), args[1], convert(args[2]), args[3]); } catch (SSLHandshakeException she) { @@ -216,39 +180,8 @@ public static void main(String args[]) throws Exception { System.out.println("Test Passed."); } - /* - * Create an initialized SSLContext to use for these tests. - */ - public SSLEngineAlpnTest(String expectedAP) throws Exception { - - KeyStore ks = KeyStore.getInstance("JKS"); - KeyStore ts = KeyStore.getInstance("JKS"); - - char[] passphrase = "passphrase".toCharArray(); - - ks.load(new FileInputStream(keyFilename), passphrase); - ts.load(new FileInputStream(trustFilename), passphrase); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - KeyManager [] kms = kmf.getKeyManagers(); - if (!(kms[0] instanceof X509ExtendedKeyManager)) { - throw new Exception("kms[0] not X509ExtendedKeyManager"); - } - - kms = new KeyManager[] { new MyX509ExtendedKeyManager( - (X509ExtendedKeyManager) kms[0], expectedAP, - !hasCallback && hasServerAPs) }; - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(ts); - - SSLContext sslCtx = SSLContext.getInstance("TLS"); - - sslCtx.init(kms, tmf.getTrustManagers(), null); - - sslc = sslCtx; + public SSLEngineAlpnTest() throws Exception { + super(); } /* @@ -295,8 +228,7 @@ private void runTest(String[] serverAPs, String callbackAP, boolean dataDone = false; - createSSLEngines(serverAPs, callbackAP, clientAPs); - createBuffers(); + configureSSLEngines(serverAPs, callbackAP, clientAPs); SSLEngineResult clientResult; // results from client's last operation SSLEngineResult serverResult; // results from server's last operation @@ -316,12 +248,12 @@ private void runTest(String[] serverAPs, String callbackAP, clientResult = clientEngine.wrap(clientOut, cTOs); log("client wrap: ", clientResult); - runDelegatedTasks(clientResult, clientEngine); + runDelegatedTasks(clientEngine); checkAPResult(clientEngine, clientResult, expectedAP); serverResult = serverEngine.wrap(serverOut, sTOc); log("server wrap: ", serverResult); - runDelegatedTasks(serverResult, serverEngine); + runDelegatedTasks(serverEngine); checkAPResult(serverEngine, serverResult, expectedAP); cTOs.flip(); @@ -331,12 +263,12 @@ private void runTest(String[] serverAPs, String callbackAP, clientResult = clientEngine.unwrap(sTOc, clientIn); log("client unwrap: ", clientResult); - runDelegatedTasks(clientResult, clientEngine); + runDelegatedTasks(clientEngine); checkAPResult(clientEngine, clientResult, expectedAP); serverResult = serverEngine.unwrap(cTOs, serverIn); log("server unwrap: ", serverResult); - runDelegatedTasks(serverResult, serverEngine); + runDelegatedTasks(serverEngine); checkAPResult(serverEngine, serverResult, expectedAP); cTOs.compact(); @@ -408,13 +340,12 @@ private static void checkAPResult(SSLEngine engine, SSLEngineResult result, * Using the SSLContext created during object creation, * create/configure the SSLEngines we'll use for this test. */ - private void createSSLEngines(String[] serverAPs, String callbackAP, + private void configureSSLEngines(String[] serverAPs, String callbackAP, String[] clientAPs) throws Exception { /* * Configure the serverEngine to act as a server in the SSL/TLS * handshake. Also, require SSL client authentication. */ - serverEngine = sslc.createSSLEngine(); serverEngine.setUseClientMode(false); SSLParameters sslp = serverEngine.getSSLParameters(); @@ -459,7 +390,6 @@ private void createSSLEngines(String[] serverAPs, String callbackAP, /* * Similar to above, but using client mode instead. */ - clientEngine = sslc.createSSLEngine("client", 80); clientEngine.setUseClientMode(true); sslp = clientEngine.getSSLParameters(); if (clientAPs != null) { @@ -474,83 +404,10 @@ private void createSSLEngines(String[] serverAPs, String callbackAP, } } - /* - * Create and size the buffers appropriately. - */ - private void createBuffers() { - - /* - * We'll assume the buffer sizes are the same - * between client and server. - */ - SSLSession session = clientEngine.getSession(); - int appBufferMax = session.getApplicationBufferSize(); - int netBufferMax = session.getPacketBufferSize(); - - /* - * We'll make the input buffers a bit bigger than the max needed - * size, so that unwrap()s following a successful data transfer - * won't generate BUFFER_OVERFLOWS. - * - * We'll use a mix of direct and indirect ByteBuffers for - * tutorial purposes only. In reality, only use direct - * ByteBuffers when they give a clear performance enhancement. - */ - clientIn = ByteBuffer.allocate(appBufferMax + 50); - serverIn = ByteBuffer.allocate(appBufferMax + 50); - - cTOs = ByteBuffer.allocateDirect(netBufferMax); - sTOc = ByteBuffer.allocateDirect(netBufferMax); - - clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes()); - serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes()); - } - - /* - * If the result indicates that we have outstanding tasks to do, - * go ahead and run them in this thread. - */ - private static void runDelegatedTasks(SSLEngineResult result, - SSLEngine engine) throws Exception { - - if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { - Runnable runnable; - while ((runnable = engine.getDelegatedTask()) != null) { - log("\trunning delegated task..."); - runnable.run(); - } - HandshakeStatus hsStatus = engine.getHandshakeStatus(); - if (hsStatus == HandshakeStatus.NEED_TASK) { - throw new Exception( - "handshake shouldn't need additional tasks"); - } - log("\tnew HandshakeStatus: " + hsStatus); - } - } - private static boolean isEngineClosed(SSLEngine engine) { return (engine.isOutboundDone() && engine.isInboundDone()); } - /* - * Simple check to make sure everything came across as expected. - */ - private static void checkTransfer(ByteBuffer a, ByteBuffer b) - throws Exception { - a.flip(); - b.flip(); - - if (!a.equals(b)) { - throw new Exception("Data didn't transfer cleanly"); - } else { - log("\tData transferred cleanly"); - } - - a.position(a.limit()); - b.position(b.limit()); - a.limit(a.capacity()); - b.limit(b.capacity()); - } /* * Logging code diff --git a/test/jdk/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java b/test/jdk/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java index a9373ed09f9..2d563284ca8 100644 --- a/test/jdk/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java +++ b/test/jdk/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ * @test * @bug 8051498 8145849 8158978 8170282 * @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension - * @compile MyX509ExtendedKeyManager.java + * @library /javax/net/ssl/templates * * @run main/othervm SSLServerSocketAlpnTest h2 UNUSED h2 h2 * @run main/othervm SSLServerSocketAlpnTest h2 UNUSED h2,http/1.1 h2 @@ -79,56 +79,18 @@ * This example is based on our standard SSLSocketTemplate. */ import java.io.*; -import java.security.KeyStore; import java.util.Arrays; import javax.net.ssl.*; -public class SSLServerSocketAlpnTest { +public class SSLServerSocketAlpnTest extends SSLSocketTemplate { - /* - * ============================================================= - * Set the various variables needed for the tests, then - * specify what tests to run on each side. - */ - - /* - * Should we run the client or server in a separate thread? - * Both sides can throw exceptions, but do you have a preference - * as to which side should be the main thread. - */ - static boolean separateServerThread = false; - - /* - * Where do we find the keystores? - */ - static String pathToStores = "../etc"; - static String keyStoreFile = "keystore"; - static String trustStoreFile = "truststore"; - static String passwd = "passphrase"; - - static String keyFilename = System.getProperty("test.src", ".") + "/" - + pathToStores + "/" + keyStoreFile; - static String trustFilename = System.getProperty("test.src", ".") + "/" - + pathToStores + "/" + trustStoreFile; - - private static boolean hasServerAPs; // whether server APs are present private static boolean hasCallback; // whether a callback is present - /* - * SSLContext - */ - SSLContext mySSLContext = null; - - /* - * Is the server ready to serve? - */ - volatile static boolean serverReady = false; - /* * Turn on SSL debugging? */ - static boolean debug = false; + static boolean debug = Boolean.getBoolean("test.debug"); static String[] serverAPs; static String callbackAP; @@ -144,16 +106,8 @@ public class SSLServerSocketAlpnTest { * smart about it.... */ - /* - * Define the server side of the test. - * - * If the server prematurely exits, serverReady will be set to true - * to avoid infinite hangs. - */ - void doServerSide() throws Exception { - SSLServerSocketFactory sslssf = mySSLContext.getServerSocketFactory(); - SSLServerSocket sslServerSocket - = (SSLServerSocket) sslssf.createServerSocket(serverPort); + @Override + protected void configureServerSocket(SSLServerSocket sslServerSocket) { sslServerSocket.setNeedClientAuth(true); SSLParameters sslp = sslServerSocket.getSSLParameters(); @@ -178,13 +132,16 @@ void doServerSide() throws Exception { sslServerSocket.setSSLParameters(sslp); serverPort = sslServerSocket.getLocalPort(); + } - /* - * Signal Client, we're ready for his connect. - */ - serverReady = true; - - SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); + /* + * Define the server side of the test. + * + * If the server prematurely exits, serverReady will be set to true + * to avoid infinite hangs. + */ + @Override + protected void runServerApplication(SSLSocket sslSocket) throws Exception { if (sslSocket.getHandshakeApplicationProtocol() != null) { throw new Exception ("getHandshakeApplicationProtocol() should " @@ -245,26 +202,9 @@ void doServerSide() throws Exception { sslSocket.close(); } - /* - * Define the client side of the test. - * - * If the server prematurely exits, serverReady will be set to true - * to avoid infinite hangs. - */ - void doClientSide() throws Exception { - - /* - * Wait for server to get started. - */ - while (!serverReady) { - Thread.sleep(50); - } - - SSLSocketFactory sslsf = mySSLContext.getSocketFactory(); - SSLSocket sslSocket - = (SSLSocket) sslsf.createSocket("localhost", serverPort); - - SSLParameters sslp = sslSocket.getSSLParameters(); + @Override + protected void configureClientSocket(SSLSocket socket) { + SSLParameters sslp = socket.getSSLParameters(); /* * The default ciphersuite ordering from the SSLContext may not @@ -278,7 +218,17 @@ void doClientSide() throws Exception { // Set the ALPN selection. sslp.setApplicationProtocols(clientAPs); - sslSocket.setSSLParameters(sslp); + socket.setSSLParameters(sslp); + } + + /* + * Define the client side of the test. + * + * If the server prematurely exits, serverReady will be set to true + * to avoid infinite hangs. + */ + @Override + protected void runClientApplication(SSLSocket sslSocket) throws Exception { if (sslSocket.getHandshakeApplicationProtocol() != null) { throw new Exception ("getHandshakeApplicationProtocol() should " @@ -332,9 +282,6 @@ void doClientSide() throws Exception { // use any free port by default volatile int serverPort = 0; - volatile Exception serverException = null; - volatile Exception clientException = null; - public static void main(String[] args) throws Exception { if (debug) { @@ -351,14 +298,13 @@ public static void main(String[] args) throws Exception { clientAPs = convert(args[2]); expectedAP = args[3]; - hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used? hasCallback = !callbackAP.equals("UNUSED"); // is callback being used? /* * Start the tests. */ try { - new SSLServerSocketAlpnTest(); + new SSLServerSocketAlpnTest().run(); } catch (SSLHandshakeException she) { if (args[3].equals("ERROR")) { System.out.println("Caught the expected exception: " + she); @@ -370,40 +316,6 @@ public static void main(String[] args) throws Exception { System.out.println("Test Passed."); } - SSLContext getSSLContext(String keyFilename, String trustFilename) - throws Exception { - SSLContext ctx = SSLContext.getInstance("TLS"); - - // Keystores - KeyStore keyKS = KeyStore.getInstance("JKS"); - keyKS.load(new FileInputStream(keyFilename), passwd.toCharArray()); - - KeyStore trustKS = KeyStore.getInstance("JKS"); - trustKS.load(new FileInputStream(trustFilename), passwd.toCharArray()); - - // Generate KeyManager and TrustManager - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(keyKS, passwd.toCharArray()); - - KeyManager[] kms = kmf.getKeyManagers(); - if (!(kms[0] instanceof X509ExtendedKeyManager)) { - throw new Exception("kms[0] not X509ExtendedKeyManager"); - } - - kms = new KeyManager[] { new MyX509ExtendedKeyManager( - (X509ExtendedKeyManager) kms[0], expectedAP, - !hasCallback && hasServerAPs) }; - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(trustKS); - TrustManager[] tms = tmf.getTrustManagers(); - - // initial SSLContext - ctx.init(kms, tms, null); - - return ctx; - } - /* * Convert a comma-separated list into an array of strings. */ @@ -425,143 +337,4 @@ private static String[] convert(String list) { return strings; } - - Thread clientThread = null; - Thread serverThread = null; - - /* - * Primary constructor, used to drive remainder of the test. - * - * Fork off the other side, then do your work. - */ - SSLServerSocketAlpnTest() throws Exception { - Exception startException = null; - mySSLContext = getSSLContext(keyFilename, trustFilename); - try { - if (separateServerThread) { - startServer(true); - startClient(false); - } else { - startClient(true); - startServer(false); - } - } catch (Exception e) { - startException = e; - } - - /* - * Wait for other side to close down. - */ - if (separateServerThread) { - if (serverThread != null) { - serverThread.join(); - } - } else { - if (clientThread != null) { - clientThread.join(); - } - } - - /* - * When we get here, the test is pretty much over. - * Which side threw the error? - */ - Exception local; - Exception remote; - - if (separateServerThread) { - remote = serverException; - local = clientException; - } else { - remote = clientException; - local = serverException; - } - - Exception exception = null; - - /* - * Check various exception conditions. - */ - if ((local != null) && (remote != null)) { - // If both failed, return the curthread's exception. - local.initCause(remote); - exception = local; - } else if (local != null) { - exception = local; - } else if (remote != null) { - exception = remote; - } else if (startException != null) { - exception = startException; - } - - /* - * If there was an exception *AND* a startException, - * output it. - */ - if (exception != null) { - if (exception != startException && startException != null) { - exception.addSuppressed(startException); - } - throw exception; - } - - // Fall-through: no exception to throw! - } - - void startServer(boolean newThread) throws Exception { - if (newThread) { - serverThread = new Thread() { - @Override - public void run() { - try { - doServerSide(); - } catch (Exception e) { - /* - * Our server thread just died. - * - * Release the client, if not active already... - */ - System.err.println("Server died..."); - serverReady = true; - serverException = e; - } - } - }; - serverThread.start(); - } else { - try { - doServerSide(); - } catch (Exception e) { - serverException = e; - } finally { - serverReady = true; - } - } - } - - void startClient(boolean newThread) throws Exception { - if (newThread) { - clientThread = new Thread() { - @Override - public void run() { - try { - doClientSide(); - } catch (Exception e) { - /* - * Our client thread just died. - */ - System.err.println("Client died..."); - clientException = e; - } - } - }; - clientThread.start(); - } else { - try { - doClientSide(); - } catch (Exception e) { - clientException = e; - } - } - } } diff --git a/test/jdk/javax/net/ssl/ALPN/SSLSocketAlpnTest.java b/test/jdk/javax/net/ssl/ALPN/SSLSocketAlpnTest.java index ef72474f417..51625f9c14f 100644 --- a/test/jdk/javax/net/ssl/ALPN/SSLSocketAlpnTest.java +++ b/test/jdk/javax/net/ssl/ALPN/SSLSocketAlpnTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ * @test * @bug 8051498 8145849 8170282 * @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension - * @compile MyX509ExtendedKeyManager.java + * @library /javax/net/ssl/templates * * @run main/othervm SSLSocketAlpnTest h2 UNUSED h2 h2 * @run main/othervm SSLSocketAlpnTest h2 UNUSED h2,http/1.1 h2 @@ -78,56 +78,18 @@ * This example is based on our standard SSLSocketTemplate. */ import java.io.*; -import java.security.KeyStore; import java.util.Arrays; import javax.net.ssl.*; -public class SSLSocketAlpnTest { +public class SSLSocketAlpnTest extends SSLSocketTemplate { - /* - * ============================================================= - * Set the various variables needed for the tests, then - * specify what tests to run on each side. - */ - - /* - * Should we run the client or server in a separate thread? - * Both sides can throw exceptions, but do you have a preference - * as to which side should be the main thread. - */ - static boolean separateServerThread = false; - - /* - * Where do we find the keystores? - */ - static String pathToStores = "../etc"; - static String keyStoreFile = "keystore"; - static String trustStoreFile = "truststore"; - static String passwd = "passphrase"; - - static String keyFilename = System.getProperty("test.src", ".") + "/" - + pathToStores + "/" + keyStoreFile; - static String trustFilename = System.getProperty("test.src", ".") + "/" - + pathToStores + "/" + trustStoreFile; - - private static boolean hasServerAPs; // whether server APs are present private static boolean hasCallback; // whether a callback is present - /* - * SSLContext - */ - SSLContext mySSLContext = null; - - /* - * Is the server ready to serve? - */ - volatile static boolean serverReady = false; - /* * Turn on SSL debugging? */ - static boolean debug = false; + static boolean debug = Boolean.getBoolean("test.debug"); static String[] serverAPs; static String callbackAP; @@ -143,28 +105,20 @@ public class SSLSocketAlpnTest { * smart about it.... */ + @Override + protected void configureServerSocket(SSLServerSocket socket) { + socket.setNeedClientAuth(true); + } + /* * Define the server side of the test. * * If the server prematurely exits, serverReady will be set to true * to avoid infinite hangs. */ - void doServerSide() throws Exception { - SSLServerSocketFactory sslssf = mySSLContext.getServerSocketFactory(); - SSLServerSocket sslServerSocket - = (SSLServerSocket) sslssf.createServerSocket(serverPort); - // for both client/server to call into X509KM - sslServerSocket.setNeedClientAuth(true); - - serverPort = sslServerSocket.getLocalPort(); - - /* - * Signal Client, we're ready for his connect. - */ - serverReady = true; - - SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); - + @Override + protected void runServerApplication(SSLSocket sslSocket) throws Exception { + System.out.println("in runServerApplication(SSLSocket)"); SSLParameters sslp = sslSocket.getSSLParameters(); /* @@ -206,6 +160,7 @@ void doServerSide() throws Exception { } } + System.out.println("server starting handshake"); sslSocket.startHandshake(); if (sslSocket.getHandshakeApplicationProtocol() != null) { @@ -247,18 +202,9 @@ void doServerSide() throws Exception { * If the server prematurely exits, serverReady will be set to true * to avoid infinite hangs. */ - void doClientSide() throws Exception { - - /* - * Wait for server to get started. - */ - while (!serverReady) { - Thread.sleep(50); - } - - SSLSocketFactory sslsf = mySSLContext.getSocketFactory(); - SSLSocket sslSocket - = (SSLSocket) sslsf.createSocket("localhost", serverPort); + @Override + protected void runClientApplication(SSLSocket sslSocket) throws Exception { + System.out.println("in runClientApplication(SSLSocket)"); SSLParameters sslp = sslSocket.getSSLParameters(); @@ -281,6 +227,7 @@ void doClientSide() throws Exception { + "return null before the handshake starts"); } + System.out.println("Client starting handshake"); sslSocket.startHandshake(); if (sslSocket.getHandshakeApplicationProtocol() != null) { @@ -321,16 +268,6 @@ void doClientSide() throws Exception { sslSocket.close(); } - /* - * ============================================================= - * The remainder is just support stuff - */ - // use any free port by default - volatile int serverPort = 0; - - volatile Exception serverException = null; - volatile Exception clientException = null; - public static void main(String[] args) throws Exception { if (debug) { @@ -347,14 +284,13 @@ public static void main(String[] args) throws Exception { clientAPs = convert(args[2]); expectedAP = args[3]; - hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used? hasCallback = !callbackAP.equals("UNUSED"); // is callback being used? /* * Start the tests. */ try { - new SSLSocketAlpnTest(); + new SSLSocketAlpnTest().run(); } catch (SSLHandshakeException she) { if (args[3].equals("ERROR")) { System.out.println("Caught the expected exception: " + she); @@ -366,40 +302,6 @@ public static void main(String[] args) throws Exception { System.out.println("Test Passed."); } - SSLContext getSSLContext(String keyFilename, String trustFilename) - throws Exception { - SSLContext ctx = SSLContext.getInstance("TLS"); - - // Keystores - KeyStore keyKS = KeyStore.getInstance("JKS"); - keyKS.load(new FileInputStream(keyFilename), passwd.toCharArray()); - - KeyStore trustKS = KeyStore.getInstance("JKS"); - trustKS.load(new FileInputStream(trustFilename), passwd.toCharArray()); - - // Generate KeyManager and TrustManager - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(keyKS, passwd.toCharArray()); - - KeyManager[] kms = kmf.getKeyManagers(); - if (!(kms[0] instanceof X509ExtendedKeyManager)) { - throw new Exception("kms[0] not X509ExtendedKeyManager"); - } - - kms = new KeyManager[] { new MyX509ExtendedKeyManager( - (X509ExtendedKeyManager) kms[0], expectedAP, - !hasCallback && hasServerAPs) }; - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(trustKS); - TrustManager[] tms = tmf.getTrustManagers(); - - // initial SSLContext - ctx.init(kms, tms, null); - - return ctx; - } - /* * Convert a comma-separated list into an array of strings. */ @@ -421,143 +323,4 @@ private static String[] convert(String list) { return strings; } - - Thread clientThread = null; - Thread serverThread = null; - - /* - * Primary constructor, used to drive remainder of the test. - * - * Fork off the other side, then do your work. - */ - SSLSocketAlpnTest() throws Exception { - Exception startException = null; - mySSLContext = getSSLContext(keyFilename, trustFilename); - try { - if (separateServerThread) { - startServer(true); - startClient(false); - } else { - startClient(true); - startServer(false); - } - } catch (Exception e) { - startException = e; - } - - /* - * Wait for other side to close down. - */ - if (separateServerThread) { - if (serverThread != null) { - serverThread.join(); - } - } else { - if (clientThread != null) { - clientThread.join(); - } - } - - /* - * When we get here, the test is pretty much over. - * Which side threw the error? - */ - Exception local; - Exception remote; - - if (separateServerThread) { - remote = serverException; - local = clientException; - } else { - remote = clientException; - local = serverException; - } - - Exception exception = null; - - /* - * Check various exception conditions. - */ - if ((local != null) && (remote != null)) { - // If both failed, return the curthread's exception. - local.initCause(remote); - exception = local; - } else if (local != null) { - exception = local; - } else if (remote != null) { - exception = remote; - } else if (startException != null) { - exception = startException; - } - - /* - * If there was an exception *AND* a startException, - * output it. - */ - if (exception != null) { - if (exception != startException && startException != null) { - exception.addSuppressed(startException); - } - throw exception; - } - - // Fall-through: no exception to throw! - } - - void startServer(boolean newThread) throws Exception { - if (newThread) { - serverThread = new Thread() { - @Override - public void run() { - try { - doServerSide(); - } catch (Exception e) { - /* - * Our server thread just died. - * - * Release the client, if not active already... - */ - System.err.println("Server died..."); - serverReady = true; - serverException = e; - } - } - }; - serverThread.start(); - } else { - try { - doServerSide(); - } catch (Exception e) { - serverException = e; - } finally { - serverReady = true; - } - } - } - - void startClient(boolean newThread) throws Exception { - if (newThread) { - clientThread = new Thread() { - @Override - public void run() { - try { - doClientSide(); - } catch (Exception e) { - /* - * Our client thread just died. - */ - System.err.println("Client died..."); - clientException = e; - } - } - }; - clientThread.start(); - } else { - try { - doClientSide(); - } catch (Exception e) { - clientException = e; - } - } - } } diff --git a/test/jdk/javax/net/ssl/SSLEngine/HandshakeWithInvalidRecordVersion.java b/test/jdk/javax/net/ssl/SSLEngine/HandshakeWithInvalidRecordVersion.java index 71119489b85..295ad66646c 100644 --- a/test/jdk/javax/net/ssl/SSLEngine/HandshakeWithInvalidRecordVersion.java +++ b/test/jdk/javax/net/ssl/SSLEngine/HandshakeWithInvalidRecordVersion.java @@ -37,19 +37,9 @@ import java.nio.*; import java.util.Arrays; -public class HandshakeWithInvalidRecordVersion implements SSLContextTemplate { +public class HandshakeWithInvalidRecordVersion extends SSLContextTemplate { private static final boolean DEBUG = Boolean.getBoolean("test.debug"); - private static final String PATH_TO_STORES = "../etc"; - private static final String KEYSTORE_FILE = "keystore"; - private static final String TRUSTSTORE_FILE = "truststore"; - - private static final String KEYSTORE_PATH = - System.getProperty("test.src", "./") + "/" + PATH_TO_STORES + - "/" + KEYSTORE_FILE; - private static final String TRUSTSTORE_PATH = - System.getProperty("test.src", "./") + "/" + PATH_TO_STORES + - "/" + TRUSTSTORE_FILE; public static void main(String [] args) throws Exception { var runner = new HandshakeWithInvalidRecordVersion(); diff --git a/test/jdk/javax/net/ssl/TLSCommon/interop/AbstractPeer.java b/test/jdk/javax/net/ssl/TLSCommon/interop/AbstractPeer.java index 1bfc3ebcdbb..9950caf1921 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/interop/AbstractPeer.java +++ b/test/jdk/javax/net/ssl/TLSCommon/interop/AbstractPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,13 +49,6 @@ protected void printLog() throws IOException { System.out.println(Utilities.readFile(logPath).orElse("")); } - /* - * Deletes log file if exists. - */ - protected void deleteLog() throws IOException { - Utilities.deleteFile(getLogPath()); - } - /* * The negotiated application protocol. */ diff --git a/test/jdk/javax/net/ssl/TLSCommon/interop/JdkProcClient.java b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkProcClient.java index 91d1a8d1ead..7d3cb7d1665 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/interop/JdkProcClient.java +++ b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkProcClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,7 +148,6 @@ protected Path getLogPath() { @Override public void close() throws IOException { printLog(); - deleteLog(); } public static void main(String[] args) throws Exception { diff --git a/test/jdk/javax/net/ssl/TLSCommon/interop/JdkProcServer.java b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkProcServer.java index b07a039203e..a6c8a13e0c6 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/interop/JdkProcServer.java +++ b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkProcServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -166,7 +166,6 @@ public void signalStop() { public void close() throws IOException { printLog(); deletePort(); - deleteLog(); } private static int readPort() { diff --git a/test/jdk/javax/net/ssl/TLSv12/DisabledShortDSAKeys.java b/test/jdk/javax/net/ssl/TLSv12/DisabledShortDSAKeys.java index fa201aa8374..39937f8b743 100644 --- a/test/jdk/javax/net/ssl/TLSv12/DisabledShortDSAKeys.java +++ b/test/jdk/javax/net/ssl/TLSv12/DisabledShortDSAKeys.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ * @test * @bug 8139565 * @summary Restrict certificates with DSA keys less than 1024 bits - * + * @library /javax/net/ssl/templates * @run main/othervm DisabledShortDSAKeys PKIX TLSv1.2 * @run main/othervm DisabledShortDSAKeys SunX509 TLSv1.2 * @run main/othervm DisabledShortDSAKeys PKIX TLSv1.1 @@ -55,73 +55,15 @@ import java.util.Base64; -public class DisabledShortDSAKeys { +public class DisabledShortDSAKeys extends SSLContextTemplate { - /* - * ============================================================= - * Set the various variables needed for the tests, then - * specify what tests to run on each side. - */ - - /* + /* * Should we run the client or server in a separate thread? * Both sides can throw exceptions, but do you have a preference * as to which side should be the main thread. */ static boolean separateServerThread = true; - /* - * Where do we find the keystores? - */ - // Certificates and key used in the test. - static String trustedCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIIDDjCCAs2gAwIBAgIJAO5/hbm1ByJOMAkGByqGSM44BAMwHzELMAkGA1UEBhMC\n" + - "VVMxEDAOBgNVBAoTB0V4YW1wbGUwHhcNMTYwMjE2MDQzNTQ2WhcNMzcwMTI2MDQz\n" + - "NTQ2WjAfMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXhhbXBsZTCCAbgwggEsBgcq\n" + - "hkjOOAQBMIIBHwKBgQC4aSK8nBYdWJtuBkz6yoDyjZnNuGFSpDmx1ggKpLpcnPuw\n" + - "YKAbUhqdYhZtaIqQ4aO0T1ZS/HuOM0zvddnMUidFNX3RUvDkvdD/JYOnjqzCm+xW\n" + - "U0NFuPHZdapQY5KFk3ugkqZpHLY1StZbu0qugZOZjbBOMwB7cHAbMDuVpEr8DQIV\n" + - "AOi+ig+h3okFbWEE9MztiI2+DqNrAoGBAKh2EZbuWU9NoHglhVzfDUoz8CeyW6W6\n" + - "rUZuIOQsjWaYOeRPWX0UVAGq9ykIOfamEpurKt4H8ge/pHaL9iazJjonMHOXG12A\n" + - "0lALsMDGv22zVaJzXjOBvdPzc87opr0LIVgHASKOcDYjsICKNYPlS2cL3MJoD+bj\n" + - "NAR67b90VBbEA4GFAAKBgQCGrkRp2tdj2mZF7Qz0tO6p3xSysbEfN6QZxOJYPTvM\n" + - "yIYfLV9Yoy7XaRd/mCpJo/dqmsZMzowtyi+u+enuVpOLKiq/lyCktL+xUzZAjLT+\n" + - "9dafHlS1wR3pDSa1spo9xTEi4Ff/DQDHcdGalBxSXX/UdRtSecIYAp5/fkt3QZ5v\n" + - "0aOBkTCBjjAdBgNVHQ4EFgQUX4qbP5PgBx1J8BJ8qEgfoKVLSnQwTwYDVR0jBEgw\n" + - "RoAUX4qbP5PgBx1J8BJ8qEgfoKVLSnShI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" + - "VQQKEwdFeGFtcGxlggkA7n+FubUHIk4wDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8E\n" + - "BAMCAgQwCQYHKoZIzjgEAwMwADAtAhUAkr5bINXyy/McAx6qwhb6r0/QJUgCFFUP\n" + - "CZokA4/NqJIgq8ThpTQAE8SB\n" + - "-----END CERTIFICATE-----"; - - static String targetCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICUjCCAhGgAwIBAgIJAIiDrs/4W8rtMAkGByqGSM44BAMwHzELMAkGA1UEBhMC\n" + - "VVMxEDAOBgNVBAoTB0V4YW1wbGUwHhcNMTYwMjE2MDQzNTQ2WhcNMzUxMTAzMDQz\n" + - "NTQ2WjA5MQswCQYDVQQGEwJVUzEQMA4GA1UECgwHRXhhbXBsZTEYMBYGA1UEAwwP\n" + - "d3d3LmV4YW1wbGUuY29tMIHwMIGoBgcqhkjOOAQBMIGcAkEAs6A0p3TysTtVXGSv\n" + - "ThR/8GHpbL49KyWRJBMIlmLc5jl/wxJgnL1t07p4YTOEa6ecyTFos04Z8n2GARmp\n" + - "zYlUywIVAJLDcf4JXhZbguRFSQdWwWhZkh+LAkBLCzh3Xvpmc/5CDqU+QHqDcuSk\n" + - "5B8+ZHaHRi2KQ00ejilpF2qZpW5JdHe4m3Pggh0MIuaAGX+leM4JKlnObj14A0MA\n" + - "AkAYb+DYlFgStFhF1ip7rFzY8K6i/3ellkXI2umI/XVwxUQTHSlk5nFOep5Dfzm9\n" + - "pADJwuSe1qGHsHB5LpMZPVpto4GEMIGBMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgPo\n" + - "MB0GA1UdDgQWBBT8nsFyccF4q1dtpWE1dkNK5UiXtTAfBgNVHSMEGDAWgBRfips/\n" + - "k+AHHUnwEnyoSB+gpUtKdDAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" + - "CCsGAQUFBwMDMAkGByqGSM44BAMDMAAwLQIUIcIlxpIwaZXdpMC+U076unR1Mp8C\n" + - "FQCD/NE8O0xwq57nwFfp7tUvUHYMMA==\n" + - "-----END CERTIFICATE-----"; - - // Private key in the format of PKCS#8, key size is 512 bits. - static String targetPrivateKey = - "MIHGAgEAMIGoBgcqhkjOOAQBMIGcAkEAs6A0p3TysTtVXGSvThR/8GHpbL49KyWR\n" + - "JBMIlmLc5jl/wxJgnL1t07p4YTOEa6ecyTFos04Z8n2GARmpzYlUywIVAJLDcf4J\n" + - "XhZbguRFSQdWwWhZkh+LAkBLCzh3Xvpmc/5CDqU+QHqDcuSk5B8+ZHaHRi2KQ00e\n" + - "jilpF2qZpW5JdHe4m3Pggh0MIuaAGX+leM4JKlnObj14BBYCFHB2Wek2g5hpNj5y\n" + - "RQfCc6CFO0dv"; - - static char passphrase[] = "passphrase".toCharArray(); - /* * Is the server ready to serve? */ @@ -139,8 +81,8 @@ public class DisabledShortDSAKeys { * to avoid infinite hangs. */ void doServerSide() throws Exception { - SSLContext context = generateSSLContext(null, targetCertStr, - targetPrivateKey); + SSLContext context = createSSLContext(null, + new Cert[]{Cert.CA_DSA_512}, getServerContextParameters()); SSLServerSocketFactory sslssf = context.getServerSocketFactory(); SSLServerSocket sslServerSocket = (SSLServerSocket)sslssf.createServerSocket(serverPort); @@ -178,7 +120,8 @@ void doClientSide() throws Exception { Thread.sleep(50); } - SSLContext context = generateSSLContext(trustedCertStr, null, null); + SSLContext context = createSSLContext(new Cert[]{Cert.CA_DSA_1024}, + null, getClientContextParameters()); SSLSocketFactory sslsf = context.getSocketFactory(); try (SSLSocket sslSocket = @@ -215,72 +158,15 @@ private static void parseArguments(String[] args) { enabledProtocol = args[1]; } - private static SSLContext generateSSLContext(String trustedCertStr, - String keyCertStr, String keySpecStr) throws Exception { - - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - // create a key store - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(null, null); - - // import the trused cert - Certificate trusedCert = null; - ByteArrayInputStream is = null; - if (trustedCertStr != null) { - is = new ByteArrayInputStream(trustedCertStr.getBytes()); - trusedCert = cf.generateCertificate(is); - is.close(); - - ks.setCertificateEntry("DSA Export Signer", trusedCert); - } - - if (keyCertStr != null) { - // generate the private key. - PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - Base64.getMimeDecoder().decode(keySpecStr)); - KeyFactory kf = KeyFactory.getInstance("DSA"); - DSAPrivateKey priKey = - (DSAPrivateKey)kf.generatePrivate(priKeySpec); - - // generate certificate chain - is = new ByteArrayInputStream(keyCertStr.getBytes()); - Certificate keyCert = cf.generateCertificate(is); - is.close(); - - Certificate[] chain = null; - if (trusedCert != null) { - chain = new Certificate[2]; - chain[0] = keyCert; - chain[1] = trusedCert; - } else { - chain = new Certificate[1]; - chain[0] = keyCert; - } - - // import the key entry. - ks.setKeyEntry("Whatever", priKey, passphrase, chain); - } - - // create SSL context - TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm); - tmf.init(ks); - - SSLContext ctx = SSLContext.getInstance("TLS"); - if (keyCertStr != null && !keyCertStr.isEmpty()) { - KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); - kmf.init(ks, passphrase); - - ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - ks = null; - } else { - ctx.init(null, tmf.getTrustManagers(), null); - } - - return ctx; + @Override + protected ContextParameters getServerContextParameters() { + return new ContextParameters(enabledProtocol, tmAlgorithm, "NewSunX509"); } + @Override + protected ContextParameters getClientContextParameters() { + return new ContextParameters(enabledProtocol, tmAlgorithm, "NewSunX509"); + } // use any free port by default volatile int serverPort = 0; diff --git a/test/jdk/javax/net/ssl/TLSv12/DisabledShortRSAKeys.java b/test/jdk/javax/net/ssl/TLSv12/DisabledShortRSAKeys.java index 63fb1baa231..3f275d8a285 100644 --- a/test/jdk/javax/net/ssl/TLSv12/DisabledShortRSAKeys.java +++ b/test/jdk/javax/net/ssl/TLSv12/DisabledShortRSAKeys.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. * 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,86 +42,35 @@ * @run main/othervm DisabledShortRSAKeys SunX509 SSLv3 */ -import java.net.*; -import java.util.*; import java.io.*; import javax.net.ssl.*; import java.security.Security; -import java.security.KeyStore; -import java.security.KeyFactory; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.security.spec.*; -import java.security.interfaces.*; -import java.util.Base64; - public class DisabledShortRSAKeys extends SSLSocketTemplate { - /* - * Where do we find the keystores? - */ - // Certificates and key used in the test. - static String trustedCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTEwODE5MDE1MjE5WhcNMzIwNzI5MDE1MjE5WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + - "KoZIhvcNAQEBBQADgY0AMIGJAoGBAM8orG08DtF98TMSscjGsidd1ZoN4jiDpi8U\n" + - "ICz+9dMm1qM1d7O2T+KH3/mxyox7Rc2ZVSCaUD0a3CkhPMnlAx8V4u0H+E9sqso6\n" + - "iDW3JpOyzMExvZiRgRG/3nvp55RMIUV4vEHOZ1QbhuqG4ebN0Vz2DkRft7+flthf\n" + - "vDld6f5JAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLl81dnfp0wDrv0OJ1sxlWzH83Xh\n" + - "MGMGA1UdIwRcMFqAFLl81dnfp0wDrv0OJ1sxlWzH83XhoT+kPTA7MQswCQYDVQQG\n" + - "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + - "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" + - "BQADgYEALlgaH1gWtoBZ84EW8Hu6YtGLQ/L9zIFmHonUPZwn3Pr//icR9Sqhc3/l\n" + - "pVTxOINuFHLRz4BBtEylzRIOPzK3tg8XwuLb1zd0db90x3KBCiAL6E6cklGEPwLe\n" + - "XYMHDn9eDsaq861Tzn6ZwzMgw04zotPMoZN0mVd/3Qca8UJFucE=\n" + - "-----END CERTIFICATE-----"; - - static String targetCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICNDCCAZ2gAwIBAgIBDDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTExMTA3MTM1NTUyWhcNMzEwNzI1MTM1NTUyWjBPMQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" + - "BAMTCWxvY2FsaG9zdDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC3Pb49OSPfOD2G\n" + - "HSXFCFx1GJEZfqG9ZUf7xuIi/ra5dLjPGAaoY5QF2QOa8VnOriQCXDfyXHxsuRnE\n" + - "OomxL7EVAgMBAAGjeDB2MAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUXNCJK3/dtCIc\n" + - "xb+zlA/JINlvs/MwHwYDVR0jBBgwFoAUuXzV2d+nTAOu/Q4nWzGVbMfzdeEwJwYD\n" + - "VR0lBCAwHgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAzANBgkqhkiG9w0B\n" + - "AQQFAAOBgQB2qIDUxA2caMPpGtUACZAPRUtrGssCINIfItETXJZCx/cRuZ5sP4D9\n" + - "N1acoNDn0hCULe3lhXAeTC9NZ97680yJzregQMV5wATjo1FGsKY30Ma+sc/nfzQW\n" + - "+h/7RhYtoG0OTsiaDCvyhI6swkNJzSzrAccPY4+ZgU8HiDLzZTmM3Q==\n" + - "-----END CERTIFICATE-----"; - - // Private key in the format of PKCS#8, key size is 512 bits. - static String targetPrivateKey = - "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAtz2+PTkj3zg9hh0l\n" + - "xQhcdRiRGX6hvWVH+8biIv62uXS4zxgGqGOUBdkDmvFZzq4kAlw38lx8bLkZxDqJ\n" + - "sS+xFQIDAQABAkByx/5Oo2hQ/w2q4L8z+NTRlJ3vdl8iIDtC/4XPnfYfnGptnpG6\n" + - "ZThQRvbMZiai0xHQPQMszvAHjZVme1eDl3EBAiEA3aKJHynPVCEJhpfCLWuMwX5J\n" + - "1LntwJO7NTOyU5m8rPECIQDTpzn5X44r2rzWBDna/Sx7HW9IWCxNgUD2Eyi2nA7W\n" + - "ZQIgJerEorw4aCAuzQPxiGu57PB6GRamAihEAtoRTBQlH0ECIQDN08FgTtnesgCU\n" + - "DFYLLcw1CiHvc7fZw4neBDHCrC8NtQIgA8TOUkGnpCZlQ0KaI8KfKWI+vxFcgFnH\n" + - "3fnqsTgaUs4="; - - static char passphrase[] = "passphrase".toCharArray(); - /* * Turn on SSL debugging? */ static boolean debug = false; + private final String enabledProtocol; + private final String tmAlgorithm; + + public DisabledShortRSAKeys(String tmAlgorithm, String enabledProtocol) { + this.tmAlgorithm = tmAlgorithm; + this.enabledProtocol = enabledProtocol; + } + @Override - protected SSLContext createClientSSLContext() throws Exception { - return generateSSLContext(trustedCertStr, null, null); + public SSLContext createClientSSLContext() throws Exception { + return createSSLContext(new Cert[]{Cert.CA_RSA_512}, null, + new ContextParameters(enabledProtocol, tmAlgorithm, "NewSunX509")); } @Override - protected SSLContext createServerSSLContext() throws Exception { - return generateSSLContext(null, targetCertStr, targetPrivateKey); + public SSLContext createServerSSLContext() throws Exception { + return createSSLContext(null, new Cert[]{Cert.EE_RSA_512}, + new ContextParameters(enabledProtocol, tmAlgorithm, "NewSunX509")); } @Override @@ -159,84 +108,6 @@ protected void runClientApplication(SSLSocket socket) throws Exception { } } - /* - * ============================================================= - * The remainder is just support stuff - */ - private static String tmAlgorithm; // trust manager - private static String enabledProtocol; // the target protocol - - private static void parseArguments(String[] args) { - tmAlgorithm = args[0]; - enabledProtocol = args[1]; - } - - private static SSLContext generateSSLContext(String trustedCertStr, - String keyCertStr, String keySpecStr) throws Exception { - - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - // create a key store - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(null, null); - - // import the trused cert - Certificate trusedCert = null; - ByteArrayInputStream is = null; - if (trustedCertStr != null) { - is = new ByteArrayInputStream(trustedCertStr.getBytes()); - trusedCert = cf.generateCertificate(is); - is.close(); - - ks.setCertificateEntry("RSA Export Signer", trusedCert); - } - - if (keyCertStr != null) { - // generate the private key. - PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - Base64.getMimeDecoder().decode(keySpecStr)); - KeyFactory kf = KeyFactory.getInstance("RSA"); - RSAPrivateKey priKey = - (RSAPrivateKey)kf.generatePrivate(priKeySpec); - - // generate certificate chain - is = new ByteArrayInputStream(keyCertStr.getBytes()); - Certificate keyCert = cf.generateCertificate(is); - is.close(); - - Certificate[] chain = null; - if (trusedCert != null) { - chain = new Certificate[2]; - chain[0] = keyCert; - chain[1] = trusedCert; - } else { - chain = new Certificate[1]; - chain[0] = keyCert; - } - - // import the key entry. - ks.setKeyEntry("Whatever", priKey, passphrase, chain); - } - - // create SSL context - TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm); - tmf.init(ks); - - SSLContext ctx = SSLContext.getInstance("TLS"); - if (keyCertStr != null && !keyCertStr.isEmpty()) { - KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); - kmf.init(ks, passphrase); - - ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - ks = null; - } else { - ctx.init(null, tmf.getTrustManagers(), null); - } - - return ctx; - } - public static void main(String[] args) throws Exception { Security.setProperty("jdk.certpath.disabledAlgorithms", "RSA keySize < 1024"); @@ -247,15 +118,12 @@ public static void main(String[] args) throws Exception { System.setProperty("javax.net.debug", "all"); } - /* - * Get the customized arguments. - */ - parseArguments(args); + String tmAlgorithm = args[0]; + String enabledProtocol = args[1]; /* * Start the tests. */ - new DisabledShortRSAKeys().run(); + new DisabledShortRSAKeys(tmAlgorithm, enabledProtocol).run(); } - } diff --git a/test/jdk/javax/net/ssl/TLSv12/ShortRSAKey512.java b/test/jdk/javax/net/ssl/TLSv12/ShortRSAKey512.java index 627536a2417..c9ff202bd2c 100644 --- a/test/jdk/javax/net/ssl/TLSv12/ShortRSAKey512.java +++ b/test/jdk/javax/net/ssl/TLSv12/ShortRSAKey512.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. * 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,25 +33,18 @@ * * SunJSSE does not support dynamic system properties, no way to re-use * system properties in samevm/agentvm mode. + * + * @library /javax/net/ssl/templates * @run main/othervm ShortRSAKey512 PKIX * @run main/othervm ShortRSAKey512 SunX509 */ -import java.net.*; -import java.util.*; import java.io.*; import javax.net.ssl.*; import java.security.Security; -import java.security.KeyStore; -import java.security.KeyFactory; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.security.spec.*; -import java.security.interfaces.*; -import java.util.Base64; -public class ShortRSAKey512 { +public class ShortRSAKey512 extends SSLContextTemplate { /* * ============================================================= @@ -66,57 +59,6 @@ public class ShortRSAKey512 { */ static boolean separateServerThread = false; - /* - * Where do we find the keystores? - */ - // Certificates and key used in the test. - static String trustedCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTEwODE5MDE1MjE5WhcNMzIwNzI5MDE1MjE5WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + - "KoZIhvcNAQEBBQADgY0AMIGJAoGBAM8orG08DtF98TMSscjGsidd1ZoN4jiDpi8U\n" + - "ICz+9dMm1qM1d7O2T+KH3/mxyox7Rc2ZVSCaUD0a3CkhPMnlAx8V4u0H+E9sqso6\n" + - "iDW3JpOyzMExvZiRgRG/3nvp55RMIUV4vEHOZ1QbhuqG4ebN0Vz2DkRft7+flthf\n" + - "vDld6f5JAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLl81dnfp0wDrv0OJ1sxlWzH83Xh\n" + - "MGMGA1UdIwRcMFqAFLl81dnfp0wDrv0OJ1sxlWzH83XhoT+kPTA7MQswCQYDVQQG\n" + - "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + - "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" + - "BQADgYEALlgaH1gWtoBZ84EW8Hu6YtGLQ/L9zIFmHonUPZwn3Pr//icR9Sqhc3/l\n" + - "pVTxOINuFHLRz4BBtEylzRIOPzK3tg8XwuLb1zd0db90x3KBCiAL6E6cklGEPwLe\n" + - "XYMHDn9eDsaq861Tzn6ZwzMgw04zotPMoZN0mVd/3Qca8UJFucE=\n" + - "-----END CERTIFICATE-----"; - - static String targetCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICNDCCAZ2gAwIBAgIBDDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTExMTA3MTM1NTUyWhcNMzEwNzI1MTM1NTUyWjBPMQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" + - "BAMTCWxvY2FsaG9zdDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC3Pb49OSPfOD2G\n" + - "HSXFCFx1GJEZfqG9ZUf7xuIi/ra5dLjPGAaoY5QF2QOa8VnOriQCXDfyXHxsuRnE\n" + - "OomxL7EVAgMBAAGjeDB2MAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUXNCJK3/dtCIc\n" + - "xb+zlA/JINlvs/MwHwYDVR0jBBgwFoAUuXzV2d+nTAOu/Q4nWzGVbMfzdeEwJwYD\n" + - "VR0lBCAwHgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAzANBgkqhkiG9w0B\n" + - "AQQFAAOBgQB2qIDUxA2caMPpGtUACZAPRUtrGssCINIfItETXJZCx/cRuZ5sP4D9\n" + - "N1acoNDn0hCULe3lhXAeTC9NZ97680yJzregQMV5wATjo1FGsKY30Ma+sc/nfzQW\n" + - "+h/7RhYtoG0OTsiaDCvyhI6swkNJzSzrAccPY4+ZgU8HiDLzZTmM3Q==\n" + - "-----END CERTIFICATE-----"; - - // Private key in the format of PKCS#8, key size is 512 bits. - static String targetPrivateKey = - "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAtz2+PTkj3zg9hh0l\n" + - "xQhcdRiRGX6hvWVH+8biIv62uXS4zxgGqGOUBdkDmvFZzq4kAlw38lx8bLkZxDqJ\n" + - "sS+xFQIDAQABAkByx/5Oo2hQ/w2q4L8z+NTRlJ3vdl8iIDtC/4XPnfYfnGptnpG6\n" + - "ZThQRvbMZiai0xHQPQMszvAHjZVme1eDl3EBAiEA3aKJHynPVCEJhpfCLWuMwX5J\n" + - "1LntwJO7NTOyU5m8rPECIQDTpzn5X44r2rzWBDna/Sx7HW9IWCxNgUD2Eyi2nA7W\n" + - "ZQIgJerEorw4aCAuzQPxiGu57PB6GRamAihEAtoRTBQlH0ECIQDN08FgTtnesgCU\n" + - "DFYLLcw1CiHvc7fZw4neBDHCrC8NtQIgA8TOUkGnpCZlQ0KaI8KfKWI+vxFcgFnH\n" + - "3fnqsTgaUs4="; - - static char passphrase[] = "passphrase".toCharArray(); - /* * Is the server ready to serve? */ @@ -134,8 +76,8 @@ public class ShortRSAKey512 { * to avoid infinite hangs. */ void doServerSide() throws Exception { - SSLContext context = generateSSLContext(null, targetCertStr, - targetPrivateKey); + SSLContext context = createSSLContext(null, + new Cert[]{Cert.EE_RSA_MD5_512}, getServerContextParameters()); SSLServerSocketFactory sslssf = context.getServerSocketFactory(); try (SSLServerSocket sslServerSocket = (SSLServerSocket) sslssf.createServerSocket(serverPort)) { @@ -174,7 +116,8 @@ void doClientSide() throws Exception { Thread.sleep(50); } - SSLContext context = generateSSLContext(trustedCertStr, null, null); + SSLContext context = createSSLContext(new Cert[]{Cert.CA_RSA_MD5_512}, + null, getClientContextParameters()); SSLSocketFactory sslsf = context.getSocketFactory(); System.out.println("Client connects to port " + serverPort); @@ -197,6 +140,16 @@ void doClientSide() throws Exception { } } + @Override + protected ContextParameters getServerContextParameters() { + return new ContextParameters("TLSv1.2", tmAlgorithm, "NewSunX509"); + } + + @Override + protected ContextParameters getClientContextParameters() { + return new ContextParameters("TLSv1.2", tmAlgorithm, "NewSunX509"); + } + /* * ============================================================= * The remainder is just support stuff @@ -207,72 +160,6 @@ private static void parseArguments(String[] args) { tmAlgorithm = args[0]; } - private static SSLContext generateSSLContext(String trustedCertStr, - String keyCertStr, String keySpecStr) throws Exception { - - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - // create a key store - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(null, null); - - // import the trused cert - Certificate trusedCert = null; - ByteArrayInputStream is = null; - if (trustedCertStr != null) { - is = new ByteArrayInputStream(trustedCertStr.getBytes()); - trusedCert = cf.generateCertificate(is); - is.close(); - - ks.setCertificateEntry("RSA Export Signer", trusedCert); - } - - if (keyCertStr != null) { - // generate the private key. - PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - Base64.getMimeDecoder().decode(keySpecStr)); - KeyFactory kf = KeyFactory.getInstance("RSA"); - RSAPrivateKey priKey = - (RSAPrivateKey)kf.generatePrivate(priKeySpec); - - // generate certificate chain - is = new ByteArrayInputStream(keyCertStr.getBytes()); - Certificate keyCert = cf.generateCertificate(is); - is.close(); - - Certificate[] chain = null; - if (trusedCert != null) { - chain = new Certificate[2]; - chain[0] = keyCert; - chain[1] = trusedCert; - } else { - chain = new Certificate[1]; - chain[0] = keyCert; - } - - // import the key entry. - ks.setKeyEntry("Whatever", priKey, passphrase, chain); - } - - // create SSL context - TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm); - tmf.init(ks); - - SSLContext ctx = SSLContext.getInstance("TLS"); - if (keyCertStr != null && !keyCertStr.isEmpty()) { - KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); - kmf.init(ks, passphrase); - - ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - ks = null; - } else { - ctx.init(null, tmf.getTrustManagers(), null); - } - - return ctx; - } - // use any free port by default volatile int serverPort = 0; diff --git a/test/jdk/javax/net/ssl/TLSv12/ShortRSAKeyGCM.java b/test/jdk/javax/net/ssl/TLSv12/ShortRSAKeyGCM.java index 6ccfa03bcc1..df6767eadfb 100644 --- a/test/jdk/javax/net/ssl/TLSv12/ShortRSAKeyGCM.java +++ b/test/jdk/javax/net/ssl/TLSv12/ShortRSAKeyGCM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. * 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,6 +32,7 @@ * @test * @bug 7030966 * @summary Support AEAD CipherSuites + * @library /javax/net/ssl/templates * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 * @run main/othervm ShortRSAKeyGCM PKIX TLS_RSA_WITH_AES_128_GCM_SHA256 * @run main/othervm ShortRSAKeyGCM PKIX TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 @@ -70,7 +71,7 @@ import java.security.interfaces.*; -public class ShortRSAKeyGCM { +public class ShortRSAKeyGCM extends SSLContextTemplate { /* * ============================================================= @@ -85,57 +86,6 @@ public class ShortRSAKeyGCM { */ static boolean separateServerThread = true; - /* - * Where do we find the keystores? - */ - // Certificates and key used in the test. - static String trustedCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTEwODE5MDE1MjE5WhcNMzIwNzI5MDE1MjE5WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + - "KoZIhvcNAQEBBQADgY0AMIGJAoGBAM8orG08DtF98TMSscjGsidd1ZoN4jiDpi8U\n" + - "ICz+9dMm1qM1d7O2T+KH3/mxyox7Rc2ZVSCaUD0a3CkhPMnlAx8V4u0H+E9sqso6\n" + - "iDW3JpOyzMExvZiRgRG/3nvp55RMIUV4vEHOZ1QbhuqG4ebN0Vz2DkRft7+flthf\n" + - "vDld6f5JAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLl81dnfp0wDrv0OJ1sxlWzH83Xh\n" + - "MGMGA1UdIwRcMFqAFLl81dnfp0wDrv0OJ1sxlWzH83XhoT+kPTA7MQswCQYDVQQG\n" + - "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + - "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" + - "BQADgYEALlgaH1gWtoBZ84EW8Hu6YtGLQ/L9zIFmHonUPZwn3Pr//icR9Sqhc3/l\n" + - "pVTxOINuFHLRz4BBtEylzRIOPzK3tg8XwuLb1zd0db90x3KBCiAL6E6cklGEPwLe\n" + - "XYMHDn9eDsaq861Tzn6ZwzMgw04zotPMoZN0mVd/3Qca8UJFucE=\n" + - "-----END CERTIFICATE-----"; - - static String targetCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICNDCCAZ2gAwIBAgIBDDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTExMTA3MTM1NTUyWhcNMzEwNzI1MTM1NTUyWjBPMQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" + - "BAMTCWxvY2FsaG9zdDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC3Pb49OSPfOD2G\n" + - "HSXFCFx1GJEZfqG9ZUf7xuIi/ra5dLjPGAaoY5QF2QOa8VnOriQCXDfyXHxsuRnE\n" + - "OomxL7EVAgMBAAGjeDB2MAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUXNCJK3/dtCIc\n" + - "xb+zlA/JINlvs/MwHwYDVR0jBBgwFoAUuXzV2d+nTAOu/Q4nWzGVbMfzdeEwJwYD\n" + - "VR0lBCAwHgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAzANBgkqhkiG9w0B\n" + - "AQQFAAOBgQB2qIDUxA2caMPpGtUACZAPRUtrGssCINIfItETXJZCx/cRuZ5sP4D9\n" + - "N1acoNDn0hCULe3lhXAeTC9NZ97680yJzregQMV5wATjo1FGsKY30Ma+sc/nfzQW\n" + - "+h/7RhYtoG0OTsiaDCvyhI6swkNJzSzrAccPY4+ZgU8HiDLzZTmM3Q==\n" + - "-----END CERTIFICATE-----"; - - // Private key in the format of PKCS#8, key size is 512 bits. - static String targetPrivateKey = - "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAtz2+PTkj3zg9hh0l\n" + - "xQhcdRiRGX6hvWVH+8biIv62uXS4zxgGqGOUBdkDmvFZzq4kAlw38lx8bLkZxDqJ\n" + - "sS+xFQIDAQABAkByx/5Oo2hQ/w2q4L8z+NTRlJ3vdl8iIDtC/4XPnfYfnGptnpG6\n" + - "ZThQRvbMZiai0xHQPQMszvAHjZVme1eDl3EBAiEA3aKJHynPVCEJhpfCLWuMwX5J\n" + - "1LntwJO7NTOyU5m8rPECIQDTpzn5X44r2rzWBDna/Sx7HW9IWCxNgUD2Eyi2nA7W\n" + - "ZQIgJerEorw4aCAuzQPxiGu57PB6GRamAihEAtoRTBQlH0ECIQDN08FgTtnesgCU\n" + - "DFYLLcw1CiHvc7fZw4neBDHCrC8NtQIgA8TOUkGnpCZlQ0KaI8KfKWI+vxFcgFnH\n" + - "3fnqsTgaUs4="; - - static char passphrase[] = "passphrase".toCharArray(); - /* * Is the server ready to serve? */ @@ -153,8 +103,8 @@ public class ShortRSAKeyGCM { * to avoid infinite hangs. */ void doServerSide() throws Exception { - SSLContext context = generateSSLContext(null, targetCertStr, - targetPrivateKey); + SSLContext context = createSSLContext(null, new Cert[]{Cert.EE_RSA_MD5_512}, + getServerContextParameters()); SSLServerSocketFactory sslssf = context.getServerSocketFactory(); SSLServerSocket sslServerSocket = (SSLServerSocket)sslssf.createServerSocket(serverPort); @@ -192,7 +142,8 @@ void doClientSide() throws Exception { Thread.sleep(50); } - SSLContext context = generateSSLContext(trustedCertStr, null, null); + SSLContext context = createSSLContext(new Cert[]{Cert.CA_RSA_MD5_512}, + null, getClientContextParameters()); SSLSocketFactory sslsf = context.getSocketFactory(); SSLSocket sslSocket = @@ -226,72 +177,15 @@ private static void parseArguments(String[] args) { cipherSuite = args[1]; } - private static SSLContext generateSSLContext(String trustedCertStr, - String keyCertStr, String keySpecStr) throws Exception { - - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - // create a key store - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(null, null); - - // import the trused cert - Certificate trusedCert = null; - ByteArrayInputStream is = null; - if (trustedCertStr != null) { - is = new ByteArrayInputStream(trustedCertStr.getBytes()); - trusedCert = cf.generateCertificate(is); - is.close(); - - ks.setCertificateEntry("RSA Export Signer", trusedCert); - } - - if (keyCertStr != null) { - // generate the private key. - PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - Base64.getMimeDecoder().decode(keySpecStr)); - KeyFactory kf = KeyFactory.getInstance("RSA"); - RSAPrivateKey priKey = - (RSAPrivateKey)kf.generatePrivate(priKeySpec); - - // generate certificate chain - is = new ByteArrayInputStream(keyCertStr.getBytes()); - Certificate keyCert = cf.generateCertificate(is); - is.close(); - - Certificate[] chain = null; - if (trusedCert != null) { - chain = new Certificate[2]; - chain[0] = keyCert; - chain[1] = trusedCert; - } else { - chain = new Certificate[1]; - chain[0] = keyCert; - } - - // import the key entry. - ks.setKeyEntry("Whatever", priKey, passphrase, chain); - } - - // create SSL context - TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm); - tmf.init(ks); - - SSLContext ctx = SSLContext.getInstance("TLS"); - if (keyCertStr != null && !keyCertStr.isEmpty()) { - KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); - kmf.init(ks, passphrase); - - ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - ks = null; - } else { - ctx.init(null, tmf.getTrustManagers(), null); - } - - return ctx; + @Override + protected ContextParameters getServerContextParameters() { + return new ContextParameters("TLSv1.2", tmAlgorithm, "NewSunX509"); } + @Override + protected ContextParameters getClientContextParameters() { + return new ContextParameters("TLSv1.2", tmAlgorithm, "NewSunX509"); + } // use any free port by default volatile int serverPort = 0; diff --git a/test/jdk/javax/net/ssl/TLSv12/SignatureAlgorithms.java b/test/jdk/javax/net/ssl/TLSv12/SignatureAlgorithms.java index 8b51703df41..52191ec0882 100644 --- a/test/jdk/javax/net/ssl/TLSv12/SignatureAlgorithms.java +++ b/test/jdk/javax/net/ssl/TLSv12/SignatureAlgorithms.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * 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,6 +32,7 @@ * @test * @bug 8049321 * @summary Support SHA256WithDSA in JSSE + * @library /javax/net/ssl/templates * @run main/othervm SignatureAlgorithms PKIX "SHA-224,SHA-256" * TLS_DHE_DSS_WITH_AES_128_CBC_SHA * @run main/othervm SignatureAlgorithms PKIX "SHA-1,SHA-224" @@ -46,20 +47,14 @@ * TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 */ -import java.net.*; import java.util.*; import java.io.*; import javax.net.ssl.*; import java.security.Security; -import java.security.KeyStore; -import java.security.KeyFactory; import java.security.cert.Certificate; import java.security.cert.X509Certificate; -import java.security.cert.CertificateFactory; -import java.security.spec.*; -import java.security.interfaces.*; -public class SignatureAlgorithms { +public class SignatureAlgorithms extends SSLContextTemplate { /* * ============================================================= @@ -74,131 +69,6 @@ public class SignatureAlgorithms { */ static boolean separateServerThread = true; - /* - * Where do we find the keystores? - */ - // Certificates and key (DSA) used in the test. - static String trustedCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIIDYTCCAyGgAwIBAgIJAK8/gw6zg/DPMAkGByqGSM44BAMwOzELMAkGA1UEBhMC\n" + - "VVMxDTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNl\n" + - "MB4XDTE1MTIwMzEzNTIyNVoXDTM2MTExMjEzNTIyNVowOzELMAkGA1UEBhMCVVMx\n" + - "DTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNlMIIB\n" + - "uDCCASwGByqGSM44BAEwggEfAoGBAPH+b+GSMX6KS7jXDRevzc464DFG4X+uxu5V\n" + - "b3U4yhsU8A8cuH4gwin6L/IDkmZQ7N0zC0jRsiGVSMsFETTq10F39pH2eBfUv/hJ\n" + - "cLfBnIjBEtVqV/dExK88Hul2sZ4mQihQ4issPl7hsroS9EWYicnX0oNAqAB9PO5Y\n" + - "zKbfpL7TAhUA13WW48rln2UP/LaAgtnzKhqcNtMCgYEA3Rv0GirTbAaor8iURd82\n" + - "b5FlDTevOCTuq7ZIpfZVV30neS7cBYNet6m/3/4cfUlbbrqhbqIJ2I+I81drnN0Y\n" + - "lyN4KkuxEcB6OTwfWkIUj6rvPaCQrBH8Q213bDq3HHtYNaP8OoeQUyVXW+SEGADC\n" + - "J1+z8uqP3lIB6ltdgOiV/GQDgYUAAoGBAOXRppuJSGdt6AiZkb81P1DCUgIUlZFI\n" + - "J9GxWrjbbHDmGllMwPNhK6dU7LJKJJuYVPW+95rUGlSJEjRqSlHuyHkNb6e3e7qx\n" + - "tmx1/oIyq+oLult50hBS7uBvLLR0JbIKjBzzkudL8Rjze4G/Wq7KDM2T1JOP49tW\n" + - "eocCvaC8h8uQo4GtMIGqMB0GA1UdDgQWBBT17HcqLllsqnZzP+kElcGcBGmubjBr\n" + - "BgNVHSMEZDBigBT17HcqLllsqnZzP+kElcGcBGmubqE/pD0wOzELMAkGA1UEBhMC\n" + - "VVMxDTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNl\n" + - "ggkArz+DDrOD8M8wDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwCQYHKoZI\n" + - "zjgEAwMvADAsAhQ6Y1I6LtIEBMqNo8o6GIe4LLEJuwIUbVQUKi8tvtWyRoxm8AFV\n" + - "0axJYUU=\n" + - "-----END CERTIFICATE-----"; - - static String[] targetCertStr = { - // DSA-SHA1 - "-----BEGIN CERTIFICATE-----\n" + - "MIIDKTCCAumgAwIBAgIJAOy5c0b+8stFMAkGByqGSM44BAMwOzELMAkGA1UEBhMC\n" + - "VVMxDTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNl\n" + - "MB4XDTE1MTIwMzEzNTIyNVoXDTM1MDgyMDEzNTIyNVowTzELMAkGA1UEBhMCVVMx\n" + - "DTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVzdCBTZXJpdmNlMRIw\n" + - "EAYDVQQDDAlsb2NhbGhvc3QwggG3MIIBLAYHKoZIzjgEATCCAR8CgYEA8f5v4ZIx\n" + - "fopLuNcNF6/NzjrgMUbhf67G7lVvdTjKGxTwDxy4fiDCKfov8gOSZlDs3TMLSNGy\n" + - "IZVIywURNOrXQXf2kfZ4F9S/+Elwt8GciMES1WpX90TErzwe6XaxniZCKFDiKyw+\n" + - "XuGyuhL0RZiJydfSg0CoAH087ljMpt+kvtMCFQDXdZbjyuWfZQ/8toCC2fMqGpw2\n" + - "0wKBgQDdG/QaKtNsBqivyJRF3zZvkWUNN684JO6rtkil9lVXfSd5LtwFg163qb/f\n" + - "/hx9SVtuuqFuognYj4jzV2uc3RiXI3gqS7ERwHo5PB9aQhSPqu89oJCsEfxDbXds\n" + - "Orcce1g1o/w6h5BTJVdb5IQYAMInX7Py6o/eUgHqW12A6JX8ZAOBhAACgYB+zYqn\n" + - "jJwG4GZpBIN/6qhzbp0flChsV+Trlu0SL0agAQzb6XdI/4JnO87Pgbxaxh3VNAj3\n" + - "3+Ghr1NLBuBfTKzJ4j9msWT3EpLupkMyNtXvBYM0iyMrll67lSjMdv++wLEw35Af\n" + - "/bzVcjGyA5Q0i0cuEzDmHTVfi0OydynbwSLxtKNjMGEwCwYDVR0PBAQDAgPoMB0G\n" + - "A1UdDgQWBBQXJI8AxM0qsYCbbkIMuI5zJ+nMEDAfBgNVHSMEGDAWgBT17HcqLlls\n" + - "qnZzP+kElcGcBGmubjASBgNVHREBAf8ECDAGhwR/AAABMAkGByqGSM44BAMDLwAw\n" + - "LAIUXgyJ0xll4FrZAKXi8bj7Kiz+SA4CFH9WCSZIBYA9lmJkiTgRS7iM/6IC\n" + - "-----END CERTIFICATE-----", - - // DSA-SHA224 - "-----BEGIN CERTIFICATE-----\n" + - "MIIDLzCCAuugAwIBAgIJAOy5c0b+8stGMAsGCWCGSAFlAwQDATA7MQswCQYDVQQG\n" + - "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + - "Y2UwHhcNMTUxMjAzMTU0NDM5WhcNMzUwODIwMTU0NDM5WjBPMQswCQYDVQQGEwJV\n" + - "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Ux\n" + - "EjAQBgNVBAMMCWxvY2FsaG9zdDCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQDx/m/h\n" + - "kjF+iku41w0Xr83OOuAxRuF/rsbuVW91OMobFPAPHLh+IMIp+i/yA5JmUOzdMwtI\n" + - "0bIhlUjLBRE06tdBd/aR9ngX1L/4SXC3wZyIwRLValf3RMSvPB7pdrGeJkIoUOIr\n" + - "LD5e4bK6EvRFmInJ19KDQKgAfTzuWMym36S+0wIVANd1luPK5Z9lD/y2gILZ8yoa\n" + - "nDbTAoGBAN0b9Boq02wGqK/IlEXfNm+RZQ03rzgk7qu2SKX2VVd9J3ku3AWDXrep\n" + - "v9/+HH1JW266oW6iCdiPiPNXa5zdGJcjeCpLsRHAejk8H1pCFI+q7z2gkKwR/ENt\n" + - "d2w6txx7WDWj/DqHkFMlV1vkhBgAwidfs/Lqj95SAepbXYDolfxkA4GEAAKBgA81\n" + - "CJKEv+pwiqYgxtw/9rkQ9748WP3mKrEC06kjUG+94/Z9dQloNFFfj6LiO1bymc5l\n" + - "6QIR8XCi4Po3N80K3+WxhBGFhY+RkVWTh43JV8epb41aH2qiWErarBwBGEh8LyGT\n" + - "i30db+Nkz2gfvyz9H/9T0jmYgfLEOlMCusali1qHo2MwYTALBgNVHQ8EBAMCA+gw\n" + - "HQYDVR0OBBYEFBqSP0S4+X+zOCTEnlp2hbAjV/W5MB8GA1UdIwQYMBaAFPXsdyou\n" + - "WWyqdnM/6QSVwZwEaa5uMBIGA1UdEQEB/wQIMAaHBH8AAAEwCwYJYIZIAWUDBAMB\n" + - "AzEAMC4CFQChiRaOnAnsCSJFwdpK22jSxU/mhQIVALgLbj/G39+1Ej8UuSWnEQyU\n" + - "4DA+\n" + - "-----END CERTIFICATE-----", - - // DSA-SHA256 - "-----BEGIN CERTIFICATE-----\n" + - "MIIDLTCCAuugAwIBAgIJAOy5c0b+8stHMAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" + - "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + - "Y2UwHhcNMTUxMjAzMTU0NjUxWhcNMzUwODIwMTU0NjUxWjBPMQswCQYDVQQGEwJV\n" + - "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Ux\n" + - "EjAQBgNVBAMMCWxvY2FsaG9zdDCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQDx/m/h\n" + - "kjF+iku41w0Xr83OOuAxRuF/rsbuVW91OMobFPAPHLh+IMIp+i/yA5JmUOzdMwtI\n" + - "0bIhlUjLBRE06tdBd/aR9ngX1L/4SXC3wZyIwRLValf3RMSvPB7pdrGeJkIoUOIr\n" + - "LD5e4bK6EvRFmInJ19KDQKgAfTzuWMym36S+0wIVANd1luPK5Z9lD/y2gILZ8yoa\n" + - "nDbTAoGBAN0b9Boq02wGqK/IlEXfNm+RZQ03rzgk7qu2SKX2VVd9J3ku3AWDXrep\n" + - "v9/+HH1JW266oW6iCdiPiPNXa5zdGJcjeCpLsRHAejk8H1pCFI+q7z2gkKwR/ENt\n" + - "d2w6txx7WDWj/DqHkFMlV1vkhBgAwidfs/Lqj95SAepbXYDolfxkA4GEAAKBgEF7\n" + - "2qiYxGrjX4KCOy0k5nK/RYlgLy4gYDChihQpiaa+fbA5JOBOxPWsh7rdtmJuDrEJ\n" + - "keacU223+DIhOKC49fa+EvhLNqo6U1oPn8n/yvBsvvnWkcynw5KfNzaLlaPmzugh\n" + - "v9xl/GhyZNAXc1QUcW3C+ceHVNrKnkfbTKZz5eRSo2MwYTALBgNVHQ8EBAMCA+gw\n" + - "HQYDVR0OBBYEFNMkPrt40oO9Dpy+bcbQdEvOlNlyMB8GA1UdIwQYMBaAFPXsdyou\n" + - "WWyqdnM/6QSVwZwEaa5uMBIGA1UdEQEB/wQIMAaHBH8AAAEwCwYJYIZIAWUDBAMC\n" + - "Ay8AMCwCFCvA2QiKSe/n+6GqSYQwgQ/zL5M9AhQfSiuWdMJKWpgPJKakvzhBUbMb\n" + - "vA==\n" + - "-----END CERTIFICATE-----"}; - - // Private key in the format of PKCS#8, key size is 1024 bits. - static String[] targetPrivateKey = { - // For cert DSA-SHA1 - "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAPH+b+GSMX6KS7jXDRevzc464DFG\n" + - "4X+uxu5Vb3U4yhsU8A8cuH4gwin6L/IDkmZQ7N0zC0jRsiGVSMsFETTq10F39pH2\n" + - "eBfUv/hJcLfBnIjBEtVqV/dExK88Hul2sZ4mQihQ4issPl7hsroS9EWYicnX0oNA\n" + - "qAB9PO5YzKbfpL7TAhUA13WW48rln2UP/LaAgtnzKhqcNtMCgYEA3Rv0GirTbAao\n" + - "r8iURd82b5FlDTevOCTuq7ZIpfZVV30neS7cBYNet6m/3/4cfUlbbrqhbqIJ2I+I\n" + - "81drnN0YlyN4KkuxEcB6OTwfWkIUj6rvPaCQrBH8Q213bDq3HHtYNaP8OoeQUyVX\n" + - "W+SEGADCJ1+z8uqP3lIB6ltdgOiV/GQEFgIUOiB7J/lrFrNduQ8nDNTe8VspoAI=", - - // For cert DSA-SHA224 - "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAPH+b+GSMX6KS7jXDRevzc464DFG\n" + - "4X+uxu5Vb3U4yhsU8A8cuH4gwin6L/IDkmZQ7N0zC0jRsiGVSMsFETTq10F39pH2\n" + - "eBfUv/hJcLfBnIjBEtVqV/dExK88Hul2sZ4mQihQ4issPl7hsroS9EWYicnX0oNA\n" + - "qAB9PO5YzKbfpL7TAhUA13WW48rln2UP/LaAgtnzKhqcNtMCgYEA3Rv0GirTbAao\n" + - "r8iURd82b5FlDTevOCTuq7ZIpfZVV30neS7cBYNet6m/3/4cfUlbbrqhbqIJ2I+I\n" + - "81drnN0YlyN4KkuxEcB6OTwfWkIUj6rvPaCQrBH8Q213bDq3HHtYNaP8OoeQUyVX\n" + - "W+SEGADCJ1+z8uqP3lIB6ltdgOiV/GQEFgIUOj9F5mxWd9W1tiLSdsOAt8BUBzE=", - - // For cert DSA-SHA256 - "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAPH+b+GSMX6KS7jXDRevzc464DFG\n" + - "4X+uxu5Vb3U4yhsU8A8cuH4gwin6L/IDkmZQ7N0zC0jRsiGVSMsFETTq10F39pH2\n" + - "eBfUv/hJcLfBnIjBEtVqV/dExK88Hul2sZ4mQihQ4issPl7hsroS9EWYicnX0oNA\n" + - "qAB9PO5YzKbfpL7TAhUA13WW48rln2UP/LaAgtnzKhqcNtMCgYEA3Rv0GirTbAao\n" + - "r8iURd82b5FlDTevOCTuq7ZIpfZVV30neS7cBYNet6m/3/4cfUlbbrqhbqIJ2I+I\n" + - "81drnN0YlyN4KkuxEcB6OTwfWkIUj6rvPaCQrBH8Q213bDq3HHtYNaP8OoeQUyVX\n" + - "W+SEGADCJ1+z8uqP3lIB6ltdgOiV/GQEFgIUQ2WGgg+OO39Aujj0e4lM4pP4/9g="}; - - - static char passphrase[] = "passphrase".toCharArray(); - /* * Turn on SSL debugging? */ @@ -209,6 +79,12 @@ public class SignatureAlgorithms { */ volatile boolean serverReady = false; + private final Cert[] SERVER_CERTS = { + SSLContextTemplate.Cert.EE_DSA_SHA1_1024, + SSLContextTemplate.Cert.EE_DSA_SHA224_1024, + SSLContextTemplate.Cert.EE_DSA_SHA256_1024, + }; + /* * Define the server side of the test. * @@ -216,9 +92,7 @@ public class SignatureAlgorithms { * to avoid infinite hangs. */ void doServerSide() throws Exception { - - SSLContext context = generateSSLContext( - null, targetCertStr, targetPrivateKey); + SSLContext context = createSSLContext(null, SERVER_CERTS, getServerContextParameters()); SSLServerSocketFactory sslssf = context.getServerSocketFactory(); try (SSLServerSocket sslServerSocket = (SSLServerSocket)sslssf.createServerSocket(serverPort)) { @@ -260,7 +134,7 @@ void doClientSide() throws Exception { Thread.sleep(50); } - SSLContext context = generateSSLContext(trustedCertStr, null, null); + SSLContext context = createSSLContext(new Cert[]{Cert.CA_DSA_SHA1_1024}, null, getClientContextParameters()); SSLSocketFactory sslsf = context.getSocketFactory(); try (SSLSocket sslSocket = @@ -343,75 +217,14 @@ private static void parseArguments(String[] args) { cipherSuite = args[2]; } - private static SSLContext generateSSLContext(String trustedCertStr, - String[] keyCertStrs, String[] keySpecStrs) throws Exception { - - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - // create a key store - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(null, null); - - // import the trused cert - Certificate trusedCert = null; - ByteArrayInputStream is = null; - if (trustedCertStr != null) { - is = new ByteArrayInputStream(trustedCertStr.getBytes()); - trusedCert = cf.generateCertificate(is); - is.close(); - - ks.setCertificateEntry("DSA Signer", trusedCert); - } - - if (keyCertStrs != null && keyCertStrs.length != 0) { - for (int i = 0; i < keyCertStrs.length; i++) { - String keyCertStr = keyCertStrs[i]; - String keySpecStr = keySpecStrs[i]; - - // generate the private key. - PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - Base64.getMimeDecoder().decode(keySpecStr)); - KeyFactory kf = KeyFactory.getInstance("DSA"); - DSAPrivateKey priKey = - (DSAPrivateKey)kf.generatePrivate(priKeySpec); - - // generate certificate chain - is = new ByteArrayInputStream(keyCertStr.getBytes()); - Certificate keyCert = cf.generateCertificate(is); - is.close(); - - Certificate[] chain = null; - if (trusedCert != null) { - chain = new Certificate[2]; - chain[0] = keyCert; - chain[1] = trusedCert; - } else { - chain = new Certificate[1]; - chain[0] = keyCert; - } - - // import the key entry. - ks.setKeyEntry("DSA Entry " + i, priKey, passphrase, chain); - } - } - - // create SSL context - TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm); - tmf.init(ks); - - SSLContext ctx = SSLContext.getInstance("TLS"); - if (keyCertStrs != null && keyCertStrs.length != 0) { - KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); - kmf.init(ks, passphrase); - - ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - ks = null; - } else { - ctx.init(null, tmf.getTrustManagers(), null); - } + @Override + protected ContextParameters getServerContextParameters() { + return new ContextParameters("TLSv1.2", tmAlgorithm, "NewSunX509"); + } - return ctx; + @Override + protected ContextParameters getClientContextParameters() { + return new ContextParameters("TLSv1.2", tmAlgorithm, "NewSunX509"); } diff --git a/test/jdk/javax/net/ssl/TLSv13/EngineOutOfSeqCCS.java b/test/jdk/javax/net/ssl/TLSv13/EngineOutOfSeqCCS.java index 94a2c0fe311..639fd80674c 100644 --- a/test/jdk/javax/net/ssl/TLSv13/EngineOutOfSeqCCS.java +++ b/test/jdk/javax/net/ssl/TLSv13/EngineOutOfSeqCCS.java @@ -25,7 +25,8 @@ * @test * @bug 8326643 * @summary Test for out-of-sequence change_cipher_spec in TLSv1.3 - * @library /javax/net/ssl/templates + * @library /javax/net/ssl/templates /test/lib + * @build jdk.test.lib.Utils * @run main/othervm EngineOutOfSeqCCS */ diff --git a/test/jdk/javax/net/ssl/templates/SSLContextTemplate.java b/test/jdk/javax/net/ssl/templates/SSLContextTemplate.java index fd2fcd8099d..a39cd8668ed 100644 --- a/test/jdk/javax/net/ssl/templates/SSLContextTemplate.java +++ b/test/jdk/javax/net/ssl/templates/SSLContextTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * 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,66 +39,188 @@ /** * SSLContext template to speed up JSSE tests. */ -public interface SSLContextTemplate { +public abstract class SSLContextTemplate { + + /* + * ======================================= + * Certificates and keys used in the test. + */ + // Trusted certificates. + Cert[] TRUSTED_CERTS = { + Cert.CA_ECDSA_SECP256R1, + Cert.CA_ECDSA_SECT283R1, + Cert.CA_RSA_2048, + Cert.CA_DSA_2048 }; + + // End entity certificate. + Cert[] END_ENTITY_CERTS = { + Cert.EE_ECDSA_SECP256R1, + Cert.EE_ECDSA_SECT283R1, + Cert.EE_RSA_2048, + Cert.EE_EC_RSA_SECP256R1, + Cert.EE_DSA_2048 }; + /* * Create an instance of SSLContext for client use. */ - default SSLContext createClientSSLContext() throws Exception { + protected SSLContext createClientSSLContext() throws Exception { return createSSLContext( - createClientKeyManager(), createClientTrustManager(), + createClientKeyManager(), getClientContextParameters()); } /* * Create an instance of SSLContext for server use. */ - default SSLContext createServerSSLContext() throws Exception { + protected SSLContext createServerSSLContext() throws Exception { return createSSLContext( - createServerKeyManager(), createServerTrustManager(), + createServerKeyManager(), getServerContextParameters()); } - /* - * Create an instance of KeyManager for client use. + private SSLContext createSSLContext(TrustManager trustManager, + KeyManager keyManager, + ContextParameters params) throws Exception { + SSLContext context = SSLContext.getInstance(params.contextProtocol); + context.init( + new KeyManager[] {keyManager}, + new TrustManager[] {trustManager}, + null); + return context; + } + + /** + * Creates a TrustManager with TRUSTED_CERTS and client context parameters */ - default KeyManager createClientKeyManager() throws Exception { - return createKeyManager( - endEntityCertStrs, - endEntityPrivateKeys, - endEntityPrivateKeyAlgs, - endEntityPrivateKeyNames, - getServerContextParameters()); + protected TrustManager createClientTrustManager() throws Exception { + return createTrustManager(TRUSTED_CERTS, getClientContextParameters()); } - /* - * Create an instance of TrustManager for client use. + /** + * Creates a TrustManager with TRUSTED_CERTS and server context parameters */ - default TrustManager createClientTrustManager() throws Exception { - return createTrustManager( - trustedCertStrs, - getServerContextParameters()); + protected TrustManager createServerTrustManager() throws Exception { + return createTrustManager(TRUSTED_CERTS, getServerContextParameters()); } - /* - * Create an instance of KeyManager for server use. + + /** + * Creates a TrustManager with the given array of trusted certs and + * context parameters. */ - default KeyManager createServerKeyManager() throws Exception { - return createKeyManager( - endEntityCertStrs, - endEntityPrivateKeys, - endEntityPrivateKeyAlgs, - endEntityPrivateKeyNames, - getServerContextParameters()); + protected TrustManager createTrustManager(Cert[] trustedCerts, + ContextParameters params) throws Exception { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + ByteArrayInputStream is; + + KeyStore ts = KeyStore.getInstance("JKS"); + ts.load(null, null); + + if (trustedCerts != null && trustedCerts.length != 0) { + Certificate[] trustedCert = new Certificate[trustedCerts.length]; + for (int i = 0; i < trustedCerts.length; i++) { + is = new ByteArrayInputStream(trustedCerts[i].certStr.getBytes()); + try { + trustedCert[i] = cf.generateCertificate(is); + } finally { + is.close(); + } + + ts.setCertificateEntry( + "trusted-cert-" + trustedCerts[i].name(), trustedCert[i]); + } + } + + // Create an SSLContext object. + TrustManagerFactory tmf = + TrustManagerFactory.getInstance(params.tmAlgorithm); + tmf.init(ts); + return tmf.getTrustManagers()[0]; + } + + /** + * Create a key manager with Cert.END_ENTITY_CERTS and the client + * context parameters. + */ + protected KeyManager createClientKeyManager() throws Exception { + return createKeyManager(END_ENTITY_CERTS, getClientContextParameters()); + } + + /** + * Create a key manager with Cert.END_ENTITY_CERTS and the server + * context parameters + */ + protected KeyManager createServerKeyManager() throws Exception { + return createKeyManager(END_ENTITY_CERTS, getServerContextParameters()); + } + + /** + * Creates a KeyManager with the given end-entity Cert's and context + * parameters + */ + protected KeyManager createKeyManager(Cert[] endEntityCerts, + ContextParameters params) throws Exception { + KeyStore ks = null; // key store + char[] passphrase = "passphrase".toCharArray(); + + if (endEntityCerts == null || endEntityCerts.length == 0) { + return null; + + } else { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + ks = KeyStore.getInstance("JKS"); + ks.load(null, null); + + for (Cert endEntityCert : endEntityCerts) { + // generate the private key. + PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( + Base64.getMimeDecoder().decode(endEntityCert.privKeyStr)); + KeyFactory kf = + KeyFactory.getInstance( + endEntityCert.keyAlgo); + PrivateKey priKey = kf.generatePrivate(priKeySpec); + + // generate certificate chain + ByteArrayInputStream is = new ByteArrayInputStream( + endEntityCert.certStr.getBytes()); + Certificate keyCert = null; + try { + keyCert = cf.generateCertificate(is); + } finally { + is.close(); + } + + Certificate[] chain = new Certificate[]{keyCert}; + + // import the key entry. + ks.setKeyEntry("cert-" + endEntityCert.name(), + priKey, passphrase, chain); + } + + KeyManagerFactory kmf = + KeyManagerFactory.getInstance(params.kmAlgorithm); + kmf.init(ks, passphrase); + return kmf.getKeyManagers()[0]; + } } /* - * Create an instance of TrustManager for server use. + * Create an instance of SSLContext with the specified trust/key materials. */ - default TrustManager createServerTrustManager() throws Exception { - return createTrustManager( - trustedCertStrs, - getServerContextParameters()); + protected SSLContext createSSLContext( + Cert[] trustedCerts, + Cert[] endEntityCerts, + ContextParameters params) throws Exception { + + // Generate certificate from cert string. + TrustManager tm = createTrustManager(trustedCerts, params); + + KeyManager km = createKeyManager(endEntityCerts, params); + + SSLContext context = SSLContext.getInstance(params.contextProtocol); + context.init(km == null ? null : new KeyManager[]{km}, new TrustManager[]{tm}, null); + return context; } /* @@ -121,452 +243,1086 @@ static final class ContextParameters { /* * Get the client side parameters of SSLContext. */ - default ContextParameters getClientContextParameters() { + protected ContextParameters getClientContextParameters() { return new ContextParameters("TLS", "PKIX", "NewSunX509"); } /* * Get the server side parameters of SSLContext. */ - default ContextParameters getServerContextParameters() { + protected ContextParameters getServerContextParameters() { return new ContextParameters("TLS", "PKIX", "NewSunX509"); } - /* - * ======================================= - * Certificates and keys used in the test. - */ - // Trusted certificates. - final static String[] trustedCertStrs = { - // SHA256withECDSA, curve prime256v1 - // Validity - // Not Before: May 22 07:18:16 2018 GMT - // Not After : May 17 07:18:16 2038 GMT - // Subject Key Identifier: - // 60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86 - "-----BEGIN CERTIFICATE-----\n" + - "MIIBvjCCAWOgAwIBAgIJAIvFG6GbTroCMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" + - "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + - "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYTAlVT\n" + - "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTBZ\n" + - "MBMGByqGSM49AgEGCCqGSM49AwEHA0IABBz1WeVb6gM2mh85z3QlvaB/l11b5h0v\n" + - "LIzmkC3DKlVukZT+ltH2Eq1oEkpXuf7QmbM0ibrUgtjsWH3mULfmcWmjUDBOMB0G\n" + - "A1UdDgQWBBRgz71z//oaMNKk7NNJcUbvGjWghjAfBgNVHSMEGDAWgBRgz71z//oa\n" + - "MNKk7NNJcUbvGjWghjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQCG\n" + - "6wluh1r2/T6L31mZXRKf9JxeSf9pIzoLj+8xQeUChQIhAJ09wAi1kV8yePLh2FD9\n" + - "2YEHlSQUAbwwqCDEVB5KxaqP\n" + - "-----END CERTIFICATE-----", - // -----BEGIN PRIVATE KEY----- - // MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/HcHdoLJCdq3haVd - // XZTSKP00YzM3xX97l98vGL/RI1KhRANCAAQc9VnlW+oDNpofOc90Jb2gf5ddW+Yd - // LyyM5pAtwypVbpGU/pbR9hKtaBJKV7n+0JmzNIm61ILY7Fh95lC35nFp - // -----END PRIVATE KEY----- - - // SHA256withRSA, 2048 bits - // Validity - // Not Before: May 22 07:18:16 2018 GMT - // Not After : May 17 07:18:16 2038 GMT - // Subject Key Identifier: - // 0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C - "-----BEGIN CERTIFICATE-----\n" + - "MIIDSTCCAjGgAwIBAgIJAI4ZF3iy8zG+MA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" + - "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" + - "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYT\n" + - "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + - "ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALpMcY7aWieXDEM1/YJf\n" + - "JW27b4nRIFZyEYhEloyGsKTuQiiQjc8cqRZFNXe2vwziDB4IyTEl0Hjl5QF6ZaQE\n" + - "huPzzwvQm1pv64KrRXrmj3FisQK8B5OWLty9xp6xDqsaMRoyObLK+oIb20T5fSlE\n" + - "evmo1vYjnh8CX0Yzx5Gr5ye6YSEHQvYOWEws8ad17OlyToR2KMeC8w4qo6rs59pW\n" + - "g7Mxn9vo22ImDzrtAbTbXbCias3xlE0Bp0h5luyf+5U4UgksoL9B9r2oP4GrLNEV\n" + - "oJk57t8lwaR0upiv3CnS8LcJELpegZub5ggqLY8ZPYFQPjlK6IzLOm6rXPgZiZ3m\n" + - "RL0CAwEAAaNQME4wHQYDVR0OBBYEFA3dk8n+S701t+iZeJD721o92xVMMB8GA1Ud\n" + - "IwQYMBaAFA3dk8n+S701t+iZeJD721o92xVMMAwGA1UdEwQFMAMBAf8wDQYJKoZI\n" + - "hvcNAQELBQADggEBAJTRC3rKUUhVH07/1+stUungSYgpM08dY4utJq0BDk36BbmO\n" + - "0AnLDMbkwFdHEoqF6hQIfpm7SQTmXk0Fss6Eejm8ynYr6+EXiRAsaXOGOBCzF918\n" + - "/RuKOzqABfgSU4UBKECLM5bMfQTL60qx+HdbdVIpnikHZOFfmjCDVxoHsGyXc1LW\n" + - "Jhkht8IGOgc4PMGvyzTtRFjz01kvrVQZ75aN2E0GQv6dCxaEY0i3ypSzjUWAKqDh\n" + - "3e2OLwUSvumcdaxyCdZAOUsN6pDBQ+8VRG7KxnlRlY1SMEk46QgQYLbPDe/+W/yH\n" + - "ca4PejicPeh+9xRAwoTpiE2gulfT7Lm+fVM7Ruc=\n" + - "-----END CERTIFICATE-----", - - // -----BEGIN PRIVATE KEY----- - // MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC6THGO2lonlwxD - // Nf2CXyVtu2+J0SBWchGIRJaMhrCk7kIokI3PHKkWRTV3tr8M4gweCMkxJdB45eUB - // emWkBIbj888L0Jtab+uCq0V65o9xYrECvAeTli7cvcaesQ6rGjEaMjmyyvqCG9tE - // +X0pRHr5qNb2I54fAl9GM8eRq+cnumEhB0L2DlhMLPGndezpck6EdijHgvMOKqOq - // 7OfaVoOzMZ/b6NtiJg867QG0212womrN8ZRNAadIeZbsn/uVOFIJLKC/Qfa9qD+B - // qyzRFaCZOe7fJcGkdLqYr9wp0vC3CRC6XoGbm+YIKi2PGT2BUD45SuiMyzpuq1z4 - // GYmd5kS9AgMBAAECggEAFHSoU2MuWwJ+2jJnb5U66t2V1bAcuOE1g5zkWvG/G5z9 - // rq6Qo5kmB8f5ovdx6tw3MGUOklLwnRXBG3RxDJ1iokz3AvkY1clMNsDPlDsUrQKF - // JSO4QUBQTPSZhnsyfR8XHSU+qJ8Y+ohMfzpVv95BEoCzebtXdVgxVegBlcEmVHo2 - // kMmkRN+bYNsr8eb2r+b0EpyumS39ZgKYh09+cFb78y3T6IFMGcVJTP6nlGBFkmA/ - // 25pYeCF2tSki08qtMJZQAvKfw0Kviibk7ZxRbJqmc7B1yfnOEHP6ftjuvKl2+RP/ - // +5P5f8CfIP6gtA0LwSzAqQX/hfIKrGV5j0pCqrD0kQKBgQDeNR6Xi4sXVq79lihO - // a1bSeV7r8yoQrS8x951uO+ox+UIZ1MsAULadl7zB/P0er92p198I9M/0Jth3KBuS - // zj45mucvpiiGvmQlMKMEfNq4nN7WHOu55kufPswQB2mR4J3xmwI+4fM/nl1zc82h - // De8JSazRldJXNhfx0RGFPmgzbwKBgQDWoVXrXLbCAn41oVnWB8vwY9wjt92ztDqJ - // HMFA/SUohjePep9UDq6ooHyAf/Lz6oE5NgeVpPfTDkgvrCFVKnaWdwALbYoKXT2W - // 9FlyJox6eQzrtHAacj3HJooXWuXlphKSizntfxj3LtMR9BmrmRJOfK+SxNOVJzW2 - // +MowT20EkwKBgHmpB8jdZBgxI7o//m2BI5Y1UZ1KE5vx1kc7VXzHXSBjYqeV9FeF - // 2ZZLP9POWh/1Fh4pzTmwIDODGT2UPhSQy0zq3O0fwkyT7WzXRknsuiwd53u/dejg - // iEL2NPAJvulZ2+AuiHo5Z99LK8tMeidV46xoJDDUIMgTG+UQHNGhK5gNAoGAZn/S - // Cn7SgMC0CWSvBHnguULXZO9wH1wZAFYNLL44OqwuaIUFBh2k578M9kkke7woTmwx - // HxQTjmWpr6qimIuY6q6WBN8hJ2Xz/d1fwhYKzIp20zHuv5KDUlJjbFfqpsuy3u1C - // kts5zwI7pr1ObRbDGVyOdKcu7HI3QtR5qqyjwaUCgYABo7Wq6oHva/9V34+G3Goh - // 63bYGUnRw2l5BD11yhQv8XzGGZFqZVincD8gltNThB0Dc/BI+qu3ky4YdgdZJZ7K - // z51GQGtaHEbrHS5caV79yQ8QGY5mUVH3E+VXSxuIqb6pZq2DH4sTAEFHyncddmOH - // zoXBInYwRG9KE/Bw5elhUw== - // -----END PRIVATE KEY----- - - - // SHA256withDSA, 2048 bits - // Validity - // Not Before: May 22 07:18:18 2018 GMT - // Not After : May 17 07:18:18 2038 GMT - // Subject Key Identifier: - // 76:66:9E:F7:3B:DD:45:E5:3B:D9:72:3C:3F:F0:54:39:86:31:26:53 - "-----BEGIN CERTIFICATE-----\n" + - "MIIErjCCBFSgAwIBAgIJAOktYLNCbr02MAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" + - "EwJVUzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2\n" + - "Y2UwHhcNMTgwNTIyMDcxODE4WhcNMzgwNTE3MDcxODE4WjA7MQswCQYDVQQGEwJV\n" + - "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Uw\n" + - "ggNHMIICOQYHKoZIzjgEATCCAiwCggEBAO5GyPhSm0ze3LSu+gicdULLj05iOfTL\n" + - "UvZQ29sYz41zmqrLBQbdKiHqgJu2Re9sgTb5suLNjF047TOLPnU3jhPtWm2X8Xzi\n" + - "VGIcHym/Q/MeZxStt/88seqroI3WOKzIML2GcrishT+lcGrtH36Tf1+ue2Snn3PS\n" + - "WyxygNqPjllP5uUjYmFLvAf4QLMldkd/D2VxcwsHjB8y5iUZsXezc/LEhRZS/02m\n" + - "ivqlRw3AMkq/OVe/ZtxFWsP0nsfxEGdZuaUFpppGfixxFvymrB3+J51cTt+pZBDq\n" + - "D2y0DYfc+88iCs4jwHTfcDIpLb538HBjBj2rEgtQESQmB0ooD/+wsPsCIQC1bYch\n" + - "gElNtDYL3FgpLgNSUYp7gIWv9ehaC7LO2z7biQKCAQBitvFOnDkUja8NAF7lDpOV\n" + - "b5ipQ8SicBLW3kQamxhyuyxgZyy/PojZ/oPorkqW/T/A0rhnG6MssEpAtdiwVB+c\n" + - "rBYGo3bcwmExJhdOJ6dYuKFppPWhCwKMHs9npK+lqBMl8l5j58xlcFeC7ZfGf8GY\n" + - "GkhFW0c44vEQhMMbac6ZTTP4mw+1t7xJfmDMlLEyIpTXaAAk8uoVLWzQWnR40sHi\n" + - "ybvS0u3JxQkb7/y8tOOZu8qlz/YOS7lQ6UxUGX27Ce1E0+agfPphetoRAlS1cezq\n" + - "Wa7r64Ga0nkj1kwkcRqjgTiJx0NwnUXr78VAXFhVF95+O3lfqhvdtEGtkhDGPg7N\n" + - "A4IBBgACggEBAMmSHQK0w2i+iqUjOPzn0yNEZrzepLlLeQ1tqtn0xnlv5vBAeefD\n" + - "Pm9dd3tZOjufVWP7hhEz8xPobb1CS4e3vuQiv5UBfhdPL3f3l9T7JMAKPH6C9Vve\n" + - "OQXE5eGqbjsySbcmseHoYUt1WCSnSda1opX8zchX04e7DhGfE2/L9flpYEoSt8lI\n" + - "vMNjgOwvKdW3yvPt1/eBBHYNFG5gWPv/Q5KoyCtHS03uqGm4rNc/wZTIEEfd66C+\n" + - "QRaUltjOaHmtwOdDHaNqwhYZSVOip+Mo+TfyzHFREcdHLapo7ZXqbdYkRGxRR3d+\n" + - "3DfHaraJO0OKoYlPkr3JMvM/MSGR9AnZOcejUDBOMB0GA1UdDgQWBBR2Zp73O91F\n" + - "5TvZcjw/8FQ5hjEmUzAfBgNVHSMEGDAWgBR2Zp73O91F5TvZcjw/8FQ5hjEmUzAM\n" + - "BgNVHRMEBTADAQH/MAsGCWCGSAFlAwQDAgNHADBEAiBzriYE41M2y9Hy5ppkL0Qn\n" + - "dIlNc8JhXT/PHW7GDtViagIgMko8Qoj9gDGPK3+O9E8DC3wGiiF9CObM4LN387ok\n" + - "J+g=\n" + - "-----END CERTIFICATE-----" - // -----BEGIN PRIVATE KEY----- - // MIICZQIBADCCAjkGByqGSM44BAEwggIsAoIBAQDuRsj4UptM3ty0rvoInHVCy49O - // Yjn0y1L2UNvbGM+Nc5qqywUG3Soh6oCbtkXvbIE2+bLizYxdOO0ziz51N44T7Vpt - // l/F84lRiHB8pv0PzHmcUrbf/PLHqq6CN1jisyDC9hnK4rIU/pXBq7R9+k39frntk - // p59z0lsscoDaj45ZT+blI2JhS7wH+ECzJXZHfw9lcXMLB4wfMuYlGbF3s3PyxIUW - // Uv9Npor6pUcNwDJKvzlXv2bcRVrD9J7H8RBnWbmlBaaaRn4scRb8pqwd/iedXE7f - // qWQQ6g9stA2H3PvPIgrOI8B033AyKS2+d/BwYwY9qxILUBEkJgdKKA//sLD7AiEA - // tW2HIYBJTbQ2C9xYKS4DUlGKe4CFr/XoWguyzts+24kCggEAYrbxTpw5FI2vDQBe - // 5Q6TlW+YqUPEonAS1t5EGpsYcrssYGcsvz6I2f6D6K5Klv0/wNK4ZxujLLBKQLXY - // sFQfnKwWBqN23MJhMSYXTienWLihaaT1oQsCjB7PZ6SvpagTJfJeY+fMZXBXgu2X - // xn/BmBpIRVtHOOLxEITDG2nOmU0z+JsPtbe8SX5gzJSxMiKU12gAJPLqFS1s0Fp0 - // eNLB4sm70tLtycUJG+/8vLTjmbvKpc/2Dku5UOlMVBl9uwntRNPmoHz6YXraEQJU - // tXHs6lmu6+uBmtJ5I9ZMJHEao4E4icdDcJ1F6+/FQFxYVRfefjt5X6ob3bRBrZIQ - // xj4OzQQjAiEAsceWOM8do4etxp2zgnoNXV8PUUyqWhz1+0srcKV7FR4= - // -----END PRIVATE KEY----- - }; - // End entity certificate. - final static String[] endEntityCertStrs = { - // SHA256withECDSA, curve prime256v1 - // Validity - // Not Before: May 22 07:18:16 2018 GMT - // Not After : May 17 07:18:16 2038 GMT - // Authority Key Identifier: - // 60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86 - "-----BEGIN CERTIFICATE-----\n" + - "MIIBqjCCAVCgAwIBAgIJAPLY8qZjgNRAMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" + - "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + - "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYTAlVT\n" + - "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTEY\n" + - "MBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\n" + - "QgAEb+9n05qfXnfHUb0xtQJNS4JeSi6IjOfW5NqchvKnfJey9VkJzR7QHLuOESdf\n" + - "xlR7q8YIWgih3iWLGfB+wxHiOqMjMCEwHwYDVR0jBBgwFoAUYM+9c//6GjDSpOzT\n" + - "SXFG7xo1oIYwCgYIKoZIzj0EAwIDSAAwRQIgWpRegWXMheiD3qFdd8kMdrkLxRbq\n" + - "1zj8nQMEwFTUjjQCIQDRIrAjZX+YXHN9b0SoWWLPUq0HmiFIi8RwMnO//wJIGQ==\n" + - "-----END CERTIFICATE-----", - - // SHA256withRSA, 2048 bits - // Validity - // Not Before: May 22 07:18:16 2018 GMT - // Not After : May 17 07:18:16 2038 GMT - // Authority Key Identifier: - // 0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C - "-----BEGIN CERTIFICATE-----\n" + - "MIIDNjCCAh6gAwIBAgIJAO2+yPcFryUTMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" + - "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" + - "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYT\n" + - "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + - "ZTEYMBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOC\n" + - "AQ8AMIIBCgKCAQEAszfBobWfZIp8AgC6PiWDDavP65mSvgCXUGxACbxVNAfkLhNR\n" + - "QOsHriRB3X1Q3nvO9PetC6wKlvE9jlnDDj7D+1j1r1CHO7ms1fq8rfcQYdkanDtu\n" + - "4AlHo8v+SSWX16MIXFRYDj2VVHmyPtgbltcg4zGAuwT746FdLI94uXjJjq1IOr/v\n" + - "0VIlwE5ORWH5Xc+5Tj+oFWK0E4a4GHDgtKKhn2m72hN56/GkPKGkguP5NRS1qYYV\n" + - "/EFkdyQMOV8J1M7HaicSft4OL6eKjTrgo93+kHk+tv0Dc6cpVBnalX3TorG8QI6B\n" + - "cHj1XQd78oAlAC+/jF4pc0mwi0un49kdK9gRfQIDAQABoyMwITAfBgNVHSMEGDAW\n" + - "gBQN3ZPJ/ku9NbfomXiQ+9taPdsVTDANBgkqhkiG9w0BAQsFAAOCAQEApXS0nKwm\n" + - "Kp8gpmO2yG1rpd1+2wBABiMU4JZaTqmma24DQ3RzyS+V2TeRb29dl5oTUEm98uc0\n" + - "GPZvhK8z5RFr4YE17dc04nI/VaNDCw4y1NALXGs+AHkjoPjLyGbWpi1S+gfq2sNB\n" + - "Ekkjp6COb/cb9yiFXOGVls7UOIjnVZVd0r7KaPFjZhYh82/f4PA/A1SnIKd1+nfH\n" + - "2yk7mSJNC7Z3qIVDL8MM/jBVwiC3uNe5GPB2uwhd7k5LGAVN3j4HQQGB0Sz+VC1h\n" + - "92oi6xDa+YBva2fvHuCd8P50DDjxmp9CemC7rnZ5j8egj88w14X44Xjb/Fd/ApG9\n" + - "e57NnbT7KM+Grw==\n" + - "-----END CERTIFICATE-----", - - // SHA256withRSA, curv prime256v1 - // Validity - // Not Before: May 22 07:18:16 2018 GMT - // Not After : May 21 07:18:16 2028 GMT - // Authority Key Identifier: - // 0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C - "-----BEGIN CERTIFICATE-----\n" + - "MIICazCCAVOgAwIBAgIJAO2+yPcFryUUMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" + - "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" + - "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0yODA1MjEwNzE4MTZaMFUxCzAJBgNVBAYT\n" + - "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + - "ZTEYMBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0D\n" + - "AQcDQgAE59MERNTlVZ1eeps8Z3Oue5ZkgQdPtD+WIE6tj3PbIKpxGPDxvfNP959A\n" + - "yQjEK/ehWQVrCMmNoEkIzY+IIBgB06MjMCEwHwYDVR0jBBgwFoAUDd2Tyf5LvTW3\n" + - "6Jl4kPvbWj3bFUwwDQYJKoZIhvcNAQELBQADggEBAFOTVEqs70ykhZiIdrEsF1Ra\n" + - "I3B2rLvwXZk52uSltk2/bzVvewA577ZCoxQ1pL7ynkisPfBN1uVYtHjM1VA3RC+4\n" + - "+TAK78dnI7otYjWoHp5rvs4l6c/IbOspS290IlNuDUxMErEm5wxIwj+Aukx/1y68\n" + - "hOyCvHBLMY2c1LskH1MMBbDuS1aI+lnGpToi+MoYObxGcV458vxuT8+wwV8Fkpvd\n" + - "ll8IIFmeNPRv+1E+lXbES6CSNCVaZ/lFhPgdgYKleN7sfspiz50DG4dqafuEAaX5\n" + - "xaK1NWXJxTRz0ROH/IUziyuDW6jphrlgit4+3NCzp6vP9hAJQ8Vhcj0n15BKHIQ=\n" + - "-----END CERTIFICATE-----", - - // SHA256withDSA, 2048 bits - // Validity - // Not Before: May 22 07:18:20 2018 GMT - // Not After : May 17 07:18:20 2038 GMT - // Authority Key Identifier: - // 76:66:9E:F7:3B:DD:45:E5:3B:D9:72:3C:3F:F0:54:39:86:31:26:53 - "-----BEGIN CERTIFICATE-----\n" + - "MIIEnDCCBEGgAwIBAgIJAP/jh1qVhNVjMAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" + - "EwJVUzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2\n" + - "Y2UwHhcNMTgwNTIyMDcxODIwWhcNMzgwNTE3MDcxODIwWjBVMQswCQYDVQQGEwJV\n" + - "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Ux\n" + - "GDAWBgNVBAMMD1JlZ3Jlc3Npb24gVGVzdDCCA0cwggI6BgcqhkjOOAQBMIICLQKC\n" + - "AQEAmlavgoJrMcjqWRVcDE2dmWAPREgnzQvneEDef68cprDzjSwvOs5QeFyx75ib\n" + - "ado1e6jO/rW1prCGWHDD1oA/Tn4Pk3vu0nUxzvl1qATc+aJbpUU5Op0bvp6LbCsQ\n" + - "QslV9FeRh7Eb7bP6gpc/kHCBzEgC1VCK7prccXWy+t6SMOHbND3h+UbckfSaUuaV\n" + - "sVJNTD1D6GElfRj4Nmz1BGPfSYvKorwNZEU3gXwFgtDoAcGx7tcyClLpDHfqRfw/\n" + - "7yiqLyeiP7D4hl5lMNouJWDlAdMFp0FMgS3s9VDFinIcr6VtBWMTG7+4+czHAB+3\n" + - "fvrwlqNzhBn3uFHrekN/w8fNxwIhAJo7Sae1za7IMW0Q6hE5B4b+s2B/FaKPoA4E\n" + - "jtZu13B9AoIBAQCOZqLMKfvqZWUgT0PQ3QjR7dAFdd06I9Y3+TOQzZk1+j+vw/6E\n" + - "X4vFItX4gihb/u5Q9CdmpwhVGi7bvo+7+/IKeTgoQ6f5+PSug7SrWWUQ5sPwaZui\n" + - "zXZJ5nTeZDucFc2yFx0wgnjbPwiUxZklOT7xGiOMtzOTa2koCz5KuIBL+/wPKKxm\n" + - "ypo9VoY9xfbdU6LMXZv/lpD5XTM9rYHr/vUTNkukvV6Hpm0YMEWhVZKUJiqCqTqG\n" + - "XHaleOxSw6uQWB/+TznifcC7gB48UOQjCqOKf5VuwQneJLhlhU/jhRV3xtr+hLZa\n" + - "hW1wYhVi8cjLDrZFKlgEQqhB4crnJU0mJY+tA4IBBQACggEAID0ezl00/X8mv7eb\n" + - "bzovum1+DEEP7FM57k6HZEG2N3ve4CW+0m9Cd+cWPz8wkZ+M0j/Eqa6F0IdbkXEc\n" + - "Q7CuzvUyJ57xQ3L/WCgXsiS+Bh8O4Mz7GwW22CGmHqafbVv+hKBfr8MkskO6GJUt\n" + - "SUF/CVLzB4gMIvZMH26tBP2xK+i7FeEK9kT+nGdzQSZBAhFYpEVCBplHZO24/OYq\n" + - "1DNoU327nUuXIhmsfA8N0PjiWbIZIjTPwBGr9H0LpATI7DIDNcvRRvtROP+pBU9y\n" + - "fuykPkptg9C0rCM9t06bukpOSaEz/2VIQdLE8fHYFA6pHZ6CIc2+5cfvMgTPhcjz\n" + - "W2jCt6MjMCEwHwYDVR0jBBgwFoAUdmae9zvdReU72XI8P/BUOYYxJlMwCwYJYIZI\n" + - "AWUDBAMCA0gAMEUCIQCeI5fN08b9BpOaHdc3zQNGjp24FOL/RxlBLeBAorswJgIg\n" + - "JEZ8DhYxQy1O7mmZ2UIT7op6epWMB4dENjs0qWPmcKo=\n" + - "-----END CERTIFICATE-----" - }; - - // Private key in the format of PKCS#8. - final static String[] endEntityPrivateKeys = { - // - // EC private key related to cert endEntityCertStrs[0]. - // - "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgn5K03bpTLjEtFQRa\n" + - "JUtx22gtmGEvvSUSQdimhGthdtihRANCAARv72fTmp9ed8dRvTG1Ak1Lgl5KLoiM\n" + - "59bk2pyG8qd8l7L1WQnNHtAcu44RJ1/GVHurxghaCKHeJYsZ8H7DEeI6", - - // - // RSA private key related to cert endEntityCertStrs[1]. - // - "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzN8GhtZ9kinwC\n" + - "ALo+JYMNq8/rmZK+AJdQbEAJvFU0B+QuE1FA6weuJEHdfVDee870960LrAqW8T2O\n" + - "WcMOPsP7WPWvUIc7uazV+ryt9xBh2RqcO27gCUejy/5JJZfXowhcVFgOPZVUebI+\n" + - "2BuW1yDjMYC7BPvjoV0sj3i5eMmOrUg6v+/RUiXATk5FYfldz7lOP6gVYrQThrgY\n" + - "cOC0oqGfabvaE3nr8aQ8oaSC4/k1FLWphhX8QWR3JAw5XwnUzsdqJxJ+3g4vp4qN\n" + - "OuCj3f6QeT62/QNzpylUGdqVfdOisbxAjoFwePVdB3vygCUAL7+MXilzSbCLS6fj\n" + - "2R0r2BF9AgMBAAECggEASIkPkMCuw4WdTT44IwERus3IOIYOs2IP3BgEDyyvm4B6\n" + - "JP/iihDWKfA4zEl1Gqcni1RXMHswSglXra682J4kui02Ov+vzEeJIY37Ibn2YnP5\n" + - "ZjRT2s9GtI/S2o4hl8A/mQb2IMViFC+xKehTukhV4j5d6NPKk0XzLR7gcMjnYxwn\n" + - "l21fS6D2oM1xRG/di7sL+uLF8EXLRzfiWDNi12uQv4nwtxPKvuKhH6yzHt7YqMH0\n" + - "46pmDKDaxV4w1JdycjCb6NrCJOYZygoQobuZqOQ30UZoZsPJrtovkncFr1e+lNcO\n" + - "+aWDfOLCtTH046dEQh5oCShyXMybNlry/QHsOtHOwQKBgQDh2iIjs+FPpQy7Z3EX\n" + - "DGEvHYqPjrYO9an2KSRr1m9gzRlWYxKY46WmPKwjMerYtra0GP+TBHrgxsfO8tD2\n" + - "wUAII6sd1qup0a/Sutgf2JxVilLykd0+Ge4/Cs51tCdJ8EqDV2B6WhTewOY2EGvg\n" + - "JiKYkeNwgRX/9M9CFSAMAk0hUQKBgQDLJAartL3DoGUPjYtpJnfgGM23yAGl6G5r\n" + - "NSXDn80BiYIC1p0bG3N0xm3yAjqOtJAUj9jZbvDNbCe3GJfLARMr23legX4tRrgZ\n" + - "nEdKnAFKAKL01oM+A5/lHdkwaZI9yyv+hgSVdYzUjB8rDmzeVQzo1BT7vXypt2yV\n" + - "6O1OnUpCbQKBgA/0rzDChopv6KRcvHqaX0tK1P0rYeVQqb9ATNhpf9jg5Idb3HZ8\n" + - "rrk91BNwdVz2G5ZBpdynFl9G69rNAMJOCM4KZw5mmh4XOEq09Ivba8AHU7DbaTv3\n" + - "7QL7KnbaUWRB26HHzIMYVh0el6T+KADf8NXCiMTr+bfpfbL3dxoiF3zhAoGAbCJD\n" + - "Qse1dBs/cKYCHfkSOsI5T6kx52Tw0jS6Y4X/FOBjyqr/elyEexbdk8PH9Ar931Qr\n" + - "NKMvn8oA4iA/PRrXX7M2yi3YQrWwbkGYWYjtzrzEAdzmg+5eARKAeJrZ8/bg9l3U\n" + - "ttKaItJsDPlizn8rngy3FsJpR9aSAMK6/+wOiYkCgYEA1tZkI1rD1W9NYZtbI9BE\n" + - "qlJVFi2PBOJMKNuWdouPX3HLQ72GJSQff2BFzLTELjweVVJ0SvY4IipzpQOHQOBy\n" + - "5qh/p6izXJZh3IHtvwVBjHoEVplg1b2+I5e3jDCfqnwcQw82dW5SxOJMg1h/BD0I\n" + - "qAL3go42DYeYhu/WnECMeis=", - - // - // EC private key related to cert endEntityCertStrs[2]. - // - "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgGVc7hICpmp91jbYe\n" + - "nrr8nYHD37RZP3VENY+szuA7WjuhRANCAATn0wRE1OVVnV56mzxnc657lmSBB0+0\n" + - "P5YgTq2Pc9sgqnEY8PG980/3n0DJCMQr96FZBWsIyY2gSQjNj4ggGAHT", - - // - // DSA private key related to cert endEntityCertStrs[3]. - // - "MIICZQIBADCCAjoGByqGSM44BAEwggItAoIBAQCaVq+CgmsxyOpZFVwMTZ2ZYA9E\n" + - "SCfNC+d4QN5/rxymsPONLC86zlB4XLHvmJtp2jV7qM7+tbWmsIZYcMPWgD9Ofg+T\n" + - "e+7SdTHO+XWoBNz5olulRTk6nRu+notsKxBCyVX0V5GHsRvts/qClz+QcIHMSALV\n" + - "UIrumtxxdbL63pIw4ds0PeH5RtyR9JpS5pWxUk1MPUPoYSV9GPg2bPUEY99Ji8qi\n" + - "vA1kRTeBfAWC0OgBwbHu1zIKUukMd+pF/D/vKKovJ6I/sPiGXmUw2i4lYOUB0wWn\n" + - "QUyBLez1UMWKchyvpW0FYxMbv7j5zMcAH7d++vCWo3OEGfe4Uet6Q3/Dx83HAiEA\n" + - "mjtJp7XNrsgxbRDqETkHhv6zYH8Voo+gDgSO1m7XcH0CggEBAI5moswp++plZSBP\n" + - "Q9DdCNHt0AV13Toj1jf5M5DNmTX6P6/D/oRfi8Ui1fiCKFv+7lD0J2anCFUaLtu+\n" + - "j7v78gp5OChDp/n49K6DtKtZZRDmw/Bpm6LNdknmdN5kO5wVzbIXHTCCeNs/CJTF\n" + - "mSU5PvEaI4y3M5NraSgLPkq4gEv7/A8orGbKmj1Whj3F9t1Tosxdm/+WkPldMz2t\n" + - "gev+9RM2S6S9XoembRgwRaFVkpQmKoKpOoZcdqV47FLDq5BYH/5POeJ9wLuAHjxQ\n" + - "5CMKo4p/lW7BCd4kuGWFT+OFFXfG2v6EtlqFbXBiFWLxyMsOtkUqWARCqEHhyucl\n" + - "TSYlj60EIgIgLfA75+8KcKxdN8mr6gzGjQe7jPFGG42Ejhd7Q2F4wuw=" - }; - - // Private key algorithm of endEntityPrivateKeys. - final static String[] endEntityPrivateKeyAlgs = { - "EC", - "RSA", - "EC", - "DSA", - }; - - // Private key names of endEntityPrivateKeys. - static final String[] endEntityPrivateKeyNames = { - "ecdsa", - "rsa", - "ec-rsa", - "dsa", - }; + enum Cert { - /* - * Create an instance of SSLContext with the specified trust/key materials. - */ - private SSLContext createSSLContext( - KeyManager keyManager, - TrustManager trustManager, - ContextParameters params) throws Exception { + CA_ECDSA_SECP256R1( + "EC", + // SHA256withECDSA, curve secp256r1 + // Validity + // Not Before: May 22 07:18:16 2018 GMT + // Not After : May 17 07:18:16 2038 GMT + // Subject Key Identifier: + // 60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86 + "-----BEGIN CERTIFICATE-----\n" + + "MIIBvjCCAWOgAwIBAgIJAIvFG6GbTroCMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" + + "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + + "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYTAlVT\n" + + "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTBZ\n" + + "MBMGByqGSM49AgEGCCqGSM49AwEHA0IABBz1WeVb6gM2mh85z3QlvaB/l11b5h0v\n" + + "LIzmkC3DKlVukZT+ltH2Eq1oEkpXuf7QmbM0ibrUgtjsWH3mULfmcWmjUDBOMB0G\n" + + "A1UdDgQWBBRgz71z//oaMNKk7NNJcUbvGjWghjAfBgNVHSMEGDAWgBRgz71z//oa\n" + + "MNKk7NNJcUbvGjWghjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQCG\n" + + "6wluh1r2/T6L31mZXRKf9JxeSf9pIzoLj+8xQeUChQIhAJ09wAi1kV8yePLh2FD9\n" + + "2YEHlSQUAbwwqCDEVB5KxaqP\n" + + "-----END CERTIFICATE-----", + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/HcHdoLJCdq3haVd\n" + + "XZTSKP00YzM3xX97l98vGL/RI1KhRANCAAQc9VnlW+oDNpofOc90Jb2gf5ddW+Yd\n" + + "LyyM5pAtwypVbpGU/pbR9hKtaBJKV7n+0JmzNIm61ILY7Fh95lC35nFp"), - SSLContext context = SSLContext.getInstance(params.contextProtocol); - context.init( - new KeyManager[] { - keyManager - }, - new TrustManager[] { - trustManager - }, - null); + CA_ECDSA_SECP384R1( + "EC", + // SHA384withECDSA, curve secp384r1 + // Validity + // Not Before: Jun 24 08:15:06 2019 GMT + // Not After : Jun 19 08:15:06 2039 GMT + // Subject Key Identifier: + // 0a:93:a9:a0:bf:e7:d5:48:9d:4f:89:15:c6:51:98:80:05:51:4e:4e + "-----BEGIN CERTIFICATE-----\n" + + "MIICCDCCAY6gAwIBAgIUCpOpoL/n1UidT4kVxlGYgAVRTk4wCgYIKoZIzj0EAwMw\n" + + "OzELMAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0Ug\n" + + "VGVzdCBTZXJpdmNlMB4XDTE5MDYyNDA4MTUwNloXDTM5MDYxOTA4MTUwNlowOzEL\n" + + "MAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVz\n" + + "dCBTZXJpdmNlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAENVQN1wXWFdgC6u/dDdiC\n" + + "y+WtMTF66oL/0BSm+1ZqsogamzCryawOcHgiuXgWzx5CQ3LuOC+tDFyXpGfHuCvb\n" + + "dkzxPrP5n9NrR8/uRPe5l1KOUbchviU8z9cTP+LZxnZDo1MwUTAdBgNVHQ4EFgQU\n" + + "SktSFArR1p/5mXV0kyo0RxIVa/UwHwYDVR0jBBgwFoAUSktSFArR1p/5mXV0kyo0\n" + + "RxIVa/UwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjBZvoNmq3/v\n" + + "RD2gBTyvxjS9h0rsMRLHDnvul/KWngytwGPTOBo0Y8ixQXSjdKoc3rkCMQDkiNgx\n" + + "IDxuHedmrLQKIPnVcthTmwv7//jHiqGoKofwChMo2a1P+DQdhszmeHD/ARQ=\n" + + "-----END CERTIFICATE-----", + "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDChlbt0NF8oIKODSxn2\n" + + "WXCXuJm3z78LRkzYQS3Nx5NMjei5ytkFZz4qvD4XXMWlTEyhZANiAAQ1VA3XBdYV\n" + + "2ALq790N2ILL5a0xMXrqgv/QFKb7VmqyiBqbMKvJrA5weCK5eBbPHkJDcu44L60M\n" + + "XJekZ8e4K9t2TPE+s/mf02tHz+5E97mXUo5RtyG+JTzP1xM/4tnGdkM="), - return context; - } + CA_ECDSA_SECP521R1( + "EC", + // SHA512withECDSA, curve secp521r1 + // Validity + // Not Before: Jun 24 08:15:06 2019 GMT + // Not After : Jun 19 08:15:06 2039 GMT + // Subject Key Identifier: + // 25:ca:68:76:6d:29:17:9b:71:78:45:2d:d4:c6:e4:5d:fe:25:ff:90 + "-----BEGIN CERTIFICATE-----\n" + + "MIICUzCCAbSgAwIBAgIUJcpodm0pF5txeEUt1MbkXf4l/5AwCgYIKoZIzj0EAwQw\n" + + "OzELMAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0Ug\n" + + "VGVzdCBTZXJpdmNlMB4XDTE5MDYyNDA4MTUwNloXDTM5MDYxOTA4MTUwNlowOzEL\n" + + "MAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVz\n" + + "dCBTZXJpdmNlMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAmFD5VmB2MdyJ6k+E\n" + + "eP4JncrE65ySL07gVmFwnr8otOt3NtRAyzmviMNNXXjo5R5NqNjKP4pr92JjT0sO\n" + + "D65yngkBtH151Ev/fiKPLxkXL9GzfKdWHVhDX7Zg6DUydzukzZV2/dIyloAIqwlz\n" + + "QVKJqT7RypDufdng8hnE9YfKo6ypZiujUzBRMB0GA1UdDgQWBBRAIrxa7WqtqUCe\n" + + "HFuKREDC92spvTAfBgNVHSMEGDAWgBRAIrxa7WqtqUCeHFuKREDC92spvTAPBgNV\n" + + "HRMBAf8EBTADAQH/MAoGCCqGSM49BAMEA4GMADCBiAJCAe22iirZnODCmlpxcv57\n" + + "3g5BEE60C+dtYmTqR4DtFyDaTRQ5CFf4ZxvQPIbD+SXi5Cbrl6qtrZG0cjUihPkC\n" + + "Hi1hAkIAiEcO7nMPgQLny+GrciojfN+bZXME/dPz6KHBm/89f8Me+jawVnv6y+df\n" + + "2Sbafh1KV6ntWQtB4bK3MXV8Ym9Eg1I=\n" + + "-----END CERTIFICATE-----", + "MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAV8dZszV6+nLw3LeA\n" + + "Q+qLJLGaqyjlsQkaopCPcmoRdy1HX6AzB/YnKsPkHp/9DQN6A2JgUhFG5B0XvKSk\n" + + "BqNNuSGhgYkDgYYABACYUPlWYHYx3InqT4R4/gmdysTrnJIvTuBWYXCevyi063c2\n" + + "1EDLOa+Iw01deOjlHk2o2Mo/imv3YmNPSw4PrnKeCQG0fXnUS/9+Io8vGRcv0bN8\n" + + "p1YdWENftmDoNTJ3O6TNlXb90jKWgAirCXNBUompPtHKkO592eDyGcT1h8qjrKlm\n" + + "Kw=="), - /* - * Create an instance of KeyManager with the specified key materials. - */ - static KeyManager createKeyManager( - String[] keyMaterialCerts, - String[] keyMaterialKeys, - String[] keyMaterialKeyAlgs, - String[] keyMaterialKeyNames, - ContextParameters params) throws Exception { + CA_ECDSA_SECT283R1( + "EC", + // SHA1withECDSA, curve sect283r1 + // Validity + // Not Before: May 26 06:06:52 2020 GMT + // Not After : May 21 06:06:52 2040 GMT + // Subject Key Identifier: + // CF:A3:99:ED:4C:6E:04:41:09:21:31:33:B6:80:D5:A7:BF:2B:98:04 + "-----BEGIN CERTIFICATE-----\n" + + "MIIB8TCCAY+gAwIBAgIJANQFsBngZ3iMMAsGByqGSM49BAEFADBdMQswCQYDVQQG\n" + + "EwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNBMQ8wDQYDVQQKEwZPcmFjbGUx\n" + + "DzANBgNVBAsTBkpQR1NRRTESMBAGA1UEAxMJc2VjdDI4M3IxMB4XDTIwMDUyNjE4\n" + + "MDY1MloXDTQwMDUyMTE4MDY1MlowXTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNB\n" + + "MQswCQYDVQQHEwJTQTEPMA0GA1UEChMGT3JhY2xlMQ8wDQYDVQQLEwZKUEdTUUUx\n" + + "EjAQBgNVBAMTCXNlY3QyODNyMTBeMBAGByqGSM49AgEGBSuBBAARA0oABALatmDt\n" + + "QIhjpK4vJjv4GgC8CUH/VAWLUSQRU7yGGQ3NF8rVBARv0aehiII0nzjDVX5KrP/A\n" + + "w/DmW7q8PfEAIktuaA/tcKv/OKMyMDAwHQYDVR0OBBYEFM+jme1MbgRBCSExM7aA\n" + + "1ae/K5gEMA8GA1UdEwEB/wQFMAMBAf8wCwYHKoZIzj0EAQUAA08AMEwCJAGHsAP8\n" + + "HlcVqszra+fxq35juTxHJIfxTKIr7f54Ywtz7AJowgIkAxydv8g+dkuniOUAj0Xt\n" + + "FnGVp6HzKX5KM1zLpfqmix8ZPP/A\n" + + "-----END CERTIFICATE-----", + "MIGQAgEAMBAGByqGSM49AgEGBSuBBAARBHkwdwIBAQQkAdcyn/FxiNvuTsSgDehq\n" + + "SGFiTxAKNMMJfmsO6GHekzszFqjPoUwDSgAEAtq2YO1AiGOkri8mO/gaALwJQf9U\n" + + "BYtRJBFTvIYZDc0XytUEBG/Rp6GIgjSfOMNVfkqs/8DD8OZburw98QAiS25oD+1w\n" + + "q/84"), - char[] passphrase = "passphrase".toCharArray(); + CA_RSA_2048( + "RSA", + // SHA256withRSA, 2048 bits + // Validity + // Not Before: May 22 07:18:16 2018 GMT + // Not After : May 17 07:18:16 2038 GMT + // Subject Key Identifier: + // 0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C + "-----BEGIN CERTIFICATE-----\n" + + "MIIDSTCCAjGgAwIBAgIJAI4ZF3iy8zG+MA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" + + "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" + + "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYT\n" + + "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + + "ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALpMcY7aWieXDEM1/YJf\n" + + "JW27b4nRIFZyEYhEloyGsKTuQiiQjc8cqRZFNXe2vwziDB4IyTEl0Hjl5QF6ZaQE\n" + + "huPzzwvQm1pv64KrRXrmj3FisQK8B5OWLty9xp6xDqsaMRoyObLK+oIb20T5fSlE\n" + + "evmo1vYjnh8CX0Yzx5Gr5ye6YSEHQvYOWEws8ad17OlyToR2KMeC8w4qo6rs59pW\n" + + "g7Mxn9vo22ImDzrtAbTbXbCias3xlE0Bp0h5luyf+5U4UgksoL9B9r2oP4GrLNEV\n" + + "oJk57t8lwaR0upiv3CnS8LcJELpegZub5ggqLY8ZPYFQPjlK6IzLOm6rXPgZiZ3m\n" + + "RL0CAwEAAaNQME4wHQYDVR0OBBYEFA3dk8n+S701t+iZeJD721o92xVMMB8GA1Ud\n" + + "IwQYMBaAFA3dk8n+S701t+iZeJD721o92xVMMAwGA1UdEwQFMAMBAf8wDQYJKoZI\n" + + "hvcNAQELBQADggEBAJTRC3rKUUhVH07/1+stUungSYgpM08dY4utJq0BDk36BbmO\n" + + "0AnLDMbkwFdHEoqF6hQIfpm7SQTmXk0Fss6Eejm8ynYr6+EXiRAsaXOGOBCzF918\n" + + "/RuKOzqABfgSU4UBKECLM5bMfQTL60qx+HdbdVIpnikHZOFfmjCDVxoHsGyXc1LW\n" + + "Jhkht8IGOgc4PMGvyzTtRFjz01kvrVQZ75aN2E0GQv6dCxaEY0i3ypSzjUWAKqDh\n" + + "3e2OLwUSvumcdaxyCdZAOUsN6pDBQ+8VRG7KxnlRlY1SMEk46QgQYLbPDe/+W/yH\n" + + "ca4PejicPeh+9xRAwoTpiE2gulfT7Lm+fVM7Ruc=\n" + + "-----END CERTIFICATE-----", + "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC6THGO2lonlwxD\n" + + "Nf2CXyVtu2+J0SBWchGIRJaMhrCk7kIokI3PHKkWRTV3tr8M4gweCMkxJdB45eUB\n" + + "emWkBIbj888L0Jtab+uCq0V65o9xYrECvAeTli7cvcaesQ6rGjEaMjmyyvqCG9tE\n" + + "+X0pRHr5qNb2I54fAl9GM8eRq+cnumEhB0L2DlhMLPGndezpck6EdijHgvMOKqOq\n" + + "7OfaVoOzMZ/b6NtiJg867QG0212womrN8ZRNAadIeZbsn/uVOFIJLKC/Qfa9qD+B\n" + + "qyzRFaCZOe7fJcGkdLqYr9wp0vC3CRC6XoGbm+YIKi2PGT2BUD45SuiMyzpuq1z4\n" + + "GYmd5kS9AgMBAAECggEAFHSoU2MuWwJ+2jJnb5U66t2V1bAcuOE1g5zkWvG/G5z9\n" + + "rq6Qo5kmB8f5ovdx6tw3MGUOklLwnRXBG3RxDJ1iokz3AvkY1clMNsDPlDsUrQKF\n" + + "JSO4QUBQTPSZhnsyfR8XHSU+qJ8Y+ohMfzpVv95BEoCzebtXdVgxVegBlcEmVHo2\n" + + "kMmkRN+bYNsr8eb2r+b0EpyumS39ZgKYh09+cFb78y3T6IFMGcVJTP6nlGBFkmA/\n" + + "25pYeCF2tSki08qtMJZQAvKfw0Kviibk7ZxRbJqmc7B1yfnOEHP6ftjuvKl2+RP/\n" + + "+5P5f8CfIP6gtA0LwSzAqQX/hfIKrGV5j0pCqrD0kQKBgQDeNR6Xi4sXVq79lihO\n" + + "a1bSeV7r8yoQrS8x951uO+ox+UIZ1MsAULadl7zB/P0er92p198I9M/0Jth3KBuS\n" + + "zj45mucvpiiGvmQlMKMEfNq4nN7WHOu55kufPswQB2mR4J3xmwI+4fM/nl1zc82h\n" + + "De8JSazRldJXNhfx0RGFPmgzbwKBgQDWoVXrXLbCAn41oVnWB8vwY9wjt92ztDqJ\n" + + "HMFA/SUohjePep9UDq6ooHyAf/Lz6oE5NgeVpPfTDkgvrCFVKnaWdwALbYoKXT2W\n" + + "9FlyJox6eQzrtHAacj3HJooXWuXlphKSizntfxj3LtMR9BmrmRJOfK+SxNOVJzW2\n" + + "+MowT20EkwKBgHmpB8jdZBgxI7o//m2BI5Y1UZ1KE5vx1kc7VXzHXSBjYqeV9FeF\n" + + "2ZZLP9POWh/1Fh4pzTmwIDODGT2UPhSQy0zq3O0fwkyT7WzXRknsuiwd53u/dejg\n" + + "iEL2NPAJvulZ2+AuiHo5Z99LK8tMeidV46xoJDDUIMgTG+UQHNGhK5gNAoGAZn/S\n" + + "Cn7SgMC0CWSvBHnguULXZO9wH1wZAFYNLL44OqwuaIUFBh2k578M9kkke7woTmwx\n" + + "HxQTjmWpr6qimIuY6q6WBN8hJ2Xz/d1fwhYKzIp20zHuv5KDUlJjbFfqpsuy3u1C\n" + + "kts5zwI7pr1ObRbDGVyOdKcu7HI3QtR5qqyjwaUCgYABo7Wq6oHva/9V34+G3Goh\n" + + "63bYGUnRw2l5BD11yhQv8XzGGZFqZVincD8gltNThB0Dc/BI+qu3ky4YdgdZJZ7K\n" + + "z51GQGtaHEbrHS5caV79yQ8QGY5mUVH3E+VXSxuIqb6pZq2DH4sTAEFHyncddmOH\n" + + "zoXBInYwRG9KE/Bw5elhUw=="), - // Generate certificate from cert string. - CertificateFactory cf = CertificateFactory.getInstance("X.509"); + CA_RSA_512( // for DisabledShortRSAKeys test + "RSA", + // md5WithRSAEncryption, 1024 bits + // Validity + // Not Before: Aug 19 01:52:19 2011 GMT + // Not After : Jul 29 01:52:19 2032 GMT + // X509v3 Authority Key Identifier: + // keyid:B9:7C:D5:D9:DF:A7:4C:03:AE:FD:0E:27:5B:31:95:6C:C7:F3:75:E1 + // DirName:/C=US/O=Java/OU=SunJSSE Test Serivce + // serial:00 + "-----BEGIN CERTIFICATE-----\n" + + "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTEwODE5MDE1MjE5WhcNMzIwNzI5MDE1MjE5WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + + "KoZIhvcNAQEBBQADgY0AMIGJAoGBAM8orG08DtF98TMSscjGsidd1ZoN4jiDpi8U\n" + + "ICz+9dMm1qM1d7O2T+KH3/mxyox7Rc2ZVSCaUD0a3CkhPMnlAx8V4u0H+E9sqso6\n" + + "iDW3JpOyzMExvZiRgRG/3nvp55RMIUV4vEHOZ1QbhuqG4ebN0Vz2DkRft7+flthf\n" + + "vDld6f5JAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLl81dnfp0wDrv0OJ1sxlWzH83Xh\n" + + "MGMGA1UdIwRcMFqAFLl81dnfp0wDrv0OJ1sxlWzH83XhoT+kPTA7MQswCQYDVQQG\n" + + "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + + "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" + + "BQADgYEALlgaH1gWtoBZ84EW8Hu6YtGLQ/L9zIFmHonUPZwn3Pr//icR9Sqhc3/l\n" + + "pVTxOINuFHLRz4BBtEylzRIOPzK3tg8XwuLb1zd0db90x3KBCiAL6E6cklGEPwLe\n" + + "XYMHDn9eDsaq861Tzn6ZwzMgw04zotPMoZN0mVd/3Qca8UJFucE=\n" + + "-----END CERTIFICATE-----", + "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAtz2+PTkj3zg9hh0l\n" + + "xQhcdRiRGX6hvWVH+8biIv62uXS4zxgGqGOUBdkDmvFZzq4kAlw38lx8bLkZxDqJ\n" + + "sS+xFQIDAQABAkByx/5Oo2hQ/w2q4L8z+NTRlJ3vdl8iIDtC/4XPnfYfnGptnpG6\n" + + "ZThQRvbMZiai0xHQPQMszvAHjZVme1eDl3EBAiEA3aKJHynPVCEJhpfCLWuMwX5J\n" + + "1LntwJO7NTOyU5m8rPECIQDTpzn5X44r2rzWBDna/Sx7HW9IWCxNgUD2Eyi2nA7W\n" + + "ZQIgJerEorw4aCAuzQPxiGu57PB6GRamAihEAtoRTBQlH0ECIQDN08FgTtnesgCU\n" + + "DFYLLcw1CiHvc7fZw4neBDHCrC8NtQIgA8TOUkGnpCZlQ0KaI8KfKWI+vxFcgFnH\n" + + "3fnqsTgaUs4=" - // Import the key materials. - // - // Note that certification paths bigger than one are not supported yet. - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(null, null); - ByteArrayInputStream is; - for (int i = 0; i < keyMaterialCerts.length; i++) { - String keyCertStr = keyMaterialCerts[i]; - - // generate the private key. - PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - Base64.getMimeDecoder().decode(keyMaterialKeys[i])); - KeyFactory kf = - KeyFactory.getInstance(keyMaterialKeyAlgs[i]); - PrivateKey priKey = kf.generatePrivate(priKeySpec); - - // generate certificate chain - is = new ByteArrayInputStream(keyCertStr.getBytes()); - Certificate keyCert = null; - try { - keyCert = cf.generateCertificate(is); - } finally { - is.close(); - } + ), - Certificate[] chain = new Certificate[] { keyCert }; + CA_RSA_MD5_512 ( // for ShortRSAKeys512 and ShortRSAKeyGCM tests + "RSA", + // Signature Algorithm: md5WithRSAEncryption + // Issuer: C = US, O = Java, OU = SunJSSE Test Serivce + // Validity + // Not Before: Aug 19 01:52:19 2011 GMT + // Not After : Jul 29 01:52:19 2032 GMT + // Authority Key Identifier: + // B9:7C:D5:D9:DF:A7:4C:03:AE:FD:0E:27:5B:31:95:6C:C7:F3:75:E1 + "-----BEGIN CERTIFICATE-----\n" + + "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTEwODE5MDE1MjE5WhcNMzIwNzI5MDE1MjE5WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + + "KoZIhvcNAQEBBQADgY0AMIGJAoGBAM8orG08DtF98TMSscjGsidd1ZoN4jiDpi8U\n" + + "ICz+9dMm1qM1d7O2T+KH3/mxyox7Rc2ZVSCaUD0a3CkhPMnlAx8V4u0H+E9sqso6\n" + + "iDW3JpOyzMExvZiRgRG/3nvp55RMIUV4vEHOZ1QbhuqG4ebN0Vz2DkRft7+flthf\n" + + "vDld6f5JAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLl81dnfp0wDrv0OJ1sxlWzH83Xh\n" + + "MGMGA1UdIwRcMFqAFLl81dnfp0wDrv0OJ1sxlWzH83XhoT+kPTA7MQswCQYDVQQG\n" + + "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + + "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" + + "BQADgYEALlgaH1gWtoBZ84EW8Hu6YtGLQ/L9zIFmHonUPZwn3Pr//icR9Sqhc3/l\n" + + "pVTxOINuFHLRz4BBtEylzRIOPzK3tg8XwuLb1zd0db90x3KBCiAL6E6cklGEPwLe\n" + + "XYMHDn9eDsaq861Tzn6ZwzMgw04zotPMoZN0mVd/3Qca8UJFucE=\n" + + "-----END CERTIFICATE-----", + "" + ), - // import the key entry. - ks.setKeyEntry("cert-" + keyMaterialKeyNames[i], - priKey, passphrase, chain); - } + CA_DSA_2048( + "DSA", + // SHA256withDSA, 2048 bits + // Validity + // Not Before: May 22 07:18:18 2018 GMT + // Not After : May 17 07:18:18 2038 GMT + // Subject Key Identifier: + // 76:66:9E:F7:3B:DD:45:E5:3B:D9:72:3C:3F:F0:54:39:86:31:26:53 + "-----BEGIN CERTIFICATE-----\n" + + "MIIErjCCBFSgAwIBAgIJAOktYLNCbr02MAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" + + "EwJVUzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2\n" + + "Y2UwHhcNMTgwNTIyMDcxODE4WhcNMzgwNTE3MDcxODE4WjA7MQswCQYDVQQGEwJV\n" + + "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Uw\n" + + "ggNHMIICOQYHKoZIzjgEATCCAiwCggEBAO5GyPhSm0ze3LSu+gicdULLj05iOfTL\n" + + "UvZQ29sYz41zmqrLBQbdKiHqgJu2Re9sgTb5suLNjF047TOLPnU3jhPtWm2X8Xzi\n" + + "VGIcHym/Q/MeZxStt/88seqroI3WOKzIML2GcrishT+lcGrtH36Tf1+ue2Snn3PS\n" + + "WyxygNqPjllP5uUjYmFLvAf4QLMldkd/D2VxcwsHjB8y5iUZsXezc/LEhRZS/02m\n" + + "ivqlRw3AMkq/OVe/ZtxFWsP0nsfxEGdZuaUFpppGfixxFvymrB3+J51cTt+pZBDq\n" + + "D2y0DYfc+88iCs4jwHTfcDIpLb538HBjBj2rEgtQESQmB0ooD/+wsPsCIQC1bYch\n" + + "gElNtDYL3FgpLgNSUYp7gIWv9ehaC7LO2z7biQKCAQBitvFOnDkUja8NAF7lDpOV\n" + + "b5ipQ8SicBLW3kQamxhyuyxgZyy/PojZ/oPorkqW/T/A0rhnG6MssEpAtdiwVB+c\n" + + "rBYGo3bcwmExJhdOJ6dYuKFppPWhCwKMHs9npK+lqBMl8l5j58xlcFeC7ZfGf8GY\n" + + "GkhFW0c44vEQhMMbac6ZTTP4mw+1t7xJfmDMlLEyIpTXaAAk8uoVLWzQWnR40sHi\n" + + "ybvS0u3JxQkb7/y8tOOZu8qlz/YOS7lQ6UxUGX27Ce1E0+agfPphetoRAlS1cezq\n" + + "Wa7r64Ga0nkj1kwkcRqjgTiJx0NwnUXr78VAXFhVF95+O3lfqhvdtEGtkhDGPg7N\n" + + "A4IBBgACggEBAMmSHQK0w2i+iqUjOPzn0yNEZrzepLlLeQ1tqtn0xnlv5vBAeefD\n" + + "Pm9dd3tZOjufVWP7hhEz8xPobb1CS4e3vuQiv5UBfhdPL3f3l9T7JMAKPH6C9Vve\n" + + "OQXE5eGqbjsySbcmseHoYUt1WCSnSda1opX8zchX04e7DhGfE2/L9flpYEoSt8lI\n" + + "vMNjgOwvKdW3yvPt1/eBBHYNFG5gWPv/Q5KoyCtHS03uqGm4rNc/wZTIEEfd66C+\n" + + "QRaUltjOaHmtwOdDHaNqwhYZSVOip+Mo+TfyzHFREcdHLapo7ZXqbdYkRGxRR3d+\n" + + "3DfHaraJO0OKoYlPkr3JMvM/MSGR9AnZOcejUDBOMB0GA1UdDgQWBBR2Zp73O91F\n" + + "5TvZcjw/8FQ5hjEmUzAfBgNVHSMEGDAWgBR2Zp73O91F5TvZcjw/8FQ5hjEmUzAM\n" + + "BgNVHRMEBTADAQH/MAsGCWCGSAFlAwQDAgNHADBEAiBzriYE41M2y9Hy5ppkL0Qn\n" + + "dIlNc8JhXT/PHW7GDtViagIgMko8Qoj9gDGPK3+O9E8DC3wGiiF9CObM4LN387ok\n" + + "J+g=\n" + + "-----END CERTIFICATE-----", + "MIICZQIBADCCAjkGByqGSM44BAEwggIsAoIBAQDuRsj4UptM3ty0rvoInHVCy49O" + + "Yjn0y1L2UNvbGM+Nc5qqywUG3Soh6oCbtkXvbIE2+bLizYxdOO0ziz51N44T7Vpt" + + "l/F84lRiHB8pv0PzHmcUrbf/PLHqq6CN1jisyDC9hnK4rIU/pXBq7R9+k39frntk" + + "p59z0lsscoDaj45ZT+blI2JhS7wH+ECzJXZHfw9lcXMLB4wfMuYlGbF3s3PyxIUW" + + "Uv9Npor6pUcNwDJKvzlXv2bcRVrD9J7H8RBnWbmlBaaaRn4scRb8pqwd/iedXE7f" + + "qWQQ6g9stA2H3PvPIgrOI8B033AyKS2+d/BwYwY9qxILUBEkJgdKKA//sLD7AiEA" + + "tW2HIYBJTbQ2C9xYKS4DUlGKe4CFr/XoWguyzts+24kCggEAYrbxTpw5FI2vDQBe" + + "5Q6TlW+YqUPEonAS1t5EGpsYcrssYGcsvz6I2f6D6K5Klv0/wNK4ZxujLLBKQLXY" + + "sFQfnKwWBqN23MJhMSYXTienWLihaaT1oQsCjB7PZ6SvpagTJfJeY+fMZXBXgu2X" + + "xn/BmBpIRVtHOOLxEITDG2nOmU0z+JsPtbe8SX5gzJSxMiKU12gAJPLqFS1s0Fp0" + + "eNLB4sm70tLtycUJG+/8vLTjmbvKpc/2Dku5UOlMVBl9uwntRNPmoHz6YXraEQJU" + + "tXHs6lmu6+uBmtJ5I9ZMJHEao4E4icdDcJ1F6+/FQFxYVRfefjt5X6ob3bRBrZIQ" + + "xj4OzQQjAiEAsceWOM8do4etxp2zgnoNXV8PUUyqWhz1+0srcKV7FR4="), - KeyManagerFactory kmf = - KeyManagerFactory.getInstance(params.kmAlgorithm); - kmf.init(ks, passphrase); + EE_ECDSA_SECT283R1( + "EC", + // SHA1withECDSA, curve sect283r1 + // Validity + // Not Before: May 26 06:08:15 2020 GMT + // Not After : May 21 06:08:15 2040 GMT + // Authority Key Identifier: + // CF:A3:99:ED:4C:6E:04:41:09:21:31:33:B6:80:D5:A7:BF:2B:98:04 + "-----BEGIN CERTIFICATE-----\n" + + "MIICFTCCAbOgAwIBAgIJAM0Dd9zxR9CeMAsGByqGSM49BAEFADBdMQswCQYDVQQG\n" + + "EwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNBMQ8wDQYDVQQKEwZPcmFjbGUx\n" + + "DzANBgNVBAsTBkpQR1NRRTESMBAGA1UEAxMJc2VjdDI4M3IxMB4XDTIwMDUyNjE4\n" + + "MDgxNVoXDTQwMDUyMTE4MDgxNVowYDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNB\n" + + "MQswCQYDVQQHEwJTQTEPMA0GA1UEChMGT3JhY2xlMQ8wDQYDVQQLEwZKUEdTUUUx\n" + + "FTATBgNVBAMMDHNlY3QyODNyMV9lZTBeMBAGByqGSM49AgEGBSuBBAARA0oABAMP\n" + + "oaMP2lIiCrNaFSePtZA8nBnqJXSGCz8kosKeYTqz/SPE1AN6BvM4xl0kPQZvJWMz\n" + + "fyTcm2Ar0PdbIh8f22vJfO+0JpfhnqNTMFEwHQYDVR0OBBYEFOzDGNWQhslU5ei4\n" + + "SYda/ro9DickMA8GA1UdEwQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUz6OZ7UxuBEEJ\n" + + "ITEztoDVp78rmAQwCwYHKoZIzj0EAQUAA08AMEwCJALYBWSYdbhRiW4mNulQh6/v\n" + + "dfHG3y/oMjzJEmT/A0WYl96ohgIkAbDC0Ke632RXtCZ4xa2FrmzP41Vb80mSH1iY\n" + + "FCJ3LVoTEUgN\n" + + "-----END CERTIFICATE-----", + "MIGQAgEAMBAGByqGSM49AgEGBSuBBAARBHkwdwIBAQQkAXq9LPYU+XSrImPzgO1e\n" + + "hsgjfTBXlWGveFUtn0OHPtbp7hzpoUwDSgAEAw+how/aUiIKs1oVJ4+1kDycGeol\n" + + "dIYLPySiwp5hOrP9I8TUA3oG8zjGXSQ9Bm8lYzN/JNybYCvQ91siHx/ba8l877Qm\n" + + "l+Ge"), - KeyManager[] km = kmf.getKeyManagers(); + CA_DSA_512( + "DSA", + // dsaWithSHA1, 512 bits + // Validity + // Not Before: Feb 16 04:35:46 2016 GMT + // Not After : Nov 3 04:35:46 2035 GMT + // Authority Key Identifier: + // 5F:8A:9B:3F:93:E0:07:1D:49:F0:12:7C:A8:48:1F:A0:A5:4B:4A:74 + "-----BEGIN CERTIFICATE-----\n" + + "MIICUjCCAhGgAwIBAgIJAIiDrs/4W8rtMAkGByqGSM44BAMwHzELMAkGA1UEBhMC\n" + + "VVMxEDAOBgNVBAoTB0V4YW1wbGUwHhcNMTYwMjE2MDQzNTQ2WhcNMzUxMTAzMDQz\n" + + "NTQ2WjA5MQswCQYDVQQGEwJVUzEQMA4GA1UECgwHRXhhbXBsZTEYMBYGA1UEAwwP\n" + + "d3d3LmV4YW1wbGUuY29tMIHwMIGoBgcqhkjOOAQBMIGcAkEAs6A0p3TysTtVXGSv\n" + + "ThR/8GHpbL49KyWRJBMIlmLc5jl/wxJgnL1t07p4YTOEa6ecyTFos04Z8n2GARmp\n" + + "zYlUywIVAJLDcf4JXhZbguRFSQdWwWhZkh+LAkBLCzh3Xvpmc/5CDqU+QHqDcuSk\n" + + "5B8+ZHaHRi2KQ00ejilpF2qZpW5JdHe4m3Pggh0MIuaAGX+leM4JKlnObj14A0MA\n" + + "AkAYb+DYlFgStFhF1ip7rFzY8K6i/3ellkXI2umI/XVwxUQTHSlk5nFOep5Dfzm9\n" + + "pADJwuSe1qGHsHB5LpMZPVpto4GEMIGBMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgPo\n" + + "MB0GA1UdDgQWBBT8nsFyccF4q1dtpWE1dkNK5UiXtTAfBgNVHSMEGDAWgBRfips/\n" + + "k+AHHUnwEnyoSB+gpUtKdDAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" + + "CCsGAQUFBwMDMAkGByqGSM44BAMDMAAwLQIUIcIlxpIwaZXdpMC+U076unR1Mp8C\n" + + "FQCD/NE8O0xwq57nwFfp7tUvUHYMMA==\n" + + "-----END CERTIFICATE-----", + "MIHGAgEAMIGoBgcqhkjOOAQBMIGcAkEAs6A0p3TysTtVXGSvThR/8GHpbL49KyWR\n" + + "JBMIlmLc5jl/wxJgnL1t07p4YTOEa6ecyTFos04Z8n2GARmpzYlUywIVAJLDcf4J\n" + + "XhZbguRFSQdWwWhZkh+LAkBLCzh3Xvpmc/5CDqU+QHqDcuSk5B8+ZHaHRi2KQ00e\n" + + "jilpF2qZpW5JdHe4m3Pggh0MIuaAGX+leM4JKlnObj14BBYCFHB2Wek2g5hpNj5y\n" + + "RQfCc6CFO0dv" + ), - return km[0]; - } + CA_DSA_1024( + "DSA", + // dsaWithSHA1, 1024 bits + // Validity + // Not Before: Apr 24 12:25:43 2020 GMT + // Not After : Apr 22 12:25:43 2030 GMT + // Authority Key Identifier: + // E1:3C:01:52:EB:D1:38:F7:CF:F1:E3:5E:DB:54:75:7F:5E:AB:2D:36 + "-----BEGIN CERTIFICATE-----\n" + + "MIIC9TCCArWgAwIBAgIUd52yKk0OxQuxdaYRAfq5VLuF1ZAwCQYHKoZIzjgEAzAu\n" + + "MQswCQYDVQQGEwJVUzENMAsGA1UECgwESmF2YTEQMA4GA1UECwwHU3VuSlNTRTAe\n" + + "Fw0yMDA0MjQxMjI1NDJaFw0zMDA0MjIxMjI1NDJaMC4xCzAJBgNVBAYTAlVTMQ0w\n" + + "CwYDVQQKDARKYXZhMRAwDgYDVQQLDAdTdW5KU1NFMIIBtjCCASsGByqGSM44BAEw\n" + + "ggEeAoGBAKgyb2XpANq43T8yBf5v0PTBOddLPxd0f0FotASron5rQr86JjBTfgIW\n" + + "oE4u7nYlO6bp/M4Dw6qZr+HaDu9taIDOj6LL51eUShVsOgS7XZcUzLT8vPnkEDDo\n" + + "u326x0B7fuNCbMLm+ipM2d4FhLUTt4Qb5TcY6l7dOGHeWiL7nl43AhUAoGr8DY2m\n" + + "WHZPHk2XbZ5wpaM2lLcCgYBKiFbFFViH/ylHJRPtYtjtJw4ls1scbVP4TRHnKoZc\n" + + "HPAird1fDYgGC2b0GQNAMABhI+L+ogxS7qakySpJCheuN25AjiSyilygQdlXoWRt\n" + + "Mggsh8EQZT7iP4V4e9m3xRHzb5ECvsSTdZB1BQMcC90W2Avq+orqgBnr2in9UEd8\n" + + "qwOBhAACgYAgVWxjYWlWIv7s4BnNMQoPKppi205f3aC6wv6Rqk4BnYYYrFONEmzQ\n" + + "hzj6lSXfxLpTu4lg2zNeIraZggoS0ztkbZNNADEmAHx+OLshiJJxu2/KfoopJOZg\n" + + "8ARmuaKOkWbkW9y4hWhfBlVwZbckG3Eibff0xronIXXy7B7UKaccyqNTMFEwHQYD\n" + + "VR0OBBYEFOE8AVLr0Tj3z/HjXttUdX9eqy02MB8GA1UdIwQYMBaAFOE8AVLr0Tj3\n" + + "z/HjXttUdX9eqy02MA8GA1UdEwEB/wQFMAMBAf8wCQYHKoZIzjgEAwMvADAsAhRC\n" + + "YLduLniBEJ51SfBWIkvNW6OG7QIUSKaTY6rgEFDEMoTqOjFChR22nkk=\n" + + "-----END CERTIFICATE-----", + "MIIBSgIBADCCASsGByqGSM44BAEwggEeAoGBAKgyb2XpANq43T8yBf5v0PTBOddL\n" + + "Pxd0f0FotASron5rQr86JjBTfgIWoE4u7nYlO6bp/M4Dw6qZr+HaDu9taIDOj6LL\n" + + "51eUShVsOgS7XZcUzLT8vPnkEDDou326x0B7fuNCbMLm+ipM2d4FhLUTt4Qb5TcY\n" + + "6l7dOGHeWiL7nl43AhUAoGr8DY2mWHZPHk2XbZ5wpaM2lLcCgYBKiFbFFViH/ylH\n" + + "JRPtYtjtJw4ls1scbVP4TRHnKoZcHPAird1fDYgGC2b0GQNAMABhI+L+ogxS7qak\n" + + "ySpJCheuN25AjiSyilygQdlXoWRtMggsh8EQZT7iP4V4e9m3xRHzb5ECvsSTdZB1\n" + + "BQMcC90W2Avq+orqgBnr2in9UEd8qwQWAhQ7rSn+WvIxeuZ/CK4p04eMe5JzpA=="), - /* - * Create an instance of TrustManager with the specified trust materials. - */ - static TrustManager createTrustManager( - String[] trustedMaterials, - ContextParameters params) throws Exception { + CA_ED25519( + "EdDSA", + // ED25519 + // Validity + // Not Before: May 24 23:32:35 2020 GMT + // Not After : May 22 23:32:35 2030 GMT + // X509v3 Authority Key Identifier: + // keyid:06:76:DB:88:EB:61:55:4C:C9:63:41:C2:A0:A8:57:3F:D7:F1:B8:EC + "-----BEGIN CERTIFICATE-----\n" + + "MIIByTCCAXugAwIBAgIUCyxKvhErehsygx50JYArsHby9hAwBQYDK2VwMDsxCzAJ\n" + + "BgNVBAYTAlVTMQ0wCwYDVQQKDARqYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3Qg\n" + + "U2VyaXZjZTAeFw0yMDA1MjQyMzMyMzVaFw0zMDA1MjIyMzMyMzVaMDsxCzAJBgNV\n" + + "BAYTAlVTMQ0wCwYDVQQKDARqYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" + + "aXZjZTAqMAUGAytlcAMhAKdotuYIkH8PYbopSLbaf1BtqUY2d6AbTgK2prMzQ6B3\n" + + "o4GQMIGNMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAZ224jrYVVMyWNBwqCo\n" + + "Vz/X8bjsMB8GA1UdIwQYMBaAFAZ224jrYVVMyWNBwqCoVz/X8bjsMA4GA1UdDwEB\n" + + "/wQEAwIBhjAqBgNVHSUBAf8EIDAeBggrBgEFBQcDAwYIKwYBBQUHAwgGCCsGAQUF\n" + + "BwMJMAUGAytlcANBADVAArvME8xFigFhCCCOTBoy/4ldGkDZQ/GT3Q6xnAP558FU\n" + + "0G32OprKQZP43D9bmFU0LMgCVM9bHWU+bu/10AU=\n" + + "-----END CERTIFICATE-----", + "MC4CAQAwBQYDK2VwBCIEII/VYp8nu/eqq2L5y7/3IzavBgis4LWP6Rikv0N8SpgL"), - // Generate certificate from cert string. - CertificateFactory cf = CertificateFactory.getInstance("X.509"); + CA_ED448( + "EdDSA", + // ED448 + // Validity + // Not Before: May 24 23:23:43 2020 GMT + // Not After : May 22 23:23:43 2030 GMT + // X509v3 Authority Key Identifier: + // keyid:F5:D5:9D:FB:6F:B7:50:29:DF:F0:B8:83:10:5F:9B:C4:A8:1C:E9:F4 + "-----BEGIN CERTIFICATE-----\n" + + "MIICFDCCAZSgAwIBAgIUKcmLeKilq0LN40sniBJO7F1gb/owBQYDK2VxMDsxCzAJ\n" + + "BgNVBAYTAlVTMQ0wCwYDVQQKDARqYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3Qg\n" + + "U2VyaXZjZTAeFw0yMDA1MjQyMzIzNDNaFw0zMDA1MjIyMzIzNDNaMDsxCzAJBgNV\n" + + "BAYTAlVTMQ0wCwYDVQQKDARqYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" + + "aXZjZTBDMAUGAytlcQM6APYP8iSXS8xPVDike5RgCByfTtg4GGtpYfoBtt6G5szA\n" + + "55ExAKjm03wtk29nEPU2mCHF2QgfBzUrgKOBkDCBjTAPBgNVHRMBAf8EBTADAQH/\n" + + "MB0GA1UdDgQWBBT11Z37b7dQKd/wuIMQX5vEqBzp9DAfBgNVHSMEGDAWgBT11Z37\n" + + "b7dQKd/wuIMQX5vEqBzp9DAOBgNVHQ8BAf8EBAMCAYYwKgYDVR0lAQH/BCAwHgYI\n" + + "KwYBBQUHAwMGCCsGAQUFBwMIBggrBgEFBQcDCTAFBgMrZXEDcwAlRXA2gPb52yV3\n" + + "MKJErjmKlYSFExj5w5jafbbd0QgI1yDs+qSaZLjQ8ljwabmLDg+KR+167m0djQDI\n" + + "OOoVuL7bgM0RL836KnuuBzm+gTdPp0gCXy3k9lL0KA0V2YLJHXXzu3suu+7rdgoP\n" + + "plCh2hWdLgA=\n" + + "-----END CERTIFICATE-----", + "MEcCAQAwBQYDK2VxBDsEOd6/hRZqkUyTlJSwdN5gO/HnoWYda1fD83YUm5j6m2Bg\n" + + "hAQi+QadFsQLD7R6PI/4Q0twXqlKnxU5Ug=="), - // Import the trusted certs. - KeyStore ts = KeyStore.getInstance("PKCS12"); - ts.load(null, null); + CA_DSA_SHA1_1024( // for SignatureAlgorithms test + "DSA", + // Signature Algorithm: dsaWithSHA1 + // Validity + // Not Before: Dec 3 13:52:25 2015 GMT + // Not After : Nov 12 13:52:25 2036 GMT + // Authority Key Identifier: + // F5:EC:77:2A:2E:59:6C:AA:76:73:3F:E9:04:95:C1:9C:04:69:AE:6E + "-----BEGIN CERTIFICATE-----\n" + + "MIIDYTCCAyGgAwIBAgIJAK8/gw6zg/DPMAkGByqGSM44BAMwOzELMAkGA1UEBhMC\n" + + "VVMxDTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNl\n" + + "MB4XDTE1MTIwMzEzNTIyNVoXDTM2MTExMjEzNTIyNVowOzELMAkGA1UEBhMCVVMx\n" + + "DTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNlMIIB\n" + + "uDCCASwGByqGSM44BAEwggEfAoGBAPH+b+GSMX6KS7jXDRevzc464DFG4X+uxu5V\n" + + "b3U4yhsU8A8cuH4gwin6L/IDkmZQ7N0zC0jRsiGVSMsFETTq10F39pH2eBfUv/hJ\n" + + "cLfBnIjBEtVqV/dExK88Hul2sZ4mQihQ4issPl7hsroS9EWYicnX0oNAqAB9PO5Y\n" + + "zKbfpL7TAhUA13WW48rln2UP/LaAgtnzKhqcNtMCgYEA3Rv0GirTbAaor8iURd82\n" + + "b5FlDTevOCTuq7ZIpfZVV30neS7cBYNet6m/3/4cfUlbbrqhbqIJ2I+I81drnN0Y\n" + + "lyN4KkuxEcB6OTwfWkIUj6rvPaCQrBH8Q213bDq3HHtYNaP8OoeQUyVXW+SEGADC\n" + + "J1+z8uqP3lIB6ltdgOiV/GQDgYUAAoGBAOXRppuJSGdt6AiZkb81P1DCUgIUlZFI\n" + + "J9GxWrjbbHDmGllMwPNhK6dU7LJKJJuYVPW+95rUGlSJEjRqSlHuyHkNb6e3e7qx\n" + + "tmx1/oIyq+oLult50hBS7uBvLLR0JbIKjBzzkudL8Rjze4G/Wq7KDM2T1JOP49tW\n" + + "eocCvaC8h8uQo4GtMIGqMB0GA1UdDgQWBBT17HcqLllsqnZzP+kElcGcBGmubjBr\n" + + "BgNVHSMEZDBigBT17HcqLllsqnZzP+kElcGcBGmubqE/pD0wOzELMAkGA1UEBhMC\n" + + "VVMxDTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNl\n" + + "ggkArz+DDrOD8M8wDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwCQYHKoZI\n" + + "zjgEAwMvADAsAhQ6Y1I6LtIEBMqNo8o6GIe4LLEJuwIUbVQUKi8tvtWyRoxm8AFV\n" + + "0axJYUU=\n" + + "-----END CERTIFICATE-----", + "" + ), - Certificate[] trustedCert = - new Certificate[trustedMaterials.length]; - ByteArrayInputStream is; - for (int i = 0; i < trustedMaterials.length; i++) { - String trustedCertStr = trustedMaterials[i]; - - is = new ByteArrayInputStream(trustedCertStr.getBytes()); - try { - trustedCert[i] = cf.generateCertificate(is); - } finally { - is.close(); - } + CA_SHA1_RSA_2048( // for DHEKeySizing.java + "RSA", + // Signature Algorithm: sha1WithRSAEncryption + // Issuer: OU = SunJSSE Test Serivce, O = Java, C = US + // Validity + // Not Before: Sep 18 04:38:31 2013 GMT + // Not After : Dec 17 04:38:31 2013 GMT + "-----BEGIN CERTIFICATE-----\n" + + "MIIC8jCCAdqgAwIBAgIEUjkuRzANBgkqhkiG9w0BAQUFADA7MR0wGwYDVQQLExRT\n" + + "dW5KU1NFIFRlc3QgU2VyaXZjZTENMAsGA1UEChMESmF2YTELMAkGA1UEBhMCVVMw\n" + + "HhcNMTMwOTE4MDQzODMxWhcNMTMxMjE3MDQzODMxWjA7MR0wGwYDVQQLExRTdW5K\n" + + "U1NFIFRlc3QgU2VyaXZjZTENMAsGA1UEChMESmF2YTELMAkGA1UEBhMCVVMwggEi\n" + + "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCO+IGeaskJAvEcYc7pCl9neK3E\n" + + "a28fwWLtChufYNaC9hQfZlUdETWYjV7fZJVJKT/oLzdDNMWuVA0LKXArpI3thLNK\n" + + "QLXisdF9hKPlZRDazACL9kWUUtJ0FzpEySK4e8wW/z9FuU6e6iO19FbjxAfInJqk\n" + + "3EDiEhB5g73S2vtvPCxgq2DvWw9TDl/LIqdKG2JCS93koXCCaHmQ7MrIOqHPd+8r\n" + + "RbGpatXT9qyHKppUv9ATxVygO4rA794mgCFxpT+fkhz+NEB0twTkM65T1hnnOv5n\n" + + "ZIxkcjBggt85UlZtnP3b9P7SYxsWIa46Oc38Od2f3YejfVg6B+PqPgWNl3+/AgMB\n" + + "AAEwDQYJKoZIhvcNAQEFBQADggEBAAlrP6DFLRPSy0IgQhcI2i56tR/na8pezSte\n" + + "ZHcCdaCZPDy4UP8mpLJ9QCjEB5VJv8hPm4xdK7ULnKGOGHgYqDpV2ZHvQlhV1woQ\n" + + "TZGb/LM3c6kAs0j4j9KM2fq3iYUYexjIkS1KzsziflxMM6igS9BRMBR2LQyU+cYq\n" + + "YEsFzkF7Aj2ET4v/+tgot9mRr2NioJcaJkdsPDpMU3IKB1cczfu+OuLQ/GCG0Fqu\n" + + "6ijCeCqfnaAbemHbJeVZZ6Qgka3uC2YMntLBmLkhqEo1d9zGYLoh7oWL77y5ibQZ\n" + + "LK5/H/zikcu579TWjlDHcqL3arCwBcrtsjSaPrRSWMrWV/6c0qw=\n" + + "-----END CERTIFICATE-----", + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCO+IGeaskJAvEc\n" + + "Yc7pCl9neK3Ea28fwWLtChufYNaC9hQfZlUdETWYjV7fZJVJKT/oLzdDNMWuVA0L\n" + + "KXArpI3thLNKQLXisdF9hKPlZRDazACL9kWUUtJ0FzpEySK4e8wW/z9FuU6e6iO1\n" + + "9FbjxAfInJqk3EDiEhB5g73S2vtvPCxgq2DvWw9TDl/LIqdKG2JCS93koXCCaHmQ\n" + + "7MrIOqHPd+8rRbGpatXT9qyHKppUv9ATxVygO4rA794mgCFxpT+fkhz+NEB0twTk\n" + + "M65T1hnnOv5nZIxkcjBggt85UlZtnP3b9P7SYxsWIa46Oc38Od2f3YejfVg6B+Pq\n" + + "PgWNl3+/AgMBAAECggEAPdb5Ycc4m4A9QBSCRcRpzbyiFLKPh0HDg1n65q4hOtYr\n" + + "kAVYTVFTSF/lqGS+Ob3w2YIKujQKSUQrvCc5UHdFuHXMgxKIWbymK0+DAMb9SlYw\n" + + "6lkkcWp9gx9E4dnJ/df2SAAxovvrKMuHlL1SFASHhVtPfH2URvSfUaANLDXxyYOs\n" + + "8BX0Nr6wazhWjLjXo9yIGnKSvFfB8XisYcA78kEgas43zhmIGCDPqaYyyffOfRbx\n" + + "pM1KNwGmlN86iWR1CbwA/wwhcMySWQueS+s7cHbpRqZIYJF9jEeELiwi0vxjealS\n" + + "EMuHYedIRFMWaDIq9XyjrvXamHb0Z25jlXBNZHaM0QKBgQDE9adl+zAezR/n79vw\n" + + "0XiX2Fx1UEo3ApZHuoA2Q/PcBk+rlKqqQ3IwTcy6Wo648wK7v6Nq7w5nEWcsf0dU\n" + + "QA2Ng/AJEev/IfF34x7sKGYxtk1gcE0EuSBA3R+ocEZxnNw1Ryd5nUU24s8d4jCP\n" + + "Mkothnyaim+zE2raDlEtVc0CaQKBgQC509av+02Uq5oMjzbQp5PBJfQFjATOQT15\n" + + "eefYnVYurkQ1kcVfixkrO2ORhg4SjmI2Z5hJDgGtXdwgidpzkad+R2epS5qLMyno\n" + + "lQVpY6bMpEZ7Mos0yQygxnm8uNohEcTExOe+nP5fNJVpzBsGmfeyYOhnPQlf6oqf\n" + + "0cHizedb5wKBgQC/l5LyMil6HOGHlhzmIm3jj7VI7QR0hJC5T6N+phVml8ESUDjA\n" + + "DYHbmSKouISTRtkG14FY+RiSjCxH7bvuKazFV2289PETquogTA/9e8MFYqfcQwG4\n" + + "sXi9gBxWlnj/9a2EKiYtOB5nKLR/BlNkSHA93tAA6N+FXEMZwMmYhxk42QKBgAuY\n" + + "HQgD3PZOsqDf+qKQIhbmAFCsSMx5o5VFtuJ8BpmJA/Z3ruHkMuDQpsi4nX4o5hXQ\n" + + "5t6AAjjH52kcUMXvK40kdWJJtk3DFnVNfvXxYsHX6hHbuHXFqYUKfSP6QJnZmvZP\n" + + "9smcz/4usLfWJUWHK740b6upUkFqx9Vq5/b3s9y3AoGAdM5TW7LkkOFsdMGVAUzR\n" + + "9iXmCWElHTK2Pcp/3yqDBHSfiQx6Yp5ANyPnE9NBM0yauCfOyBB2oxLO4Rdv3Rqk\n" + + "9V9kyR/YAGr7dJaPcQ7pZX0OpkzgueAOJYPrx5VUzPYUtklYV1ycFZTfKlpFCxT+\n" + + "Ei6KUo0NXSdUIcB4yib1J10=" + ), - ts.setCertificateEntry("trusted-cert-" + i, trustedCert[i]); - } - // Create an SSLContext object. - TrustManagerFactory tmf = - TrustManagerFactory.getInstance(params.tmAlgorithm); - tmf.init(ts); + EE_DSA_SHA1_1024( // for SignatureAlgorithms test + "DSA", + // Signature Algorithm: dsaWithSHA1 + // Validity + // Not Before: Dec 3 13:52:25 2015 GMT + // Not After : Aug 20 13:52:25 2035 GMT + // Authority Key Identifier: + // F5:EC:77:2A:2E:59:6C:AA:76:73:3F:E9:04:95:C1:9C:04:69:AE:6E + "-----BEGIN CERTIFICATE-----\n" + + "MIIDKTCCAumgAwIBAgIJAOy5c0b+8stFMAkGByqGSM44BAMwOzELMAkGA1UEBhMC\n" + + "VVMxDTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNl\n" + + "MB4XDTE1MTIwMzEzNTIyNVoXDTM1MDgyMDEzNTIyNVowTzELMAkGA1UEBhMCVVMx\n" + + "DTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVzdCBTZXJpdmNlMRIw\n" + + "EAYDVQQDDAlsb2NhbGhvc3QwggG3MIIBLAYHKoZIzjgEATCCAR8CgYEA8f5v4ZIx\n" + + "fopLuNcNF6/NzjrgMUbhf67G7lVvdTjKGxTwDxy4fiDCKfov8gOSZlDs3TMLSNGy\n" + + "IZVIywURNOrXQXf2kfZ4F9S/+Elwt8GciMES1WpX90TErzwe6XaxniZCKFDiKyw+\n" + + "XuGyuhL0RZiJydfSg0CoAH087ljMpt+kvtMCFQDXdZbjyuWfZQ/8toCC2fMqGpw2\n" + + "0wKBgQDdG/QaKtNsBqivyJRF3zZvkWUNN684JO6rtkil9lVXfSd5LtwFg163qb/f\n" + + "/hx9SVtuuqFuognYj4jzV2uc3RiXI3gqS7ERwHo5PB9aQhSPqu89oJCsEfxDbXds\n" + + "Orcce1g1o/w6h5BTJVdb5IQYAMInX7Py6o/eUgHqW12A6JX8ZAOBhAACgYB+zYqn\n" + + "jJwG4GZpBIN/6qhzbp0flChsV+Trlu0SL0agAQzb6XdI/4JnO87Pgbxaxh3VNAj3\n" + + "3+Ghr1NLBuBfTKzJ4j9msWT3EpLupkMyNtXvBYM0iyMrll67lSjMdv++wLEw35Af\n" + + "/bzVcjGyA5Q0i0cuEzDmHTVfi0OydynbwSLxtKNjMGEwCwYDVR0PBAQDAgPoMB0G\n" + + "A1UdDgQWBBQXJI8AxM0qsYCbbkIMuI5zJ+nMEDAfBgNVHSMEGDAWgBT17HcqLlls\n" + + "qnZzP+kElcGcBGmubjASBgNVHREBAf8ECDAGhwR/AAABMAkGByqGSM44BAMDLwAw\n" + + "LAIUXgyJ0xll4FrZAKXi8bj7Kiz+SA4CFH9WCSZIBYA9lmJkiTgRS7iM/6IC\n" + + "-----END CERTIFICATE-----", + "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAPH+b+GSMX6KS7jXDRevzc464DFG\n" + + "4X+uxu5Vb3U4yhsU8A8cuH4gwin6L/IDkmZQ7N0zC0jRsiGVSMsFETTq10F39pH2\n" + + "eBfUv/hJcLfBnIjBEtVqV/dExK88Hul2sZ4mQihQ4issPl7hsroS9EWYicnX0oNA\n" + + "qAB9PO5YzKbfpL7TAhUA13WW48rln2UP/LaAgtnzKhqcNtMCgYEA3Rv0GirTbAao\n" + + "r8iURd82b5FlDTevOCTuq7ZIpfZVV30neS7cBYNet6m/3/4cfUlbbrqhbqIJ2I+I\n" + + "81drnN0YlyN4KkuxEcB6OTwfWkIUj6rvPaCQrBH8Q213bDq3HHtYNaP8OoeQUyVX\n" + + "W+SEGADCJ1+z8uqP3lIB6ltdgOiV/GQEFgIUOiB7J/lrFrNduQ8nDNTe8VspoAI=" + ), + + EE_DSA_SHA224_1024( // for SignatureAlgorithms test + "DSA", + // Signature Algorithm: dsa_with_SHA224 + // Validity + // Not Before: Dec 3 15:44:39 2015 GMT + // Not After : Aug 20 15:44:39 2035 GMT + // Authority Key Identifier: + // F5:EC:77:2A:2E:59:6C:AA:76:73:3F:E9:04:95:C1:9C:04:69:AE:6E + "-----BEGIN CERTIFICATE-----\n" + + "MIIDLzCCAuugAwIBAgIJAOy5c0b+8stGMAsGCWCGSAFlAwQDATA7MQswCQYDVQQG\n" + + "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + + "Y2UwHhcNMTUxMjAzMTU0NDM5WhcNMzUwODIwMTU0NDM5WjBPMQswCQYDVQQGEwJV\n" + + "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Ux\n" + + "EjAQBgNVBAMMCWxvY2FsaG9zdDCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQDx/m/h\n" + + "kjF+iku41w0Xr83OOuAxRuF/rsbuVW91OMobFPAPHLh+IMIp+i/yA5JmUOzdMwtI\n" + + "0bIhlUjLBRE06tdBd/aR9ngX1L/4SXC3wZyIwRLValf3RMSvPB7pdrGeJkIoUOIr\n" + + "LD5e4bK6EvRFmInJ19KDQKgAfTzuWMym36S+0wIVANd1luPK5Z9lD/y2gILZ8yoa\n" + + "nDbTAoGBAN0b9Boq02wGqK/IlEXfNm+RZQ03rzgk7qu2SKX2VVd9J3ku3AWDXrep\n" + + "v9/+HH1JW266oW6iCdiPiPNXa5zdGJcjeCpLsRHAejk8H1pCFI+q7z2gkKwR/ENt\n" + + "d2w6txx7WDWj/DqHkFMlV1vkhBgAwidfs/Lqj95SAepbXYDolfxkA4GEAAKBgA81\n" + + "CJKEv+pwiqYgxtw/9rkQ9748WP3mKrEC06kjUG+94/Z9dQloNFFfj6LiO1bymc5l\n" + + "6QIR8XCi4Po3N80K3+WxhBGFhY+RkVWTh43JV8epb41aH2qiWErarBwBGEh8LyGT\n" + + "i30db+Nkz2gfvyz9H/9T0jmYgfLEOlMCusali1qHo2MwYTALBgNVHQ8EBAMCA+gw\n" + + "HQYDVR0OBBYEFBqSP0S4+X+zOCTEnlp2hbAjV/W5MB8GA1UdIwQYMBaAFPXsdyou\n" + + "WWyqdnM/6QSVwZwEaa5uMBIGA1UdEQEB/wQIMAaHBH8AAAEwCwYJYIZIAWUDBAMB\n" + + "AzEAMC4CFQChiRaOnAnsCSJFwdpK22jSxU/mhQIVALgLbj/G39+1Ej8UuSWnEQyU\n" + + "4DA+\n" + + "-----END CERTIFICATE-----", + "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAPH+b+GSMX6KS7jXDRevzc464DFG\n" + + "4X+uxu5Vb3U4yhsU8A8cuH4gwin6L/IDkmZQ7N0zC0jRsiGVSMsFETTq10F39pH2\n" + + "eBfUv/hJcLfBnIjBEtVqV/dExK88Hul2sZ4mQihQ4issPl7hsroS9EWYicnX0oNA\n" + + "qAB9PO5YzKbfpL7TAhUA13WW48rln2UP/LaAgtnzKhqcNtMCgYEA3Rv0GirTbAao\n" + + "r8iURd82b5FlDTevOCTuq7ZIpfZVV30neS7cBYNet6m/3/4cfUlbbrqhbqIJ2I+I\n" + + "81drnN0YlyN4KkuxEcB6OTwfWkIUj6rvPaCQrBH8Q213bDq3HHtYNaP8OoeQUyVX\n" + + "W+SEGADCJ1+z8uqP3lIB6ltdgOiV/GQEFgIUOj9F5mxWd9W1tiLSdsOAt8BUBzE=" + ), + + EE_DSA_SHA256_1024( // for SignatureAlgorithms test + "DSA", + // Signature Algorithm: dsa_with_SHA256 + // Validity + // Not Before: Dec 3 15:46:51 2015 GMT + // Not After : Aug 20 15:46:51 2035 GMT + // Authority Key Identifier: + // F5:EC:77:2A:2E:59:6C:AA:76:73:3F:E9:04:95:C1:9C:04:69:AE:6E + "-----BEGIN CERTIFICATE-----\n" + + "MIIDLTCCAuugAwIBAgIJAOy5c0b+8stHMAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" + + "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + + "Y2UwHhcNMTUxMjAzMTU0NjUxWhcNMzUwODIwMTU0NjUxWjBPMQswCQYDVQQGEwJV\n" + + "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Ux\n" + + "EjAQBgNVBAMMCWxvY2FsaG9zdDCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQDx/m/h\n" + + "kjF+iku41w0Xr83OOuAxRuF/rsbuVW91OMobFPAPHLh+IMIp+i/yA5JmUOzdMwtI\n" + + "0bIhlUjLBRE06tdBd/aR9ngX1L/4SXC3wZyIwRLValf3RMSvPB7pdrGeJkIoUOIr\n" + + "LD5e4bK6EvRFmInJ19KDQKgAfTzuWMym36S+0wIVANd1luPK5Z9lD/y2gILZ8yoa\n" + + "nDbTAoGBAN0b9Boq02wGqK/IlEXfNm+RZQ03rzgk7qu2SKX2VVd9J3ku3AWDXrep\n" + + "v9/+HH1JW266oW6iCdiPiPNXa5zdGJcjeCpLsRHAejk8H1pCFI+q7z2gkKwR/ENt\n" + + "d2w6txx7WDWj/DqHkFMlV1vkhBgAwidfs/Lqj95SAepbXYDolfxkA4GEAAKBgEF7\n" + + "2qiYxGrjX4KCOy0k5nK/RYlgLy4gYDChihQpiaa+fbA5JOBOxPWsh7rdtmJuDrEJ\n" + + "keacU223+DIhOKC49fa+EvhLNqo6U1oPn8n/yvBsvvnWkcynw5KfNzaLlaPmzugh\n" + + "v9xl/GhyZNAXc1QUcW3C+ceHVNrKnkfbTKZz5eRSo2MwYTALBgNVHQ8EBAMCA+gw\n" + + "HQYDVR0OBBYEFNMkPrt40oO9Dpy+bcbQdEvOlNlyMB8GA1UdIwQYMBaAFPXsdyou\n" + + "WWyqdnM/6QSVwZwEaa5uMBIGA1UdEQEB/wQIMAaHBH8AAAEwCwYJYIZIAWUDBAMC\n" + + "Ay8AMCwCFCvA2QiKSe/n+6GqSYQwgQ/zL5M9AhQfSiuWdMJKWpgPJKakvzhBUbMb\n" + + "vA==\n" + + "-----END CERTIFICATE-----", + "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAPH+b+GSMX6KS7jXDRevzc464DFG\n" + + "4X+uxu5Vb3U4yhsU8A8cuH4gwin6L/IDkmZQ7N0zC0jRsiGVSMsFETTq10F39pH2\n" + + "eBfUv/hJcLfBnIjBEtVqV/dExK88Hul2sZ4mQihQ4issPl7hsroS9EWYicnX0oNA\n" + + "qAB9PO5YzKbfpL7TAhUA13WW48rln2UP/LaAgtnzKhqcNtMCgYEA3Rv0GirTbAao\n" + + "r8iURd82b5FlDTevOCTuq7ZIpfZVV30neS7cBYNet6m/3/4cfUlbbrqhbqIJ2I+I\n" + + "81drnN0YlyN4KkuxEcB6OTwfWkIUj6rvPaCQrBH8Q213bDq3HHtYNaP8OoeQUyVX\n" + + "W+SEGADCJ1+z8uqP3lIB6ltdgOiV/GQEFgIUQ2WGgg+OO39Aujj0e4lM4pP4/9g=" + ), + + EE_RSA_MD5_512 ( // for ShortRSAKeys512 and ShortRSAKeyGCM tests + "RSA", + // md5WithRSAEncryption + // Validity + // Not Before: Nov 7 13:55:52 2011 GMT + // Not After : Jul 25 13:55:52 2031 GMT + // Authority Key Identifier: + // B9:7C:D5:D9:DF:A7:4C:03:AE:FD:0E:27:5B:31:95:6C:C7:F3:75:E1 + "-----BEGIN CERTIFICATE-----\n" + + "MIICNDCCAZ2gAwIBAgIBDDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTExMTA3MTM1NTUyWhcNMzEwNzI1MTM1NTUyWjBPMQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" + + "BAMTCWxvY2FsaG9zdDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC3Pb49OSPfOD2G\n" + + "HSXFCFx1GJEZfqG9ZUf7xuIi/ra5dLjPGAaoY5QF2QOa8VnOriQCXDfyXHxsuRnE\n" + + "OomxL7EVAgMBAAGjeDB2MAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUXNCJK3/dtCIc\n" + + "xb+zlA/JINlvs/MwHwYDVR0jBBgwFoAUuXzV2d+nTAOu/Q4nWzGVbMfzdeEwJwYD\n" + + "VR0lBCAwHgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAzANBgkqhkiG9w0B\n" + + "AQQFAAOBgQB2qIDUxA2caMPpGtUACZAPRUtrGssCINIfItETXJZCx/cRuZ5sP4D9\n" + + "N1acoNDn0hCULe3lhXAeTC9NZ97680yJzregQMV5wATjo1FGsKY30Ma+sc/nfzQW\n" + + "+h/7RhYtoG0OTsiaDCvyhI6swkNJzSzrAccPY4+ZgU8HiDLzZTmM3Q==\n" + + "-----END CERTIFICATE-----", + "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAtz2+PTkj3zg9hh0l\n" + + "xQhcdRiRGX6hvWVH+8biIv62uXS4zxgGqGOUBdkDmvFZzq4kAlw38lx8bLkZxDqJ\n" + + "sS+xFQIDAQABAkByx/5Oo2hQ/w2q4L8z+NTRlJ3vdl8iIDtC/4XPnfYfnGptnpG6\n" + + "ZThQRvbMZiai0xHQPQMszvAHjZVme1eDl3EBAiEA3aKJHynPVCEJhpfCLWuMwX5J\n" + + "1LntwJO7NTOyU5m8rPECIQDTpzn5X44r2rzWBDna/Sx7HW9IWCxNgUD2Eyi2nA7W\n" + + "ZQIgJerEorw4aCAuzQPxiGu57PB6GRamAihEAtoRTBQlH0ECIQDN08FgTtnesgCU\n" + + "DFYLLcw1CiHvc7fZw4neBDHCrC8NtQIgA8TOUkGnpCZlQ0KaI8KfKWI+vxFcgFnH\n" + + "3fnqsTgaUs4=" + ), - TrustManager[] tms = tmf.getTrustManagers(); - return tms[0]; + EE_ECDSA_SECP256R1( + "EC", + // SHA256withECDSA, curve secp256r1 + // Validity + // Not Before: May 22 07:18:16 2018 GMT + // Not After : May 17 07:18:16 2038 GMT + // Authority Key Identifier: + // 60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86 + "-----BEGIN CERTIFICATE-----\n" + + "MIIBqjCCAVCgAwIBAgIJAPLY8qZjgNRAMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" + + "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + + "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYTAlVT\n" + + "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTEY\n" + + "MBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\n" + + "QgAEb+9n05qfXnfHUb0xtQJNS4JeSi6IjOfW5NqchvKnfJey9VkJzR7QHLuOESdf\n" + + "xlR7q8YIWgih3iWLGfB+wxHiOqMjMCEwHwYDVR0jBBgwFoAUYM+9c//6GjDSpOzT\n" + + "SXFG7xo1oIYwCgYIKoZIzj0EAwIDSAAwRQIgWpRegWXMheiD3qFdd8kMdrkLxRbq\n" + + "1zj8nQMEwFTUjjQCIQDRIrAjZX+YXHN9b0SoWWLPUq0HmiFIi8RwMnO//wJIGQ==\n" + + "-----END CERTIFICATE-----", + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgn5K03bpTLjEtFQRa\n" + + "JUtx22gtmGEvvSUSQdimhGthdtihRANCAARv72fTmp9ed8dRvTG1Ak1Lgl5KLoiM\n" + + "59bk2pyG8qd8l7L1WQnNHtAcu44RJ1/GVHurxghaCKHeJYsZ8H7DEeI6"), + + EE_ECDSA_SECP384R1( + "EC", + // SHA384withECDSA, curve secp384r1 + // Validity + // Not Before: Jun 24 08:15:06 2019 GMT + // Not After : Jun 19 08:15:06 2039 GMT + // Authority Key Identifier: + // 40:2D:AA:EE:66:AA:33:27:AD:9B:5D:52:9B:60:67:6A:2B:AD:52:D2 + "-----BEGIN CERTIFICATE-----\n" + + "MIICEjCCAZegAwIBAgIUS3F0AqAXWRg07CnbknJzxofyBQMwCgYIKoZIzj0EAwMw\n" + + "OzELMAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0Ug\n" + + "VGVzdCBTZXJpdmNlMB4XDTE5MDYyNDA4MTUwNloXDTM5MDYxOTA4MTUwNlowVTEL\n" + + "MAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVz\n" + + "dCBTZXJpdmNlMRgwFgYDVQQDDA9SZWdyZXNzaW9uIFRlc3QwdjAQBgcqhkjOPQIB\n" + + "BgUrgQQAIgNiAARqElz8b6T07eyKomIinhztV3/3XBk9bKGtJ0W+JOltjuhMmP/w\n" + + "G8ASSevpgqgpi6EzpBZaaJxE3zNfkNnxXOZmQi2Ypd1uK0zRdbEOKg0XOcTTZwEj\n" + + "iLjYmt3O0pwpklijQjBAMB0GA1UdDgQWBBRALaruZqozJ62bXVKbYGdqK61S0jAf\n" + + "BgNVHSMEGDAWgBRKS1IUCtHWn/mZdXSTKjRHEhVr9TAKBggqhkjOPQQDAwNpADBm\n" + + "AjEArVDFKf48xijN6huVUJzKCOP0zlWB5Js+DItIkZmLQuhciPLhLIB/rChf3Y4C\n" + + "xuP4AjEAmfLhQRI0O3pifpYzYSVh2G7/jHNG4eO+2dvgAcU+Lh2IIj/cpLaPFSvL\n" + + "J8FXY9Nj\n" + + "-----END CERTIFICATE-----", + "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDASuI9EtK29APXPipkc\n" + + "qDA+qwlewMjv/OcjUJ77kP1Vz62oVF9iY9SRIyFIUju8wt+hZANiAARqElz8b6T0\n" + + "7eyKomIinhztV3/3XBk9bKGtJ0W+JOltjuhMmP/wG8ASSevpgqgpi6EzpBZaaJxE\n" + + "3zNfkNnxXOZmQi2Ypd1uK0zRdbEOKg0XOcTTZwEjiLjYmt3O0pwpklg="), + + EE_ECDSA_SECP521R1( + "EC", + // SHA512withECDSA, curve secp521r1 + // Validity + // Not Before: Jun 24 08:15:06 2019 GMT + // Not After : Jun 19 08:15:06 2039 GMT + // Authority Key Identifier: + // 7B:AA:79:A4:49:DD:59:34:F0:86:6C:51:C7:30:F4:CE:C5:81:8A:28 + "-----BEGIN CERTIFICATE-----\n" + + "MIICXDCCAb2gAwIBAgIUck4QTsbHNqUfPxfGPJLYbedFPdswCgYIKoZIzj0EAwQw\n" + + "OzELMAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0Ug\n" + + "VGVzdCBTZXJpdmNlMB4XDTE5MDYyNDA4MTUwNloXDTM5MDYxOTA4MTUwNlowVTEL\n" + + "MAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVz\n" + + "dCBTZXJpdmNlMRgwFgYDVQQDDA9SZWdyZXNzaW9uIFRlc3QwgZswEAYHKoZIzj0C\n" + + "AQYFK4EEACMDgYYABAGa2zDLhYQHHCLI3YBqFYJTzrnDIjzwXrxhcRTS8DYkcrjZ\n" + + "+Fih1YyNhix0sdjH+3EqElXAHHuVzn3n3hPOtQCWlQCICkErB34S0cvmtRkeW8Fi\n" + + "hrR5tvJEzEZjPSgwn81kKyhV2L70je6i7Cw884Va8bODckpgw0vTmbQb7T9dupkv\n" + + "1aNCMEAwHQYDVR0OBBYEFHuqeaRJ3Vk08IZsUccw9M7FgYooMB8GA1UdIwQYMBaA\n" + + "FEAivFrtaq2pQJ4cW4pEQML3aym9MAoGCCqGSM49BAMEA4GMADCBiAJCAb33KHdY\n" + + "WDbusORWoY8Euglpd5zsF15hJsk7wtpD5HST1/NWmdCx405w+TV6a9Gr4VPHeaIQ\n" + + "99i/+f237ALL5p6IAkIBbwwFL1vt3c/bx+niyuffQPNjly80rdC9puqAqriSiboS\n" + + "efhxjidJ9HLaIRCMEPyd6vAsC8mO8YvL1uCuEQLsiGM=\n" + + "-----END CERTIFICATE-----", + "MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIB8C/2OX2Dt9vFszzV\n" + + "hcAe0CbkMlvu9uQ/L7Vz88heuIj0rUZIPGshvgIJt1hCMT8HZxYHvDa4lbUvqjFB\n" + + "+zafvPWhgYkDgYYABAGa2zDLhYQHHCLI3YBqFYJTzrnDIjzwXrxhcRTS8DYkcrjZ\n" + + "+Fih1YyNhix0sdjH+3EqElXAHHuVzn3n3hPOtQCWlQCICkErB34S0cvmtRkeW8Fi\n" + + "hrR5tvJEzEZjPSgwn81kKyhV2L70je6i7Cw884Va8bODckpgw0vTmbQb7T9dupkv\n" + + "1Q=="), + + EE_RSA_2048( + "RSA", + // SHA256withRSA, 2048 bits + // Validity + // Not Before: May 22 07:18:16 2018 GMT + // Not After : May 17 07:18:16 2038 GMT + // Authority Key Identifier: + // 0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C + "-----BEGIN CERTIFICATE-----\n" + + "MIIDNjCCAh6gAwIBAgIJAO2+yPcFryUTMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" + + "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" + + "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYT\n" + + "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + + "ZTEYMBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOC\n" + + "AQ8AMIIBCgKCAQEAszfBobWfZIp8AgC6PiWDDavP65mSvgCXUGxACbxVNAfkLhNR\n" + + "QOsHriRB3X1Q3nvO9PetC6wKlvE9jlnDDj7D+1j1r1CHO7ms1fq8rfcQYdkanDtu\n" + + "4AlHo8v+SSWX16MIXFRYDj2VVHmyPtgbltcg4zGAuwT746FdLI94uXjJjq1IOr/v\n" + + "0VIlwE5ORWH5Xc+5Tj+oFWK0E4a4GHDgtKKhn2m72hN56/GkPKGkguP5NRS1qYYV\n" + + "/EFkdyQMOV8J1M7HaicSft4OL6eKjTrgo93+kHk+tv0Dc6cpVBnalX3TorG8QI6B\n" + + "cHj1XQd78oAlAC+/jF4pc0mwi0un49kdK9gRfQIDAQABoyMwITAfBgNVHSMEGDAW\n" + + "gBQN3ZPJ/ku9NbfomXiQ+9taPdsVTDANBgkqhkiG9w0BAQsFAAOCAQEApXS0nKwm\n" + + "Kp8gpmO2yG1rpd1+2wBABiMU4JZaTqmma24DQ3RzyS+V2TeRb29dl5oTUEm98uc0\n" + + "GPZvhK8z5RFr4YE17dc04nI/VaNDCw4y1NALXGs+AHkjoPjLyGbWpi1S+gfq2sNB\n" + + "Ekkjp6COb/cb9yiFXOGVls7UOIjnVZVd0r7KaPFjZhYh82/f4PA/A1SnIKd1+nfH\n" + + "2yk7mSJNC7Z3qIVDL8MM/jBVwiC3uNe5GPB2uwhd7k5LGAVN3j4HQQGB0Sz+VC1h\n" + + "92oi6xDa+YBva2fvHuCd8P50DDjxmp9CemC7rnZ5j8egj88w14X44Xjb/Fd/ApG9\n" + + "e57NnbT7KM+Grw==\n" + + "-----END CERTIFICATE-----", + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzN8GhtZ9kinwC\n" + + "ALo+JYMNq8/rmZK+AJdQbEAJvFU0B+QuE1FA6weuJEHdfVDee870960LrAqW8T2O\n" + + "WcMOPsP7WPWvUIc7uazV+ryt9xBh2RqcO27gCUejy/5JJZfXowhcVFgOPZVUebI+\n" + + "2BuW1yDjMYC7BPvjoV0sj3i5eMmOrUg6v+/RUiXATk5FYfldz7lOP6gVYrQThrgY\n" + + "cOC0oqGfabvaE3nr8aQ8oaSC4/k1FLWphhX8QWR3JAw5XwnUzsdqJxJ+3g4vp4qN\n" + + "OuCj3f6QeT62/QNzpylUGdqVfdOisbxAjoFwePVdB3vygCUAL7+MXilzSbCLS6fj\n" + + "2R0r2BF9AgMBAAECggEASIkPkMCuw4WdTT44IwERus3IOIYOs2IP3BgEDyyvm4B6\n" + + "JP/iihDWKfA4zEl1Gqcni1RXMHswSglXra682J4kui02Ov+vzEeJIY37Ibn2YnP5\n" + + "ZjRT2s9GtI/S2o4hl8A/mQb2IMViFC+xKehTukhV4j5d6NPKk0XzLR7gcMjnYxwn\n" + + "l21fS6D2oM1xRG/di7sL+uLF8EXLRzfiWDNi12uQv4nwtxPKvuKhH6yzHt7YqMH0\n" + + "46pmDKDaxV4w1JdycjCb6NrCJOYZygoQobuZqOQ30UZoZsPJrtovkncFr1e+lNcO\n" + + "+aWDfOLCtTH046dEQh5oCShyXMybNlry/QHsOtHOwQKBgQDh2iIjs+FPpQy7Z3EX\n" + + "DGEvHYqPjrYO9an2KSRr1m9gzRlWYxKY46WmPKwjMerYtra0GP+TBHrgxsfO8tD2\n" + + "wUAII6sd1qup0a/Sutgf2JxVilLykd0+Ge4/Cs51tCdJ8EqDV2B6WhTewOY2EGvg\n" + + "JiKYkeNwgRX/9M9CFSAMAk0hUQKBgQDLJAartL3DoGUPjYtpJnfgGM23yAGl6G5r\n" + + "NSXDn80BiYIC1p0bG3N0xm3yAjqOtJAUj9jZbvDNbCe3GJfLARMr23legX4tRrgZ\n" + + "nEdKnAFKAKL01oM+A5/lHdkwaZI9yyv+hgSVdYzUjB8rDmzeVQzo1BT7vXypt2yV\n" + + "6O1OnUpCbQKBgA/0rzDChopv6KRcvHqaX0tK1P0rYeVQqb9ATNhpf9jg5Idb3HZ8\n" + + "rrk91BNwdVz2G5ZBpdynFl9G69rNAMJOCM4KZw5mmh4XOEq09Ivba8AHU7DbaTv3\n" + + "7QL7KnbaUWRB26HHzIMYVh0el6T+KADf8NXCiMTr+bfpfbL3dxoiF3zhAoGAbCJD\n" + + "Qse1dBs/cKYCHfkSOsI5T6kx52Tw0jS6Y4X/FOBjyqr/elyEexbdk8PH9Ar931Qr\n" + + "NKMvn8oA4iA/PRrXX7M2yi3YQrWwbkGYWYjtzrzEAdzmg+5eARKAeJrZ8/bg9l3U\n" + + "ttKaItJsDPlizn8rngy3FsJpR9aSAMK6/+wOiYkCgYEA1tZkI1rD1W9NYZtbI9BE\n" + + "qlJVFi2PBOJMKNuWdouPX3HLQ72GJSQff2BFzLTELjweVVJ0SvY4IipzpQOHQOBy\n" + + "5qh/p6izXJZh3IHtvwVBjHoEVplg1b2+I5e3jDCfqnwcQw82dW5SxOJMg1h/BD0I\n" + + "qAL3go42DYeYhu/WnECMeis="), + + EE_EC_RSA_SECP256R1( + "EC", + // SHA256withRSA, curve secp256r1 + // Validity + // Not Before: May 22 07:18:16 2018 GMT + // Not After : May 21 07:18:16 2028 GMT + // Authority Key Identifier: + // 0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C + "-----BEGIN CERTIFICATE-----\n" + + "MIICazCCAVOgAwIBAgIJAO2+yPcFryUUMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" + + "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" + + "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0yODA1MjEwNzE4MTZaMFUxCzAJBgNVBAYT\n" + + "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + + "ZTEYMBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0D\n" + + "AQcDQgAE59MERNTlVZ1eeps8Z3Oue5ZkgQdPtD+WIE6tj3PbIKpxGPDxvfNP959A\n" + + "yQjEK/ehWQVrCMmNoEkIzY+IIBgB06MjMCEwHwYDVR0jBBgwFoAUDd2Tyf5LvTW3\n" + + "6Jl4kPvbWj3bFUwwDQYJKoZIhvcNAQELBQADggEBAFOTVEqs70ykhZiIdrEsF1Ra\n" + + "I3B2rLvwXZk52uSltk2/bzVvewA577ZCoxQ1pL7ynkisPfBN1uVYtHjM1VA3RC+4\n" + + "+TAK78dnI7otYjWoHp5rvs4l6c/IbOspS290IlNuDUxMErEm5wxIwj+Aukx/1y68\n" + + "hOyCvHBLMY2c1LskH1MMBbDuS1aI+lnGpToi+MoYObxGcV458vxuT8+wwV8Fkpvd\n" + + "ll8IIFmeNPRv+1E+lXbES6CSNCVaZ/lFhPgdgYKleN7sfspiz50DG4dqafuEAaX5\n" + + "xaK1NWXJxTRz0ROH/IUziyuDW6jphrlgit4+3NCzp6vP9hAJQ8Vhcj0n15BKHIQ=\n" + + "-----END CERTIFICATE-----", + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgGVc7hICpmp91jbYe\n" + + "nrr8nYHD37RZP3VENY+szuA7WjuhRANCAATn0wRE1OVVnV56mzxnc657lmSBB0+0\n" + + "P5YgTq2Pc9sgqnEY8PG980/3n0DJCMQr96FZBWsIyY2gSQjNj4ggGAHT"), + + EE_RSA_512( + "RSA", + // md5WithRSAEncryption, 512 bits + // Validity + // Not Before: Nov 7 13:55:52 2011 GMT + // Not After : Jul 25 13:55:52 2031 GMT + // X509v3 Authority Key Identifier: + // B9:7C:D5:D9:DF:A7:4C:03:AE:FD:0E:27:5B:31:95:6C:C7:F3:75:E1 + "-----BEGIN CERTIFICATE-----\n" + + "MIICNDCCAZ2gAwIBAgIBDDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTExMTA3MTM1NTUyWhcNMzEwNzI1MTM1NTUyWjBPMQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" + + "BAMTCWxvY2FsaG9zdDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC3Pb49OSPfOD2G\n" + + "HSXFCFx1GJEZfqG9ZUf7xuIi/ra5dLjPGAaoY5QF2QOa8VnOriQCXDfyXHxsuRnE\n" + + "OomxL7EVAgMBAAGjeDB2MAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUXNCJK3/dtCIc\n" + + "xb+zlA/JINlvs/MwHwYDVR0jBBgwFoAUuXzV2d+nTAOu/Q4nWzGVbMfzdeEwJwYD\n" + + "VR0lBCAwHgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAzANBgkqhkiG9w0B\n" + + "AQQFAAOBgQB2qIDUxA2caMPpGtUACZAPRUtrGssCINIfItETXJZCx/cRuZ5sP4D9\n" + + "N1acoNDn0hCULe3lhXAeTC9NZ97680yJzregQMV5wATjo1FGsKY30Ma+sc/nfzQW\n" + + "+h/7RhYtoG0OTsiaDCvyhI6swkNJzSzrAccPY4+ZgU8HiDLzZTmM3Q==\n" + + "-----END CERTIFICATE-----", + "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAtz2+PTkj3zg9hh0l\n" + + "xQhcdRiRGX6hvWVH+8biIv62uXS4zxgGqGOUBdkDmvFZzq4kAlw38lx8bLkZxDqJ\n" + + "sS+xFQIDAQABAkByx/5Oo2hQ/w2q4L8z+NTRlJ3vdl8iIDtC/4XPnfYfnGptnpG6\n" + + "ZThQRvbMZiai0xHQPQMszvAHjZVme1eDl3EBAiEA3aKJHynPVCEJhpfCLWuMwX5J\n" + + "1LntwJO7NTOyU5m8rPECIQDTpzn5X44r2rzWBDna/Sx7HW9IWCxNgUD2Eyi2nA7W\n" + + "ZQIgJerEorw4aCAuzQPxiGu57PB6GRamAihEAtoRTBQlH0ECIQDN08FgTtnesgCU\n" + + "DFYLLcw1CiHvc7fZw4neBDHCrC8NtQIgA8TOUkGnpCZlQ0KaI8KfKWI+vxFcgFnH\n" + + "3fnqsTgaUs4=" + ), + + EE_DSA_2048( + "DSA", + // SHA256withDSA, 2048 bits + // Validity + // Not Before: May 22 07:18:20 2018 GMT + // Not After : May 17 07:18:20 2038 GMT + // Authority Key Identifier: + // 76:66:9E:F7:3B:DD:45:E5:3B:D9:72:3C:3F:F0:54:39:86:31:26:53 + "-----BEGIN CERTIFICATE-----\n" + + "MIIEnDCCBEGgAwIBAgIJAP/jh1qVhNVjMAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" + + "EwJVUzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2\n" + + "Y2UwHhcNMTgwNTIyMDcxODIwWhcNMzgwNTE3MDcxODIwWjBVMQswCQYDVQQGEwJV\n" + + "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Ux\n" + + "GDAWBgNVBAMMD1JlZ3Jlc3Npb24gVGVzdDCCA0cwggI6BgcqhkjOOAQBMIICLQKC\n" + + "AQEAmlavgoJrMcjqWRVcDE2dmWAPREgnzQvneEDef68cprDzjSwvOs5QeFyx75ib\n" + + "ado1e6jO/rW1prCGWHDD1oA/Tn4Pk3vu0nUxzvl1qATc+aJbpUU5Op0bvp6LbCsQ\n" + + "QslV9FeRh7Eb7bP6gpc/kHCBzEgC1VCK7prccXWy+t6SMOHbND3h+UbckfSaUuaV\n" + + "sVJNTD1D6GElfRj4Nmz1BGPfSYvKorwNZEU3gXwFgtDoAcGx7tcyClLpDHfqRfw/\n" + + "7yiqLyeiP7D4hl5lMNouJWDlAdMFp0FMgS3s9VDFinIcr6VtBWMTG7+4+czHAB+3\n" + + "fvrwlqNzhBn3uFHrekN/w8fNxwIhAJo7Sae1za7IMW0Q6hE5B4b+s2B/FaKPoA4E\n" + + "jtZu13B9AoIBAQCOZqLMKfvqZWUgT0PQ3QjR7dAFdd06I9Y3+TOQzZk1+j+vw/6E\n" + + "X4vFItX4gihb/u5Q9CdmpwhVGi7bvo+7+/IKeTgoQ6f5+PSug7SrWWUQ5sPwaZui\n" + + "zXZJ5nTeZDucFc2yFx0wgnjbPwiUxZklOT7xGiOMtzOTa2koCz5KuIBL+/wPKKxm\n" + + "ypo9VoY9xfbdU6LMXZv/lpD5XTM9rYHr/vUTNkukvV6Hpm0YMEWhVZKUJiqCqTqG\n" + + "XHaleOxSw6uQWB/+TznifcC7gB48UOQjCqOKf5VuwQneJLhlhU/jhRV3xtr+hLZa\n" + + "hW1wYhVi8cjLDrZFKlgEQqhB4crnJU0mJY+tA4IBBQACggEAID0ezl00/X8mv7eb\n" + + "bzovum1+DEEP7FM57k6HZEG2N3ve4CW+0m9Cd+cWPz8wkZ+M0j/Eqa6F0IdbkXEc\n" + + "Q7CuzvUyJ57xQ3L/WCgXsiS+Bh8O4Mz7GwW22CGmHqafbVv+hKBfr8MkskO6GJUt\n" + + "SUF/CVLzB4gMIvZMH26tBP2xK+i7FeEK9kT+nGdzQSZBAhFYpEVCBplHZO24/OYq\n" + + "1DNoU327nUuXIhmsfA8N0PjiWbIZIjTPwBGr9H0LpATI7DIDNcvRRvtROP+pBU9y\n" + + "fuykPkptg9C0rCM9t06bukpOSaEz/2VIQdLE8fHYFA6pHZ6CIc2+5cfvMgTPhcjz\n" + + "W2jCt6MjMCEwHwYDVR0jBBgwFoAUdmae9zvdReU72XI8P/BUOYYxJlMwCwYJYIZI\n" + + "AWUDBAMCA0gAMEUCIQCeI5fN08b9BpOaHdc3zQNGjp24FOL/RxlBLeBAorswJgIg\n" + + "JEZ8DhYxQy1O7mmZ2UIT7op6epWMB4dENjs0qWPmcKo=\n" + + "-----END CERTIFICATE-----", + "MIICZQIBADCCAjoGByqGSM44BAEwggItAoIBAQCaVq+CgmsxyOpZFVwMTZ2ZYA9E\n" + + "SCfNC+d4QN5/rxymsPONLC86zlB4XLHvmJtp2jV7qM7+tbWmsIZYcMPWgD9Ofg+T\n" + + "e+7SdTHO+XWoBNz5olulRTk6nRu+notsKxBCyVX0V5GHsRvts/qClz+QcIHMSALV\n" + + "UIrumtxxdbL63pIw4ds0PeH5RtyR9JpS5pWxUk1MPUPoYSV9GPg2bPUEY99Ji8qi\n" + + "vA1kRTeBfAWC0OgBwbHu1zIKUukMd+pF/D/vKKovJ6I/sPiGXmUw2i4lYOUB0wWn\n" + + "QUyBLez1UMWKchyvpW0FYxMbv7j5zMcAH7d++vCWo3OEGfe4Uet6Q3/Dx83HAiEA\n" + + "mjtJp7XNrsgxbRDqETkHhv6zYH8Voo+gDgSO1m7XcH0CggEBAI5moswp++plZSBP\n" + + "Q9DdCNHt0AV13Toj1jf5M5DNmTX6P6/D/oRfi8Ui1fiCKFv+7lD0J2anCFUaLtu+\n" + + "j7v78gp5OChDp/n49K6DtKtZZRDmw/Bpm6LNdknmdN5kO5wVzbIXHTCCeNs/CJTF\n" + + "mSU5PvEaI4y3M5NraSgLPkq4gEv7/A8orGbKmj1Whj3F9t1Tosxdm/+WkPldMz2t\n" + + "gev+9RM2S6S9XoembRgwRaFVkpQmKoKpOoZcdqV47FLDq5BYH/5POeJ9wLuAHjxQ\n" + + "5CMKo4p/lW7BCd4kuGWFT+OFFXfG2v6EtlqFbXBiFWLxyMsOtkUqWARCqEHhyucl\n" + + "TSYlj60EIgIgLfA75+8KcKxdN8mr6gzGjQe7jPFGG42Ejhd7Q2F4wuw="), + + EE_DSA_1024( + "DSA", + // dsaWithSHA1, 1024 bits + // Validity + // Not Before: Apr 24 12:25:43 2020 GMT + // Not After : Apr 22 12:25:43 2030 GMT + // Authority Key Identifier: + // E1:3C:01:52:EB:D1:38:F7:CF:F1:E3:5E:DB:54:75:7F:5E:AB:2D:36 + "-----BEGIN CERTIFICATE-----\n" + + "MIIDADCCAr+gAwIBAgIUd2XJ5F2VTbk9a92w/NzLXR5zjUQwCQYHKoZIzjgEAzAu\n" + + "MQswCQYDVQQGEwJVUzENMAsGA1UECgwESmF2YTEQMA4GA1UECwwHU3VuSlNTRTAe\n" + + "Fw0yMDA0MjQxMjI1NDNaFw0zMDA0MjIxMjI1NDNaMEgxCzAJBgNVBAYTAlVTMQ0w\n" + + "CwYDVQQKDARKYXZhMRAwDgYDVQQLDAdTdW5KU1NFMRgwFgYDVQQDDA9SZWdyZXNz\n" + + "aW9uIFRlc3QwggG3MIIBLAYHKoZIzjgEATCCAR8CgYEA7fSkxYISlMJT+i8N5VOb\n" + + "lHhjrPYAy3oR2/YXQW6T0hCMhm8jmxgk1bDId9ZKHrxsM05EkCtRYaqag4ZZeGde\n" + + "ywv3IwwYqCQfGtkPwT9QAsdSABYwGOrlhEtZtBG1yQ44c+Rz/Vs+PtkAyZbf5VG1\n" + + "iSxFb9bI5QFJWJ9a2VpZh58CFQCCGALQoK4MsQP8V72WlB7Bvt9erwKBgQDCxu0G\n" + + "M2iZr0J8DaAo9/ChS4m7E7h6Jz9KOm2cFhzYGekkUXNzny7nyz6Qpgbuf8KNFKjt\n" + + "qoUDC8tlcVQAUlTcESC0TZXR3h21hl9wzIBhE+kJ1j8v1KAxfOaJOxObk5QEvIaA\n" + + "5j+jiHGwRS5tDqywOatz+emwMZv1wKnCNBElNgOBhAACgYBHjuQKucCuuvy/4DpG\n" + + "rSIzdueK+HrzOW8h2pfvz3lzpsyV6XJPC6we9CjaQjU01VcjwN2PoYtbGyml0pbK\n" + + "We4sdgn6LDL1aCM/WKRSxGHVTx+wkhKQ719YtiC0T6sA+eLirc6VT3/6+FbQWC+2\n" + + "bG7N19sGpV/RAXMBpRXUnBJSQaNCMEAwHQYDVR0OBBYEFNNZxyxuQmKvWowofr/S\n" + + "HdCIS+W8MB8GA1UdIwQYMBaAFOE8AVLr0Tj3z/HjXttUdX9eqy02MAkGByqGSM44\n" + + "BAMDMAAwLQIUUzzMhZ9St/Vo/YdgNTHdTw4cm14CFQCE6tWG157Wl5YFyYsGHsLY\n" + + "NN8uCA==\n" + + "-----END CERTIFICATE-----", + "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAO30pMWCEpTCU/ovDeVTm5R4Y6z2\n" + + "AMt6Edv2F0Fuk9IQjIZvI5sYJNWwyHfWSh68bDNORJArUWGqmoOGWXhnXssL9yMM\n" + + "GKgkHxrZD8E/UALHUgAWMBjq5YRLWbQRtckOOHPkc/1bPj7ZAMmW3+VRtYksRW/W\n" + + "yOUBSVifWtlaWYefAhUAghgC0KCuDLED/Fe9lpQewb7fXq8CgYEAwsbtBjNoma9C\n" + + "fA2gKPfwoUuJuxO4eic/SjptnBYc2BnpJFFzc58u58s+kKYG7n/CjRSo7aqFAwvL\n" + + "ZXFUAFJU3BEgtE2V0d4dtYZfcMyAYRPpCdY/L9SgMXzmiTsTm5OUBLyGgOY/o4hx\n" + + "sEUubQ6ssDmrc/npsDGb9cCpwjQRJTYEFgIUNRiLmNzfTYOuVsjkySPzP5gPImM="), + + EE_ED25519( + "EdDSA", + // ED25519 + // Validity + // Not Before: May 24 23:32:36 2020 GMT + // Not After : May 22 23:32:36 2030 GMT + // X509v3 Authority Key Identifier: + // keyid:06:76:DB:88:EB:61:55:4C:C9:63:41:C2:A0:A8:57:3F:D7:F1:B8:EC + "-----BEGIN CERTIFICATE-----\n" + + "MIIBlDCCAUagAwIBAgIUFTt/jcgQ65nhTG8LkrWFJhhEGuwwBQYDK2VwMDsxCzAJ\n" + + "BgNVBAYTAlVTMQ0wCwYDVQQKDARqYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3Qg\n" + + "U2VyaXZjZTAeFw0yMDA1MjQyMzMyMzZaFw0zMDA1MjIyMzMyMzZaMFUxCzAJBgNV\n" + + "BAYTAlVTMQ0wCwYDVQQKDARqYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" + + "aXZjZTEYMBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MCowBQYDK2VwAyEAGAYQmKb7\n" + + "WNYpVxIdsc49lI1emNjF06/Jl85zlG0wc9OjQjBAMB0GA1UdDgQWBBQkJ2E4/S8Z\n" + + "EIM1v9uTc0eYtYNk3zAfBgNVHSMEGDAWgBQGdtuI62FVTMljQcKgqFc/1/G47DAF\n" + + "BgMrZXADQQCVZnl/AyIEtZ8r45e/hcfxwuezgRX+7e9NHZFV1A/TMGcBRORDfDUi\n" + + "bbh72K528fjT7P4/WoXvm1zJKOAzUOUL\n" + + "-----END CERTIFICATE-----", + "MC4CAQAwBQYDK2VwBCIEIGBmdh4tfc0lng/LWokhfFLlo0ZlmTn2lbI639qou2KP"), + + EE_ED448( + "EdDSA", + // ED448 + // Validity + // Not Before: May 24 23:23:43 2020 GMT + // Not After : May 22 23:23:43 2030 GMT + // X509v3 Authority Key Identifier: + // keyid:F5:D5:9D:FB:6F:B7:50:29:DF:F0:B8:83:10:5F:9B:C4:A8:1C:E9:F4 + "-----BEGIN CERTIFICATE-----\n" + + "MIIB3zCCAV+gAwIBAgIUNlWzFrH2+BILqM3SNYQjKoY98S8wBQYDK2VxMDsxCzAJ\n" + + "BgNVBAYTAlVTMQ0wCwYDVQQKDARqYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3Qg\n" + + "U2VyaXZjZTAeFw0yMDA1MjQyMzIzNDNaFw0zMDA1MjIyMzIzNDNaMFUxCzAJBgNV\n" + + "BAYTAlVTMQ0wCwYDVQQKDARqYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" + + "aXZjZTEYMBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MEMwBQYDK2VxAzoAoIubPNAg\n" + + "F11u3MQ5d9wujg10+80I0xzYzTqzzXrfJNtw+eU8NbUk86xiCvlMzJRH0Oo3DbY8\n" + + "NAKAo0IwQDAdBgNVHQ4EFgQUUiI1+qT1x+HsDgfZRIU6hUaAbmUwHwYDVR0jBBgw\n" + + "FoAU9dWd+2+3UCnf8LiDEF+bxKgc6fQwBQYDK2VxA3MAx8P0mle08s5YDd/p58dt\n" + + "yORqvDPwo5IYPasqN8Zeen1B9u1xF/kvDGFxCJ6D9Gi4ynnDx0FZFMkA83evZcxJ\n" + + "+X+swt7FyHwXrdkZcvjRKEcsWhkj+0FlxYF/NZzLTGuGIPYJnRLEwf/zr+5NDxKs\n" + + "fCoA\n" + + "-----END CERTIFICATE-----", + "MEcCAQAwBQYDK2VxBDsEOfbhmUSuKP9WCO7Nr6JxVq5rfJESk1MNMyYhC134SiAP\n" + + "Suw0Cu7RZVadpfPR7Kiwb2b/JXjMdY1HAA=="), + + EE_RSASSA_PSS( + "RSASSA-PSS", + // Signature Algorithm: rsassaPss + // Hash Algorithm: sha256 + // Mask Algorithm: mgf1 with sha256 + // + // Validity + // Not Before: Jun 6 07:11:00 2018 GMT + // Not After : Jun 1 07:11:00 2038 GMT + // X509v3 Authority Key Identifier: + // 1F:16:2B:79:8A:55:89:99:98:02:5F:84:18:D0:7B:1A:23:D8:88:0C + "-----BEGIN CERTIFICATE-----\n" + + "MIIDZjCCAh2gAwIBAgIUHxwPs3eAgJ057nJwiLgWZWeNqdgwPgYJKoZIhvcNAQEK\n" + + "MDGgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogQC\n" + + "AgDeMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xODA2MDYwNzExMDBaFw0zODA2\n" + + "MDEwNzExMDBaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASAwCwYJKoZIhvcNAQEK\n" + + "A4IBDwAwggEKAoIBAQCl8r4Qrg27BYUO/1Va2Ix8QPGzN/lvzmKvP5Ff26ovNW4v\n" + + "RUx68HzAhhiWtcl+PwLSbJqJreEkTlle7PnRAypby3fO7ZAK0Y3YiHquaBg7d+7Y\n" + + "FhhHwv8gG0lZcyA0BkXFJHqdq76qar0xHC6DVezXm0K3mcceymGtFR9BzWmAj+7D\n" + + "YsSwvtTQ7WNoQmf0cdDMSM71IwaTwIwvT2wzX1vv5hcdDyXdr64WFqWSA9sNJ2K6\n" + + "arxaaU1klwKSgDokF6njafWQ4UxdR67d5W1MYoiioDs2Yy3utsMpO2OUzZVBZNdT\n" + + "gkr1jsJhIurpz/5K51lwJIRQBezEFSb+60AFVoMJAgMBAAGjUDBOMB0GA1UdDgQW\n" + + "BBQfFit5ilWJmZgCX4QY0HsaI9iIDDAfBgNVHSMEGDAWgBQfFit5ilWJmZgCX4QY\n" + + "0HsaI9iIDDAMBgNVHRMEBTADAQH/MD4GCSqGSIb3DQEBCjAxoA0wCwYJYIZIAWUD\n" + + "BAIBoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCAaIEAgIA3gOCAQEAa4yUQ3gh\n" + + "d1YWPdEa1sv2hdkhtenw6m5yxbmaQl2+nIKSpk4RfpXC7K1EYwBF8TdfFbD8hGGh\n" + + "5n81BT0/dn1R9SRGCv7KTxx4lfQt31frlsw/tVciwyXQtcUZ6DqfnLP0/aRVLNgx\n" + + "zaP542JUHFYLTC3EGz2zUgv70ZUTlIsPG3/p8YO1iXdnYGQyzOuQPUBpI7nS7UtR\n" + + "Ug8VE9ACpBxxI3qChMahFZGHlXCCSjSmxpQa6UO4SQl8q5tPNnqdzWwvAW8qkCy4\n" + + "6barRQ4sMcGayhHh/uSTx7bcl0FMJpcI1ygbw7/Pc03zKtw0gMTBMns7q4yXjb/u\n" + + "ef47nW0t+LRAAg==\n" + + "-----END CERTIFICATE-----", + "MIIEuwIBADALBgkqhkiG9w0BAQoEggSnMIIEowIBAAKCAQEApfK+EK4NuwWFDv9V\n" + + "WtiMfEDxszf5b85irz+RX9uqLzVuL0VMevB8wIYYlrXJfj8C0myaia3hJE5ZXuz5\n" + + "0QMqW8t3zu2QCtGN2Ih6rmgYO3fu2BYYR8L/IBtJWXMgNAZFxSR6nau+qmq9MRwu\n" + + "g1Xs15tCt5nHHsphrRUfQc1pgI/uw2LEsL7U0O1jaEJn9HHQzEjO9SMGk8CML09s\n" + + "M19b7+YXHQ8l3a+uFhalkgPbDSdiumq8WmlNZJcCkoA6JBep42n1kOFMXUeu3eVt\n" + + "TGKIoqA7NmMt7rbDKTtjlM2VQWTXU4JK9Y7CYSLq6c/+SudZcCSEUAXsxBUm/utA\n" + + "BVaDCQIDAQABAoIBAAc4vRS0vlw5LUUtz2UYr2Ro3xvRf8Vh0eGWfpkRUiKjzJu6\n" + + "BE4FUSh/rWpBlvcrfs/xcfgz3OxbjIAZB/YUkS9Vd21F4VLXM7kMl2onlYZg/b/h\n" + + "lkTpM3kONu7xl6Er9LVTlRJveuinpHwSoeONRbVMSGb9BjFM1VtW4/lVGxZBG05D\n" + + "y9i/o4vCZqULn9cAumOwicKuCyTcS58XcMJ+puSPfRA71PYLxqFkASAoJsUwCXpo\n" + + "gs39lLsIFgrfO8mBO1ux/SE+QaRc+9XqFSHHKD1XqF/9zSYBgWjE910EcpdYEdZx\n" + + "GEkwea7Fn4brO5OpIrHY/45naqbUOBzv6gufMAECgYEAz7PHCdcrQvmOb8EiNbQH\n" + + "uvSimwObWJFeN1ykp6mfRbSnkXw7p8+M4Tc8HFi8QLpoq63Ev2AwoaQCQvHbFC2Y\n" + + "1Cz0EkC0aOp+tZP7U2AUBdkcDesZAJQTad0zV6KesyIUXdxZXDG8JJ1XSNWfTJV4\n" + + "QD+BjLZ0jiAyCIfVYvWQqYkCgYEAzIln1nKTixLMPr5CldSmR7ZarEtPJU+hHwVg\n" + + "dV/Lc6d2Yy9JgunOXRo4BXB1TEo8JFbK3HBQH6tS8li4qDr7WK5wyYfh8qb4WZyu\n" + + "lc562f2WVYntcN8/Ojb+Vyrt7lk9sq/8KoVHxEAWd6mqL9VTPYuAu1Vw9fTGIZfB\n" + + "lDeELYECgYAvdzU4UXzofGGJtohb332YwwlaBZP9xJLUcg6K5l+orWVSASMc8XiP\n" + + "i3DoRXsYC8GZ4kdBOPlEJ1gA9oaLcPQpIPDSLwlLpLM6Scw4vI822uvnXl/DWxOo\n" + + "sM1n7Jj59QLUhGPDhvYpI+/rjC4wcUQe4qR3hMbUKBVnD6u7RsU9iQKBgQCQ17VK\n" + + "7bSCRfuRaxaoGADww7gOTv5rQ6qr1xjpxb7D1hFGR9Rc+smCsPB/GZZXQjK44SWj\n" + + "WX3ED4Ubzaxmpe4cbNu+O5XMSmWQwB36RFBHUwdE5/nXdqDFzu/qNqJrqZLBmVKP\n" + + "ofaiiWffsaytVvotmT6+atElvAMbAua42V+nAQKBgHtIn3mYMHLriYGhQzpkFEA2\n" + + "8YcAMlKppueOMAKVy8nLu2r3MidmLAhMiKJQKG45I3Yg0/t/25tXLiOPJlwrOebh\n" + + "xQqUBI/JUOIpGAEnr48jhOXnCS+i+z294G5U/RgjXrlR4bCPvrtCmwzWwe0h79w2\n" + + "Q2hO5ZTW6UD9CVA85whf"), + + DSA_SHA1_1024_EXPIRED( // for NullCerts test + "DSA", + // Signature Algorithm: dsaWithSHA1 + // Issuer: C = US, ST = CA, L = Cupertino, O = Dummy, OU = Dummy, CN = Example + // Validity + // Not Before: Mar 11 06:33:43 2001 GMT + // Not After : Dec 6 06:33:43 2003 GMT + "-----BEGIN CERTIFICATE-----\n" + + "MIIC9TCCArMCBDqrHEcwCwYHKoZIzjgEAwUAMGAxCzAJBgNVBAYTAlVTMQswCQYD\n" + + "VQQIEwJDQTESMBAGA1UEBxMJQ3VwZXJ0aW5vMQ4wDAYDVQQKEwVEdW1teTEOMAwG\n" + + "A1UECxMFRHVtbXkxEDAOBgNVBAMTB0V4YW1wbGUwHhcNMDEwMzExMDYzMzQzWhcN\n" + + "MDMxMjA2MDYzMzQzWjBgMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNV\n" + + "BAcTCUN1cGVydGlubzEOMAwGA1UEChMFRHVtbXkxDjAMBgNVBAsTBUR1bW15MRAw\n" + + "DgYDVQQDEwdFeGFtcGxlMIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIp\n" + + "Ut9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7\n" + + "gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1\n" + + "VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUC\n" + + "gYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCB\n" + + "gLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6\n" + + "ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAPqO/boo\n" + + "m+n+tAdqetoQ2ZRoS8BpYIEFOJt4OJ8flb52T3vGNNdapq9pbjN+HKrT62ggNhZs\n" + + "hajxYwFCpaidKZuGQXvvpHkj0UHjhZFry6Dd41cfEG13dfgACf8uooeTzPGFvUPv\n" + + "TCHcPRh820BZMeOqdS4PjWPyf3HEtiTtFWR7MAsGByqGSM44BAMFAAMvADAsAhRH\n" + + "dZQef04MwUTlAALf2J6PIcgmQAIUB2H/RnW2tVg+mbCl5jQLfudsEhI=\n" + + "-----END CERTIFICATE-----", + "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdS\n" + + "PO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVCl\n" + + "pJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith\n" + + "1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7L\n" + + "vKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3\n" + + "zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImo\n" + + "g9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFgIUZC+jBuwAPm8ejkybfAm2gT49ApY=" + ); + + final String keyAlgo; + final String certStr; + final String privKeyStr; + + Cert(String keyAlgo, String certStr, String privKeyStr) { + this.keyAlgo = keyAlgo; + this.certStr = certStr; + this.privKeyStr = privKeyStr; + } } } diff --git a/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java b/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java index 621aaea3546..00aa69aa834 100644 --- a/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java +++ b/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * 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,12 +28,16 @@ * @test * @bug 8250839 * @summary Improve test template SSLEngineTemplate with SSLContextTemplate - * @build SSLContextTemplate + * @library /test/lib + * @build SSLContextTemplate jdk.test.lib.Utils * @run main/othervm SSLEngineTemplate */ + +import java.util.Objects; import javax.net.ssl.*; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import java.nio.ByteBuffer; +import jdk.test.lib.Utils; /** * A SSLEngine usage example which simplifies the presentation @@ -51,7 +55,7 @@ * (wrap/unwrap) pass before any application data is consumed or * produced. */ -public class SSLEngineTemplate implements SSLContextTemplate { +public class SSLEngineTemplate extends SSLContextTemplate { protected final SSLEngine clientEngine; // client Engine protected final ByteBuffer clientOut; // write side of clientEngine protected final ByteBuffer clientIn; // read side of clientEngine @@ -92,14 +96,22 @@ protected SSLEngineTemplate() throws Exception { cTOs = ByteBuffer.allocateDirect(netBufferMax); sTOc = ByteBuffer.allocateDirect(netBufferMax); - clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes()); - serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes()); + clientOut = createClientOutputBuffer(); + serverOut = createServerOutputBuffer(); + } + + protected ByteBuffer createServerOutputBuffer() { + return ByteBuffer.wrap("Hello Client, I'm Server".getBytes()); } // // Protected methods could be used to customize the test case. // + protected ByteBuffer createClientOutputBuffer() { + return ByteBuffer.wrap("Hi Server, I'm Client".getBytes()); + } + /* * Configure the client side engine. */ @@ -256,4 +268,75 @@ static void checkTransfer(ByteBuffer a, ByteBuffer b) a.limit(a.capacity()); b.limit(b.capacity()); } + + /** + * Given a TLS record containing one or more handshake messages, return + * the specific handshake message as a ByteBuffer (a slice of the record) + * + * @param tlsRecord A ByteBuffer containing a TLS record. It is + * assumed that the position of the ByteBuffer is on the + * first byte of the TLS record header. + * @param hsMsgId The message identifier for the handshake message + * being sought. + * + * Message Identifiers + * + * @param isDtls Indicates whether DTLS protocol being used. + * @return a ByteBuffer containing the TLS handshake message. + * The position of the returned ByteBuffer will be on the + * first byte of the TLS handshake message data, + * immediately following the handshake header. + * If the message is not found, null will be returned. + * @throws SSLException if the incoming ByteBuffer does not contain + * a well-formed TLS message. + */ + protected static ByteBuffer extractHandshakeMsg( + ByteBuffer tlsRecord, int hsMsgId, boolean isDtls) + throws SSLException { + Objects.requireNonNull(tlsRecord); + tlsRecord.mark(); + + // Process the TLS record header + int type = Byte.toUnsignedInt(tlsRecord.get()); + int ver_major = Byte.toUnsignedInt(tlsRecord.get()); + int ver_minor = Byte.toUnsignedInt(tlsRecord.get()); + // Skip DTLS-specific bytes + if (isDtls) { + tlsRecord.position(tlsRecord.position() + 8); + } + int recLen = Short.toUnsignedInt(tlsRecord.getShort()); + + if (recLen > tlsRecord.remaining()) { + throw new SSLException("Incomplete record in buffer: " + + "Record length = " + recLen + + ", Remaining = " + + tlsRecord.remaining()); + } + + while (tlsRecord.hasRemaining()) { + // Grab the handshake message header. + int msgHdr = tlsRecord.getInt(); + int msgType = (msgHdr >> 24) & 0x000000FF; + int msgLen = msgHdr & 0x00FFFFFF; + // Skip DTLS-specific bytes + if (isDtls) { + tlsRecord.position(tlsRecord.position() + 8); + } + + if (msgType == hsMsgId) { + // Slice the buffer such that it contains the entire + // handshake message (less the handshake header). + ByteBuffer buf = Utils.slice(tlsRecord, tlsRecord.position(), msgLen); + tlsRecord.reset(); + return buf; + } else { + // Skip to the next handshake message, if there is one + tlsRecord.position(tlsRecord.position() + msgLen); + } + } + + tlsRecord.reset(); + return null; + } } diff --git a/test/jdk/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java b/test/jdk/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java deleted file mode 100644 index 54b4e3c6840..00000000000 --- a/test/jdk/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java +++ /dev/null @@ -1,532 +0,0 @@ -/* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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. - */ - -// -// SunJSSE does not support dynamic system properties, no way to re-use -// system properties in samevm/agentvm mode. -// - -/* - * @test - * @bug 7105780 - * @summary Add SSLSocket client/SSLEngine server to templates directory. - * @run main/othervm SSLSocketSSLEngineTemplate TLSv1 - * @run main/othervm SSLSocketSSLEngineTemplate TLSv1.1 - * @run main/othervm SSLSocketSSLEngineTemplate TLSv1.2 - * @run main/othervm SSLSocketSSLEngineTemplate TLSv1.3 - */ - -/** - * A SSLSocket/SSLEngine interop test case. This is not the way to - * code SSLEngine-based servers, but works for what we need to do here, - * which is to make sure that SSLEngine/SSLSockets can talk to each other. - * SSLEngines can use direct or indirect buffers, and different code - * is used to get at the buffer contents internally, so we test that here. - * - * The test creates one SSLSocket (client) and one SSLEngine (server). - * The SSLSocket talks to a raw ServerSocket, and the server code - * does the translation between byte [] and ByteBuffers that the SSLEngine - * can use. The "transport" layer consists of a Socket Input/OutputStream - * and two byte buffers for the SSLEngines: think of them - * as directly connected pipes. - * - * Again, this is a *very* simple example: real code will be much more - * involved. For example, different threading and I/O models could be - * used, transport mechanisms could close unexpectedly, and so on. - * - * When this application runs, notice that several messages - * (wrap/unwrap) pass before any application data is consumed or - * produced. (For more information, please see the SSL/TLS - * specifications.) There may several steps for a successful handshake, - * so it's typical to see the following series of operations: - * - * client server message - * ====== ====== ======= - * write() ... ClientHello - * ... unwrap() ClientHello - * ... wrap() ServerHello/Certificate - * read() ... ServerHello/Certificate - * write() ... ClientKeyExchange - * write() ... ChangeCipherSpec - * write() ... Finished - * ... unwrap() ClientKeyExchange - * ... unwrap() ChangeCipherSpec - * ... unwrap() Finished - * ... wrap() ChangeCipherSpec - * ... wrap() Finished - * read() ... ChangeCipherSpec - * read() ... Finished - */ -import javax.net.ssl.*; -import javax.net.ssl.SSLEngineResult.*; -import java.io.*; -import java.net.*; -import java.security.*; -import java.nio.*; - -public class SSLSocketSSLEngineTemplate { - - /* - * Enables logging of the SSL/TLS operations. - */ - private static final boolean logging = true; - - /* - * Enables the JSSE system debugging system property: - * - * -Djavax.net.debug=all - * - * This gives a lot of low-level information about operations underway, - * including specific handshake messages, and might be best examined - * after gaining some familiarity with this application. - */ - private static final boolean debug = false; - private final SSLContext sslc; - private SSLEngine serverEngine; // server-side SSLEngine - private SSLSocket clientSocket; - - private final byte[] serverMsg = - "Hi there Client, I'm a Server.".getBytes(); - private final byte[] clientMsg = - "Hello Server, I'm a Client! Pleased to meet you!".getBytes(); - - private ByteBuffer serverOut; // write side of serverEngine - private ByteBuffer serverIn; // read side of serverEngine - - private volatile Exception clientException; - private volatile Exception serverException; - - /* - * For data transport, this example uses local ByteBuffers. - */ - private ByteBuffer cTOs; // "reliable" transport client->server - private ByteBuffer sTOc; // "reliable" transport server->client - - /* - * The following is to set up the keystores/trust material. - */ - private static final String pathToStores = "../etc"; - private static final String keyStoreFile = "keystore"; - private static final String trustStoreFile = "truststore"; - private static final String keyFilename = - System.getProperty("test.src", ".") + "/" + pathToStores - + "/" + keyStoreFile; - private static final String trustFilename = - System.getProperty("test.src", ".") + "/" + pathToStores - + "/" + trustStoreFile; - - /* - * Main entry point for this test. - */ - public static void main(String args[]) throws Exception { - String protocol = args[0]; - - // reset security properties to make sure that the algorithms - // and keys used in this test are not disabled. - Security.setProperty("jdk.tls.disabledAlgorithms", ""); - Security.setProperty("jdk.certpath.disabledAlgorithms", ""); - - if (debug) { - System.setProperty("javax.net.debug", "all"); - } - - /* - * Run the tests with direct and indirect buffers. - */ - SSLSocketSSLEngineTemplate test = - new SSLSocketSSLEngineTemplate(protocol); - log("-------------------------------------"); - log("Testing " + protocol + " for direct buffers ..."); - test.runTest(true); - - log("---------------------------------------"); - log("Testing " + protocol + " for indirect buffers ..."); - test.runTest(false); - - log("Test Passed."); - } - - /* - * Create an initialized SSLContext to use for these tests. - */ - public SSLSocketSSLEngineTemplate(String protocol) throws Exception { - - KeyStore ks = KeyStore.getInstance("JKS"); - KeyStore ts = KeyStore.getInstance("JKS"); - - char[] passphrase = "passphrase".toCharArray(); - - try (FileInputStream keyFile = new FileInputStream(keyFilename); - FileInputStream trustFile = new FileInputStream(trustFilename)) { - ks.load(keyFile, passphrase); - ts.load(trustFile, passphrase); - } - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(ts); - - SSLContext sslCtx = SSLContext.getInstance(protocol); - - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - - sslc = sslCtx; - } - - /* - * Run the test. - * - * Sit in a tight loop, with the server engine calling wrap/unwrap - * regardless of whether data is available or not. We do this until - * we get the application data. Then we shutdown and go to the next one. - * - * The main loop handles all of the I/O phases of the SSLEngine's - * lifetime: - * - * initial handshaking - * application data transfer - * engine closing - * - * One could easily separate these phases into separate - * sections of code. - */ - private void runTest(boolean direct) throws Exception { - clientSocket = null; - boolean serverClose = direct; - - // generates the server-side Socket - try (ServerSocket serverSocket = new ServerSocket()) { - serverSocket.setReuseAddress(false); - serverSocket.bind(null); - int port = serverSocket.getLocalPort(); - log("Port: " + port); - Thread thread = createClientThread(port, serverClose); - - createSSLEngine(); - createBuffers(direct); - - // server-side socket that will read - try (Socket socket = serverSocket.accept()) { - socket.setSoTimeout(500); - - boolean closed = false; - // will try to read one more time in case client message - // is fragmented to multiple pieces - boolean retry = true; - - InputStream is = socket.getInputStream(); - OutputStream os = socket.getOutputStream(); - - SSLEngineResult serverResult; // results from last operation - - /* - * Examining the SSLEngineResults could be much more involved, - * and may alter the overall flow of the application. - * - * For example, if we received a BUFFER_OVERFLOW when trying - * to write to the output pipe, we could reallocate a larger - * pipe, but instead we wait for the peer to drain it. - */ - byte[] inbound = new byte[8192]; - byte[] outbound = new byte[8192]; - - while (!isEngineClosed(serverEngine)) { - int len; - - // Inbound data - log("================"); - - // Read from the Client side. - try { - len = is.read(inbound); - if (len == -1) { - logSocketStatus(clientSocket); - if (clientSocket.isClosed() - || clientSocket.isOutputShutdown()) { - log("Client socket was closed or shutdown output"); - break; - } else { - throw new Exception("Unexpected EOF"); - } - } - cTOs.put(inbound, 0, len); - } catch (SocketTimeoutException ste) { - // swallow. Nothing yet, probably waiting on us. - } - - cTOs.flip(); - - serverResult = serverEngine.unwrap(cTOs, serverIn); - log("server unwrap: ", serverResult); - runDelegatedTasks(serverResult, serverEngine); - cTOs.compact(); - - // Outbound data - log("----"); - - serverResult = serverEngine.wrap(serverOut, sTOc); - log("server wrap: ", serverResult); - runDelegatedTasks(serverResult, serverEngine); - - sTOc.flip(); - - if ((len = sTOc.remaining()) != 0) { - sTOc.get(outbound, 0, len); - os.write(outbound, 0, len); - // Give the other side a chance to process - } - - sTOc.compact(); - - if (!closed && (serverOut.remaining() == 0)) { - closed = true; - - /* - * We'll alternate initiatating the shutdown. - * When the server initiates, it will take one more - * loop, but tests the orderly shutdown. - */ - if (serverClose) { - serverEngine.closeOutbound(); - } - serverIn.flip(); - - /* - * A sanity check to ensure we got what was sent. - */ - if (serverIn.remaining() != clientMsg.length) { - if (retry && - serverIn.remaining() < clientMsg.length) { - log("Need to read more from client"); - serverIn.compact(); - retry = false; - continue; - } else { - throw new Exception( - "Client: Data length error"); - } - } - - for (int i = 0; i < clientMsg.length; i++) { - if (clientMsg[i] != serverIn.get()) { - throw new Exception( - "Client: Data content error"); - } - } - serverIn.compact(); - } - } - } catch (Exception e) { - serverException = e; - } finally { - // Wait for the client to join up with us. - if (thread != null) { - thread.join(); - } - } - } finally { - if (serverException != null) { - if (clientException != null) { - serverException.initCause(clientException); - } - throw serverException; - } - if (clientException != null) { - if (serverException != null) { - clientException.initCause(serverException); - } - throw clientException; - } - } - } - - /* - * Create a client thread which does simple SSLSocket operations. - * We'll write and read one data packet. - */ - private Thread createClientThread(final int port, - final boolean serverClose) throws Exception { - - Thread t = new Thread("ClientThread") { - - @Override - public void run() { - // client-side socket - try (SSLSocket sslSocket = (SSLSocket)sslc.getSocketFactory(). - createSocket("localhost", port)) { - clientSocket = sslSocket; - - OutputStream os = sslSocket.getOutputStream(); - InputStream is = sslSocket.getInputStream(); - - // write(byte[]) goes in one shot. - os.write(clientMsg); - - byte[] inbound = new byte[2048]; - int pos = 0; - - int len; - while ((len = is.read(inbound, pos, 2048 - pos)) != -1) { - pos += len; - // Let the client do the closing. - if ((pos == serverMsg.length) && !serverClose) { - sslSocket.close(); - break; - } - } - - if (pos != serverMsg.length) { - throw new Exception("Client: Data length error"); - } - - for (int i = 0; i < serverMsg.length; i++) { - if (inbound[i] != serverMsg[i]) { - throw new Exception("Client: Data content error"); - } - } - } catch (Exception e) { - clientException = e; - } - } - }; - t.start(); - return t; - } - - /* - * Using the SSLContext created during object creation, - * create/configure the SSLEngines we'll use for this test. - */ - private void createSSLEngine() throws Exception { - /* - * Configure the serverEngine to act as a server in the SSL/TLS - * handshake. - */ - serverEngine = sslc.createSSLEngine(); - serverEngine.setUseClientMode(false); - serverEngine.getNeedClientAuth(); - } - - /* - * Create and size the buffers appropriately. - */ - private void createBuffers(boolean direct) { - - SSLSession session = serverEngine.getSession(); - int appBufferMax = session.getApplicationBufferSize(); - int netBufferMax = session.getPacketBufferSize(); - - /* - * We'll make the input buffers a bit bigger than the max needed - * size, so that unwrap()s following a successful data transfer - * won't generate BUFFER_OVERFLOWS. - * - * We'll use a mix of direct and indirect ByteBuffers for - * tutorial purposes only. In reality, only use direct - * ByteBuffers when they give a clear performance enhancement. - */ - if (direct) { - serverIn = ByteBuffer.allocateDirect(appBufferMax + 50); - cTOs = ByteBuffer.allocateDirect(netBufferMax); - sTOc = ByteBuffer.allocateDirect(netBufferMax); - } else { - serverIn = ByteBuffer.allocate(appBufferMax + 50); - cTOs = ByteBuffer.allocate(netBufferMax); - sTOc = ByteBuffer.allocate(netBufferMax); - } - - serverOut = ByteBuffer.wrap(serverMsg); - } - - /* - * If the result indicates that we have outstanding tasks to do, - * go ahead and run them in this thread. - */ - private static void runDelegatedTasks(SSLEngineResult result, - SSLEngine engine) throws Exception { - - if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { - Runnable runnable; - while ((runnable = engine.getDelegatedTask()) != null) { - log("\trunning delegated task..."); - runnable.run(); - } - HandshakeStatus hsStatus = engine.getHandshakeStatus(); - if (hsStatus == HandshakeStatus.NEED_TASK) { - throw new Exception( - "handshake shouldn't need additional tasks"); - } - log("\tnew HandshakeStatus: " + hsStatus); - } - } - - private static boolean isEngineClosed(SSLEngine engine) { - return (engine.isOutboundDone() && engine.isInboundDone()); - } - - private static void logSocketStatus(Socket socket) { - log("##### " + socket + " #####"); - log("isBound: " + socket.isBound()); - log("isConnected: " + socket.isConnected()); - log("isClosed: " + socket.isClosed()); - log("isInputShutdown: " + socket.isInputShutdown()); - log("isOutputShutdown: " + socket.isOutputShutdown()); - } - - /* - * Logging code - */ - private static boolean resultOnce = true; - - private static void log(String str, SSLEngineResult result) { - if (!logging) { - return; - } - if (resultOnce) { - resultOnce = false; - log("The format of the SSLEngineResult is: \n" - + "\t\"getStatus() / getHandshakeStatus()\" +\n" - + "\t\"bytesConsumed() / bytesProduced()\"\n"); - } - HandshakeStatus hsStatus = result.getHandshakeStatus(); - log(str - + result.getStatus() + "/" + hsStatus + ", " - + result.bytesConsumed() + "/" + result.bytesProduced() - + " bytes"); - if (hsStatus == HandshakeStatus.FINISHED) { - log("\t...ready for application data"); - } - } - - private static void log(String str) { - if (logging) { - if (debug) { - System.err.println(str); - } else { - System.out.println(str); - } - } - } -} diff --git a/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java b/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java index eceefb9506d..fa6cccbcdcf 100644 --- a/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java +++ b/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * 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,17 @@ * @run main/othervm SSLSocketTemplate */ -import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; -import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManagerFactory; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketTimeoutException; -import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.KeyFactory; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.security.spec.PKCS8EncodedKeySpec; -import java.util.Base64; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -66,7 +56,7 @@ * test/jdk/sun/security/ssl/ServerHandshaker/AnonCipherWithWantClientAuth.java * test/jdk/sun/net/www/protocol/https/HttpsClient/ServerIdentityTest.java */ -public class SSLSocketTemplate { +public class SSLSocketTemplate extends SSLContextTemplate { /* * ================== @@ -128,53 +118,6 @@ protected void runClientApplication(int serverPort) throws Exception { // blank } - /* - * Create an instance of SSLContext for client use. - */ - protected SSLContext createClientSSLContext() throws Exception { - return createSSLContext(TRUSTED_CERTS, END_ENTITY_CERTS, - getClientContextParameters()); - } - - /* - * Create an instance of SSLContext for server use. - */ - protected SSLContext createServerSSLContext() throws Exception { - return createSSLContext(TRUSTED_CERTS, END_ENTITY_CERTS, - getServerContextParameters()); - } - - /* - * The parameters used to configure SSLContext. - */ - protected static final class ContextParameters { - final String contextProtocol; - final String tmAlgorithm; - final String kmAlgorithm; - - ContextParameters(String contextProtocol, - String tmAlgorithm, String kmAlgorithm) { - - this.contextProtocol = contextProtocol; - this.tmAlgorithm = tmAlgorithm; - this.kmAlgorithm = kmAlgorithm; - } - } - - /* - * Get the client side parameters of SSLContext. - */ - protected ContextParameters getClientContextParameters() { - return new ContextParameters("TLS", "PKIX", "NewSunX509"); - } - - /* - * Get the server side parameters of SSLContext. - */ - protected ContextParameters getServerContextParameters() { - return new ContextParameters("TLS", "PKIX", "NewSunX509"); - } - /* * Does the client side use customized connection other than * explicit Socket.connect(), for example, URL.openConnection()? @@ -296,7 +239,7 @@ protected void doServerSide() throws Exception { /* * Define the client side of the test. */ - private void doClientSide() throws Exception { + protected void doClientSide() throws Exception { // Wait for server to get started. // @@ -360,116 +303,6 @@ private void doClientSide() throws Exception { } } - /* - * ============================================= - * Stuffs to customize the SSLContext instances. - */ - - /* - * ======================================= - * Certificates and keys used in the test. - */ - // Trusted certificates. - protected final static Cert[] TRUSTED_CERTS = { - Cert.CA_ECDSA_SECP256R1, - Cert.CA_ECDSA_SECT283R1, - Cert.CA_RSA_2048, - Cert.CA_DSA_2048 }; - - // End entity certificate. - protected final static Cert[] END_ENTITY_CERTS = { - Cert.EE_ECDSA_SECP256R1, - Cert.EE_ECDSA_SECT283R1, - Cert.EE_RSA_2048, - Cert.EE_EC_RSA_SECP256R1, - Cert.EE_DSA_2048 }; - - /* - * Create an instance of SSLContext with the specified trust/key materials. - */ - public static SSLContext createSSLContext( - Cert[] trustedCerts, - Cert[] endEntityCerts, - ContextParameters params) throws Exception { - - KeyStore ts = null; // trust store - KeyStore ks = null; // key store - char passphrase[] = "passphrase".toCharArray(); - - // Generate certificate from cert string. - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - // Import the trused certs. - ByteArrayInputStream is; - if (trustedCerts != null && trustedCerts.length != 0) { - ts = KeyStore.getInstance("JKS"); - ts.load(null, null); - - Certificate[] trustedCert = new Certificate[trustedCerts.length]; - for (int i = 0; i < trustedCerts.length; i++) { - is = new ByteArrayInputStream(trustedCerts[i].certStr.getBytes()); - try { - trustedCert[i] = cf.generateCertificate(is); - } finally { - is.close(); - } - - ts.setCertificateEntry( - "trusted-cert-" + trustedCerts[i].name(), trustedCert[i]); - } - } - - // Import the key materials. - if (endEntityCerts != null && endEntityCerts.length != 0) { - ks = KeyStore.getInstance("JKS"); - ks.load(null, null); - - for (int i = 0; i < endEntityCerts.length; i++) { - // generate the private key. - PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - Base64.getMimeDecoder().decode(endEntityCerts[i].privKeyStr)); - KeyFactory kf = - KeyFactory.getInstance( - endEntityCerts[i].keyAlgo); - PrivateKey priKey = kf.generatePrivate(priKeySpec); - - // generate certificate chain - is = new ByteArrayInputStream( - endEntityCerts[i].certStr.getBytes()); - Certificate keyCert = null; - try { - keyCert = cf.generateCertificate(is); - } finally { - is.close(); - } - - Certificate[] chain = new Certificate[] { keyCert }; - - // import the key entry. - ks.setKeyEntry("cert-" + endEntityCerts[i].name(), - priKey, passphrase, chain); - } - } - - // Create an SSLContext object. - TrustManagerFactory tmf = - TrustManagerFactory.getInstance(params.tmAlgorithm); - tmf.init(ts); - - SSLContext context = SSLContext.getInstance(params.contextProtocol); - if (endEntityCerts != null && endEntityCerts.length != 0 && ks != null) { - KeyManagerFactory kmf = - KeyManagerFactory.getInstance(params.kmAlgorithm); - kmf.init(ks, passphrase); - - context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - } else { - context.init(null, tmf.getTrustManagers(), null); - } - - return context; - } - /* * ================================================= * Stuffs to boot up the client-server mode testing. @@ -599,7 +432,7 @@ public void run() { } } - private void startClient(boolean newThread) throws Exception { + private void startClient(boolean newThread) { if (newThread) { clientThread = new Thread() { @Override @@ -631,534 +464,4 @@ private synchronized void logException(String prefix, Throwable cause) { cause.printStackTrace(System.out); } - public static enum Cert { - - CA_ECDSA_SECP256R1( - "EC", - // SHA256withECDSA, curve secp256r1 - // Validity - // Not Before: May 22 07:18:16 2018 GMT - // Not After : May 17 07:18:16 2038 GMT - // Subject Key Identifier: - // 60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86 - "-----BEGIN CERTIFICATE-----\n" + - "MIIBvjCCAWOgAwIBAgIJAIvFG6GbTroCMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" + - "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + - "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYTAlVT\n" + - "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTBZ\n" + - "MBMGByqGSM49AgEGCCqGSM49AwEHA0IABBz1WeVb6gM2mh85z3QlvaB/l11b5h0v\n" + - "LIzmkC3DKlVukZT+ltH2Eq1oEkpXuf7QmbM0ibrUgtjsWH3mULfmcWmjUDBOMB0G\n" + - "A1UdDgQWBBRgz71z//oaMNKk7NNJcUbvGjWghjAfBgNVHSMEGDAWgBRgz71z//oa\n" + - "MNKk7NNJcUbvGjWghjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQCG\n" + - "6wluh1r2/T6L31mZXRKf9JxeSf9pIzoLj+8xQeUChQIhAJ09wAi1kV8yePLh2FD9\n" + - "2YEHlSQUAbwwqCDEVB5KxaqP\n" + - "-----END CERTIFICATE-----", - "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/HcHdoLJCdq3haVd\n" + - "XZTSKP00YzM3xX97l98vGL/RI1KhRANCAAQc9VnlW+oDNpofOc90Jb2gf5ddW+Yd\n" + - "LyyM5pAtwypVbpGU/pbR9hKtaBJKV7n+0JmzNIm61ILY7Fh95lC35nFp"), - - CA_ECDSA_SECP384R1( - "EC", - // SHA384withECDSA, curve secp384r1 - // Validity - // Not Before: Jun 24 08:15:06 2019 GMT - // Not After : Jun 19 08:15:06 2039 GMT - // Subject Key Identifier: - // 0a:93:a9:a0:bf:e7:d5:48:9d:4f:89:15:c6:51:98:80:05:51:4e:4e - "-----BEGIN CERTIFICATE-----\n" + - "MIICCDCCAY6gAwIBAgIUCpOpoL/n1UidT4kVxlGYgAVRTk4wCgYIKoZIzj0EAwMw\n" + - "OzELMAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0Ug\n" + - "VGVzdCBTZXJpdmNlMB4XDTE5MDYyNDA4MTUwNloXDTM5MDYxOTA4MTUwNlowOzEL\n" + - "MAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVz\n" + - "dCBTZXJpdmNlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAENVQN1wXWFdgC6u/dDdiC\n" + - "y+WtMTF66oL/0BSm+1ZqsogamzCryawOcHgiuXgWzx5CQ3LuOC+tDFyXpGfHuCvb\n" + - "dkzxPrP5n9NrR8/uRPe5l1KOUbchviU8z9cTP+LZxnZDo1MwUTAdBgNVHQ4EFgQU\n" + - "SktSFArR1p/5mXV0kyo0RxIVa/UwHwYDVR0jBBgwFoAUSktSFArR1p/5mXV0kyo0\n" + - "RxIVa/UwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjBZvoNmq3/v\n" + - "RD2gBTyvxjS9h0rsMRLHDnvul/KWngytwGPTOBo0Y8ixQXSjdKoc3rkCMQDkiNgx\n" + - "IDxuHedmrLQKIPnVcthTmwv7//jHiqGoKofwChMo2a1P+DQdhszmeHD/ARQ=\n" + - "-----END CERTIFICATE-----", - "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDChlbt0NF8oIKODSxn2\n" + - "WXCXuJm3z78LRkzYQS3Nx5NMjei5ytkFZz4qvD4XXMWlTEyhZANiAAQ1VA3XBdYV\n" + - "2ALq790N2ILL5a0xMXrqgv/QFKb7VmqyiBqbMKvJrA5weCK5eBbPHkJDcu44L60M\n" + - "XJekZ8e4K9t2TPE+s/mf02tHz+5E97mXUo5RtyG+JTzP1xM/4tnGdkM="), - - CA_ECDSA_SECP521R1( - "EC", - // SHA512withECDSA, curve secp521r1 - // Validity - // Not Before: Jun 24 08:15:06 2019 GMT - // Not After : Jun 19 08:15:06 2039 GMT - // Subject Key Identifier: - // 25:ca:68:76:6d:29:17:9b:71:78:45:2d:d4:c6:e4:5d:fe:25:ff:90 - "-----BEGIN CERTIFICATE-----\n" + - "MIICUzCCAbSgAwIBAgIUJcpodm0pF5txeEUt1MbkXf4l/5AwCgYIKoZIzj0EAwQw\n" + - "OzELMAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0Ug\n" + - "VGVzdCBTZXJpdmNlMB4XDTE5MDYyNDA4MTUwNloXDTM5MDYxOTA4MTUwNlowOzEL\n" + - "MAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVz\n" + - "dCBTZXJpdmNlMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAmFD5VmB2MdyJ6k+E\n" + - "eP4JncrE65ySL07gVmFwnr8otOt3NtRAyzmviMNNXXjo5R5NqNjKP4pr92JjT0sO\n" + - "D65yngkBtH151Ev/fiKPLxkXL9GzfKdWHVhDX7Zg6DUydzukzZV2/dIyloAIqwlz\n" + - "QVKJqT7RypDufdng8hnE9YfKo6ypZiujUzBRMB0GA1UdDgQWBBRAIrxa7WqtqUCe\n" + - "HFuKREDC92spvTAfBgNVHSMEGDAWgBRAIrxa7WqtqUCeHFuKREDC92spvTAPBgNV\n" + - "HRMBAf8EBTADAQH/MAoGCCqGSM49BAMEA4GMADCBiAJCAe22iirZnODCmlpxcv57\n" + - "3g5BEE60C+dtYmTqR4DtFyDaTRQ5CFf4ZxvQPIbD+SXi5Cbrl6qtrZG0cjUihPkC\n" + - "Hi1hAkIAiEcO7nMPgQLny+GrciojfN+bZXME/dPz6KHBm/89f8Me+jawVnv6y+df\n" + - "2Sbafh1KV6ntWQtB4bK3MXV8Ym9Eg1I=\n" + - "-----END CERTIFICATE-----", - "MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAV8dZszV6+nLw3LeA\n" + - "Q+qLJLGaqyjlsQkaopCPcmoRdy1HX6AzB/YnKsPkHp/9DQN6A2JgUhFG5B0XvKSk\n" + - "BqNNuSGhgYkDgYYABACYUPlWYHYx3InqT4R4/gmdysTrnJIvTuBWYXCevyi063c2\n" + - "1EDLOa+Iw01deOjlHk2o2Mo/imv3YmNPSw4PrnKeCQG0fXnUS/9+Io8vGRcv0bN8\n" + - "p1YdWENftmDoNTJ3O6TNlXb90jKWgAirCXNBUompPtHKkO592eDyGcT1h8qjrKlm\n" + - "Kw=="), - - CA_ECDSA_SECT283R1( - "EC", - // SHA1withECDSA, curve sect283r1 - // Validity - // Not Before: May 26 06:06:52 2020 GMT - // Not After : May 21 06:06:52 2040 GMT - // Subject Key Identifier: - // CF:A3:99:ED:4C:6E:04:41:09:21:31:33:B6:80:D5:A7:BF:2B:98:04 - "-----BEGIN CERTIFICATE-----\n" + - "MIIB8TCCAY+gAwIBAgIJANQFsBngZ3iMMAsGByqGSM49BAEFADBdMQswCQYDVQQG\n" + - "EwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNBMQ8wDQYDVQQKEwZPcmFjbGUx\n" + - "DzANBgNVBAsTBkpQR1NRRTESMBAGA1UEAxMJc2VjdDI4M3IxMB4XDTIwMDUyNjE4\n" + - "MDY1MloXDTQwMDUyMTE4MDY1MlowXTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNB\n" + - "MQswCQYDVQQHEwJTQTEPMA0GA1UEChMGT3JhY2xlMQ8wDQYDVQQLEwZKUEdTUUUx\n" + - "EjAQBgNVBAMTCXNlY3QyODNyMTBeMBAGByqGSM49AgEGBSuBBAARA0oABALatmDt\n" + - "QIhjpK4vJjv4GgC8CUH/VAWLUSQRU7yGGQ3NF8rVBARv0aehiII0nzjDVX5KrP/A\n" + - "w/DmW7q8PfEAIktuaA/tcKv/OKMyMDAwHQYDVR0OBBYEFM+jme1MbgRBCSExM7aA\n" + - "1ae/K5gEMA8GA1UdEwEB/wQFMAMBAf8wCwYHKoZIzj0EAQUAA08AMEwCJAGHsAP8\n" + - "HlcVqszra+fxq35juTxHJIfxTKIr7f54Ywtz7AJowgIkAxydv8g+dkuniOUAj0Xt\n" + - "FnGVp6HzKX5KM1zLpfqmix8ZPP/A\n" + - "-----END CERTIFICATE-----", - "MIGQAgEAMBAGByqGSM49AgEGBSuBBAARBHkwdwIBAQQkAdcyn/FxiNvuTsSgDehq\n" + - "SGFiTxAKNMMJfmsO6GHekzszFqjPoUwDSgAEAtq2YO1AiGOkri8mO/gaALwJQf9U\n" + - "BYtRJBFTvIYZDc0XytUEBG/Rp6GIgjSfOMNVfkqs/8DD8OZburw98QAiS25oD+1w\n" + - "q/84"), - - CA_RSA_2048( - "RSA", - // SHA256withRSA, 2048 bits - // Validity - // Not Before: May 22 07:18:16 2018 GMT - // Not After : May 17 07:18:16 2038 GMT - // Subject Key Identifier: - // 0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C - "-----BEGIN CERTIFICATE-----\n" + - "MIIDSTCCAjGgAwIBAgIJAI4ZF3iy8zG+MA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" + - "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" + - "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYT\n" + - "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + - "ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALpMcY7aWieXDEM1/YJf\n" + - "JW27b4nRIFZyEYhEloyGsKTuQiiQjc8cqRZFNXe2vwziDB4IyTEl0Hjl5QF6ZaQE\n" + - "huPzzwvQm1pv64KrRXrmj3FisQK8B5OWLty9xp6xDqsaMRoyObLK+oIb20T5fSlE\n" + - "evmo1vYjnh8CX0Yzx5Gr5ye6YSEHQvYOWEws8ad17OlyToR2KMeC8w4qo6rs59pW\n" + - "g7Mxn9vo22ImDzrtAbTbXbCias3xlE0Bp0h5luyf+5U4UgksoL9B9r2oP4GrLNEV\n" + - "oJk57t8lwaR0upiv3CnS8LcJELpegZub5ggqLY8ZPYFQPjlK6IzLOm6rXPgZiZ3m\n" + - "RL0CAwEAAaNQME4wHQYDVR0OBBYEFA3dk8n+S701t+iZeJD721o92xVMMB8GA1Ud\n" + - "IwQYMBaAFA3dk8n+S701t+iZeJD721o92xVMMAwGA1UdEwQFMAMBAf8wDQYJKoZI\n" + - "hvcNAQELBQADggEBAJTRC3rKUUhVH07/1+stUungSYgpM08dY4utJq0BDk36BbmO\n" + - "0AnLDMbkwFdHEoqF6hQIfpm7SQTmXk0Fss6Eejm8ynYr6+EXiRAsaXOGOBCzF918\n" + - "/RuKOzqABfgSU4UBKECLM5bMfQTL60qx+HdbdVIpnikHZOFfmjCDVxoHsGyXc1LW\n" + - "Jhkht8IGOgc4PMGvyzTtRFjz01kvrVQZ75aN2E0GQv6dCxaEY0i3ypSzjUWAKqDh\n" + - "3e2OLwUSvumcdaxyCdZAOUsN6pDBQ+8VRG7KxnlRlY1SMEk46QgQYLbPDe/+W/yH\n" + - "ca4PejicPeh+9xRAwoTpiE2gulfT7Lm+fVM7Ruc=\n" + - "-----END CERTIFICATE-----", - "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC6THGO2lonlwxD\n" + - "Nf2CXyVtu2+J0SBWchGIRJaMhrCk7kIokI3PHKkWRTV3tr8M4gweCMkxJdB45eUB\n" + - "emWkBIbj888L0Jtab+uCq0V65o9xYrECvAeTli7cvcaesQ6rGjEaMjmyyvqCG9tE\n" + - "+X0pRHr5qNb2I54fAl9GM8eRq+cnumEhB0L2DlhMLPGndezpck6EdijHgvMOKqOq\n" + - "7OfaVoOzMZ/b6NtiJg867QG0212womrN8ZRNAadIeZbsn/uVOFIJLKC/Qfa9qD+B\n" + - "qyzRFaCZOe7fJcGkdLqYr9wp0vC3CRC6XoGbm+YIKi2PGT2BUD45SuiMyzpuq1z4\n" + - "GYmd5kS9AgMBAAECggEAFHSoU2MuWwJ+2jJnb5U66t2V1bAcuOE1g5zkWvG/G5z9\n" + - "rq6Qo5kmB8f5ovdx6tw3MGUOklLwnRXBG3RxDJ1iokz3AvkY1clMNsDPlDsUrQKF\n" + - "JSO4QUBQTPSZhnsyfR8XHSU+qJ8Y+ohMfzpVv95BEoCzebtXdVgxVegBlcEmVHo2\n" + - "kMmkRN+bYNsr8eb2r+b0EpyumS39ZgKYh09+cFb78y3T6IFMGcVJTP6nlGBFkmA/\n" + - "25pYeCF2tSki08qtMJZQAvKfw0Kviibk7ZxRbJqmc7B1yfnOEHP6ftjuvKl2+RP/\n" + - "+5P5f8CfIP6gtA0LwSzAqQX/hfIKrGV5j0pCqrD0kQKBgQDeNR6Xi4sXVq79lihO\n" + - "a1bSeV7r8yoQrS8x951uO+ox+UIZ1MsAULadl7zB/P0er92p198I9M/0Jth3KBuS\n" + - "zj45mucvpiiGvmQlMKMEfNq4nN7WHOu55kufPswQB2mR4J3xmwI+4fM/nl1zc82h\n" + - "De8JSazRldJXNhfx0RGFPmgzbwKBgQDWoVXrXLbCAn41oVnWB8vwY9wjt92ztDqJ\n" + - "HMFA/SUohjePep9UDq6ooHyAf/Lz6oE5NgeVpPfTDkgvrCFVKnaWdwALbYoKXT2W\n" + - "9FlyJox6eQzrtHAacj3HJooXWuXlphKSizntfxj3LtMR9BmrmRJOfK+SxNOVJzW2\n" + - "+MowT20EkwKBgHmpB8jdZBgxI7o//m2BI5Y1UZ1KE5vx1kc7VXzHXSBjYqeV9FeF\n" + - "2ZZLP9POWh/1Fh4pzTmwIDODGT2UPhSQy0zq3O0fwkyT7WzXRknsuiwd53u/dejg\n" + - "iEL2NPAJvulZ2+AuiHo5Z99LK8tMeidV46xoJDDUIMgTG+UQHNGhK5gNAoGAZn/S\n" + - "Cn7SgMC0CWSvBHnguULXZO9wH1wZAFYNLL44OqwuaIUFBh2k578M9kkke7woTmwx\n" + - "HxQTjmWpr6qimIuY6q6WBN8hJ2Xz/d1fwhYKzIp20zHuv5KDUlJjbFfqpsuy3u1C\n" + - "kts5zwI7pr1ObRbDGVyOdKcu7HI3QtR5qqyjwaUCgYABo7Wq6oHva/9V34+G3Goh\n" + - "63bYGUnRw2l5BD11yhQv8XzGGZFqZVincD8gltNThB0Dc/BI+qu3ky4YdgdZJZ7K\n" + - "z51GQGtaHEbrHS5caV79yQ8QGY5mUVH3E+VXSxuIqb6pZq2DH4sTAEFHyncddmOH\n" + - "zoXBInYwRG9KE/Bw5elhUw=="), - - CA_DSA_2048( - "DSA", - // SHA256withDSA, 2048 bits - // Validity - // Not Before: May 22 07:18:18 2018 GMT - // Not After : May 17 07:18:18 2038 GMT - // Subject Key Identifier: - // 76:66:9E:F7:3B:DD:45:E5:3B:D9:72:3C:3F:F0:54:39:86:31:26:53 - "-----BEGIN CERTIFICATE-----\n" + - "MIIErjCCBFSgAwIBAgIJAOktYLNCbr02MAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" + - "EwJVUzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2\n" + - "Y2UwHhcNMTgwNTIyMDcxODE4WhcNMzgwNTE3MDcxODE4WjA7MQswCQYDVQQGEwJV\n" + - "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Uw\n" + - "ggNHMIICOQYHKoZIzjgEATCCAiwCggEBAO5GyPhSm0ze3LSu+gicdULLj05iOfTL\n" + - "UvZQ29sYz41zmqrLBQbdKiHqgJu2Re9sgTb5suLNjF047TOLPnU3jhPtWm2X8Xzi\n" + - "VGIcHym/Q/MeZxStt/88seqroI3WOKzIML2GcrishT+lcGrtH36Tf1+ue2Snn3PS\n" + - "WyxygNqPjllP5uUjYmFLvAf4QLMldkd/D2VxcwsHjB8y5iUZsXezc/LEhRZS/02m\n" + - "ivqlRw3AMkq/OVe/ZtxFWsP0nsfxEGdZuaUFpppGfixxFvymrB3+J51cTt+pZBDq\n" + - "D2y0DYfc+88iCs4jwHTfcDIpLb538HBjBj2rEgtQESQmB0ooD/+wsPsCIQC1bYch\n" + - "gElNtDYL3FgpLgNSUYp7gIWv9ehaC7LO2z7biQKCAQBitvFOnDkUja8NAF7lDpOV\n" + - "b5ipQ8SicBLW3kQamxhyuyxgZyy/PojZ/oPorkqW/T/A0rhnG6MssEpAtdiwVB+c\n" + - "rBYGo3bcwmExJhdOJ6dYuKFppPWhCwKMHs9npK+lqBMl8l5j58xlcFeC7ZfGf8GY\n" + - "GkhFW0c44vEQhMMbac6ZTTP4mw+1t7xJfmDMlLEyIpTXaAAk8uoVLWzQWnR40sHi\n" + - "ybvS0u3JxQkb7/y8tOOZu8qlz/YOS7lQ6UxUGX27Ce1E0+agfPphetoRAlS1cezq\n" + - "Wa7r64Ga0nkj1kwkcRqjgTiJx0NwnUXr78VAXFhVF95+O3lfqhvdtEGtkhDGPg7N\n" + - "A4IBBgACggEBAMmSHQK0w2i+iqUjOPzn0yNEZrzepLlLeQ1tqtn0xnlv5vBAeefD\n" + - "Pm9dd3tZOjufVWP7hhEz8xPobb1CS4e3vuQiv5UBfhdPL3f3l9T7JMAKPH6C9Vve\n" + - "OQXE5eGqbjsySbcmseHoYUt1WCSnSda1opX8zchX04e7DhGfE2/L9flpYEoSt8lI\n" + - "vMNjgOwvKdW3yvPt1/eBBHYNFG5gWPv/Q5KoyCtHS03uqGm4rNc/wZTIEEfd66C+\n" + - "QRaUltjOaHmtwOdDHaNqwhYZSVOip+Mo+TfyzHFREcdHLapo7ZXqbdYkRGxRR3d+\n" + - "3DfHaraJO0OKoYlPkr3JMvM/MSGR9AnZOcejUDBOMB0GA1UdDgQWBBR2Zp73O91F\n" + - "5TvZcjw/8FQ5hjEmUzAfBgNVHSMEGDAWgBR2Zp73O91F5TvZcjw/8FQ5hjEmUzAM\n" + - "BgNVHRMEBTADAQH/MAsGCWCGSAFlAwQDAgNHADBEAiBzriYE41M2y9Hy5ppkL0Qn\n" + - "dIlNc8JhXT/PHW7GDtViagIgMko8Qoj9gDGPK3+O9E8DC3wGiiF9CObM4LN387ok\n" + - "J+g=\n" + - "-----END CERTIFICATE-----", - "MIICZQIBADCCAjkGByqGSM44BAEwggIsAoIBAQDuRsj4UptM3ty0rvoInHVCy49O" + - "Yjn0y1L2UNvbGM+Nc5qqywUG3Soh6oCbtkXvbIE2+bLizYxdOO0ziz51N44T7Vpt" + - "l/F84lRiHB8pv0PzHmcUrbf/PLHqq6CN1jisyDC9hnK4rIU/pXBq7R9+k39frntk" + - "p59z0lsscoDaj45ZT+blI2JhS7wH+ECzJXZHfw9lcXMLB4wfMuYlGbF3s3PyxIUW" + - "Uv9Npor6pUcNwDJKvzlXv2bcRVrD9J7H8RBnWbmlBaaaRn4scRb8pqwd/iedXE7f" + - "qWQQ6g9stA2H3PvPIgrOI8B033AyKS2+d/BwYwY9qxILUBEkJgdKKA//sLD7AiEA" + - "tW2HIYBJTbQ2C9xYKS4DUlGKe4CFr/XoWguyzts+24kCggEAYrbxTpw5FI2vDQBe" + - "5Q6TlW+YqUPEonAS1t5EGpsYcrssYGcsvz6I2f6D6K5Klv0/wNK4ZxujLLBKQLXY" + - "sFQfnKwWBqN23MJhMSYXTienWLihaaT1oQsCjB7PZ6SvpagTJfJeY+fMZXBXgu2X" + - "xn/BmBpIRVtHOOLxEITDG2nOmU0z+JsPtbe8SX5gzJSxMiKU12gAJPLqFS1s0Fp0" + - "eNLB4sm70tLtycUJG+/8vLTjmbvKpc/2Dku5UOlMVBl9uwntRNPmoHz6YXraEQJU" + - "tXHs6lmu6+uBmtJ5I9ZMJHEao4E4icdDcJ1F6+/FQFxYVRfefjt5X6ob3bRBrZIQ" + - "xj4OzQQjAiEAsceWOM8do4etxp2zgnoNXV8PUUyqWhz1+0srcKV7FR4="), - - EE_ECDSA_SECT283R1( - "EC", - // SHA1withECDSA, curve sect283r1 - // Validity - // Not Before: May 26 06:08:15 2020 GMT - // Not After : May 21 06:08:15 2040 GMT - // Authority Key Identifier: - // CF:A3:99:ED:4C:6E:04:41:09:21:31:33:B6:80:D5:A7:BF:2B:98:04 - "-----BEGIN CERTIFICATE-----\n" + - "MIICFTCCAbOgAwIBAgIJAM0Dd9zxR9CeMAsGByqGSM49BAEFADBdMQswCQYDVQQG\n" + - "EwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNBMQ8wDQYDVQQKEwZPcmFjbGUx\n" + - "DzANBgNVBAsTBkpQR1NRRTESMBAGA1UEAxMJc2VjdDI4M3IxMB4XDTIwMDUyNjE4\n" + - "MDgxNVoXDTQwMDUyMTE4MDgxNVowYDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNB\n" + - "MQswCQYDVQQHEwJTQTEPMA0GA1UEChMGT3JhY2xlMQ8wDQYDVQQLEwZKUEdTUUUx\n" + - "FTATBgNVBAMMDHNlY3QyODNyMV9lZTBeMBAGByqGSM49AgEGBSuBBAARA0oABAMP\n" + - "oaMP2lIiCrNaFSePtZA8nBnqJXSGCz8kosKeYTqz/SPE1AN6BvM4xl0kPQZvJWMz\n" + - "fyTcm2Ar0PdbIh8f22vJfO+0JpfhnqNTMFEwHQYDVR0OBBYEFOzDGNWQhslU5ei4\n" + - "SYda/ro9DickMA8GA1UdEwQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUz6OZ7UxuBEEJ\n" + - "ITEztoDVp78rmAQwCwYHKoZIzj0EAQUAA08AMEwCJALYBWSYdbhRiW4mNulQh6/v\n" + - "dfHG3y/oMjzJEmT/A0WYl96ohgIkAbDC0Ke632RXtCZ4xa2FrmzP41Vb80mSH1iY\n" + - "FCJ3LVoTEUgN\n" + - "-----END CERTIFICATE-----", - "MIGQAgEAMBAGByqGSM49AgEGBSuBBAARBHkwdwIBAQQkAXq9LPYU+XSrImPzgO1e\n" + - "hsgjfTBXlWGveFUtn0OHPtbp7hzpoUwDSgAEAw+how/aUiIKs1oVJ4+1kDycGeol\n" + - "dIYLPySiwp5hOrP9I8TUA3oG8zjGXSQ9Bm8lYzN/JNybYCvQ91siHx/ba8l877Qm\n" + - "l+Ge"), - - CA_DSA_1024( - "DSA", - // dsaWithSHA1, 1024 bits - // Validity - // Not Before: Apr 24 12:25:43 2020 GMT - // Not After : Apr 22 12:25:43 2030 GMT - // Authority Key Identifier: - // E1:3C:01:52:EB:D1:38:F7:CF:F1:E3:5E:DB:54:75:7F:5E:AB:2D:36 - "-----BEGIN CERTIFICATE-----\n" + - "MIIC9TCCArWgAwIBAgIUd52yKk0OxQuxdaYRAfq5VLuF1ZAwCQYHKoZIzjgEAzAu\n" + - "MQswCQYDVQQGEwJVUzENMAsGA1UECgwESmF2YTEQMA4GA1UECwwHU3VuSlNTRTAe\n" + - "Fw0yMDA0MjQxMjI1NDJaFw0zMDA0MjIxMjI1NDJaMC4xCzAJBgNVBAYTAlVTMQ0w\n" + - "CwYDVQQKDARKYXZhMRAwDgYDVQQLDAdTdW5KU1NFMIIBtjCCASsGByqGSM44BAEw\n" + - "ggEeAoGBAKgyb2XpANq43T8yBf5v0PTBOddLPxd0f0FotASron5rQr86JjBTfgIW\n" + - "oE4u7nYlO6bp/M4Dw6qZr+HaDu9taIDOj6LL51eUShVsOgS7XZcUzLT8vPnkEDDo\n" + - "u326x0B7fuNCbMLm+ipM2d4FhLUTt4Qb5TcY6l7dOGHeWiL7nl43AhUAoGr8DY2m\n" + - "WHZPHk2XbZ5wpaM2lLcCgYBKiFbFFViH/ylHJRPtYtjtJw4ls1scbVP4TRHnKoZc\n" + - "HPAird1fDYgGC2b0GQNAMABhI+L+ogxS7qakySpJCheuN25AjiSyilygQdlXoWRt\n" + - "Mggsh8EQZT7iP4V4e9m3xRHzb5ECvsSTdZB1BQMcC90W2Avq+orqgBnr2in9UEd8\n" + - "qwOBhAACgYAgVWxjYWlWIv7s4BnNMQoPKppi205f3aC6wv6Rqk4BnYYYrFONEmzQ\n" + - "hzj6lSXfxLpTu4lg2zNeIraZggoS0ztkbZNNADEmAHx+OLshiJJxu2/KfoopJOZg\n" + - "8ARmuaKOkWbkW9y4hWhfBlVwZbckG3Eibff0xronIXXy7B7UKaccyqNTMFEwHQYD\n" + - "VR0OBBYEFOE8AVLr0Tj3z/HjXttUdX9eqy02MB8GA1UdIwQYMBaAFOE8AVLr0Tj3\n" + - "z/HjXttUdX9eqy02MA8GA1UdEwEB/wQFMAMBAf8wCQYHKoZIzjgEAwMvADAsAhRC\n" + - "YLduLniBEJ51SfBWIkvNW6OG7QIUSKaTY6rgEFDEMoTqOjFChR22nkk=\n" + - "-----END CERTIFICATE-----", - "MIIBSgIBADCCASsGByqGSM44BAEwggEeAoGBAKgyb2XpANq43T8yBf5v0PTBOddL\n" + - "Pxd0f0FotASron5rQr86JjBTfgIWoE4u7nYlO6bp/M4Dw6qZr+HaDu9taIDOj6LL\n" + - "51eUShVsOgS7XZcUzLT8vPnkEDDou326x0B7fuNCbMLm+ipM2d4FhLUTt4Qb5TcY\n" + - "6l7dOGHeWiL7nl43AhUAoGr8DY2mWHZPHk2XbZ5wpaM2lLcCgYBKiFbFFViH/ylH\n" + - "JRPtYtjtJw4ls1scbVP4TRHnKoZcHPAird1fDYgGC2b0GQNAMABhI+L+ogxS7qak\n" + - "ySpJCheuN25AjiSyilygQdlXoWRtMggsh8EQZT7iP4V4e9m3xRHzb5ECvsSTdZB1\n" + - "BQMcC90W2Avq+orqgBnr2in9UEd8qwQWAhQ7rSn+WvIxeuZ/CK4p04eMe5JzpA=="), - - EE_ECDSA_SECP256R1( - "EC", - // SHA256withECDSA, curve secp256r1 - // Validity - // Not Before: May 22 07:18:16 2018 GMT - // Not After : May 17 07:18:16 2038 GMT - // Authority Key Identifier: - // 60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86 - "-----BEGIN CERTIFICATE-----\n" + - "MIIBqjCCAVCgAwIBAgIJAPLY8qZjgNRAMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" + - "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + - "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYTAlVT\n" + - "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTEY\n" + - "MBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\n" + - "QgAEb+9n05qfXnfHUb0xtQJNS4JeSi6IjOfW5NqchvKnfJey9VkJzR7QHLuOESdf\n" + - "xlR7q8YIWgih3iWLGfB+wxHiOqMjMCEwHwYDVR0jBBgwFoAUYM+9c//6GjDSpOzT\n" + - "SXFG7xo1oIYwCgYIKoZIzj0EAwIDSAAwRQIgWpRegWXMheiD3qFdd8kMdrkLxRbq\n" + - "1zj8nQMEwFTUjjQCIQDRIrAjZX+YXHN9b0SoWWLPUq0HmiFIi8RwMnO//wJIGQ==\n" + - "-----END CERTIFICATE-----", - "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgn5K03bpTLjEtFQRa\n" + - "JUtx22gtmGEvvSUSQdimhGthdtihRANCAARv72fTmp9ed8dRvTG1Ak1Lgl5KLoiM\n" + - "59bk2pyG8qd8l7L1WQnNHtAcu44RJ1/GVHurxghaCKHeJYsZ8H7DEeI6"), - - EE_ECDSA_SECP384R1( - "EC", - // SHA384withECDSA, curve secp384r1 - // Validity - // Not Before: Jun 24 08:15:06 2019 GMT - // Not After : Jun 19 08:15:06 2039 GMT - // Authority Key Identifier: - // 40:2D:AA:EE:66:AA:33:27:AD:9B:5D:52:9B:60:67:6A:2B:AD:52:D2 - "-----BEGIN CERTIFICATE-----\n" + - "MIICEjCCAZegAwIBAgIUS3F0AqAXWRg07CnbknJzxofyBQMwCgYIKoZIzj0EAwMw\n" + - "OzELMAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0Ug\n" + - "VGVzdCBTZXJpdmNlMB4XDTE5MDYyNDA4MTUwNloXDTM5MDYxOTA4MTUwNlowVTEL\n" + - "MAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVz\n" + - "dCBTZXJpdmNlMRgwFgYDVQQDDA9SZWdyZXNzaW9uIFRlc3QwdjAQBgcqhkjOPQIB\n" + - "BgUrgQQAIgNiAARqElz8b6T07eyKomIinhztV3/3XBk9bKGtJ0W+JOltjuhMmP/w\n" + - "G8ASSevpgqgpi6EzpBZaaJxE3zNfkNnxXOZmQi2Ypd1uK0zRdbEOKg0XOcTTZwEj\n" + - "iLjYmt3O0pwpklijQjBAMB0GA1UdDgQWBBRALaruZqozJ62bXVKbYGdqK61S0jAf\n" + - "BgNVHSMEGDAWgBRKS1IUCtHWn/mZdXSTKjRHEhVr9TAKBggqhkjOPQQDAwNpADBm\n" + - "AjEArVDFKf48xijN6huVUJzKCOP0zlWB5Js+DItIkZmLQuhciPLhLIB/rChf3Y4C\n" + - "xuP4AjEAmfLhQRI0O3pifpYzYSVh2G7/jHNG4eO+2dvgAcU+Lh2IIj/cpLaPFSvL\n" + - "J8FXY9Nj\n" + - "-----END CERTIFICATE-----", - "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDASuI9EtK29APXPipkc\n" + - "qDA+qwlewMjv/OcjUJ77kP1Vz62oVF9iY9SRIyFIUju8wt+hZANiAARqElz8b6T0\n" + - "7eyKomIinhztV3/3XBk9bKGtJ0W+JOltjuhMmP/wG8ASSevpgqgpi6EzpBZaaJxE\n" + - "3zNfkNnxXOZmQi2Ypd1uK0zRdbEOKg0XOcTTZwEjiLjYmt3O0pwpklg="), - - EE_ECDSA_SECP521R1( - "EC", - // SHA512withECDSA, curve secp521r1 - // Validity - // Not Before: Jun 24 08:15:06 2019 GMT - // Not After : Jun 19 08:15:06 2039 GMT - // Authority Key Identifier: - // 7B:AA:79:A4:49:DD:59:34:F0:86:6C:51:C7:30:F4:CE:C5:81:8A:28 - "-----BEGIN CERTIFICATE-----\n" + - "MIICXDCCAb2gAwIBAgIUck4QTsbHNqUfPxfGPJLYbedFPdswCgYIKoZIzj0EAwQw\n" + - "OzELMAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0Ug\n" + - "VGVzdCBTZXJpdmNlMB4XDTE5MDYyNDA4MTUwNloXDTM5MDYxOTA4MTUwNlowVTEL\n" + - "MAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVz\n" + - "dCBTZXJpdmNlMRgwFgYDVQQDDA9SZWdyZXNzaW9uIFRlc3QwgZswEAYHKoZIzj0C\n" + - "AQYFK4EEACMDgYYABAGa2zDLhYQHHCLI3YBqFYJTzrnDIjzwXrxhcRTS8DYkcrjZ\n" + - "+Fih1YyNhix0sdjH+3EqElXAHHuVzn3n3hPOtQCWlQCICkErB34S0cvmtRkeW8Fi\n" + - "hrR5tvJEzEZjPSgwn81kKyhV2L70je6i7Cw884Va8bODckpgw0vTmbQb7T9dupkv\n" + - "1aNCMEAwHQYDVR0OBBYEFHuqeaRJ3Vk08IZsUccw9M7FgYooMB8GA1UdIwQYMBaA\n" + - "FEAivFrtaq2pQJ4cW4pEQML3aym9MAoGCCqGSM49BAMEA4GMADCBiAJCAb33KHdY\n" + - "WDbusORWoY8Euglpd5zsF15hJsk7wtpD5HST1/NWmdCx405w+TV6a9Gr4VPHeaIQ\n" + - "99i/+f237ALL5p6IAkIBbwwFL1vt3c/bx+niyuffQPNjly80rdC9puqAqriSiboS\n" + - "efhxjidJ9HLaIRCMEPyd6vAsC8mO8YvL1uCuEQLsiGM=\n" + - "-----END CERTIFICATE-----", - "MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIB8C/2OX2Dt9vFszzV\n" + - "hcAe0CbkMlvu9uQ/L7Vz88heuIj0rUZIPGshvgIJt1hCMT8HZxYHvDa4lbUvqjFB\n" + - "+zafvPWhgYkDgYYABAGa2zDLhYQHHCLI3YBqFYJTzrnDIjzwXrxhcRTS8DYkcrjZ\n" + - "+Fih1YyNhix0sdjH+3EqElXAHHuVzn3n3hPOtQCWlQCICkErB34S0cvmtRkeW8Fi\n" + - "hrR5tvJEzEZjPSgwn81kKyhV2L70je6i7Cw884Va8bODckpgw0vTmbQb7T9dupkv\n" + - "1Q=="), - - EE_RSA_2048( - "RSA", - // SHA256withRSA, 2048 bits - // Validity - // Not Before: May 22 07:18:16 2018 GMT - // Not After : May 17 07:18:16 2038 GMT - // Authority Key Identifier: - // 0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C - "-----BEGIN CERTIFICATE-----\n" + - "MIIDNjCCAh6gAwIBAgIJAO2+yPcFryUTMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" + - "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" + - "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYT\n" + - "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + - "ZTEYMBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOC\n" + - "AQ8AMIIBCgKCAQEAszfBobWfZIp8AgC6PiWDDavP65mSvgCXUGxACbxVNAfkLhNR\n" + - "QOsHriRB3X1Q3nvO9PetC6wKlvE9jlnDDj7D+1j1r1CHO7ms1fq8rfcQYdkanDtu\n" + - "4AlHo8v+SSWX16MIXFRYDj2VVHmyPtgbltcg4zGAuwT746FdLI94uXjJjq1IOr/v\n" + - "0VIlwE5ORWH5Xc+5Tj+oFWK0E4a4GHDgtKKhn2m72hN56/GkPKGkguP5NRS1qYYV\n" + - "/EFkdyQMOV8J1M7HaicSft4OL6eKjTrgo93+kHk+tv0Dc6cpVBnalX3TorG8QI6B\n" + - "cHj1XQd78oAlAC+/jF4pc0mwi0un49kdK9gRfQIDAQABoyMwITAfBgNVHSMEGDAW\n" + - "gBQN3ZPJ/ku9NbfomXiQ+9taPdsVTDANBgkqhkiG9w0BAQsFAAOCAQEApXS0nKwm\n" + - "Kp8gpmO2yG1rpd1+2wBABiMU4JZaTqmma24DQ3RzyS+V2TeRb29dl5oTUEm98uc0\n" + - "GPZvhK8z5RFr4YE17dc04nI/VaNDCw4y1NALXGs+AHkjoPjLyGbWpi1S+gfq2sNB\n" + - "Ekkjp6COb/cb9yiFXOGVls7UOIjnVZVd0r7KaPFjZhYh82/f4PA/A1SnIKd1+nfH\n" + - "2yk7mSJNC7Z3qIVDL8MM/jBVwiC3uNe5GPB2uwhd7k5LGAVN3j4HQQGB0Sz+VC1h\n" + - "92oi6xDa+YBva2fvHuCd8P50DDjxmp9CemC7rnZ5j8egj88w14X44Xjb/Fd/ApG9\n" + - "e57NnbT7KM+Grw==\n" + - "-----END CERTIFICATE-----", - "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzN8GhtZ9kinwC\n" + - "ALo+JYMNq8/rmZK+AJdQbEAJvFU0B+QuE1FA6weuJEHdfVDee870960LrAqW8T2O\n" + - "WcMOPsP7WPWvUIc7uazV+ryt9xBh2RqcO27gCUejy/5JJZfXowhcVFgOPZVUebI+\n" + - "2BuW1yDjMYC7BPvjoV0sj3i5eMmOrUg6v+/RUiXATk5FYfldz7lOP6gVYrQThrgY\n" + - "cOC0oqGfabvaE3nr8aQ8oaSC4/k1FLWphhX8QWR3JAw5XwnUzsdqJxJ+3g4vp4qN\n" + - "OuCj3f6QeT62/QNzpylUGdqVfdOisbxAjoFwePVdB3vygCUAL7+MXilzSbCLS6fj\n" + - "2R0r2BF9AgMBAAECggEASIkPkMCuw4WdTT44IwERus3IOIYOs2IP3BgEDyyvm4B6\n" + - "JP/iihDWKfA4zEl1Gqcni1RXMHswSglXra682J4kui02Ov+vzEeJIY37Ibn2YnP5\n" + - "ZjRT2s9GtI/S2o4hl8A/mQb2IMViFC+xKehTukhV4j5d6NPKk0XzLR7gcMjnYxwn\n" + - "l21fS6D2oM1xRG/di7sL+uLF8EXLRzfiWDNi12uQv4nwtxPKvuKhH6yzHt7YqMH0\n" + - "46pmDKDaxV4w1JdycjCb6NrCJOYZygoQobuZqOQ30UZoZsPJrtovkncFr1e+lNcO\n" + - "+aWDfOLCtTH046dEQh5oCShyXMybNlry/QHsOtHOwQKBgQDh2iIjs+FPpQy7Z3EX\n" + - "DGEvHYqPjrYO9an2KSRr1m9gzRlWYxKY46WmPKwjMerYtra0GP+TBHrgxsfO8tD2\n" + - "wUAII6sd1qup0a/Sutgf2JxVilLykd0+Ge4/Cs51tCdJ8EqDV2B6WhTewOY2EGvg\n" + - "JiKYkeNwgRX/9M9CFSAMAk0hUQKBgQDLJAartL3DoGUPjYtpJnfgGM23yAGl6G5r\n" + - "NSXDn80BiYIC1p0bG3N0xm3yAjqOtJAUj9jZbvDNbCe3GJfLARMr23legX4tRrgZ\n" + - "nEdKnAFKAKL01oM+A5/lHdkwaZI9yyv+hgSVdYzUjB8rDmzeVQzo1BT7vXypt2yV\n" + - "6O1OnUpCbQKBgA/0rzDChopv6KRcvHqaX0tK1P0rYeVQqb9ATNhpf9jg5Idb3HZ8\n" + - "rrk91BNwdVz2G5ZBpdynFl9G69rNAMJOCM4KZw5mmh4XOEq09Ivba8AHU7DbaTv3\n" + - "7QL7KnbaUWRB26HHzIMYVh0el6T+KADf8NXCiMTr+bfpfbL3dxoiF3zhAoGAbCJD\n" + - "Qse1dBs/cKYCHfkSOsI5T6kx52Tw0jS6Y4X/FOBjyqr/elyEexbdk8PH9Ar931Qr\n" + - "NKMvn8oA4iA/PRrXX7M2yi3YQrWwbkGYWYjtzrzEAdzmg+5eARKAeJrZ8/bg9l3U\n" + - "ttKaItJsDPlizn8rngy3FsJpR9aSAMK6/+wOiYkCgYEA1tZkI1rD1W9NYZtbI9BE\n" + - "qlJVFi2PBOJMKNuWdouPX3HLQ72GJSQff2BFzLTELjweVVJ0SvY4IipzpQOHQOBy\n" + - "5qh/p6izXJZh3IHtvwVBjHoEVplg1b2+I5e3jDCfqnwcQw82dW5SxOJMg1h/BD0I\n" + - "qAL3go42DYeYhu/WnECMeis="), - - EE_EC_RSA_SECP256R1( - "EC", - // SHA256withRSA, curve secp256r1 - // Validity - // Not Before: May 22 07:18:16 2018 GMT - // Not After : May 21 07:18:16 2028 GMT - // Authority Key Identifier: - // 0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C - "-----BEGIN CERTIFICATE-----\n" + - "MIICazCCAVOgAwIBAgIJAO2+yPcFryUUMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" + - "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" + - "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0yODA1MjEwNzE4MTZaMFUxCzAJBgNVBAYT\n" + - "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + - "ZTEYMBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0D\n" + - "AQcDQgAE59MERNTlVZ1eeps8Z3Oue5ZkgQdPtD+WIE6tj3PbIKpxGPDxvfNP959A\n" + - "yQjEK/ehWQVrCMmNoEkIzY+IIBgB06MjMCEwHwYDVR0jBBgwFoAUDd2Tyf5LvTW3\n" + - "6Jl4kPvbWj3bFUwwDQYJKoZIhvcNAQELBQADggEBAFOTVEqs70ykhZiIdrEsF1Ra\n" + - "I3B2rLvwXZk52uSltk2/bzVvewA577ZCoxQ1pL7ynkisPfBN1uVYtHjM1VA3RC+4\n" + - "+TAK78dnI7otYjWoHp5rvs4l6c/IbOspS290IlNuDUxMErEm5wxIwj+Aukx/1y68\n" + - "hOyCvHBLMY2c1LskH1MMBbDuS1aI+lnGpToi+MoYObxGcV458vxuT8+wwV8Fkpvd\n" + - "ll8IIFmeNPRv+1E+lXbES6CSNCVaZ/lFhPgdgYKleN7sfspiz50DG4dqafuEAaX5\n" + - "xaK1NWXJxTRz0ROH/IUziyuDW6jphrlgit4+3NCzp6vP9hAJQ8Vhcj0n15BKHIQ=\n" + - "-----END CERTIFICATE-----", - "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgGVc7hICpmp91jbYe\n" + - "nrr8nYHD37RZP3VENY+szuA7WjuhRANCAATn0wRE1OVVnV56mzxnc657lmSBB0+0\n" + - "P5YgTq2Pc9sgqnEY8PG980/3n0DJCMQr96FZBWsIyY2gSQjNj4ggGAHT"), - - EE_DSA_2048( - "DSA", - // SHA256withDSA, 2048 bits - // Validity - // Not Before: May 22 07:18:20 2018 GMT - // Not After : May 17 07:18:20 2038 GMT - // Authority Key Identifier: - // 76:66:9E:F7:3B:DD:45:E5:3B:D9:72:3C:3F:F0:54:39:86:31:26:53 - "-----BEGIN CERTIFICATE-----\n" + - "MIIEnDCCBEGgAwIBAgIJAP/jh1qVhNVjMAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" + - "EwJVUzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2\n" + - "Y2UwHhcNMTgwNTIyMDcxODIwWhcNMzgwNTE3MDcxODIwWjBVMQswCQYDVQQGEwJV\n" + - "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Ux\n" + - "GDAWBgNVBAMMD1JlZ3Jlc3Npb24gVGVzdDCCA0cwggI6BgcqhkjOOAQBMIICLQKC\n" + - "AQEAmlavgoJrMcjqWRVcDE2dmWAPREgnzQvneEDef68cprDzjSwvOs5QeFyx75ib\n" + - "ado1e6jO/rW1prCGWHDD1oA/Tn4Pk3vu0nUxzvl1qATc+aJbpUU5Op0bvp6LbCsQ\n" + - "QslV9FeRh7Eb7bP6gpc/kHCBzEgC1VCK7prccXWy+t6SMOHbND3h+UbckfSaUuaV\n" + - "sVJNTD1D6GElfRj4Nmz1BGPfSYvKorwNZEU3gXwFgtDoAcGx7tcyClLpDHfqRfw/\n" + - "7yiqLyeiP7D4hl5lMNouJWDlAdMFp0FMgS3s9VDFinIcr6VtBWMTG7+4+czHAB+3\n" + - "fvrwlqNzhBn3uFHrekN/w8fNxwIhAJo7Sae1za7IMW0Q6hE5B4b+s2B/FaKPoA4E\n" + - "jtZu13B9AoIBAQCOZqLMKfvqZWUgT0PQ3QjR7dAFdd06I9Y3+TOQzZk1+j+vw/6E\n" + - "X4vFItX4gihb/u5Q9CdmpwhVGi7bvo+7+/IKeTgoQ6f5+PSug7SrWWUQ5sPwaZui\n" + - "zXZJ5nTeZDucFc2yFx0wgnjbPwiUxZklOT7xGiOMtzOTa2koCz5KuIBL+/wPKKxm\n" + - "ypo9VoY9xfbdU6LMXZv/lpD5XTM9rYHr/vUTNkukvV6Hpm0YMEWhVZKUJiqCqTqG\n" + - "XHaleOxSw6uQWB/+TznifcC7gB48UOQjCqOKf5VuwQneJLhlhU/jhRV3xtr+hLZa\n" + - "hW1wYhVi8cjLDrZFKlgEQqhB4crnJU0mJY+tA4IBBQACggEAID0ezl00/X8mv7eb\n" + - "bzovum1+DEEP7FM57k6HZEG2N3ve4CW+0m9Cd+cWPz8wkZ+M0j/Eqa6F0IdbkXEc\n" + - "Q7CuzvUyJ57xQ3L/WCgXsiS+Bh8O4Mz7GwW22CGmHqafbVv+hKBfr8MkskO6GJUt\n" + - "SUF/CVLzB4gMIvZMH26tBP2xK+i7FeEK9kT+nGdzQSZBAhFYpEVCBplHZO24/OYq\n" + - "1DNoU327nUuXIhmsfA8N0PjiWbIZIjTPwBGr9H0LpATI7DIDNcvRRvtROP+pBU9y\n" + - "fuykPkptg9C0rCM9t06bukpOSaEz/2VIQdLE8fHYFA6pHZ6CIc2+5cfvMgTPhcjz\n" + - "W2jCt6MjMCEwHwYDVR0jBBgwFoAUdmae9zvdReU72XI8P/BUOYYxJlMwCwYJYIZI\n" + - "AWUDBAMCA0gAMEUCIQCeI5fN08b9BpOaHdc3zQNGjp24FOL/RxlBLeBAorswJgIg\n" + - "JEZ8DhYxQy1O7mmZ2UIT7op6epWMB4dENjs0qWPmcKo=\n" + - "-----END CERTIFICATE-----", - "MIICZQIBADCCAjoGByqGSM44BAEwggItAoIBAQCaVq+CgmsxyOpZFVwMTZ2ZYA9E\n" + - "SCfNC+d4QN5/rxymsPONLC86zlB4XLHvmJtp2jV7qM7+tbWmsIZYcMPWgD9Ofg+T\n" + - "e+7SdTHO+XWoBNz5olulRTk6nRu+notsKxBCyVX0V5GHsRvts/qClz+QcIHMSALV\n" + - "UIrumtxxdbL63pIw4ds0PeH5RtyR9JpS5pWxUk1MPUPoYSV9GPg2bPUEY99Ji8qi\n" + - "vA1kRTeBfAWC0OgBwbHu1zIKUukMd+pF/D/vKKovJ6I/sPiGXmUw2i4lYOUB0wWn\n" + - "QUyBLez1UMWKchyvpW0FYxMbv7j5zMcAH7d++vCWo3OEGfe4Uet6Q3/Dx83HAiEA\n" + - "mjtJp7XNrsgxbRDqETkHhv6zYH8Voo+gDgSO1m7XcH0CggEBAI5moswp++plZSBP\n" + - "Q9DdCNHt0AV13Toj1jf5M5DNmTX6P6/D/oRfi8Ui1fiCKFv+7lD0J2anCFUaLtu+\n" + - "j7v78gp5OChDp/n49K6DtKtZZRDmw/Bpm6LNdknmdN5kO5wVzbIXHTCCeNs/CJTF\n" + - "mSU5PvEaI4y3M5NraSgLPkq4gEv7/A8orGbKmj1Whj3F9t1Tosxdm/+WkPldMz2t\n" + - "gev+9RM2S6S9XoembRgwRaFVkpQmKoKpOoZcdqV47FLDq5BYH/5POeJ9wLuAHjxQ\n" + - "5CMKo4p/lW7BCd4kuGWFT+OFFXfG2v6EtlqFbXBiFWLxyMsOtkUqWARCqEHhyucl\n" + - "TSYlj60EIgIgLfA75+8KcKxdN8mr6gzGjQe7jPFGG42Ejhd7Q2F4wuw="), - - EE_DSA_1024( - "DSA", - // dsaWithSHA1, 1024 bits - // Validity - // Not Before: Apr 24 12:25:43 2020 GMT - // Not After : Apr 22 12:25:43 2030 GMT - // Authority Key Identifier: - // E1:3C:01:52:EB:D1:38:F7:CF:F1:E3:5E:DB:54:75:7F:5E:AB:2D:36 - "-----BEGIN CERTIFICATE-----\n" + - "MIIDADCCAr+gAwIBAgIUd2XJ5F2VTbk9a92w/NzLXR5zjUQwCQYHKoZIzjgEAzAu\n" + - "MQswCQYDVQQGEwJVUzENMAsGA1UECgwESmF2YTEQMA4GA1UECwwHU3VuSlNTRTAe\n" + - "Fw0yMDA0MjQxMjI1NDNaFw0zMDA0MjIxMjI1NDNaMEgxCzAJBgNVBAYTAlVTMQ0w\n" + - "CwYDVQQKDARKYXZhMRAwDgYDVQQLDAdTdW5KU1NFMRgwFgYDVQQDDA9SZWdyZXNz\n" + - "aW9uIFRlc3QwggG3MIIBLAYHKoZIzjgEATCCAR8CgYEA7fSkxYISlMJT+i8N5VOb\n" + - "lHhjrPYAy3oR2/YXQW6T0hCMhm8jmxgk1bDId9ZKHrxsM05EkCtRYaqag4ZZeGde\n" + - "ywv3IwwYqCQfGtkPwT9QAsdSABYwGOrlhEtZtBG1yQ44c+Rz/Vs+PtkAyZbf5VG1\n" + - "iSxFb9bI5QFJWJ9a2VpZh58CFQCCGALQoK4MsQP8V72WlB7Bvt9erwKBgQDCxu0G\n" + - "M2iZr0J8DaAo9/ChS4m7E7h6Jz9KOm2cFhzYGekkUXNzny7nyz6Qpgbuf8KNFKjt\n" + - "qoUDC8tlcVQAUlTcESC0TZXR3h21hl9wzIBhE+kJ1j8v1KAxfOaJOxObk5QEvIaA\n" + - "5j+jiHGwRS5tDqywOatz+emwMZv1wKnCNBElNgOBhAACgYBHjuQKucCuuvy/4DpG\n" + - "rSIzdueK+HrzOW8h2pfvz3lzpsyV6XJPC6we9CjaQjU01VcjwN2PoYtbGyml0pbK\n" + - "We4sdgn6LDL1aCM/WKRSxGHVTx+wkhKQ719YtiC0T6sA+eLirc6VT3/6+FbQWC+2\n" + - "bG7N19sGpV/RAXMBpRXUnBJSQaNCMEAwHQYDVR0OBBYEFNNZxyxuQmKvWowofr/S\n" + - "HdCIS+W8MB8GA1UdIwQYMBaAFOE8AVLr0Tj3z/HjXttUdX9eqy02MAkGByqGSM44\n" + - "BAMDMAAwLQIUUzzMhZ9St/Vo/YdgNTHdTw4cm14CFQCE6tWG157Wl5YFyYsGHsLY\n" + - "NN8uCA==\n" + - "-----END CERTIFICATE-----", - "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAO30pMWCEpTCU/ovDeVTm5R4Y6z2\n" + - "AMt6Edv2F0Fuk9IQjIZvI5sYJNWwyHfWSh68bDNORJArUWGqmoOGWXhnXssL9yMM\n" + - "GKgkHxrZD8E/UALHUgAWMBjq5YRLWbQRtckOOHPkc/1bPj7ZAMmW3+VRtYksRW/W\n" + - "yOUBSVifWtlaWYefAhUAghgC0KCuDLED/Fe9lpQewb7fXq8CgYEAwsbtBjNoma9C\n" + - "fA2gKPfwoUuJuxO4eic/SjptnBYc2BnpJFFzc58u58s+kKYG7n/CjRSo7aqFAwvL\n" + - "ZXFUAFJU3BEgtE2V0d4dtYZfcMyAYRPpCdY/L9SgMXzmiTsTm5OUBLyGgOY/o4hx\n" + - "sEUubQ6ssDmrc/npsDGb9cCpwjQRJTYEFgIUNRiLmNzfTYOuVsjkySPzP5gPImM="); - - final String keyAlgo; - final String certStr; - final String privKeyStr; - - Cert(String keyAlgo, String certStr, String privKeyStr) { - this.keyAlgo = keyAlgo; - this.certStr = certStr; - this.privKeyStr = privKeyStr; - } - } } diff --git a/test/jdk/sun/awt/PaletteTester.java b/test/jdk/sun/awt/PaletteTester.java index 7fb0d6b26ad..5734e984601 100644 --- a/test/jdk/sun/awt/PaletteTester.java +++ b/test/jdk/sun/awt/PaletteTester.java @@ -50,20 +50,19 @@ public class PaletteTester { static VImageColors demo; - private static final String INSTRUCTIONS = """ - This test should be run on any Windows platform in 8-bit - (256 color) display mode only. To check for errors, run a browser - application (Firefox or Internet Explorer) at the same time - and switch between this test and the browser (by clicking on the - title bars). - - The three panels in this test should look roughly the same (there - may be some dithering differences if you switch display modes - during the test, but the overall look should be the same. If - completely different colors are being used (either for the orange - background fill, the text, the image, or the rectangles), then the - test has failed. - """; + private static final String INSTRUCTIONS = + "This test should be run on any Windows platform in 8-bit\n" + + "(256 color) display mode only. To check for errors, run a browser\n" + + "application (Firefox or Internet Explorer) at the same time\n" + + "and switch between this test and the browser (by clicking on the\n" + + "title bars).\n" + + "\n" + + "The three panels in this test should look roughly the same (there\n" + + "may be some dithering differences if you switch display modes\n" + + "during the test, but the overall look should be the same. If\n" + + "completely different colors are being used (either for the orange\n" + + "background fill, the text, the image, or the rectangles), then the\n" + + "test has failed."; private static void init() { diff --git a/test/jdk/sun/security/ec/TestEC.policy b/test/jdk/sun/security/ec/TestEC.policy index de20d3b7bd1..a8ecc8cca4f 100644 --- a/test/jdk/sun/security/ec/TestEC.policy +++ b/test/jdk/sun/security/ec/TestEC.policy @@ -1,3 +1,6 @@ grant codebase "file:${test.classes}/*" { permission java.security.AllPermission; }; +grant codebase "file:${test.classes}/../../../../test/lib/-" { + permission java.security.AllPermission; +}; diff --git a/test/jdk/sun/security/krb5/NullStringToKey.java b/test/jdk/sun/security/krb5/NullStringToKey.java new file mode 100644 index 00000000000..ca6b6d5439e --- /dev/null +++ b/test/jdk/sun/security/krb5/NullStringToKey.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8343622 + * @summary KerberosKey created with null key bytes + * @run main/othervm NullStringToKey + */ + +import javax.security.auth.kerberos.KerberosKey; +import javax.security.auth.kerberos.KerberosPrincipal; +import java.security.Security; +import java.util.List; + +public class NullStringToKey { + public static void main(String[] args) throws Exception { + + Security.removeProvider("SUN"); + Security.removeProvider("SunJCE"); + + var name = new KerberosPrincipal("me@ME.COM"); + var pass = "password".toCharArray(); + for (var alg : List.of( + "aes128-cts-hmac-sha1-96", "aes256-cts-hmac-sha1-96", + "aes128-cts-hmac-sha256-128", "aes256-cts-hmac-sha384-192")) { + System.out.println(alg); + // Do not use Utils.runAndCheckException as it might call + // MessageDigest.getInstance("MD5") at class initialization + // and we have already removed the SUN provider. + try { + new KerberosKey(name, pass, alg); + throw new RuntimeException("Didn't get expected exception"); + } catch (IllegalArgumentException e) { + // expected + System.out.println(e); + } + } + } +} diff --git a/test/jdk/sun/security/krb5/RFC396xTest.java b/test/jdk/sun/security/krb5/RFC396xTest.java index 18814aca89a..5fde5b66adc 100644 --- a/test/jdk/sun/security/krb5/RFC396xTest.java +++ b/test/jdk/sun/security/krb5/RFC396xTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,6 +51,7 @@ public class RFC396xTest { public static void main(String[] args) throws Exception { System.setProperty("sun.security.krb5.msinterop.des.s2kcharset", "utf-8"); + DkCrypto.ALLOW_WEAK_PBKDF2_ITERATION_COUNT = true; test(); } diff --git a/test/jdk/sun/security/krb5/auto/DiffSaltParams.java b/test/jdk/sun/security/krb5/auto/DiffSaltParams.java index e03b4fe5098..04ee2960daa 100644 --- a/test/jdk/sun/security/krb5/auto/DiffSaltParams.java +++ b/test/jdk/sun/security/krb5/auto/DiffSaltParams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,11 +38,11 @@ public static void main(String[] args) throws Exception { OneKDC kdc = new OneKDC(null).writeJAASConf(); kdc.addPrincipal("user1", "user1pass".toCharArray(), - "hello", new byte[]{0, 0, 1, 0}); + "hello", new byte[]{0, 1, 0, 0}); kdc.addPrincipal("user2", "user2pass".toCharArray(), "hello", null); kdc.addPrincipal("user3", "user3pass".toCharArray(), - null, new byte[]{0, 0, 1, 0}); + null, new byte[]{0, 1, 0, 0}); kdc.addPrincipal("user4", "user4pass".toCharArray()); Context.fromUserPass("user1", "user1pass".toCharArray(), true); diff --git a/test/jdk/sun/security/krb5/auto/KDC.java b/test/jdk/sun/security/krb5/auto/KDC.java index aeab113995f..c4fce1c06e6 100644 --- a/test/jdk/sun/security/krb5/auto/KDC.java +++ b/test/jdk/sun/security/krb5/auto/KDC.java @@ -351,11 +351,12 @@ public void writeKtab(String tab, boolean append, String... names) name.indexOf('/') < 0 ? PrincipalName.KRB_NT_UNKNOWN : PrincipalName.KRB_NT_SRV_HST); - ktab.addEntry(pn, - getSalt(pn), - pass, - kvno, - true); + int[] etypes = EType.getDefaults("default_tkt_enctypes"); + EncryptionKey[] keys = new EncryptionKey[etypes.length]; + for (int i = 0; i < etypes.length; i++) { + keys[i] = keyForUser(pn, etypes[i], false); + } + ktab.addEntry(pn, keys, kvno, true); } else { nativeKdc.ktadd(name, tab); } @@ -641,10 +642,7 @@ private static EncryptionKey generateRandomKey(int eType) */ private char[] getPassword(PrincipalName p, boolean server) throws KrbException { - String pn = p.toString(); - if (p.getRealmString() == null) { - pn = pn + "@" + getRealm(); - } + String pn = nameOf(p); char[] pass = passwords.get(pn); if (pass == null) { throw new KrbException(server? @@ -660,10 +658,7 @@ private char[] getPassword(PrincipalName p, boolean server) * @return the salt */ protected String getSalt(PrincipalName p) { - String pn = p.toString(); - if (p.getRealmString() == null) { - pn = pn + "@" + getRealm(); - } + String pn = nameOf(p); if (salts.containsKey(pn)) { return salts.get(pn); } @@ -695,10 +690,7 @@ protected byte[] getParams(PrincipalName p, int etype) { case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128: case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192: - String pn = p.toString(); - if (p.getRealmString() == null) { - pn = pn + "@" + getRealm(); - } + String pn = nameOf(p); if (s2kparamses.containsKey(pn)) { return s2kparamses.get(pn); } @@ -712,6 +704,23 @@ protected byte[] getParams(PrincipalName p, int etype) { } } + /** + * Returns the name of a PrincipalName inside KDC dbs. + * @param p the principal name + * @return the name + */ + private String nameOf(PrincipalName p) { + String pn = p.toString(); + if (p.getRealmString() == null) { + pn = pn + "@" + getRealm(); + } + if (pn.startsWith("krbtgt/")) { + // We always register krbtgt using REALM + pn = "krbtgt/" + pn.substring(7).toUpperCase(Locale.ROOT); + } + return pn; + } + /** * Returns the key for a given principal of the given encryption type * @param p the principal diff --git a/test/jdk/sun/security/krb5/auto/UserIterCount.java b/test/jdk/sun/security/krb5/auto/UserIterCount.java new file mode 100644 index 00000000000..a90da012a06 --- /dev/null +++ b/test/jdk/sun/security/krb5/auto/UserIterCount.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8370615 + * @summary Improve Kerberos credentialing + * @library /test/lib + * @compile -XDignore.symbol.file UserIterCount.java + * @run main jdk.test.lib.FileInstaller TestHosts TestHosts + * @run main/othervm -Djdk.net.hosts.file=TestHosts UserIterCount + */ +import sun.security.krb5.PrincipalName; + +public class UserIterCount { + + static class MyKDC extends OneKDC { + public MyKDC() throws Exception { + super(null); + } + + @Override + protected byte[] getParams(PrincipalName p, int etype) { + if (etype == 18) { + if (p.toString().startsWith(OneKDC.USER)) { + return new byte[]{0, 0, 16, 01}; + } else { + return new byte[]{0, 79, (byte)255, (byte)255}; + } + } else { + return super.getParams(p, etype); + } + } + } + + public static void main(String[] args) throws Exception { + new MyKDC().writeJAASConf(); + Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + Context.fromUserPass(OneKDC.USER2, OneKDC.PASS2, false); + } +} diff --git a/test/jdk/sun/security/ssl/ALPN/AlpnGreaseTest.java b/test/jdk/sun/security/ssl/ALPN/AlpnGreaseTest.java index 66efefeee4a..734906f03e1 100644 --- a/test/jdk/sun/security/ssl/ALPN/AlpnGreaseTest.java +++ b/test/jdk/sun/security/ssl/ALPN/AlpnGreaseTest.java @@ -53,7 +53,7 @@ * (wrap/unwrap) pass before any application data is consumed or * produced. */ -public class AlpnGreaseTest implements SSLContextTemplate { +public class AlpnGreaseTest extends SSLContextTemplate { private final SSLEngine clientEngine; // client Engine private final ByteBuffer clientOut; // write side of clientEngine diff --git a/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java b/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java index c1be3a50e0f..bbc2851a685 100644 --- a/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java +++ b/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,21 +48,23 @@ public class DisabledCurve extends SSLSocketTemplate { { { "TLSv1.2" }, { "TLSv1.2" } }, { { "TLSv1.1" }, { "TLSv1.1" } }, { { "TLSv1" }, { "TLSv1" } } }; + @Override protected SSLContext createClientSSLContext() throws Exception { return createSSLContext( - new SSLSocketTemplate.Cert[] { - SSLSocketTemplate.Cert.CA_ECDSA_SECT283R1 }, - new SSLSocketTemplate.Cert[] { - SSLSocketTemplate.Cert.EE_ECDSA_SECT283R1 }, + new SSLContextTemplate.Cert[] { + SSLContextTemplate.Cert.CA_ECDSA_SECT283R1 }, + new SSLContextTemplate.Cert[] { + SSLContextTemplate.Cert.EE_ECDSA_SECT283R1 }, getClientContextParameters()); } + @Override protected SSLContext createServerSSLContext() throws Exception { return createSSLContext( - new SSLSocketTemplate.Cert[] { - SSLSocketTemplate.Cert.CA_ECDSA_SECT283R1 }, - new SSLSocketTemplate.Cert[] { - SSLSocketTemplate.Cert.EE_ECDSA_SECT283R1 }, + new SSLContextTemplate.Cert[] { + SSLContextTemplate.Cert.CA_ECDSA_SECT283R1 }, + new SSLContextTemplate.Cert[] { + SSLContextTemplate.Cert.EE_ECDSA_SECT283R1 }, getServerContextParameters()); } diff --git a/test/jdk/sun/security/ssl/CipherSuite/RestrictSignatureScheme.java b/test/jdk/sun/security/ssl/CipherSuite/RestrictSignatureScheme.java index 3dde234a2ce..eebff3ec96c 100644 --- a/test/jdk/sun/security/ssl/CipherSuite/RestrictSignatureScheme.java +++ b/test/jdk/sun/security/ssl/CipherSuite/RestrictSignatureScheme.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * 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,21 +28,12 @@ * @summary Restrict signature algorithms and named groups * @run main/othervm RestrictSignatureScheme */ -import java.io.ByteArrayInputStream; -import java.security.KeyFactory; -import java.security.KeyStore; -import java.security.PrivateKey; + import java.security.Security; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.security.spec.PKCS8EncodedKeySpec; import java.util.Arrays; -import java.util.Base64; -import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLServerSocket; -import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.SSLException; public class RestrictSignatureScheme extends SSLSocketTemplate { @@ -58,16 +49,20 @@ public class RestrictSignatureScheme extends SSLSocketTemplate { private final SSLContext context; RestrictSignatureScheme() throws Exception { - this.context = createSSLContext(); + this.context = createSSLContext( + new Cert[]{Cert.EE_RSASSA_PSS}, + new Cert[]{Cert.EE_RSASSA_PSS}, + new ContextParameters("TLS", "PKIX", "NewSunX509") + ); } @Override - protected SSLContext createClientSSLContext() throws Exception { + public SSLContext createClientSSLContext() throws Exception { return context; } @Override - protected SSLContext createServerSSLContext() throws Exception { + public SSLContext createServerSSLContext() throws Exception { return context; } @@ -117,116 +112,4 @@ public static void main(String[] args) throws Exception { throw new Exception("The test case should be disabled"); } } - - - private static final String trustedCertStr = - /** - * Signature Algorithm: rsassaPss - * Issuer: CN = localhost - * Validity Not Before: Jun 6 07:11:00 2018 GMT - * Not After : Jun 1 07:11:00 2038 GMT - * Subject: CN = localhost - * Public Key Algorithm: rsassaPss - */ - "-----BEGIN CERTIFICATE-----\n" - + "MIIDZjCCAh2gAwIBAgIUHxwPs3eAgJ057nJwiLgWZWeNqdgwPgYJKoZIhvcNAQEK\n" - + "MDGgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogQC\n" - + "AgDeMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xODA2MDYwNzExMDBaFw0zODA2\n" - + "MDEwNzExMDBaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASAwCwYJKoZIhvcNAQEK\n" - + "A4IBDwAwggEKAoIBAQCl8r4Qrg27BYUO/1Va2Ix8QPGzN/lvzmKvP5Ff26ovNW4v\n" - + "RUx68HzAhhiWtcl+PwLSbJqJreEkTlle7PnRAypby3fO7ZAK0Y3YiHquaBg7d+7Y\n" - + "FhhHwv8gG0lZcyA0BkXFJHqdq76qar0xHC6DVezXm0K3mcceymGtFR9BzWmAj+7D\n" - + "YsSwvtTQ7WNoQmf0cdDMSM71IwaTwIwvT2wzX1vv5hcdDyXdr64WFqWSA9sNJ2K6\n" - + "arxaaU1klwKSgDokF6njafWQ4UxdR67d5W1MYoiioDs2Yy3utsMpO2OUzZVBZNdT\n" - + "gkr1jsJhIurpz/5K51lwJIRQBezEFSb+60AFVoMJAgMBAAGjUDBOMB0GA1UdDgQW\n" - + "BBQfFit5ilWJmZgCX4QY0HsaI9iIDDAfBgNVHSMEGDAWgBQfFit5ilWJmZgCX4QY\n" - + "0HsaI9iIDDAMBgNVHRMEBTADAQH/MD4GCSqGSIb3DQEBCjAxoA0wCwYJYIZIAWUD\n" - + "BAIBoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCAaIEAgIA3gOCAQEAa4yUQ3gh\n" - + "d1YWPdEa1sv2hdkhtenw6m5yxbmaQl2+nIKSpk4RfpXC7K1EYwBF8TdfFbD8hGGh\n" - + "5n81BT0/dn1R9SRGCv7KTxx4lfQt31frlsw/tVciwyXQtcUZ6DqfnLP0/aRVLNgx\n" - + "zaP542JUHFYLTC3EGz2zUgv70ZUTlIsPG3/p8YO1iXdnYGQyzOuQPUBpI7nS7UtR\n" - + "Ug8VE9ACpBxxI3qChMahFZGHlXCCSjSmxpQa6UO4SQl8q5tPNnqdzWwvAW8qkCy4\n" - + "6barRQ4sMcGayhHh/uSTx7bcl0FMJpcI1ygbw7/Pc03zKtw0gMTBMns7q4yXjb/u\n" - + "ef47nW0t+LRAAg==\n" - + "-----END CERTIFICATE-----\n"; - - private static final String keyCertStr = trustedCertStr; - - private static final String privateKey = - "MIIEuwIBADALBgkqhkiG9w0BAQoEggSnMIIEowIBAAKCAQEApfK+EK4NuwWFDv9V\n" - + "WtiMfEDxszf5b85irz+RX9uqLzVuL0VMevB8wIYYlrXJfj8C0myaia3hJE5ZXuz5\n" - + "0QMqW8t3zu2QCtGN2Ih6rmgYO3fu2BYYR8L/IBtJWXMgNAZFxSR6nau+qmq9MRwu\n" - + "g1Xs15tCt5nHHsphrRUfQc1pgI/uw2LEsL7U0O1jaEJn9HHQzEjO9SMGk8CML09s\n" - + "M19b7+YXHQ8l3a+uFhalkgPbDSdiumq8WmlNZJcCkoA6JBep42n1kOFMXUeu3eVt\n" - + "TGKIoqA7NmMt7rbDKTtjlM2VQWTXU4JK9Y7CYSLq6c/+SudZcCSEUAXsxBUm/utA\n" - + "BVaDCQIDAQABAoIBAAc4vRS0vlw5LUUtz2UYr2Ro3xvRf8Vh0eGWfpkRUiKjzJu6\n" - + "BE4FUSh/rWpBlvcrfs/xcfgz3OxbjIAZB/YUkS9Vd21F4VLXM7kMl2onlYZg/b/h\n" - + "lkTpM3kONu7xl6Er9LVTlRJveuinpHwSoeONRbVMSGb9BjFM1VtW4/lVGxZBG05D\n" - + "y9i/o4vCZqULn9cAumOwicKuCyTcS58XcMJ+puSPfRA71PYLxqFkASAoJsUwCXpo\n" - + "gs39lLsIFgrfO8mBO1ux/SE+QaRc+9XqFSHHKD1XqF/9zSYBgWjE910EcpdYEdZx\n" - + "GEkwea7Fn4brO5OpIrHY/45naqbUOBzv6gufMAECgYEAz7PHCdcrQvmOb8EiNbQH\n" - + "uvSimwObWJFeN1ykp6mfRbSnkXw7p8+M4Tc8HFi8QLpoq63Ev2AwoaQCQvHbFC2Y\n" - + "1Cz0EkC0aOp+tZP7U2AUBdkcDesZAJQTad0zV6KesyIUXdxZXDG8JJ1XSNWfTJV4\n" - + "QD+BjLZ0jiAyCIfVYvWQqYkCgYEAzIln1nKTixLMPr5CldSmR7ZarEtPJU+hHwVg\n" - + "dV/Lc6d2Yy9JgunOXRo4BXB1TEo8JFbK3HBQH6tS8li4qDr7WK5wyYfh8qb4WZyu\n" - + "lc562f2WVYntcN8/Ojb+Vyrt7lk9sq/8KoVHxEAWd6mqL9VTPYuAu1Vw9fTGIZfB\n" - + "lDeELYECgYAvdzU4UXzofGGJtohb332YwwlaBZP9xJLUcg6K5l+orWVSASMc8XiP\n" - + "i3DoRXsYC8GZ4kdBOPlEJ1gA9oaLcPQpIPDSLwlLpLM6Scw4vI822uvnXl/DWxOo\n" - + "sM1n7Jj59QLUhGPDhvYpI+/rjC4wcUQe4qR3hMbUKBVnD6u7RsU9iQKBgQCQ17VK\n" - + "7bSCRfuRaxaoGADww7gOTv5rQ6qr1xjpxb7D1hFGR9Rc+smCsPB/GZZXQjK44SWj\n" - + "WX3ED4Ubzaxmpe4cbNu+O5XMSmWQwB36RFBHUwdE5/nXdqDFzu/qNqJrqZLBmVKP\n" - + "ofaiiWffsaytVvotmT6+atElvAMbAua42V+nAQKBgHtIn3mYMHLriYGhQzpkFEA2\n" - + "8YcAMlKppueOMAKVy8nLu2r3MidmLAhMiKJQKG45I3Yg0/t/25tXLiOPJlwrOebh\n" - + "xQqUBI/JUOIpGAEnr48jhOXnCS+i+z294G5U/RgjXrlR4bCPvrtCmwzWwe0h79w2\n" - + "Q2hO5ZTW6UD9CVA85whf"; - - private static SSLContext createSSLContext() throws Exception { - // Generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - // Create a key store - KeyStore ts = KeyStore.getInstance("PKCS12"); - KeyStore ks = KeyStore.getInstance("PKCS12"); - ts.load(null, null); - ks.load(null, null); - char passphrase[] = "passphrase".toCharArray(); - - // Import the trusted cert - ts.setCertificateEntry("trusted-cert-RSASSA-PSS", - cf.generateCertificate(new ByteArrayInputStream( - trustedCertStr.getBytes()))); - - boolean hasKeyMaterials = keyCertStr != null && privateKey != null; - if (hasKeyMaterials) { - - // Generate the private key. - PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - Base64.getMimeDecoder().decode(privateKey)); - KeyFactory kf = KeyFactory.getInstance("RSASSA-PSS"); - PrivateKey priKey = kf.generatePrivate(priKeySpec); - - // Generate certificate chain - Certificate keyCert = cf.generateCertificate( - new ByteArrayInputStream(keyCertStr.getBytes())); - Certificate[] chain = new Certificate[]{keyCert}; - - // Import the key entry. - ks.setKeyEntry("cert-RSASSA-PSS", priKey, passphrase, chain); - } - - // Create SSL context - TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); - tmf.init(ts); - - SSLContext context = SSLContext.getInstance("TLS"); - if (hasKeyMaterials) { - KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); - kmf.init(ks, passphrase); - context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - } else { - context.init(null, tmf.getTrustManagers(), null); - } - - return context; - } } diff --git a/test/jdk/sun/security/ssl/ClientHandshaker/LengthCheckTest.java b/test/jdk/sun/security/ssl/ClientHandshaker/LengthCheckTest.java index 50e76cbae1e..e2908dc92ce 100644 --- a/test/jdk/sun/security/ssl/ClientHandshaker/LengthCheckTest.java +++ b/test/jdk/sun/security/ssl/ClientHandshaker/LengthCheckTest.java @@ -26,7 +26,8 @@ * @bug 8044860 * @summary Vectors and fixed length fields should be verified * for allowed sizes. - * @library /test/lib + * @library /test/lib /javax/net/ssl/templates + * @build jdk.test.lib.Utils * @modules java.base/sun.security.ssl * @run main/othervm LengthCheckTest * @key randomness @@ -70,7 +71,6 @@ import javax.net.ssl.*; import javax.net.ssl.SSLEngineResult.*; -import java.io.*; import java.security.*; import java.nio.*; import java.util.List; @@ -79,7 +79,7 @@ import jdk.test.lib.security.SecurityUtils; -public class LengthCheckTest { +public class LengthCheckTest extends SSLEngineTemplate { /* * Enables logging of the SSLEngine operations. @@ -98,41 +98,9 @@ public class LengthCheckTest { private static final boolean debug = false; private static final boolean dumpBufs = true; - private final SSLContext sslc; - - private SSLEngine clientEngine; // client Engine - private ByteBuffer clientOut; // write side of clientEngine - private ByteBuffer clientIn; // read side of clientEngine - - private SSLEngine serverEngine; // server Engine - private ByteBuffer serverOut; // write side of serverEngine - private ByteBuffer serverIn; // read side of serverEngine private HandshakeTest handshakeTest; - /* - * For data transport, this example uses local ByteBuffers. This - * isn't really useful, but the purpose of this example is to show - * SSLEngine concepts, not how to do network transport. - */ - private ByteBuffer cTOs; // "reliable" transport client->server - private ByteBuffer sTOc; // "reliable" transport server->client - - /* - * The following is to set up the keystores. - */ - private static final String pathToStores = "../../../../javax/net/ssl/etc"; - private static final String keyStoreFile = "keystore"; - private static final String trustStoreFile = "truststore"; - private static final String passwd = "passphrase"; - - private static final String keyFilename = - System.getProperty("test.src", ".") + "/" + pathToStores + - "/" + keyStoreFile; - private static final String trustFilename = - System.getProperty("test.src", ".") + "/" + pathToStores + - "/" + trustStoreFile; - // Define a few basic TLS record and message types we might need private static final int TLS_RECTYPE_CCS = 0x14; private static final int TLS_RECTYPE_ALERT = 0x15; @@ -176,20 +144,20 @@ public void execTest() throws Exception { // Send Client Hello clientResult = clientEngine.wrap(clientOut, cTOs); log("client wrap: ", clientResult); - runDelegatedTasks(clientResult, clientEngine); + runDelegatedTasks(clientEngine); cTOs.flip(); dumpByteBuffer("CLIENT-TO-SERVER", cTOs); // Server consumes Client Hello serverResult = serverEngine.unwrap(cTOs, serverIn); log("server unwrap: ", serverResult); - runDelegatedTasks(serverResult, serverEngine); + runDelegatedTasks(serverEngine); cTOs.compact(); // Server generates ServerHello/Cert/Done record serverResult = serverEngine.wrap(serverOut, sTOc); log("server wrap: ", serverResult); - runDelegatedTasks(serverResult, serverEngine); + runDelegatedTasks(serverEngine); sTOc.flip(); // Intercept the ServerHello messages and instead send @@ -220,19 +188,19 @@ public void execTest() throws Exception { gotException = true; } log("client unwrap: ", clientResult); - runDelegatedTasks(clientResult, clientEngine); + runDelegatedTasks(clientEngine); } } else { dumpByteBuffer("SERVER-TO-CLIENT", sTOc); log("client unwrap: ", clientResult); - runDelegatedTasks(clientResult, clientEngine); + runDelegatedTasks(clientEngine); } sTOc.compact(); // The Client should now send a TLS Alert clientResult = clientEngine.wrap(clientOut, cTOs); log("client wrap: ", clientResult); - runDelegatedTasks(clientResult, clientEngine); + runDelegatedTasks(clientEngine); cTOs.flip(); dumpByteBuffer("CLIENT-TO-SERVER", cTOs); @@ -264,7 +232,7 @@ public void execTest() throws Exception { // Server consumes Client Hello serverResult = serverEngine.unwrap(evilClientHello, serverIn); log("server unwrap: ", serverResult); - runDelegatedTasks(serverResult, serverEngine); + runDelegatedTasks(serverEngine); evilClientHello.compact(); // Under normal circumstances this should be a ServerHello @@ -273,7 +241,7 @@ public void execTest() throws Exception { try { serverResult = serverEngine.wrap(serverOut, sTOc); log("server wrap: ", serverResult); - runDelegatedTasks(serverResult, serverEngine); + runDelegatedTasks(serverEngine); } catch (SSLProtocolException ssle) { log("Received expected SSLProtocolException: " + ssle); gotException = true; @@ -282,7 +250,7 @@ public void execTest() throws Exception { // We expect to see the server generate an alert here serverResult = serverEngine.wrap(serverOut, sTOc); log("server wrap: ", serverResult); - runDelegatedTasks(serverResult, serverEngine); + runDelegatedTasks(serverEngine); sTOc.flip(); dumpByteBuffer("SERVER-TO-CLIENT", sTOc); @@ -326,26 +294,7 @@ public static void main(String args[]) throws Exception { * Create an initialized SSLContext to use for these tests. */ public LengthCheckTest(String testName) throws Exception { - - KeyStore ks = KeyStore.getInstance("JKS"); - KeyStore ts = KeyStore.getInstance("JKS"); - - char[] passphrase = "passphrase".toCharArray(); - - ks.load(new FileInputStream(keyFilename), passphrase); - ts.load(new FileInputStream(trustFilename), passphrase); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(ts); - - SSLContext sslCtx = SSLContext.getInstance("TLS"); - - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - - sslc = sslCtx; + super(); switch (testName) { case "ServSendLongID": @@ -378,10 +327,8 @@ public LengthCheckTest(String testName) throws Exception { * sections of code. */ private void runTest() throws Exception { - boolean dataDone = false; - - createSSLEngines(); - createBuffers(); + configureSSLEngine(); +// createBuffers(); handshakeTest.execTest(); } @@ -390,19 +337,17 @@ private void runTest() throws Exception { * Using the SSLContext created during object creation, * create/configure the SSLEngines we'll use for this test. */ - private void createSSLEngines() throws Exception { + private void configureSSLEngine() throws Exception { /* * Configure the serverEngine to act as a server in the SSL/TLS * handshake. Also, require SSL client authentication. */ - serverEngine = sslc.createSSLEngine(); serverEngine.setUseClientMode(false); serverEngine.setNeedClientAuth(false); /* * Similar to above, but using client mode instead. */ - clientEngine = sslc.createSSLEngine("client", 80); clientEngine.setUseClientMode(true); // In order to make a test that will be backwards compatible @@ -413,84 +358,6 @@ private void createSSLEngines() throws Exception { new String[]{"TLS_RSA_WITH_AES_128_CBC_SHA"}); } - /* - * Create and size the buffers appropriately. - */ - private void createBuffers() { - - /* - * We'll assume the buffer sizes are the same - * between client and server. - */ - SSLSession session = clientEngine.getSession(); - int appBufferMax = session.getApplicationBufferSize(); - int netBufferMax = session.getPacketBufferSize(); - - /* - * We'll make the input buffers a bit bigger than the max needed - * size, so that unwrap()s following a successful data transfer - * won't generate BUFFER_OVERFLOWS. - * - * We'll use a mix of direct and indirect ByteBuffers for - * tutorial purposes only. In reality, only use direct - * ByteBuffers when they give a clear performance enhancement. - */ - clientIn = ByteBuffer.allocate(appBufferMax + 50); - serverIn = ByteBuffer.allocate(appBufferMax + 50); - - cTOs = ByteBuffer.allocateDirect(netBufferMax); - sTOc = ByteBuffer.allocateDirect(netBufferMax); - - clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes()); - serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes()); - } - - /* - * If the result indicates that we have outstanding tasks to do, - * go ahead and run them in this thread. - */ - private static void runDelegatedTasks(SSLEngineResult result, - SSLEngine engine) throws Exception { - - if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { - Runnable runnable; - while ((runnable = engine.getDelegatedTask()) != null) { - log("\trunning delegated task..."); - runnable.run(); - } - HandshakeStatus hsStatus = engine.getHandshakeStatus(); - if (hsStatus == HandshakeStatus.NEED_TASK) { - throw new Exception( - "handshake shouldn't need additional tasks"); - } - log("\tnew HandshakeStatus: " + hsStatus); - } - } - - private static boolean isEngineClosed(SSLEngine engine) { - return (engine.isOutboundDone() && engine.isInboundDone()); - } - - /* - * Simple check to make sure everything came across as expected. - */ - private static void checkTransfer(ByteBuffer a, ByteBuffer b) - throws Exception { - a.flip(); - b.flip(); - - if (!a.equals(b)) { - throw new Exception("Data didn't transfer cleanly"); - } else { - log("\tData transferred cleanly"); - } - - a.position(a.limit()); - b.position(b.limit()); - a.limit(a.capacity()); - b.limit(b.capacity()); - } - /* * Logging code */ diff --git a/test/jdk/sun/security/ssl/DHKeyExchange/DHEKeySizing.java b/test/jdk/sun/security/ssl/DHKeyExchange/DHEKeySizing.java index b008361273f..33070f42905 100644 --- a/test/jdk/sun/security/ssl/DHKeyExchange/DHEKeySizing.java +++ b/test/jdk/sun/security/ssl/DHKeyExchange/DHEKeySizing.java @@ -30,6 +30,9 @@ * @test * @bug 6956398 8301700 * @summary make ephemeral DH key match the length of the certificate key + * @library /javax/net/ssl/templates + * @library /test/lib + * @build jdk.test.lib.Utils * @run main/othervm * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1643 267 * @run main/othervm -Djsse.enableFFDHE=false @@ -109,18 +112,10 @@ import javax.net.ssl.*; import javax.net.ssl.SSLEngineResult.*; -import java.io.*; import java.nio.*; -import java.security.KeyStore; -import java.security.KeyFactory; import java.security.Security; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.interfaces.*; -import java.util.Base64; -public class DHEKeySizing { +public class DHEKeySizing extends SSLEngineTemplate { private final static boolean debug = true; @@ -132,89 +127,6 @@ public class DHEKeySizing { // negotiated DH keys. private final static int KEY_LEN_BIAS = 6; - private SSLContext sslc; - private SSLEngine ssle1; // client - private SSLEngine ssle2; // server - - private ByteBuffer appOut1; // write side of ssle1 - private ByteBuffer appIn1; // read side of ssle1 - private ByteBuffer appOut2; // write side of ssle2 - private ByteBuffer appIn2; // read side of ssle2 - - private ByteBuffer oneToTwo; // "reliable" transport ssle1->ssle2 - private ByteBuffer twoToOne; // "reliable" transport ssle2->ssle1 - - /* - * Where do we find the keystores? - */ - // Certificates and key used in the test. - static String trustedCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIIC8jCCAdqgAwIBAgIEUjkuRzANBgkqhkiG9w0BAQUFADA7MR0wGwYDVQQLExRT\n" + - "dW5KU1NFIFRlc3QgU2VyaXZjZTENMAsGA1UEChMESmF2YTELMAkGA1UEBhMCVVMw\n" + - "HhcNMTMwOTE4MDQzODMxWhcNMTMxMjE3MDQzODMxWjA7MR0wGwYDVQQLExRTdW5K\n" + - "U1NFIFRlc3QgU2VyaXZjZTENMAsGA1UEChMESmF2YTELMAkGA1UEBhMCVVMwggEi\n" + - "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCO+IGeaskJAvEcYc7pCl9neK3E\n" + - "a28fwWLtChufYNaC9hQfZlUdETWYjV7fZJVJKT/oLzdDNMWuVA0LKXArpI3thLNK\n" + - "QLXisdF9hKPlZRDazACL9kWUUtJ0FzpEySK4e8wW/z9FuU6e6iO19FbjxAfInJqk\n" + - "3EDiEhB5g73S2vtvPCxgq2DvWw9TDl/LIqdKG2JCS93koXCCaHmQ7MrIOqHPd+8r\n" + - "RbGpatXT9qyHKppUv9ATxVygO4rA794mgCFxpT+fkhz+NEB0twTkM65T1hnnOv5n\n" + - "ZIxkcjBggt85UlZtnP3b9P7SYxsWIa46Oc38Od2f3YejfVg6B+PqPgWNl3+/AgMB\n" + - "AAEwDQYJKoZIhvcNAQEFBQADggEBAAlrP6DFLRPSy0IgQhcI2i56tR/na8pezSte\n" + - "ZHcCdaCZPDy4UP8mpLJ9QCjEB5VJv8hPm4xdK7ULnKGOGHgYqDpV2ZHvQlhV1woQ\n" + - "TZGb/LM3c6kAs0j4j9KM2fq3iYUYexjIkS1KzsziflxMM6igS9BRMBR2LQyU+cYq\n" + - "YEsFzkF7Aj2ET4v/+tgot9mRr2NioJcaJkdsPDpMU3IKB1cczfu+OuLQ/GCG0Fqu\n" + - "6ijCeCqfnaAbemHbJeVZZ6Qgka3uC2YMntLBmLkhqEo1d9zGYLoh7oWL77y5ibQZ\n" + - "LK5/H/zikcu579TWjlDHcqL3arCwBcrtsjSaPrRSWMrWV/6c0qw=\n" + - "-----END CERTIFICATE-----"; - - // Private key in the format of PKCS#8 - static String targetPrivateKey = - "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCO+IGeaskJAvEc\n" + - "Yc7pCl9neK3Ea28fwWLtChufYNaC9hQfZlUdETWYjV7fZJVJKT/oLzdDNMWuVA0L\n" + - "KXArpI3thLNKQLXisdF9hKPlZRDazACL9kWUUtJ0FzpEySK4e8wW/z9FuU6e6iO1\n" + - "9FbjxAfInJqk3EDiEhB5g73S2vtvPCxgq2DvWw9TDl/LIqdKG2JCS93koXCCaHmQ\n" + - "7MrIOqHPd+8rRbGpatXT9qyHKppUv9ATxVygO4rA794mgCFxpT+fkhz+NEB0twTk\n" + - "M65T1hnnOv5nZIxkcjBggt85UlZtnP3b9P7SYxsWIa46Oc38Od2f3YejfVg6B+Pq\n" + - "PgWNl3+/AgMBAAECggEAPdb5Ycc4m4A9QBSCRcRpzbyiFLKPh0HDg1n65q4hOtYr\n" + - "kAVYTVFTSF/lqGS+Ob3w2YIKujQKSUQrvCc5UHdFuHXMgxKIWbymK0+DAMb9SlYw\n" + - "6lkkcWp9gx9E4dnJ/df2SAAxovvrKMuHlL1SFASHhVtPfH2URvSfUaANLDXxyYOs\n" + - "8BX0Nr6wazhWjLjXo9yIGnKSvFfB8XisYcA78kEgas43zhmIGCDPqaYyyffOfRbx\n" + - "pM1KNwGmlN86iWR1CbwA/wwhcMySWQueS+s7cHbpRqZIYJF9jEeELiwi0vxjealS\n" + - "EMuHYedIRFMWaDIq9XyjrvXamHb0Z25jlXBNZHaM0QKBgQDE9adl+zAezR/n79vw\n" + - "0XiX2Fx1UEo3ApZHuoA2Q/PcBk+rlKqqQ3IwTcy6Wo648wK7v6Nq7w5nEWcsf0dU\n" + - "QA2Ng/AJEev/IfF34x7sKGYxtk1gcE0EuSBA3R+ocEZxnNw1Ryd5nUU24s8d4jCP\n" + - "Mkothnyaim+zE2raDlEtVc0CaQKBgQC509av+02Uq5oMjzbQp5PBJfQFjATOQT15\n" + - "eefYnVYurkQ1kcVfixkrO2ORhg4SjmI2Z5hJDgGtXdwgidpzkad+R2epS5qLMyno\n" + - "lQVpY6bMpEZ7Mos0yQygxnm8uNohEcTExOe+nP5fNJVpzBsGmfeyYOhnPQlf6oqf\n" + - "0cHizedb5wKBgQC/l5LyMil6HOGHlhzmIm3jj7VI7QR0hJC5T6N+phVml8ESUDjA\n" + - "DYHbmSKouISTRtkG14FY+RiSjCxH7bvuKazFV2289PETquogTA/9e8MFYqfcQwG4\n" + - "sXi9gBxWlnj/9a2EKiYtOB5nKLR/BlNkSHA93tAA6N+FXEMZwMmYhxk42QKBgAuY\n" + - "HQgD3PZOsqDf+qKQIhbmAFCsSMx5o5VFtuJ8BpmJA/Z3ruHkMuDQpsi4nX4o5hXQ\n" + - "5t6AAjjH52kcUMXvK40kdWJJtk3DFnVNfvXxYsHX6hHbuHXFqYUKfSP6QJnZmvZP\n" + - "9smcz/4usLfWJUWHK740b6upUkFqx9Vq5/b3s9y3AoGAdM5TW7LkkOFsdMGVAUzR\n" + - "9iXmCWElHTK2Pcp/3yqDBHSfiQx6Yp5ANyPnE9NBM0yauCfOyBB2oxLO4Rdv3Rqk\n" + - "9V9kyR/YAGr7dJaPcQ7pZX0OpkzgueAOJYPrx5VUzPYUtklYV1ycFZTfKlpFCxT+\n" + - "Ei6KUo0NXSdUIcB4yib1J10="; - - static char passphrase[] = "passphrase".toCharArray(); - - /* - * Majority of the test case is here, setup is done below. - */ - - private void createSSLEngines() throws Exception { - ssle1 = sslc.createSSLEngine("client", 1); - ssle1.setUseClientMode(true); - - ssle2 = sslc.createSSLEngine("server", 2); - ssle2.setUseClientMode(false); - } - - private boolean isHandshaking(SSLEngine e) { - return (e.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING); - } - private void checkResult(ByteBuffer bbIn, ByteBuffer bbOut, SSLEngineResult result, Status status, HandshakeStatus hsStatus, @@ -255,130 +167,127 @@ private void checkResult(ByteBuffer bbIn, ByteBuffer bbOut, private void test(String cipherSuite, boolean exportable, int lenServerKeyEx, int lenClientKeyEx) throws Exception { - createSSLEngines(); - createBuffers(); - - SSLEngineResult result1; // ssle1's results from last operation - SSLEngineResult result2; // ssle2's results from last operation + SSLEngineResult result1; // clientEngine's results from last operation + SSLEngineResult result2; // serverEngine's results from last operation String[] suites = new String [] {cipherSuite}; - ssle1.setEnabledCipherSuites(suites); - ssle2.setEnabledCipherSuites(suites); + clientEngine.setEnabledCipherSuites(suites); + serverEngine.setEnabledCipherSuites(suites); log("======================================"); log("==================="); log("client hello"); - result1 = ssle1.wrap(appOut1, oneToTwo); - checkResult(appOut1, oneToTwo, result1, + result1 = clientEngine.wrap(clientOut, cTOs); + checkResult(clientOut, cTOs, result1, Status.OK, HandshakeStatus.NEED_UNWRAP, 0, -1); - oneToTwo.flip(); + cTOs.flip(); - result2 = ssle2.unwrap(oneToTwo, appIn2); - checkResult(oneToTwo, appIn2, result2, + result2 = serverEngine.unwrap(cTOs, serverIn); + checkResult(cTOs, serverIn, result2, Status.OK, HandshakeStatus.NEED_TASK, result1.bytesProduced(), 0); - runDelegatedTasks(ssle2); - oneToTwo.compact(); + runDelegatedTasks(serverEngine); + cTOs.compact(); log("==================="); log("ServerHello"); - result2 = ssle2.wrap(appOut2, twoToOne); - checkResult(appOut2, twoToOne, result2, + result2 = serverEngine.wrap(serverOut, sTOc); + checkResult(serverOut, sTOc, result2, Status.OK, HandshakeStatus.NEED_UNWRAP, 0, -1); - twoToOne.flip(); + sTOc.flip(); - log("Message length of ServerHello series: " + twoToOne.remaining()); - if (twoToOne.remaining() < (lenServerKeyEx - KEY_LEN_BIAS) || - twoToOne.remaining() > lenServerKeyEx) { + log("Message length of ServerHello series: " + sTOc.remaining()); + if (sTOc.remaining() < (lenServerKeyEx - KEY_LEN_BIAS) || + sTOc.remaining() > lenServerKeyEx) { throw new Exception( "Expected to generate ServerHello series messages of " + - lenServerKeyEx + " bytes, but not " + twoToOne.remaining()); + lenServerKeyEx + " bytes, but not " + sTOc.remaining()); } - result1 = ssle1.unwrap(twoToOne, appIn1); - checkResult(twoToOne, appIn1, result1, + result1 = clientEngine.unwrap(sTOc, clientIn); + checkResult(sTOc, clientIn, result1, Status.OK, HandshakeStatus.NEED_TASK, result2.bytesProduced(), 0); - runDelegatedTasks(ssle1); - twoToOne.compact(); + runDelegatedTasks(clientEngine); + sTOc.compact(); log("==================="); log("Key Exchange"); - result1 = ssle1.wrap(appOut1, oneToTwo); - checkResult(appOut1, oneToTwo, result1, + result1 = clientEngine.wrap(clientOut, cTOs); + checkResult(clientOut, cTOs, result1, Status.OK, HandshakeStatus.NEED_WRAP, 0, -1); - oneToTwo.flip(); + cTOs.flip(); - log("Message length of ClientKeyExchange: " + oneToTwo.remaining()); - if (oneToTwo.remaining() < (lenClientKeyEx - KEY_LEN_BIAS) || - oneToTwo.remaining() > lenClientKeyEx) { + log("Message length of ClientKeyExchange: " + cTOs.remaining()); + if (cTOs.remaining() < (lenClientKeyEx - KEY_LEN_BIAS) || + cTOs.remaining() > lenClientKeyEx) { throw new Exception( "Expected to generate ClientKeyExchange message of " + - lenClientKeyEx + " bytes, but not " + oneToTwo.remaining()); + lenClientKeyEx + " bytes, but not " + cTOs.remaining()); } - result2 = ssle2.unwrap(oneToTwo, appIn2); - checkResult(oneToTwo, appIn2, result2, + result2 = serverEngine.unwrap(cTOs, serverIn); + checkResult(cTOs, serverIn, result2, Status.OK, HandshakeStatus.NEED_TASK, result1.bytesProduced(), 0); - runDelegatedTasks(ssle2); - oneToTwo.compact(); + runDelegatedTasks(serverEngine); + cTOs.compact(); log("==================="); log("Client CCS"); - result1 = ssle1.wrap(appOut1, oneToTwo); - checkResult(appOut1, oneToTwo, result1, + result1 = clientEngine.wrap(clientOut, cTOs); + checkResult(clientOut, cTOs, result1, Status.OK, HandshakeStatus.NEED_WRAP, 0, -1); - oneToTwo.flip(); + cTOs.flip(); - result2 = ssle2.unwrap(oneToTwo, appIn2); - checkResult(oneToTwo, appIn2, result2, + result2 = serverEngine.unwrap(cTOs, serverIn); + checkResult(cTOs, serverIn, result2, Status.OK, HandshakeStatus.NEED_UNWRAP, result1.bytesProduced(), 0); - oneToTwo.compact(); + cTOs.compact(); log("==================="); log("Client Finished"); - result1 = ssle1.wrap(appOut1, oneToTwo); - checkResult(appOut1, oneToTwo, result1, + result1 = clientEngine.wrap(clientOut, cTOs); + checkResult(clientOut, cTOs, result1, Status.OK, HandshakeStatus.NEED_UNWRAP, 0, -1); - oneToTwo.flip(); + cTOs.flip(); - result2 = ssle2.unwrap(oneToTwo, appIn2); - checkResult(oneToTwo, appIn2, result2, + result2 = serverEngine.unwrap(cTOs, serverIn); + checkResult(cTOs, serverIn, result2, Status.OK, HandshakeStatus.NEED_WRAP, result1.bytesProduced(), 0); - oneToTwo.compact(); + cTOs.compact(); log("==================="); log("Server CCS"); - result2 = ssle2.wrap(appOut2, twoToOne); - checkResult(appOut2, twoToOne, result2, + result2 = serverEngine.wrap(serverOut, sTOc); + checkResult(serverOut, sTOc, result2, Status.OK, HandshakeStatus.NEED_WRAP, 0, -1); - twoToOne.flip(); + sTOc.flip(); - result1 = ssle1.unwrap(twoToOne, appIn1); - checkResult(twoToOne, appIn1, result1, + result1 = clientEngine.unwrap(sTOc, clientIn); + checkResult(sTOc, clientIn, result1, Status.OK, HandshakeStatus.NEED_UNWRAP, result2.bytesProduced(), 0); - twoToOne.compact(); + sTOc.compact(); log("==================="); log("Server Finished"); - result2 = ssle2.wrap(appOut2, twoToOne); - checkResult(appOut2, twoToOne, result2, + result2 = serverEngine.wrap(serverOut, sTOc); + checkResult(serverOut, sTOc, result2, Status.OK, HandshakeStatus.FINISHED, 0, -1); - twoToOne.flip(); + sTOc.flip(); - result1 = ssle1.unwrap(twoToOne, appIn1); - checkResult(twoToOne, appIn1, result1, + result1 = clientEngine.unwrap(sTOc, clientIn); + checkResult(sTOc, clientIn, result1, Status.OK, HandshakeStatus.FINISHED, result2.bytesProduced(), 0); - twoToOne.compact(); + sTOc.compact(); log("==================="); log("Check Session/Ciphers"); - String cs = ssle1.getSession().getCipherSuite(); + String cs = clientEngine.getSession().getCipherSuite(); if (!cs.equals(suites[0])) { throw new Exception("suites not equal: " + cs + "/" + suites[0]); } - cs = ssle2.getSession().getCipherSuite(); + cs = serverEngine.getSession().getCipherSuite(); if (!cs.equals(suites[0])) { throw new Exception("suites not equal: " + cs + "/" + suites[0]); } @@ -415,84 +324,36 @@ public static void main(String args[]) throws Exception { */ public DHEKeySizing() throws Exception { - sslc = getSSLContext(); + super(); } - /* - * Create an initialized SSLContext to use for this test. - */ - private SSLContext getSSLContext() throws Exception { - - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - // create a key store - KeyStore ts = KeyStore.getInstance("JKS"); - KeyStore ks = KeyStore.getInstance("JKS"); - ts.load(null, null); - ks.load(null, null); - - // import the trused cert - ByteArrayInputStream is = - new ByteArrayInputStream(trustedCertStr.getBytes()); - Certificate trusedCert = cf.generateCertificate(is); - is.close(); - ts.setCertificateEntry("rsa-trusted-2048", trusedCert); - - // generate the private key. - String keySpecStr = targetPrivateKey; - PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - Base64.getMimeDecoder().decode(keySpecStr)); - KeyFactory kf = KeyFactory.getInstance("RSA"); - RSAPrivateKey priKey = (RSAPrivateKey)kf.generatePrivate(priKeySpec); - - Certificate[] chain = new Certificate[1]; - chain[0] = trusedCert; - - // import the key entry. - ks.setKeyEntry("rsa-key-2048", priKey, passphrase, chain); - - // create SSL context - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(ts); - - SSLContext sslCtx = SSLContext.getInstance("TLSv1"); - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - - return sslCtx; + @Override + protected SSLEngine configureServerEngine(SSLEngine engine) { + engine.setNeedClientAuth(false); + engine.setUseClientMode(false); + return engine; } - private void createBuffers() { - // Size the buffers as appropriate. - - SSLSession session = ssle1.getSession(); - int appBufferMax = session.getApplicationBufferSize(); - int netBufferMax = session.getPacketBufferSize(); - - appIn1 = ByteBuffer.allocateDirect(appBufferMax + 50); - appIn2 = ByteBuffer.allocateDirect(appBufferMax + 50); - - oneToTwo = ByteBuffer.allocateDirect(netBufferMax); - twoToOne = ByteBuffer.allocateDirect(netBufferMax); - - appOut1 = ByteBuffer.wrap("Hi Engine2, I'm SSLEngine1".getBytes()); - appOut2 = ByteBuffer.wrap("Hello Engine1, I'm SSLEngine2".getBytes()); + @Override + protected SSLContext createServerSSLContext() throws Exception { + return createSSLContext(null, new Cert[]{Cert.CA_SHA1_RSA_2048}, + getServerContextParameters()); + } - log("AppOut1 = " + appOut1); - log("AppOut2 = " + appOut2); - log(""); + @Override + protected SSLContext createClientSSLContext() throws Exception { + return createSSLContext(new Cert[]{Cert.CA_SHA1_RSA_2048}, null, + getClientContextParameters()); } - private static void runDelegatedTasks(SSLEngine engine) throws Exception { + @Override + protected ContextParameters getClientContextParameters() { + return new ContextParameters("TLSv1", "PKIX", "NewSunX509"); + } - Runnable runnable; - while ((runnable = engine.getDelegatedTask()) != null) { - log("running delegated task..."); - runnable.run(); - } + @Override + protected ContextParameters getServerContextParameters() { + return new ContextParameters("TLSv1", "PKIX", "NewSunX509"); } private static void log(String str) { diff --git a/test/jdk/sun/security/ssl/EngineArgs/DebugReportsOneExtraByte.java b/test/jdk/sun/security/ssl/EngineArgs/DebugReportsOneExtraByte.java index b1d9a48347a..0a5afe86c09 100644 --- a/test/jdk/sun/security/ssl/EngineArgs/DebugReportsOneExtraByte.java +++ b/test/jdk/sun/security/ssl/EngineArgs/DebugReportsOneExtraByte.java @@ -25,7 +25,8 @@ * @test * @bug 7126889 * @summary Incorrect SSLEngine debug output - * @library /test/lib + * @library /test/lib /javax/net/ssl/templates + * @build jdk.test.lib.Utils * @run main DebugReportsOneExtraByte */ /* @@ -74,54 +75,19 @@ import javax.net.ssl.*; import javax.net.ssl.SSLEngineResult.*; -import java.io.*; -import java.security.*; import java.nio.*; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.security.SecurityUtils; -public class DebugReportsOneExtraByte { +public class DebugReportsOneExtraByte extends SSLEngineTemplate { /* * Enables logging of the SSLEngine operations. */ private static boolean logging = true; - private SSLContext sslc; - - private SSLEngine clientEngine; // client Engine - private ByteBuffer clientOut; // write side of clientEngine - private ByteBuffer clientIn; // read side of clientEngine - - private SSLEngine serverEngine; // server Engine - private ByteBuffer serverOut; // write side of serverEngine - private ByteBuffer serverIn; // read side of serverEngine - - /* - * For data transport, this example uses local ByteBuffers. This - * isn't really useful, but the purpose of this example is to show - * SSLEngine concepts, not how to do network transport. - */ - private ByteBuffer cTOs; // "reliable" transport client->server - private ByteBuffer sTOc; // "reliable" transport server->client - - /* - * The following is to set up the keystores. - */ - private static String pathToStores = "../../../../javax/net/ssl/etc"; - private static String keyStoreFile = "keystore"; - private static String trustStoreFile = "truststore"; - private static String passwd = "passphrase"; - - private static String keyFilename = - System.getProperty("test.src", ".") + "/" + pathToStores + - "/" + keyStoreFile; - private static String trustFilename = - System.getProperty("test.src", ".") + "/" + pathToStores + - "/" + trustStoreFile; - /* * Main entry point for this test. */ @@ -147,26 +113,38 @@ public static void main(String args[]) throws Exception { * Create an initialized SSLContext to use for these tests. */ public DebugReportsOneExtraByte() throws Exception { + super(); + } - KeyStore ks = KeyStore.getInstance("JKS"); - KeyStore ts = KeyStore.getInstance("JKS"); - - char[] passphrase = "passphrase".toCharArray(); - - ks.load(new FileInputStream(keyFilename), passphrase); - ts.load(new FileInputStream(trustFilename), passphrase); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); + @Override + protected SSLEngine configureServerEngine(SSLEngine serverEngine) { + serverEngine.setUseClientMode(false); + // Force a block-oriented ciphersuite. + serverEngine.setEnabledCipherSuites( + new String [] {"TLS_RSA_WITH_AES_128_CBC_SHA"}); + return serverEngine; + } - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(ts); + @Override + protected ContextParameters getClientContextParameters() { + return new ContextParameters("TLSv1", "PKIX", "NewSunX509"); + } - SSLContext sslCtx = SSLContext.getInstance("TLSv1"); + @Override + protected ContextParameters getServerContextParameters() { + return new ContextParameters("TLSv1", "PKIX", "NewSunX509"); + } - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + @Override + protected ByteBuffer createClientOutputBuffer() { + // No need to write anything on the client side, it will + // just confuse the output. + return ByteBuffer.wrap("".getBytes()); + } - sslc = sslCtx; + @Override + protected ByteBuffer createServerOutputBuffer() { + return ByteBuffer.wrap("Hi Client!".getBytes()); } /* @@ -189,9 +167,6 @@ public DebugReportsOneExtraByte() throws Exception { private void runTest() throws Exception { boolean dataDone = false; - createSSLEngines(); - createBuffers(); - SSLEngineResult clientResult; // results from client's last operation SSLEngineResult serverResult; // results from server's last operation @@ -217,11 +192,11 @@ private void runTest() throws Exception { clientResult = clientEngine.wrap(clientOut, cTOs); log("client wrap: ", clientResult); - runDelegatedTasks(clientResult, clientEngine); + runDelegatedTasks(clientEngine); serverResult = serverEngine.wrap(serverOut, sTOc); log("server wrap: ", serverResult); - runDelegatedTasks(serverResult, serverEngine); + runDelegatedTasks(serverEngine); // Next wrap will split. if (serverOut.position() == 1) { @@ -235,11 +210,11 @@ private void runTest() throws Exception { clientResult = clientEngine.unwrap(sTOc, clientIn); log("client unwrap: ", clientResult); - runDelegatedTasks(clientResult, clientEngine); + runDelegatedTasks(clientEngine); serverResult = serverEngine.unwrap(cTOs, serverIn); log("server unwrap: ", serverResult); - runDelegatedTasks(serverResult, serverEngine); + runDelegatedTasks(serverEngine); cTOs.compact(); sTOc.compact(); @@ -266,111 +241,10 @@ private void runTest() throws Exception { } } - /* - * Using the SSLContext created during object creation, - * create/configure the SSLEngines we'll use for this test. - */ - private void createSSLEngines() throws Exception { - /* - * Configure the serverEngine to act as a server in the SSL/TLS - * handshake. Also, require SSL client authentication. - */ - serverEngine = sslc.createSSLEngine(); - serverEngine.setUseClientMode(false); - serverEngine.setNeedClientAuth(true); - - // Force a block-oriented ciphersuite. - serverEngine.setEnabledCipherSuites( - new String [] {"TLS_RSA_WITH_AES_128_CBC_SHA"}); - - /* - * Similar to above, but using client mode instead. - */ - clientEngine = sslc.createSSLEngine("client", 80); - clientEngine.setUseClientMode(true); - } - - /* - * Create and size the buffers appropriately. - */ - private void createBuffers() { - - /* - * We'll assume the buffer sizes are the same - * between client and server. - */ - SSLSession session = clientEngine.getSession(); - int appBufferMax = session.getApplicationBufferSize(); - int netBufferMax = session.getPacketBufferSize(); - - /* - * We'll make the input buffers a bit bigger than the max needed - * size, so that unwrap()s following a successful data transfer - * won't generate BUFFER_OVERFLOWS. - * - * We'll use a mix of direct and indirect ByteBuffers for - * tutorial purposes only. In reality, only use direct - * ByteBuffers when they give a clear performance enhancement. - */ - clientIn = ByteBuffer.allocate(appBufferMax + 50); - serverIn = ByteBuffer.allocate(appBufferMax + 50); - - cTOs = ByteBuffer.allocateDirect(netBufferMax); - sTOc = ByteBuffer.allocateDirect(netBufferMax); - - // No need to write anything on the client side, it will - // just confuse the output. - clientOut = ByteBuffer.wrap("".getBytes()); - // 10 bytes long - serverOut = ByteBuffer.wrap("Hi Client!".getBytes()); - } - - /* - * If the result indicates that we have outstanding tasks to do, - * go ahead and run them in this thread. - */ - private static void runDelegatedTasks(SSLEngineResult result, - SSLEngine engine) throws Exception { - - if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { - Runnable runnable; - while ((runnable = engine.getDelegatedTask()) != null) { - log("\trunning delegated task..."); - runnable.run(); - } - HandshakeStatus hsStatus = engine.getHandshakeStatus(); - if (hsStatus == HandshakeStatus.NEED_TASK) { - throw new Exception( - "handshake shouldn't need additional tasks"); - } - log("\tnew HandshakeStatus: " + hsStatus); - } - } - private static boolean isEngineClosed(SSLEngine engine) { return (engine.isOutboundDone() && engine.isInboundDone()); } - /* - * Simple check to make sure everything came across as expected. - */ - private static void checkTransfer(ByteBuffer a, ByteBuffer b) - throws Exception { - a.flip(); - b.flip(); - - if (!a.equals(b)) { - throw new Exception("Data didn't transfer cleanly"); - } else { - log("\tData transferred cleanly"); - } - - a.position(a.limit()); - b.position(b.limit()); - a.limit(a.capacity()); - b.limit(b.capacity()); - } - /* * Logging code */ diff --git a/test/jdk/sun/security/ssl/HandshakeOutStream/NullCerts.java b/test/jdk/sun/security/ssl/HandshakeOutStream/NullCerts.java index 51e37a0d5af..36ecd43a33a 100644 --- a/test/jdk/sun/security/ssl/HandshakeOutStream/NullCerts.java +++ b/test/jdk/sun/security/ssl/HandshakeOutStream/NullCerts.java @@ -26,6 +26,7 @@ * @bug 4453053 * @summary If a server shuts down correctly during handshaking, the client * doesn't see it. + * @library /javax/net/ssl/templates * @run main/othervm NullCerts * * SunJSSE does not support dynamic system properties, no way to re-use @@ -34,40 +35,11 @@ */ import java.io.*; -import java.net.*; -import java.security.*; import javax.net.ssl.*; -public class NullCerts { +public class NullCerts extends SSLSocketTemplate { - /* - * ============================================================= - * Set the various variables needed for the tests, then - * specify what tests to run on each side. - */ - - /* - * Should we run the client or server in a separate thread? - * Both sides can throw exceptions, but do you have a preference - * as to which side should be the main thread. - */ - private static boolean separateServerThread = true; - - /* - * Where do we find the keystores? - */ - private final static String pathToStores = "../../../../javax/net/ssl/etc"; - private final static String keyStoreFile = "keystore"; - private final static String trustStoreFile = "truststore"; - private final static String passwd = "passphrase"; - private final static char[] cpasswd = "passphrase".toCharArray(); - - /* - * Is the server ready to serve? - */ - volatile static boolean serverReady = false; - - /* + /* * Turn on SSL debugging? */ private final static boolean DEBUG = false; @@ -81,29 +53,22 @@ public class NullCerts { * smart about it.... */ + @Override + protected void configureServerSocket(SSLServerSocket socket) { + socket.setNeedClientAuth(true); + socket.setUseClientMode(false); + } + /* * Define the server side of the test. * * If the server prematurely exits, serverReady will be set to true * to avoid infinite hangs. */ - private void doServerSide() throws Exception { - SSLServerSocketFactory sslssf = - (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); - SSLServerSocket sslServerSocket = - (SSLServerSocket) sslssf.createServerSocket(serverPort, 3); - sslServerSocket.setNeedClientAuth(true); - - serverPort = sslServerSocket.getLocalPort(); - - /* - * Signal Client, we're ready for his connect. - */ - serverReady = true; - - SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); - InputStream sslIS = sslSocket.getInputStream(); - OutputStream sslOS = sslSocket.getOutputStream(); + @Override + protected void runServerApplication(SSLSocket socket) throws Exception { + InputStream sslIS = socket.getInputStream(); + OutputStream sslOS = socket.getOutputStream(); try { sslIS.read(); @@ -115,7 +80,6 @@ private void doServerSide() throws Exception { + e.toString()); } - sslSocket.close(); System.out.println("Server done and exiting!"); } @@ -125,36 +89,11 @@ private void doServerSide() throws Exception { * If the server prematurely exits, serverReady will be set to true * to avoid infinite hangs. */ - private void doClientSide() throws Exception { - - /* - * Wait for server to get started. - */ - while (!serverReady) { - Thread.sleep(50); - } + @Override + protected void runClientApplication(SSLSocket sslSocket) throws Exception { System.out.println("Starting test"); - KeyStore ks = KeyStore.getInstance("JKS"); - KeyStore uks = KeyStore.getInstance("JKS"); - SSLContext ctx = SSLContext.getInstance("TLS"); - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - - uks.load(new FileInputStream(unknownFilename), cpasswd); - kmf.init(uks, cpasswd); - - ks.load(new FileInputStream(trustFilename), cpasswd); - tmf.init(ks); - - ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - - SSLSocketFactory sslsf = - (SSLSocketFactory) ctx.getSocketFactory(); - SSLSocket sslSocket = (SSLSocket) - sslsf.createSocket("localhost", serverPort); - InputStream sslIS = sslSocket.getInputStream(); OutputStream sslOS = sslSocket.getOutputStream(); @@ -163,7 +102,6 @@ private void doClientSide() throws Exception { sslOS.flush(); sslIS.read(); - sslSocket.close(); } catch (IOException e) { String str = "\nYou will either see a bad_certificate SSLException\n" + @@ -174,131 +112,21 @@ private void doClientSide() throws Exception { } } - /* - * ============================================================= - * The remainder is just support stuff - */ - - // use any free port by default - volatile int serverPort = 0; - - private volatile Exception serverException = null; - private volatile Exception clientException = null; - - private final static String keyFilename = - System.getProperty("test.src", ".") + "/" + pathToStores + - "/" + keyStoreFile; - private final static String trustFilename = - System.getProperty("test.src", ".") + "/" + pathToStores + - "/" + trustStoreFile; - private final static String unknownFilename = - System.getProperty("test.src", ".") + "/" + pathToStores + - "/" + "unknown_keystore"; + @Override + protected KeyManager createClientKeyManager() throws Exception { + return createKeyManager(new Cert[]{Cert.DSA_SHA1_1024_EXPIRED}, + getClientContextParameters()); + } // Used for running test standalone public static void main(String[] args) throws Exception { - String testRoot = System.getProperty("test.src", "."); - System.setProperty("javax.net.ssl.keyStore", keyFilename); - System.setProperty("javax.net.ssl.keyStorePassword", passwd); - System.setProperty("javax.net.ssl.trustStore", trustFilename); - System.setProperty("javax.net.ssl.trustStorePassword", passwd); - if (DEBUG) System.setProperty("javax.net.debug", "all"); /* * Start the tests. */ - new NullCerts(); - } - - private Thread clientThread = null; - private Thread serverThread = null; - - /* - * Primary constructor, used to drive remainder of the test. - * - * Fork off the other side, then do your work. - */ - NullCerts() throws Exception { - - if (separateServerThread) { - startServer(true); - startClient(false); - } else { - startClient(true); - startServer(false); - } - - /* - * Wait for other side to close down. - */ - if (separateServerThread) { - serverThread.join(); - } else { - clientThread.join(); - } - - /* - * When we get here, the test is pretty much over. - * - * If the main thread excepted, that propagates back - * immediately. If the other thread threw an exception, we - * should report back. - */ - if (serverException != null) { - System.err.print("Server Exception:"); - throw serverException; - } - if (clientException != null) { - System.err.print("Client Exception:"); - throw clientException; - } - } - - private void startServer(boolean newThread) throws Exception { - if (newThread) { - serverThread = new Thread() { - public void run() { - try { - doServerSide(); - } catch (Exception e) { - /* - * Our server thread just died. - * - * Release the client, if not active already... - */ - System.err.println("Server died..."); - serverReady = true; - serverException = e; - } - } - }; - serverThread.start(); - } else { - doServerSide(); - } - } - - private void startClient(boolean newThread) throws Exception { - if (newThread) { - clientThread = new Thread() { - public void run() { - try { - doClientSide(); - } catch (Exception e) { - /* - * Our client thread just died. - */ - System.err.println("Client died..."); - clientException = e; - } - } - }; - clientThread.start(); - } else { - doClientSide(); - } + new NullCerts().run(); } } diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/CloseEngineException.java b/test/jdk/sun/security/ssl/SSLEngineImpl/CloseEngineException.java index 390da17f8e0..5335a92be0f 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/CloseEngineException.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/CloseEngineException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * 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,6 +31,9 @@ * @bug 4969799 * @summary javax.net.ssl.SSLSocket.SSLSocket(InetAddress,int) shouldn't * throw exception + * @library /javax/net/ssl/templates + * @library /test/lib + * @build jdk.test.lib.Utils * @run main/othervm CloseEngineException */ @@ -40,128 +43,85 @@ // import javax.net.ssl.*; -import javax.net.ssl.SSLEngineResult.*; -import java.io.*; -import java.security.*; -import java.nio.*; // Note that this test case depends on JSSE provider implementation details. -public class CloseEngineException { +public class CloseEngineException extends SSLEngineTemplate { private static boolean debug = true; - private SSLContext sslc; - private SSLEngine ssle1; // client - private SSLEngine ssle2; // server - - private static String pathToStores = "../../../../javax/net/ssl/etc"; - private static String keyStoreFile = "keystore"; - private static String trustStoreFile = "truststore"; - private static String passwd = "passphrase"; - - private static String keyFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + keyStoreFile; - private static String trustFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + trustStoreFile; - - private ByteBuffer appOut1; // write side of ssle1 - private ByteBuffer appIn1; // read side of ssle1 - private ByteBuffer appOut2; // write side of ssle2 - private ByteBuffer appIn2; // read side of ssle2 - - private ByteBuffer oneToTwo; // "reliable" transport ssle1->ssle2 - private ByteBuffer twoToOne; // "reliable" transport ssle2->ssle1 - - /* - * Majority of the test case is here, setup is done below. - */ - private void createSSLEngines() throws Exception { - ssle1 = sslc.createSSLEngine("client", 1); - ssle1.setUseClientMode(true); - - ssle2 = sslc.createSSLEngine(); - ssle2.setUseClientMode(false); - ssle2.setNeedClientAuth(true); - } - private void runTest() throws Exception { boolean dataDone = false; - createSSLEngines(); - createBuffers(); - - SSLEngineResult result1; // ssle1's results from last operation + SSLEngineResult result1; // clientEngine's results from last operation SSLEngineResult result2; // ssle2's results from last operation - while (!isEngineClosed(ssle1) && !isEngineClosed(ssle2)) { + while (!isEngineClosed(clientEngine) && !isEngineClosed(serverEngine)) { log("================"); - if (!isEngineClosed(ssle1)) { - result1 = ssle1.wrap(appOut1, oneToTwo); - runDelegatedTasks(result1, ssle1); + if (!isEngineClosed(clientEngine)) { + result1 = clientEngine.wrap(clientOut, cTOs); + runDelegatedTasks(clientEngine); log("wrap1: " + result1); - log("oneToTwo = " + oneToTwo); + log("oneToTwo = " + cTOs); log(""); - oneToTwo.flip(); + cTOs.flip(); } - if (!isEngineClosed(ssle2)) { - result2 = ssle2.wrap(appOut2, twoToOne); - runDelegatedTasks(result2, ssle2); + if (!isEngineClosed(serverEngine)) { + result2 = serverEngine.wrap(serverOut, sTOc); + runDelegatedTasks(serverEngine); log("wrap2: " + result2); - log("twoToOne = " + twoToOne); + log("twoToOne = " + sTOc); - twoToOne.flip(); + sTOc.flip(); } log("----"); - if (!isEngineClosed(ssle1) && !dataDone) { + if (!isEngineClosed(clientEngine) && !dataDone) { log("--"); - result1 = ssle1.unwrap(twoToOne, appIn1); - runDelegatedTasks(result1, ssle1); + result1 = clientEngine.unwrap(sTOc, clientIn); + runDelegatedTasks(clientEngine); log("unwrap1: " + result1); - log("twoToOne = " + twoToOne); + log("twoToOne = " + sTOc); log(""); - twoToOne.compact(); + sTOc.compact(); } - if (!isEngineClosed(ssle2)) { + if (!isEngineClosed(serverEngine)) { log("---"); - result2 = ssle2.unwrap(oneToTwo, appIn2); - runDelegatedTasks(result2, ssle2); + result2 = serverEngine.unwrap(cTOs, serverIn); + runDelegatedTasks(serverEngine); log("unwrap2: " + result2); - log("oneToTwo = " + oneToTwo); + log("oneToTwo = " + cTOs); - oneToTwo.compact(); + cTOs.compact(); } /* * If we've transfered all the data between app1 and app2, * we try to close and see what that gets us. */ - if (!dataDone && (appOut1.limit() == appIn2.position()) && - (appOut2.limit() == appIn1.position())) { + if (!dataDone && (clientOut.limit() == serverIn.position()) && + (serverOut.limit() == clientIn.position())) { - checkTransfer(appOut1, appIn2); - checkTransfer(appOut2, appIn1); + checkTransfer(clientOut, serverIn); + checkTransfer(serverOut, clientIn); - log("Closing ssle1's *OUTBOUND*..."); - ssle1.closeOutbound(); + log("Closing clientEngine's *OUTBOUND*..."); + clientEngine.closeOutbound(); dataDone = true; try { /* * Check that closed Outbound generates. */ - ssle1.beginHandshake(); + clientEngine.beginHandshake(); throw new Exception( "TEST FAILED: didn't throw Exception"); } catch (SSLException e) { @@ -174,7 +134,7 @@ private void runTest() throws Exception { /* * Check that closed Inbound generates. */ - ssle2.beginHandshake(); + serverEngine.beginHandshake(); throw new Exception( "TEST FAILED: didn't throw Exception"); } catch (SSLException e) { @@ -184,12 +144,7 @@ private void runTest() throws Exception { public static void main(String args[]) throws Exception { - CloseEngineException test; - - test = new CloseEngineException(); - - test.createSSLEngines(); - + CloseEngineException test = new CloseEngineException(); test.runTest(); System.err.println("Test Passed."); @@ -202,90 +157,20 @@ public static void main(String args[]) throws Exception { */ public CloseEngineException() throws Exception { - sslc = getSSLContext(keyFilename, trustFilename); + super(); } - /* - * Create an initialized SSLContext to use for this test. - */ - private SSLContext getSSLContext(String keyFile, String trustFile) - throws Exception { - - KeyStore ks = KeyStore.getInstance("JKS"); - KeyStore ts = KeyStore.getInstance("JKS"); - - char[] passphrase = "passphrase".toCharArray(); - - ks.load(new FileInputStream(keyFile), passphrase); - ts.load(new FileInputStream(trustFile), passphrase); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(ts); - - SSLContext sslCtx = SSLContext.getInstance("TLS"); - - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - - return sslCtx; - } - - private void createBuffers() { - // Size the buffers as appropriate. - - SSLSession session = ssle1.getSession(); - int appBufferMax = session.getApplicationBufferSize(); - int netBufferMax = session.getPacketBufferSize(); - - appIn1 = ByteBuffer.allocateDirect(appBufferMax + 50); - appIn2 = ByteBuffer.allocateDirect(appBufferMax + 50); - - oneToTwo = ByteBuffer.allocateDirect(netBufferMax); - twoToOne = ByteBuffer.allocateDirect(netBufferMax); - - appOut1 = ByteBuffer.wrap("Hi Engine2, I'm SSLEngine1".getBytes()); - appOut2 = ByteBuffer.wrap("Hello Engine1, I'm SSLEngine2".getBytes()); - - log("AppOut1 = " + appOut1); - log("AppOut2 = " + appOut2); - log(""); - } - - private static void runDelegatedTasks(SSLEngineResult result, - SSLEngine engine) throws Exception { - - if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { - Runnable runnable; - while ((runnable = engine.getDelegatedTask()) != null) { - log("running delegated task..."); - runnable.run(); - } - } + @Override + protected SSLEngine configureServerEngine(SSLEngine engine) { + engine.setUseClientMode(false); + engine.setNeedClientAuth(true); + return engine; } private static boolean isEngineClosed(SSLEngine engine) { return (engine.isOutboundDone() && engine.isInboundDone()); } - private static void checkTransfer(ByteBuffer a, ByteBuffer b) - throws Exception { - a.flip(); - b.flip(); - - if (!a.equals(b)) { - throw new Exception("Data didn't transfer cleanly"); - } else { - log("Data transferred cleanly"); - } - - a.position(a.limit()); - b.position(b.limit()); - a.limit(a.capacity()); - b.limit(b.capacity()); - } - private static void log(String str) { if (debug) { System.err.println(str); diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/CloseStart.java b/test/jdk/sun/security/ssl/SSLEngineImpl/CloseStart.java index 30c2a74234b..ba5b04148c3 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/CloseStart.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/CloseStart.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. * 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,6 +30,7 @@ * @test * @bug 5019096 * @summary Add scatter/gather APIs for SSLEngine + * @library /javax/net/ssl/templates * @run main/othervm CloseStart */ @@ -38,26 +39,8 @@ // import javax.net.ssl.*; -import javax.net.ssl.SSLEngineResult.*; -import java.io.*; -import java.security.*; -import java.nio.*; -public class CloseStart { - - private static boolean debug = false; - - private static String pathToStores = "../../../../javax/net/ssl/etc"; - private static String keyStoreFile = "keystore"; - private static String trustStoreFile = "truststore"; - private static String passwd = "passphrase"; - - private static String keyFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + keyStoreFile; - private static String trustFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + trustStoreFile; +public class CloseStart extends SSLContextTemplate { private static void checkDone(SSLEngine ssle) throws Exception { if (!ssle.isInboundDone()) { @@ -74,14 +57,17 @@ private static void runTest2(SSLEngine ssle) throws Exception { } public static void main(String args[]) throws Exception { + new CloseStart().run(); + } - SSLEngine ssle = createSSLEngine(keyFilename, trustFilename); + private void run() throws Exception { + SSLEngine ssle = createSSLEngine(); ssle.closeInbound(); if (!ssle.isInboundDone()) { throw new Exception("isInboundDone isn't done"); } - ssle = createSSLEngine(keyFilename, trustFilename); + ssle = createSSLEngine(); ssle.closeOutbound(); if (!ssle.isOutboundDone()) { throw new Exception("isOutboundDone isn't done"); @@ -93,30 +79,10 @@ public static void main(String args[]) throws Exception { /* * Create an initialized SSLContext to use for this test. */ - static private SSLEngine createSSLEngine(String keyFile, String trustFile) - throws Exception { - - SSLEngine ssle; - - KeyStore ks = KeyStore.getInstance("JKS"); - KeyStore ts = KeyStore.getInstance("JKS"); - - char[] passphrase = "passphrase".toCharArray(); - - ks.load(new FileInputStream(keyFile), passphrase); - ts.load(new FileInputStream(trustFile), passphrase); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(ts); - - SSLContext sslCtx = SSLContext.getInstance("TLS"); - - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + private SSLEngine createSSLEngine() throws Exception { - ssle = sslCtx.createSSLEngine("client", 1001); + SSLContext sslCtx = createClientSSLContext(); + SSLEngine ssle = sslCtx.createSSLEngine("client", 1001); ssle.setUseClientMode(true); return ssle; diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/DelegatedTaskWrongException.java b/test/jdk/sun/security/ssl/SSLEngineImpl/DelegatedTaskWrongException.java index 7c75f0e1402..be66e7c7f54 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/DelegatedTaskWrongException.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/DelegatedTaskWrongException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * 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,72 +30,40 @@ * @test * @bug 4969459 * @summary Delegated tasks are not reflecting the subclasses of SSLException + * @library /javax/net/ssl/templates + * @library /test/lib + * @build jdk.test.lib.Utils * @run main/othervm DelegatedTaskWrongException */ import javax.net.ssl.*; -import javax.net.ssl.SSLEngineResult.*; -import java.io.*; import java.security.*; -import java.nio.*; -public class DelegatedTaskWrongException { +public class DelegatedTaskWrongException extends SSLEngineTemplate { private static boolean debug = false; - private SSLContext sslc; - private SSLEngine ssle1; // client - private SSLEngine ssle2; // server - - private static String pathToStores = "../../../../javax/net/ssl/etc"; - private static String keyStoreFile = "keystore"; - private static String trustStoreFile = "truststore"; - private static String passwd = "passphrase"; - - private static String keyFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + keyStoreFile; - private static String trustFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + trustStoreFile; - - private ByteBuffer appOut1; // write side of ssle1 - private ByteBuffer appIn1; // read side of ssle1 - private ByteBuffer appOut2; // write side of ssle2 - private ByteBuffer appIn2; // read side of ssle2 - - private ByteBuffer oneToTwo; // "reliable" transport ssle1->ssle2 - private ByteBuffer twoToOne; // "reliable" transport ssle2->ssle1 - - /* - * Majority of the test case is here, setup is done below. - */ - private void createSSLEngines() throws Exception { - ssle1 = sslc.createSSLEngine("client", 1); - ssle1.setUseClientMode(true); - - ssle2 = sslc.createSSLEngine(); - ssle2.setUseClientMode(false); + @Override + protected SSLEngine configureServerEngine(SSLEngine engine) { + engine.setUseClientMode(false); + engine.setEnabledProtocols(new String [] { "TLSv1" }); + return engine; + } - ssle1.setEnabledProtocols(new String [] { "SSLv3" }); - ssle2.setEnabledProtocols(new String [] { "TLSv1" }); + @Override + protected SSLEngine configureClientEngine(SSLEngine engine) { + engine.setUseClientMode(true); + engine.setEnabledProtocols(new String [] { "SSLv3" }); + return engine; } private void runTest() throws Exception { - boolean dataDone = false; - - createSSLEngines(); - createBuffers(); - - SSLEngineResult result1; // ssle1's results from last operation - SSLEngineResult result2; // ssle2's results from last operation - - result1 = ssle1.wrap(appOut1, oneToTwo); - oneToTwo.flip(); - result2 = ssle2.unwrap(oneToTwo, appIn2); + clientEngine.wrap(clientOut, cTOs); + cTOs.flip(); - runDelegatedTasks(result2, ssle2); + serverEngine.unwrap(cTOs, serverIn); + runDelegatedTasks(serverEngine); try { /* @@ -103,7 +71,7 @@ private void runTest() throws Exception { * If this changes, we'll need to update this test. * Anything else and we fail. */ - result2 = ssle2.unwrap(oneToTwo, appIn2); + serverEngine.unwrap(cTOs, serverIn); throw new Exception( "TEST FAILED: Didn't generate any exception"); } catch (SSLHandshakeException e) { @@ -119,12 +87,7 @@ public static void main(String args[]) throws Exception { // and keys used in this test are not disabled. Security.setProperty("jdk.tls.disabledAlgorithms", ""); - DelegatedTaskWrongException test; - - test = new DelegatedTaskWrongException(); - - test.createSSLEngines(); - + DelegatedTaskWrongException test = new DelegatedTaskWrongException(); test.runTest(); System.out.println("Test Passed."); @@ -137,88 +100,7 @@ public static void main(String args[]) throws Exception { */ public DelegatedTaskWrongException() throws Exception { - sslc = getSSLContext(keyFilename, trustFilename); - } - - /* - * Create an initialized SSLContext to use for this test. - */ - private SSLContext getSSLContext(String keyFile, String trustFile) - throws Exception { - - KeyStore ks = KeyStore.getInstance("JKS"); - KeyStore ts = KeyStore.getInstance("JKS"); - - char[] passphrase = "passphrase".toCharArray(); - - ks.load(new FileInputStream(keyFile), passphrase); - ts.load(new FileInputStream(trustFile), passphrase); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(ts); - - SSLContext sslCtx = SSLContext.getInstance("TLS"); - - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - - return sslCtx; - } - - private void createBuffers() { - // Size the buffers as appropriate. - - SSLSession session = ssle1.getSession(); - int appBufferMax = session.getApplicationBufferSize(); - int netBufferMax = session.getPacketBufferSize(); - - appIn1 = ByteBuffer.allocateDirect(appBufferMax + 50); - appIn2 = ByteBuffer.allocateDirect(appBufferMax + 50); - - oneToTwo = ByteBuffer.allocateDirect(netBufferMax); - twoToOne = ByteBuffer.allocateDirect(netBufferMax); - - appOut1 = ByteBuffer.wrap("Hi Engine2, I'm SSLEngine1".getBytes()); - appOut2 = ByteBuffer.wrap("Hello Engine1, I'm SSLEngine2".getBytes()); - - log("AppOut1 = " + appOut1); - log("AppOut2 = " + appOut2); - log(""); - } - - private static void runDelegatedTasks(SSLEngineResult result, - SSLEngine engine) throws Exception { - - if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { - Runnable runnable; - while ((runnable = engine.getDelegatedTask()) != null) { - log("running delegated task..."); - runnable.run(); - } - } - } - - private static boolean isEngineClosed(SSLEngine engine) { - return (engine.isOutboundDone() && engine.isInboundDone()); - } - - private static void checkTransfer(ByteBuffer a, ByteBuffer b) - throws Exception { - a.flip(); - b.flip(); - - if (!a.equals(b)) { - throw new Exception("Data didn't transfer cleanly"); - } else { - log("Data transferred cleanly"); - } - - a.position(a.limit()); - b.position(b.limit()); - a.limit(a.capacity()); - b.limit(b.capacity()); + super(); } private static void log(String str) { diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/EmptyExtensionData.java b/test/jdk/sun/security/ssl/SSLEngineImpl/EmptyExtensionData.java index 7e9f314cfae..f86a1f81474 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/EmptyExtensionData.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/EmptyExtensionData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. * 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,44 +30,21 @@ * @test * @bug 6728126 * @summary Parsing Extensions in Client Hello message is done in a wrong way - * @library /test/lib + * @library /test/lib /javax/net/ssl/templates * @run main/othervm EmptyExtensionData */ import javax.net.ssl.*; import javax.net.ssl.SSLEngineResult.*; -import java.io.*; -import java.security.*; import java.nio.*; import jdk.test.lib.security.SecurityUtils; -public class EmptyExtensionData { +public class EmptyExtensionData extends SSLContextTemplate { private static boolean debug = false; - private static String pathToStores = "../../../../javax/net/ssl/etc"; - private static String keyStoreFile = "keystore"; - private static String trustStoreFile = "truststore"; - private static String passwd = "passphrase"; - - private static String keyFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + keyStoreFile; - private static String trustFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + trustStoreFile; - - private static void checkDone(SSLEngine ssle) throws Exception { - if (!ssle.isInboundDone()) { - throw new Exception("isInboundDone isn't done"); - } - if (!ssle.isOutboundDone()) { - throw new Exception("isOutboundDone isn't done"); - } - } - - private static void runTest(SSLEngine ssle) throws Exception { + private void runTest(SSLEngine ssle) throws Exception { // a client hello message with an empty extension data byte[] msg_clihello = { (byte)0x16, (byte)0x03, (byte)0x01, (byte)0x00, @@ -138,7 +115,7 @@ private static void runTest(SSLEngine ssle) throws Exception { * If the result indicates that we have outstanding tasks to do, * go ahead and run them in this thread. */ - private static void runDelegatedTasks(SSLEngineResult result, + private void runDelegatedTasks(SSLEngineResult result, SSLEngine engine) throws Exception { if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { @@ -159,46 +136,17 @@ private static void runDelegatedTasks(SSLEngineResult result, public static void main(String args[]) throws Exception { // Re-enable TLSv1 since test depends on it. SecurityUtils.removeFromDisabledTlsAlgs("TLSv1"); - - SSLEngine ssle = createSSLEngine(keyFilename, trustFilename); - runTest(ssle); - - System.out.println("Test Passed."); + new EmptyExtensionData().run(); } - /* - * Create an initialized SSLContext to use for this test. - */ - static private SSLEngine createSSLEngine(String keyFile, String trustFile) - throws Exception { - - SSLEngine ssle; - - KeyStore ks = KeyStore.getInstance("JKS"); - KeyStore ts = KeyStore.getInstance("JKS"); - - char[] passphrase = "passphrase".toCharArray(); - - ks.load(new FileInputStream(keyFile), passphrase); - ts.load(new FileInputStream(trustFile), passphrase); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(ts); - - SSLContext sslCtx = SSLContext.getInstance("TLS"); - - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - - ssle = sslCtx.createSSLEngine(); + private void run() throws Exception { + SSLEngine ssle = createServerSSLContext().createSSLEngine(); ssle.setUseClientMode(false); + runTest(ssle); - return ssle; + System.out.println("Test Passed."); } - private static void log(String str) { if (debug) { System.out.println(str); diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/EngineEnforceUseClientMode.java b/test/jdk/sun/security/ssl/SSLEngineImpl/EngineEnforceUseClientMode.java index 1457384a3f1..5f3710f8b92 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/EngineEnforceUseClientMode.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/EngineEnforceUseClientMode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. * 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,67 +30,36 @@ * @test * @bug 4980882 8207250 8237474 * @summary SSLEngine should enforce setUseClientMode + * @library /javax/net/ssl/templates + * @library /test/lib + * @build jdk.test.lib.Utils * @run main/othervm EngineEnforceUseClientMode * @author Brad R. Wetmore */ import javax.net.ssl.*; -import javax.net.ssl.SSLEngineResult.*; -import java.io.*; -import java.security.*; -import java.nio.*; -public class EngineEnforceUseClientMode { +public class EngineEnforceUseClientMode extends SSLEngineTemplate { private static boolean debug = false; - private SSLContext sslc; - private SSLEngine ssle1; // client - private SSLEngine ssle2; // server - - private SSLEngine ssle3; // server - private SSLEngine ssle4; // server - private SSLEngine ssle5; // server - - private static String pathToStores = "../../../../javax/net/ssl/etc"; - private static String keyStoreFile = "keystore"; - private static String trustStoreFile = "truststore"; - private static String passwd = "passphrase"; - - private static String keyFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + keyStoreFile; - private static String trustFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + trustStoreFile; - - private ByteBuffer appOut1; // write side of ssle1 - private ByteBuffer appIn1; // read side of ssle1 - private ByteBuffer appOut2; // write side of ssle2 - private ByteBuffer appIn2; // read side of ssle2 - - private ByteBuffer oneToTwo; // "reliable" transport ssle1->ssle2 - private ByteBuffer twoToOne; // "reliable" transport ssle2->ssle1 + private SSLEngine serverEngine2; // server + private SSLEngine serverEngine3; // server + private SSLEngine serverEngine4; // server /* * Majority of the test case is here, setup is done below. */ - private void createSSLEngines() throws Exception { - ssle1 = sslc.createSSLEngine("client", 1); - ssle1.setUseClientMode(true); - - ssle2 = sslc.createSSLEngine(); - ssle2.setUseClientMode(false); - ssle2.setNeedClientAuth(true); - + private void createAdditionalSSLEngines() throws Exception { + SSLContext sslc = createServerSSLContext(); /* * Note, these are not initialized to client/server */ - ssle3 = sslc.createSSLEngine(); - ssle4 = sslc.createSSLEngine(); - ssle5 = sslc.createSSLEngine(); + serverEngine2 = sslc.createSSLEngine(); + serverEngine3 = sslc.createSSLEngine(); + serverEngine4 = sslc.createSSLEngine(); //Check default SSLEngine role. - if (ssle5.getUseClientMode()) { + if (serverEngine4.getUseClientMode()) { throw new RuntimeException("Expected default role to be server"); } @@ -98,8 +67,7 @@ private void createSSLEngines() throws Exception { private void runTest() throws Exception { - createSSLEngines(); - createBuffers(); + createAdditionalSSLEngines(); /* * First try the engines with no client/server initialization @@ -107,35 +75,35 @@ private void runTest() throws Exception { */ try { System.out.println("Testing wrap()"); - ssle3.wrap(appOut1, oneToTwo); + serverEngine2.wrap(clientOut, cTOs); throw new RuntimeException( "wrap(): Didn't catch the exception properly"); } catch (IllegalStateException e) { System.out.println("Caught the correct exception."); - oneToTwo.flip(); - if (oneToTwo.hasRemaining()) { + cTOs.flip(); + if (cTOs.hasRemaining()) { throw new Exception("wrap generated data"); } - oneToTwo.clear(); + cTOs.clear(); } try { System.out.println("Testing unwrap()"); - ssle4.unwrap(oneToTwo, appIn1); + serverEngine3.unwrap(cTOs, clientIn); throw new RuntimeException( "unwrap(): Didn't catch the exception properly"); } catch (IllegalStateException e) { System.out.println("Caught the correct exception."); - appIn1.flip(); - if (appIn1.hasRemaining()) { + clientIn.flip(); + if (clientIn.hasRemaining()) { throw new Exception("unwrap generated data"); } - appIn1.clear(); + clientIn.clear(); } try { System.out.println("Testing beginHandshake()"); - ssle5.beginHandshake(); + serverEngine4.beginHandshake(); throw new RuntimeException( "unwrap(): Didn't catch the exception properly"); } catch (IllegalStateException e) { @@ -147,60 +115,60 @@ private void runTest() throws Exception { SSLEngineResult result1; // ssle1's results from last operation SSLEngineResult result2; // ssle2's results from last operation - while (!isEngineClosed(ssle1) || !isEngineClosed(ssle2)) { + while (!isEngineClosed(clientEngine) || !isEngineClosed(serverEngine)) { log("================"); - result1 = ssle1.wrap(appOut1, oneToTwo); - result2 = ssle2.wrap(appOut2, twoToOne); + result1 = clientEngine.wrap(clientOut, cTOs); + result2 = serverEngine.wrap(serverOut, sTOc); log("wrap1: " + result1); - log("oneToTwo = " + oneToTwo); + log("oneToTwo = " + cTOs); log(""); log("wrap2: " + result2); - log("twoToOne = " + twoToOne); + log("twoToOne = " + sTOc); - runDelegatedTasks(result1, ssle1); - runDelegatedTasks(result2, ssle2); + runDelegatedTasks(clientEngine); + runDelegatedTasks(serverEngine); - oneToTwo.flip(); - twoToOne.flip(); + cTOs.flip(); + sTOc.flip(); log("----"); - result1 = ssle1.unwrap(twoToOne, appIn1); - result2 = ssle2.unwrap(oneToTwo, appIn2); + result1 = clientEngine.unwrap(sTOc, clientIn); + result2 = serverEngine.unwrap(cTOs, serverIn); log("unwrap1: " + result1); - log("twoToOne = " + twoToOne); + log("twoToOne = " + sTOc); log(""); log("unwrap2: " + result2); - log("oneToTwo = " + oneToTwo); + log("oneToTwo = " + cTOs); - runDelegatedTasks(result1, ssle1); - runDelegatedTasks(result2, ssle2); + runDelegatedTasks(clientEngine); + runDelegatedTasks(serverEngine); - oneToTwo.compact(); - twoToOne.compact(); + cTOs.compact(); + sTOc.compact(); /* * If we've transfered all the data between app1 and app2, * we try to close and see what that gets us. */ - if (!dataDone && (appOut1.limit() == appIn2.position()) && - (appOut2.limit() == appIn1.position())) { + if (!dataDone && (clientOut.limit() == serverIn.position()) && + (serverOut.limit() == clientIn.position())) { - checkTransfer(appOut1, appIn2); - checkTransfer(appOut2, appIn1); + checkTransfer(clientOut, serverIn); + checkTransfer(serverOut, clientIn); // Should not be able to set mode now, no matter if // it is the same of different. System.out.println("Try changing modes..."); for (boolean b : new Boolean[] {true, false}) { try { - ssle2.setUseClientMode(b); + serverEngine.setUseClientMode(b); throw new RuntimeException( "setUseClientMode(" + b + "): " + "Didn't catch the exception properly"); @@ -216,12 +184,8 @@ private void runTest() throws Exception { public static void main(String args[]) throws Exception { - EngineEnforceUseClientMode test; - - test = new EngineEnforceUseClientMode(); - - test.createSSLEngines(); - + EngineEnforceUseClientMode test = new EngineEnforceUseClientMode(); + test.createAdditionalSSLEngines(); test.runTest(); System.out.println("Test Passed."); @@ -234,89 +198,13 @@ public static void main(String args[]) throws Exception { */ public EngineEnforceUseClientMode() throws Exception { - sslc = getSSLContext(keyFilename, trustFilename); - } - - /* - * Create an initialized SSLContext to use for this test. - */ - private SSLContext getSSLContext(String keyFile, String trustFile) - throws Exception { - - KeyStore ks = KeyStore.getInstance("JKS"); - KeyStore ts = KeyStore.getInstance("JKS"); - - char[] passphrase = "passphrase".toCharArray(); - - ks.load(new FileInputStream(keyFile), passphrase); - ts.load(new FileInputStream(trustFile), passphrase); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(ts); - - SSLContext sslCtx = SSLContext.getInstance("TLS"); - - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - - return sslCtx; - } - - private void createBuffers() { - // Size the buffers as appropriate. - - SSLSession session = ssle1.getSession(); - int appBufferMax = session.getApplicationBufferSize(); - int netBufferMax = session.getPacketBufferSize(); - - appIn1 = ByteBuffer.allocateDirect(appBufferMax + 50); - appIn2 = ByteBuffer.allocateDirect(appBufferMax + 50); - - oneToTwo = ByteBuffer.allocateDirect(netBufferMax); - twoToOne = ByteBuffer.allocateDirect(netBufferMax); - - appOut1 = ByteBuffer.wrap("Hi Engine2, I'm SSLEngine1".getBytes()); - appOut2 = ByteBuffer.wrap("Hello Engine1, I'm SSLEngine2".getBytes()); - - log("AppOut1 = " + appOut1); - log("AppOut2 = " + appOut2); - log(""); - } - - private static void runDelegatedTasks(SSLEngineResult result, - SSLEngine engine) throws Exception { - - if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { - Runnable runnable; - while ((runnable = engine.getDelegatedTask()) != null) { - log("running delegated task..."); - runnable.run(); - } - } + super(); } private static boolean isEngineClosed(SSLEngine engine) { return (engine.isOutboundDone() && engine.isInboundDone()); } - private static void checkTransfer(ByteBuffer a, ByteBuffer b) - throws Exception { - a.flip(); - b.flip(); - - if (!a.equals(b)) { - throw new Exception("Data didn't transfer cleanly"); - } else { - log("Data transferred cleanly"); - } - - a.position(a.limit()); - b.position(b.limit()); - a.limit(a.capacity()); - b.limit(b.capacity()); - } private static void log(String str) { if (debug) { diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/RehandshakeFinished.java b/test/jdk/sun/security/ssl/SSLEngineImpl/RehandshakeFinished.java index 6967caccb99..740500f9db9 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/RehandshakeFinished.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/RehandshakeFinished.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. * 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,6 +31,7 @@ * @bug 6207322 * @summary SSLEngine is returning a premature FINISHED message when doing * an abbreviated handshake. + * @library /javax/net/ssl/templates * @run main/othervm RehandshakeFinished * @author Brad Wetmore */ @@ -86,11 +87,9 @@ import javax.net.ssl.*; import javax.net.ssl.SSLEngineResult.*; -import java.io.*; -import java.security.*; import java.nio.*; -public class RehandshakeFinished { +public class RehandshakeFinished extends SSLContextTemplate { /* * Enables logging of the SSLEngine operations. @@ -108,7 +107,7 @@ public class RehandshakeFinished { */ private static boolean debug = false; - static private SSLContext sslc; + private final SSLContext sslc; private SSLEngine clientEngine; // client Engine private ByteBuffer clientOut; // write side of clientEngine @@ -126,46 +125,8 @@ public class RehandshakeFinished { private ByteBuffer cTOs; // "reliable" transport client->server private ByteBuffer sTOc; // "reliable" transport server->client - /* - * The following is to set up the keystores. - */ - private static String pathToStores = "../../../../javax/net/ssl/etc"; - private static String keyStoreFile = "keystore"; - private static String trustStoreFile = "truststore"; - private static String passwd = "passphrase"; - - private static String keyFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + keyStoreFile; - private static String trustFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + trustStoreFile; - - private static Exception loadException = null; - - static { - try { - KeyStore ks = KeyStore.getInstance("JKS"); - KeyStore ts = KeyStore.getInstance("JKS"); - - char[] passphrase = "passphrase".toCharArray(); - - ks.load(new FileInputStream(keyFilename), passphrase); - ts.load(new FileInputStream(trustFilename), passphrase); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - TrustManagerFactory tmf = - TrustManagerFactory.getInstance("SunX509"); - tmf.init(ts); - - SSLContext sslCtx = SSLContext.getInstance("TLSv1.2"); - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - sslc = sslCtx; - } catch (Exception e) { - loadException = e; - } + public RehandshakeFinished() throws Exception { + sslc = createServerSSLContext(); } /* @@ -176,14 +137,10 @@ public static void main(String args[]) throws Exception { System.setProperty("javax.net.debug", "all"); } - if (loadException != null) { - throw loadException; - } - + RehandshakeFinished test = new RehandshakeFinished(); // Prime the session cache with a good session // Second connection should be a simple session resumption. - if ((new RehandshakeFinished().runTest()) != - new RehandshakeFinished().runRehandshake()) { + if (test.runTest() != test.runRehandshake()) { throw new Exception("Sessions not equivalent"); } @@ -412,6 +369,11 @@ private void createSSLEngines() throws Exception { clientEngine.setUseClientMode(true); } + @Override + protected ContextParameters getServerContextParameters() { + return new ContextParameters("TLSv1.2", "PKIX", "NewSunX509"); + } + /* * Create and size the buffers appropriately. */ diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java index a3e355af361..497544bafc6 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java @@ -30,7 +30,7 @@ * @test * @bug 7031830 * @summary bad_record_mac failure on TLSv1.2 enabled connection with SSLEngine - * @library /test/lib + * @library /test/lib /javax/net/ssl/templates * @run main/othervm SSLEngineBadBufferArrayAccess */ @@ -82,19 +82,19 @@ import javax.net.ssl.SSLEngineResult.*; import java.io.*; import java.net.*; -import java.security.*; import java.nio.*; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import jdk.test.lib.security.SecurityUtils; -public class SSLEngineBadBufferArrayAccess { +public class SSLEngineBadBufferArrayAccess extends SSLContextTemplate { /* * Enables logging of the SSL/TLS operations. */ - private static boolean logging = true; + private final static boolean logging = Boolean.parseBoolean( + System.getProperty("test.logging", "true")); /* * Enables the JSSE system debugging system property: @@ -105,8 +105,9 @@ public class SSLEngineBadBufferArrayAccess { * including specific handshake messages, and might be best examined * after gaining some familiarity with this application. */ - private static boolean debug = false; - private SSLContext sslc; + private final static boolean debug = Boolean.getBoolean("test.debug"); + private final String PROTOCOL; + private SSLEngine serverEngine; // server-side SSLEngine private final byte[] serverMsg = "Hi there Client, I'm a Server".getBytes(); @@ -124,20 +125,6 @@ public class SSLEngineBadBufferArrayAccess { private ByteBuffer cTOs; // "reliable" transport client->server private ByteBuffer sTOc; // "reliable" transport server->client - /* - * The following is to set up the keystores/trust material. - */ - private static final String pathToStores = "../../../../javax/net/ssl/etc"; - private static final String keyStoreFile = "keystore"; - private static final String trustStoreFile = "truststore"; - private static final String passwd = "passphrase"; - private static String keyFilename = - System.getProperty("test.src", ".") + "/" + pathToStores - + "/" + keyStoreFile; - private static String trustFilename = - System.getProperty("test.src", ".") + "/" + pathToStores - + "/" + trustStoreFile; - /* * Is the server ready to serve? */ @@ -156,7 +143,7 @@ public class SSLEngineBadBufferArrayAccess { /* * Main entry point for this test. */ - public static void main(String args[]) throws Exception { + public static void main(String[] args) throws Exception { if (debug) { System.setProperty("javax.net.debug", "all"); } @@ -165,7 +152,7 @@ public static void main(String args[]) throws Exception { SecurityUtils.removeFromDisabledTlsAlgs("TLSv1", "TLSv1.1"); String [] protocols = new String [] { - "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" }; + "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"}; for (String protocol : protocols) { /* @@ -184,32 +171,18 @@ public static void main(String args[]) throws Exception { /* * Create an initialized SSLContext to use for these tests. */ - public SSLEngineBadBufferArrayAccess(String protocol) throws Exception { - - KeyStore ks = KeyStore.getInstance("JKS"); - KeyStore ts = KeyStore.getInstance("JKS"); - - char[] passphrase = "passphrase".toCharArray(); - - try (FileInputStream fis = new FileInputStream(keyFilename)) { - ks.load(fis, passphrase); - } - - try (FileInputStream fis = new FileInputStream(trustFilename)) { - ts.load(fis, passphrase); - } - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(ts); - - SSLContext sslCtx = SSLContext.getInstance(protocol); + public SSLEngineBadBufferArrayAccess(String protocol) { + PROTOCOL = protocol; + } - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + @Override + protected ContextParameters getServerContextParameters() { + return new ContextParameters(PROTOCOL, "PKIX", "NewSunX509"); + } - sslc = sslCtx; + @Override + protected ContextParameters getClientContextParameters() { + return new ContextParameters(PROTOCOL, "PKIX", "NewSunX509"); } /* @@ -232,6 +205,7 @@ public SSLEngineBadBufferArrayAccess(String protocol) throws Exception { private void runTest(boolean direct) throws Exception { boolean serverClose = direct; + System.out.println("Running test serverClose = " + serverClose); ServerSocket serverSocket = new ServerSocket(0); serverPort = serverSocket.getLocalPort(); @@ -244,7 +218,7 @@ private void runTest(boolean direct) throws Exception { Socket socket; try { serverSocket.setSoTimeout(30000); - socket = (Socket) serverSocket.accept(); + socket = serverSocket.accept(); } catch (SocketTimeoutException ste) { serverSocket.close(); @@ -327,7 +301,7 @@ void runServerApplication(Socket socket, boolean direct, byte[] outbound = new byte[8192]; while (!isEngineClosed(serverEngine)) { - int len = 0; + int len; // Inbound data log("================"); @@ -336,7 +310,14 @@ void runServerApplication(Socket socket, boolean direct, try { len = is.read(inbound); if (len == -1) { - throw new Exception("Unexpected EOF"); + logSocketStatus(socket); + if (socket.isClosed() + || socket.isOutputShutdown()) { + log("Client socket was closed or shutdown output"); + break; + } else { + throw new Exception("Unexpected EOF"); + } } cTOs.put(inbound, 0, len); } catch (SocketTimeoutException ste) { @@ -372,16 +353,13 @@ void runServerApplication(Socket socket, boolean direct, closed = true; /* - * We'll alternate initiatating the shutdown. + * We'll alternate initiating the shutdown. * When the server initiates, it will take one more * loop, but tests the orderly shutdown. */ if (serverClose) { serverEngine.closeOutbound(); } - } - - if (closed && isEngineClosed(serverEngine)) { serverIn.flip(); /* @@ -403,6 +381,7 @@ void runServerApplication(Socket socket, boolean direct, } } serverIn.compact(); + break; } } } @@ -450,7 +429,7 @@ void doClientSide(boolean serverClose) throws Exception { return; } - SSLSocketFactory sslsf = sslc.getSocketFactory(); + SSLSocketFactory sslsf = createClientSSLContext().getSocketFactory(); try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket()) { try { sslSocket.connect( @@ -492,6 +471,7 @@ void runClientApplication(SSLSocket sslSocket, boolean serverClose) InputStream is = sslSocket.getInputStream(); // write(byte[]) goes in one shot. + System.out.println("writing message to server."); os.write(clientMsg); byte[] inbound = new byte[2048]; @@ -499,14 +479,16 @@ void runClientApplication(SSLSocket sslSocket, boolean serverClose) int len; while ((len = is.read(inbound, pos, 2048 - pos)) != -1) { + System.out.printf("Client read %d bytes. Waiting for %d from server.%n", len, serverMsg.length); pos += len; // Let the client do the closing. if ((pos == serverMsg.length) && !serverClose) { + System.out.println("Closing the socket"); sslSocket.close(); break; } } - + System.out.println("Read everything we're going to, I guess."); if (pos != serverMsg.length) { throw new Exception("Client: Data length error"); } @@ -527,7 +509,7 @@ private void createSSLEngine() throws Exception { * Configure the serverEngine to act as a server in the SSL/TLS * handshake. */ - serverEngine = sslc.createSSLEngine(); + serverEngine = createServerSSLContext().createSSLEngine(); serverEngine.setUseClientMode(false); serverEngine.getNeedClientAuth(); } @@ -589,6 +571,15 @@ private static boolean isEngineClosed(SSLEngine engine) { return (engine.isOutboundDone() && engine.isInboundDone()); } + private static void logSocketStatus(Socket socket) { + log("##### " + socket + " #####"); + log("isBound: " + socket.isBound()); + log("isConnected: " + socket.isConnected()); + log("isClosed: " + socket.isClosed()); + log("isInputShutdown: " + socket.isInputShutdown()); + log("isOutputShutdown: " + socket.isOutputShutdown()); + } + /* * Logging code */ diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineDeadlock.java b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineDeadlock.java index d61b25bd886..3eff8bafb5e 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineDeadlock.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineDeadlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. * 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,6 +28,9 @@ * @test * @bug 6492872 * @summary Deadlock in SSLEngine + * @library /javax/net/ssl/templates + * @library /test/lib + * @build jdk.test.lib.Utils * @run main/othervm SSLEngineDeadlock * @author Brad R. Wetmore */ @@ -70,12 +73,9 @@ import javax.net.ssl.*; import javax.net.ssl.SSLEngineResult.*; -import java.io.*; -import java.security.*; -import java.nio.*; import java.lang.management.*; -public class SSLEngineDeadlock { +public class SSLEngineDeadlock extends SSLEngineTemplate { /* * Enables logging of the SSLEngine operations. @@ -93,41 +93,8 @@ public class SSLEngineDeadlock { */ private static boolean debug = false; - private SSLContext sslc; - - private SSLEngine clientEngine; // client Engine - private ByteBuffer clientOut; // write side of clientEngine - private ByteBuffer clientIn; // read side of clientEngine - - private SSLEngine serverEngine; // server Engine - private ByteBuffer serverOut; // write side of serverEngine - private ByteBuffer serverIn; // read side of serverEngine - private volatile boolean testDone = false; - /* - * For data transport, this example uses local ByteBuffers. This - * isn't really useful, but the purpose of this example is to show - * SSLEngine concepts, not how to do network transport. - */ - private ByteBuffer cTOs; // "reliable" transport client->server - private ByteBuffer sTOc; // "reliable" transport server->client - - /* - * The following is to set up the keystores. - */ - private static String pathToStores = "../../../../javax/net/ssl/etc"; - private static String keyStoreFile = "keystore"; - private static String trustStoreFile = "truststore"; - private static String passwd = "passphrase"; - - private static String keyFilename = - System.getProperty("test.src", ".") + "/" + pathToStores + - "/" + keyStoreFile; - private static String trustFilename = - System.getProperty("test.src", ".") + "/" + pathToStores + - "/" + trustStoreFile; - /* * Main entry point for this test. */ @@ -154,26 +121,7 @@ public static void main(String args[]) throws Exception { * Create an initialized SSLContext to use for these tests. */ public SSLEngineDeadlock() throws Exception { - - KeyStore ks = KeyStore.getInstance("JKS"); - KeyStore ts = KeyStore.getInstance("JKS"); - - char[] passphrase = "passphrase".toCharArray(); - - ks.load(new FileInputStream(keyFilename), passphrase); - ts.load(new FileInputStream(trustFilename), passphrase); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(ts); - - SSLContext sslCtx = SSLContext.getInstance("TLS"); - - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - - sslc = sslCtx; + super(); } /* @@ -214,9 +162,6 @@ private void doTask() { private void runTest() throws Exception { boolean dataDone = false; - createSSLEngines(); - createBuffers(); - SSLEngineResult clientResult; // results from client's last operation SSLEngineResult serverResult; // results from server's last operation @@ -287,82 +232,10 @@ public void run() { testDone = true; } - /* - * Using the SSLContext created during object creation, - * create/configure the SSLEngines we'll use for this test. - */ - private void createSSLEngines() throws Exception { - /* - * Configure the serverEngine to act as a server in the SSL/TLS - * handshake. Also, require SSL client authentication. - */ - serverEngine = sslc.createSSLEngine(); - serverEngine.setUseClientMode(false); - serverEngine.setNeedClientAuth(true); - - /* - * Similar to above, but using client mode instead. - */ - clientEngine = sslc.createSSLEngine("client", 80); - clientEngine.setUseClientMode(true); - } - - /* - * Create and size the buffers appropriately. - */ - private void createBuffers() { - - /* - * We'll assume the buffer sizes are the same - * between client and server. - */ - SSLSession session = clientEngine.getSession(); - int appBufferMax = session.getApplicationBufferSize(); - int netBufferMax = session.getPacketBufferSize(); - - /* - * We'll make the input buffers a bit bigger than the max needed - * size, so that unwrap()s following a successful data transfer - * won't generate BUFFER_OVERFLOWS. - * - * We'll use a mix of direct and indirect ByteBuffers for - * tutorial purposes only. In reality, only use direct - * ByteBuffers when they give a clear performance enhancement. - */ - clientIn = ByteBuffer.allocate(appBufferMax + 50); - serverIn = ByteBuffer.allocate(appBufferMax + 50); - - cTOs = ByteBuffer.allocateDirect(netBufferMax); - sTOc = ByteBuffer.allocateDirect(netBufferMax); - - clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes()); - serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes()); - } - private static boolean isEngineClosed(SSLEngine engine) { return (engine.isOutboundDone() && engine.isInboundDone()); } - /* - * Simple check to make sure everything came across as expected. - */ - private static void checkTransfer(ByteBuffer a, ByteBuffer b) - throws Exception { - a.flip(); - b.flip(); - - if (!a.equals(b)) { - throw new Exception("Data didn't transfer cleanly"); - } else { - log("\tData transferred cleanly"); - } - - a.position(a.limit()); - b.position(b.limit()); - a.limit(a.capacity()); - b.limit(b.capacity()); - } - /* * Detect dead lock */ diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineFailedALPN.java b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineFailedALPN.java index 0b5a2c3d054..02fea9c94f3 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineFailedALPN.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineFailedALPN.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * 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,6 +29,9 @@ * @bug 8207317 * @summary SSLEngine negotiation fail Exception behavior changed from * fail-fast to fail-lazy + * @library /javax/net/ssl/templates + * @library /test/lib + * @build jdk.test.lib.Utils * @run main/othervm SSLEngineFailedALPN */ /** @@ -68,11 +71,8 @@ */ import javax.net.ssl.*; import javax.net.ssl.SSLEngineResult.*; -import java.io.*; -import java.security.*; -import java.nio.*; -public class SSLEngineFailedALPN { +public class SSLEngineFailedALPN extends SSLEngineTemplate { /* * Enables logging of the SSLEngine operations. @@ -90,39 +90,6 @@ public class SSLEngineFailedALPN { */ private static final boolean debug = false; - private final SSLContext sslc; - - private SSLEngine clientEngine; // client Engine - private ByteBuffer clientOut; // write side of clientEngine - private ByteBuffer clientIn; // read side of clientEngine - - private SSLEngine serverEngine; // server Engine - private ByteBuffer serverOut; // write side of serverEngine - private ByteBuffer serverIn; // read side of serverEngine - - /* - * For data transport, this example uses local ByteBuffers. This - * isn't really useful, but the purpose of this example is to show - * SSLEngine concepts, not how to do network transport. - */ - private ByteBuffer cTOs; // "reliable" transport client->server - private ByteBuffer sTOc; // "reliable" transport server->client - - /* - * The following is to set up the keystores. - */ - private static final String pathToStores = "../../../../javax/net/ssl/etc"; - private static final String keyStoreFile = "keystore"; - private static final String trustStoreFile = "truststore"; - private static final char[] passphrase = "passphrase".toCharArray(); - - private static final String keyFilename = - System.getProperty("test.src", ".") + "/" + pathToStores + - "/" + keyStoreFile; - private static final String trustFilename = - System.getProperty("test.src", ".") + "/" + pathToStores + - "/" + trustStoreFile; - /* * Main entry point for this test. */ @@ -141,24 +108,7 @@ public static void main(String args[]) throws Exception { * Create an initialized SSLContext to use for these tests. */ public SSLEngineFailedALPN() throws Exception { - - KeyStore ks = KeyStore.getInstance("JKS"); - KeyStore ts = KeyStore.getInstance("JKS"); - - ks.load(new FileInputStream(keyFilename), passphrase); - ts.load(new FileInputStream(trustFilename), passphrase); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(ts); - - SSLContext sslCtx = SSLContext.getInstance("TLS"); - - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - - sslc = sslCtx; + super(); } /* @@ -181,9 +131,6 @@ public SSLEngineFailedALPN() throws Exception { private void runTest() throws Exception { boolean dataDone = false; - createSSLEngines(); - createBuffers(); - // results from client's last operation SSLEngineResult clientResult; @@ -309,113 +256,33 @@ private static void logEngineStatus(SSLEngine engine) { log("\tisOutboundDone(): " + engine.isOutboundDone()); } - /* - * Using the SSLContext created during object creation, - * create/configure the SSLEngines we'll use for this test. - */ - private void createSSLEngines() throws Exception { - /* - * Configure the serverEngine to act as a server in the SSL/TLS - * handshake. Also, require SSL client authentication. - */ - serverEngine = sslc.createSSLEngine(); - serverEngine.setUseClientMode(false); - serverEngine.setNeedClientAuth(true); + @Override + protected SSLEngine configureServerEngine(SSLEngine engine) { + engine.setUseClientMode(false); + engine.setNeedClientAuth(true); // Get/set parameters if needed - SSLParameters paramsServer = serverEngine.getSSLParameters(); + SSLParameters paramsServer = engine.getSSLParameters(); paramsServer.setApplicationProtocols(new String[]{"one"}); - serverEngine.setSSLParameters(paramsServer); + engine.setSSLParameters(paramsServer); + return engine; + } - /* - * Similar to above, but using client mode instead. - */ - clientEngine = sslc.createSSLEngine("client", 80); - clientEngine.setUseClientMode(true); + @Override + protected SSLEngine configureClientEngine(SSLEngine engine) { + engine.setUseClientMode(true); // Get/set parameters if needed - SSLParameters paramsClient = clientEngine.getSSLParameters(); + SSLParameters paramsClient = engine.getSSLParameters(); paramsClient.setApplicationProtocols(new String[]{"two"}); - clientEngine.setSSLParameters(paramsClient); - } - - /* - * Create and size the buffers appropriately. - */ - private void createBuffers() { - - /* - * We'll assume the buffer sizes are the same - * between client and server. - */ - SSLSession session = clientEngine.getSession(); - int appBufferMax = session.getApplicationBufferSize(); - int netBufferMax = session.getPacketBufferSize(); - - /* - * We'll make the input buffers a bit bigger than the max needed - * size, so that unwrap()s following a successful data transfer - * won't generate BUFFER_OVERFLOWS. - * - * We'll use a mix of direct and indirect ByteBuffers for - * tutorial purposes only. In reality, only use direct - * ByteBuffers when they give a clear performance enhancement. - */ - clientIn = ByteBuffer.allocate(appBufferMax + 50); - serverIn = ByteBuffer.allocate(appBufferMax + 50); - - cTOs = ByteBuffer.allocateDirect(netBufferMax); - sTOc = ByteBuffer.allocateDirect(netBufferMax); - - clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes()); - serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes()); - } - - /* - * If the result indicates that we have outstanding tasks to do, - * go ahead and run them in this thread. - */ - private static void runDelegatedTasks(SSLEngine engine) throws Exception { - - if (engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { - Runnable runnable; - while ((runnable = engine.getDelegatedTask()) != null) { - log(" running delegated task..."); - runnable.run(); - } - HandshakeStatus hsStatus = engine.getHandshakeStatus(); - if (hsStatus == HandshakeStatus.NEED_TASK) { - throw new Exception( - "handshake shouldn't need additional tasks"); - } - logEngineStatus(engine); - } + engine.setSSLParameters(paramsClient); + return engine; } private static boolean isEngineClosed(SSLEngine engine) { return (engine.isOutboundDone() && engine.isInboundDone()); } - /* - * Simple check to make sure everything came across as expected. - */ - private static void checkTransfer(ByteBuffer a, ByteBuffer b) - throws Exception { - a.flip(); - b.flip(); - - if (!a.equals(b)) { - throw new Exception("Data didn't transfer cleanly"); - } else { - log("\tData transferred cleanly"); - } - - a.position(a.limit()); - b.position(b.limit()); - a.limit(a.capacity()); - b.limit(b.capacity()); - } - /* * Logging code */ diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java index 58c3c4a0d3b..c0d3bbfda31 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java @@ -25,7 +25,8 @@ * @test * @bug 8164879 8300285 * @library ../../ - * @library /test/lib + * /test/lib + * /javax/net/ssl/templates * @summary Verify AEAD TLS cipher suite limits set in the jdk.tls.keyLimits * property * start a new handshake sequence to renegotiate the symmetric key with an @@ -49,23 +50,19 @@ * success. */ -import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.TrustManagerFactory; import java.io.File; import java.io.PrintWriter; import java.nio.ByteBuffer; -import java.security.KeyStore; -import java.security.SecureRandom; import java.util.Arrays; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.Utils; -public class SSLEngineKeyLimit { +public class SSLEngineKeyLimit extends SSLContextTemplate { SSLEngine eng; static ByteBuffer cTos; @@ -73,11 +70,6 @@ public class SSLEngineKeyLimit { static ByteBuffer outdata; ByteBuffer buf; static boolean ready = false; - - static String pathToStores = "../../../../javax/net/ssl/etc/"; - static String keyStoreFile = "keystore"; - static String passwd = "passphrase"; - static String keyFilename; static int dataLen = 10240; static boolean serverwrite = true; int totalDataLen = 0; @@ -164,13 +156,6 @@ public static void main(String args[]) throws Exception { } cTos = ByteBuffer.allocateDirect(dataLen*4); - keyFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + keyStoreFile; - - System.setProperty("javax.net.ssl.keyStore", keyFilename); - System.setProperty("javax.net.ssl.keyStorePassword", passwd); - sToc = ByteBuffer.allocateDirect(dataLen*4); outdata = ByteBuffer.allocateDirect(dataLen); @@ -412,19 +397,12 @@ ByteBuffer getWriteBuf() { SSLContext initContext() throws Exception { - SSLContext sc = SSLContext.getInstance("TLSv1.3"); - KeyStore ks = KeyStore.getInstance( - new File(System.getProperty("javax.net.ssl.keyStore")), - passwd.toCharArray()); - KeyManagerFactory kmf = KeyManagerFactory.getInstance( - KeyManagerFactory.getDefaultAlgorithm()); - kmf.init(ks, passwd.toCharArray()); - TrustManagerFactory tmf = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm()); - tmf.init(ks); - sc.init(kmf.getKeyManagers(), - tmf.getTrustManagers(), new SecureRandom()); - return sc; + return createServerSSLContext(); + } + + @Override + protected ContextParameters getServerContextParameters() { + return new ContextParameters("TLSv1.3", "PKIX", "NewSunX509"); } static class Server extends SSLEngineKeyLimit implements Runnable { diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/TLS13BeginHandshake.java b/test/jdk/sun/security/ssl/SSLEngineImpl/TLS13BeginHandshake.java index 7c2b9f723b1..fbd901eac84 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/TLS13BeginHandshake.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/TLS13BeginHandshake.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * 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,52 +25,38 @@ * @test * @summary Test SSLEngine.begineHandshake() triggers a KeyUpdate handshake * in TLSv1.3 + * @library /javax/net/ssl/templates + * @library /test/lib + * @build jdk.test.lib.Utils * @run main/othervm TLS13BeginHandshake */ -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLEngineResult.HandshakeStatus; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManagerFactory; -import java.io.File; -import java.nio.ByteBuffer; -import java.security.KeyStore; -import java.security.SecureRandom; - -public class TLS13BeginHandshake { - static String pathToStores = - System.getProperty("test.src") + "/../../../../javax/net/ssl/etc/"; - static String keyStoreFile = "keystore"; - static String passwd = "passphrase"; - - private SSLEngine serverEngine, clientEngine; + +public class TLS13BeginHandshake extends SSLEngineTemplate { SSLEngineResult clientResult, serverResult; - private ByteBuffer clientOut, clientIn; - private ByteBuffer serverOut, serverIn; - private ByteBuffer cTOs,sTOc; public static void main(String args[]) throws Exception{ new TLS13BeginHandshake().runDemo(); } + public TLS13BeginHandshake() throws Exception { + super(); + } + private void runDemo() throws Exception { int done = 0; - createSSLEngines(); - createBuffers(); - while (!isEngineClosed(clientEngine) || !isEngineClosed(serverEngine)) { System.out.println("================"); clientResult = clientEngine.wrap(clientOut, cTOs); System.out.println("client wrap: " + clientResult); - runDelegatedTasks(clientResult, clientEngine); + runDelegatedTasks(clientEngine); serverResult = serverEngine.wrap(serverOut, sTOc); System.out.println("server wrap: " + serverResult); - runDelegatedTasks(serverResult, serverEngine); + runDelegatedTasks(serverEngine); cTOs.flip(); sTOc.flip(); @@ -80,10 +66,11 @@ private void runDemo() throws Exception { System.out.println("client unwrap: " + clientResult); if (clientResult.getStatus() == SSLEngineResult.Status.CLOSED) { break; - } runDelegatedTasks(clientResult, clientEngine); + } + runDelegatedTasks(clientEngine); serverResult = serverEngine.unwrap(cTOs, serverIn); System.out.println("server unwrap: " + serverResult); - runDelegatedTasks(serverResult, serverEngine); + runDelegatedTasks(serverEngine); cTOs.compact(); sTOc.compact(); @@ -121,71 +108,13 @@ private static boolean isEngineClosed(SSLEngine engine) { return (engine.isOutboundDone() && engine.isInboundDone()); } - private static void checkTransfer(ByteBuffer a, ByteBuffer b) - throws Exception { - a.flip(); - b.flip(); - - if (!a.equals(b)) { - throw new Exception("Data didn't transfer cleanly"); - } else { - System.out.println("\tData transferred cleanly"); - } - - a.compact(); - b.compact(); - - } - private void createBuffers() { - SSLSession session = clientEngine.getSession(); - int appBufferMax = session.getApplicationBufferSize(); - int netBufferMax = session.getPacketBufferSize(); - - clientIn = ByteBuffer.allocate(appBufferMax + 50); - serverIn = ByteBuffer.allocate(appBufferMax + 50); - - cTOs = ByteBuffer.allocateDirect(netBufferMax); - sTOc = ByteBuffer.allocateDirect(netBufferMax); - - clientOut = ByteBuffer.wrap("client".getBytes()); - serverOut = ByteBuffer.wrap("server".getBytes()); - } - - private void createSSLEngines() throws Exception { - serverEngine = initContext().createSSLEngine(); - serverEngine.setUseClientMode(false); - serverEngine.setNeedClientAuth(true); - - clientEngine = initContext().createSSLEngine("client", 80); - clientEngine.setUseClientMode(true); + @Override + protected ContextParameters getServerContextParameters() { + return new ContextParameters("TLSv1.3", "PKIX", "NewSunX509"); } - private SSLContext initContext() throws Exception { - SSLContext sc = SSLContext.getInstance("TLSv1.3"); - KeyStore ks = KeyStore.getInstance(new File(pathToStores + keyStoreFile), - passwd.toCharArray()); - KeyManagerFactory kmf = - KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - kmf.init(ks, passwd.toCharArray()); - TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - tmf.init(ks); - sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom()); - return sc; - } - - private static void runDelegatedTasks(SSLEngineResult result, - SSLEngine engine) throws Exception { - - if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { - Runnable runnable; - while ((runnable = engine.getDelegatedTask()) != null) { - runnable.run(); - } - HandshakeStatus hsStatus = engine.getHandshakeStatus(); - if (hsStatus == HandshakeStatus.NEED_TASK) { - throw new Exception( - "handshake shouldn't need additional tasks"); - } - } + @Override + protected ContextParameters getClientContextParameters() { + return new ContextParameters("TLSv1.3", "PKIX", "NewSunX509"); } } diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/HashCodeMissing.java b/test/jdk/sun/security/ssl/SSLSessionImpl/HashCodeMissing.java index 61f0c6cb477..43ec90d8f8e 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/HashCodeMissing.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/HashCodeMissing.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ * @test * @bug 4910892 * @summary 4518403 was not properly fixed. hashcode should be hashCode. + * @library /javax/net/ssl/templates * @run main/othervm HashCodeMissing * * SunJSSE does not support dynamic system properties, no way to re-use @@ -33,72 +34,19 @@ */ import java.io.*; -import java.net.*; import javax.net.ssl.*; import java.lang.reflect.*; -public class HashCodeMissing { - - /* - * ============================================================= - * Set the various variables needed for the tests, then - * specify what tests to run on each side. - */ - - /* - * Should we run the client or server in a separate thread? - * Both sides can throw exceptions, but do you have a preference - * as to which side should be the main thread. - */ - static boolean separateServerThread = false; - - /* - * Where do we find the keystores? - */ - static String pathToStores = "../../../../javax/net/ssl/etc"; - static String keyStoreFile = "keystore"; - static String trustStoreFile = "truststore"; - static String passwd = "passphrase"; - - /* - * Is the server ready to serve? - */ - volatile static boolean serverReady = false; +public class HashCodeMissing extends SSLSocketTemplate { /* * Turn on SSL debugging? */ static boolean debug = false; - /* - * If the client or server is doing some kind of object creation - * that the other side depends on, and that thread prematurely - * exits, you may experience a hang. The test harness will - * terminate all hung threads after its timeout has expired, - * currently 3 minutes by default, but you might try to be - * smart about it.... - */ - /* - * Define the server side of the test. - * - * If the server prematurely exits, serverReady will be set to true - * to avoid infinite hangs. - */ - void doServerSide() throws Exception { - SSLServerSocketFactory sslssf = - (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); - SSLServerSocket sslServerSocket = - (SSLServerSocket) sslssf.createServerSocket(serverPort); - - serverPort = sslServerSocket.getLocalPort(); - - /* - * Signal Client, we're ready for his connect. - */ - serverReady = true; - - SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); + @Override + protected void runServerApplication(SSLSocket sslSocket) throws Exception { InputStream sslIS = sslSocket.getInputStream(); OutputStream sslOS = sslSocket.getOutputStream(); @@ -106,28 +54,10 @@ void doServerSide() throws Exception { sslOS.write(85); sslOS.flush(); - sslSocket.close(); } - /* - * Define the client side of the test. - * - * If the server prematurely exits, serverReady will be set to true - * to avoid infinite hangs. - */ - void doClientSide() throws Exception { - - /* - * Wait for server to get started. - */ - while (!serverReady) { - Thread.sleep(50); - } - - SSLSocketFactory sslsf = - (SSLSocketFactory) SSLSocketFactory.getDefault(); - SSLSocket sslSocket = (SSLSocket) - sslsf.createSocket("localhost", serverPort); + @Override + protected void runClientApplication(SSLSocket sslSocket) throws Exception { InputStream sslIS = sslSocket.getInputStream(); OutputStream sslOS = sslSocket.getOutputStream(); @@ -150,29 +80,7 @@ void doClientSide() throws Exception { System.out.println("Method = " + method); } - /* - * ============================================================= - * The remainder is just support stuff - */ - - // use any free port by default - volatile int serverPort = 0; - - volatile Exception serverException = null; - volatile Exception clientException = null; - public static void main(String[] args) throws Exception { - String keyFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + keyStoreFile; - String trustFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + trustStoreFile; - - System.setProperty("javax.net.ssl.keyStore", keyFilename); - System.setProperty("javax.net.ssl.keyStorePassword", passwd); - System.setProperty("javax.net.ssl.trustStore", trustFilename); - System.setProperty("javax.net.ssl.trustStorePassword", passwd); if (debug) System.setProperty("javax.net.debug", "all"); @@ -180,129 +88,7 @@ public static void main(String[] args) throws Exception { /* * Start the tests. */ - new HashCodeMissing(); + new HashCodeMissing().run(); } - Thread clientThread = null; - Thread serverThread = null; - - /* - * Primary constructor, used to drive remainder of the test. - * - * Fork off the other side, then do your work. - */ - HashCodeMissing() throws Exception { - try { - if (separateServerThread) { - startServer(true); - startClient(false); - } else { - startClient(true); - startServer(false); - } - } catch (Exception e) { - //swallow for now. Show later - } - - /* - * Wait for other side to close down. - */ - if (separateServerThread) { - serverThread.join(); - } else { - clientThread.join(); - } - - /* - * When we get here, the test is pretty much over. - * Which side threw the error? - */ - Exception local; - Exception remote; - String whichRemote; - - if (separateServerThread) { - remote = serverException; - local = clientException; - whichRemote = "server"; - } else { - remote = clientException; - local = serverException; - whichRemote = "client"; - } - - /* - * If both failed, return the curthread's exception, but also - * print the remote side Exception - */ - if ((local != null) && (remote != null)) { - System.out.println(whichRemote + " also threw:"); - remote.printStackTrace(); - System.out.println(); - throw local; - } - - if (remote != null) { - throw remote; - } - - if (local != null) { - throw local; - } - } - - void startServer(boolean newThread) throws Exception { - if (newThread) { - serverThread = new Thread() { - public void run() { - try { - doServerSide(); - } catch (Exception e) { - /* - * Our server thread just died. - * - * Release the client, if not active already... - */ - System.err.println("Server died..."); - serverReady = true; - serverException = e; - } - } - }; - serverThread.start(); - } else { - try { - doServerSide(); - } catch (Exception e) { - serverException = e; - } finally { - serverReady = true; - } - } - } - - void startClient(boolean newThread) throws Exception { - if (newThread) { - clientThread = new Thread() { - public void run() { - try { - doClientSide(); - } catch (Exception e) { - /* - * Our client thread just died. - */ - System.err.println("Client died..."); - clientException = e; - } - } - }; - clientThread.start(); - } else { - try { - doClientSide(); - } catch (Exception e) { - clientException = e; - } - } - } } diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/InvalidateSession.java b/test/jdk/sun/security/ssl/SSLSessionImpl/InvalidateSession.java index 2a13a8cdb8f..87eeeaebfdb 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/InvalidateSession.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/InvalidateSession.java @@ -37,7 +37,7 @@ import jdk.test.lib.security.SecurityUtils; -public class InvalidateSession implements SSLContextTemplate { +public class InvalidateSession extends SSLContextTemplate { static ServerSocketFactory serverSsf = null; static SSLSocketFactory clientSsf = null; diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/ResumeChecksClient.java b/test/jdk/sun/security/ssl/SSLSessionImpl/ResumeChecksClient.java index b8c20cc0d95..e62b00ff8e3 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/ResumeChecksClient.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/ResumeChecksClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8206929 8212885 * @summary ensure that client only resumes a session if certain properties * of the session are compatible with the new connection + * @library /javax/net/ssl/templates * @run main/othervm -Djdk.tls.client.protocols=TLSv1.2 ResumeChecksClient BASIC * @run main/othervm -Djdk.tls.client.protocols=TLSv1.3 ResumeChecksClient BASIC * @run main/othervm ResumeChecksClient BASIC @@ -43,13 +44,7 @@ import java.net.*; import java.util.*; -public class ResumeChecksClient { - - static String pathToStores = "../../../../javax/net/ssl/etc"; - static String keyStoreFile = "keystore"; - static String trustStoreFile = "truststore"; - static String passwd = "passphrase"; - +public class ResumeChecksClient extends SSLContextTemplate { enum TestMode { BASIC, VERSION_2_TO_3, @@ -59,38 +54,32 @@ enum TestMode { } public static void main(String[] args) throws Exception { + new ResumeChecksClient(TestMode.valueOf(args[0])).run(); + } - TestMode mode = TestMode.valueOf(args[0]); - - String keyFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + keyStoreFile; - String trustFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + trustStoreFile; - - System.setProperty("javax.net.ssl.keyStore", keyFilename); - System.setProperty("javax.net.ssl.keyStorePassword", passwd); - System.setProperty("javax.net.ssl.trustStore", trustFilename); - System.setProperty("javax.net.ssl.trustStorePassword", passwd); + private final TestMode testMode; + public ResumeChecksClient(TestMode mode) { + this.testMode = mode; + } + private void run() throws Exception { Server server = startServer(); server.signal(); - SSLContext sslContext = SSLContext.getDefault(); + SSLContext sslContext = createClientSSLContext(); while (!server.started) { Thread.yield(); } - SSLSession firstSession = connect(sslContext, server.port, mode, false); + SSLSession firstSession = connect(sslContext, server.port, testMode, false); server.signal(); long secondStartTime = System.currentTimeMillis(); Thread.sleep(10); - SSLSession secondSession = connect(sslContext, server.port, mode, true); + SSLSession secondSession = connect(sslContext, server.port, testMode, true); server.go = false; server.signal(); - switch (mode) { + switch (testMode) { case BASIC: // fail if session is not resumed checkResumedSession(firstSession, secondSession); @@ -105,7 +94,7 @@ public static void main(String[] args) throws Exception { } break; default: - throw new RuntimeException("unknown mode: " + mode); + throw new RuntimeException("unknown mode: " + testMode); } } @@ -287,7 +276,7 @@ private static Server startServer() { return server; } - private static class Server implements Runnable { + private static class Server extends SSLContextTemplate implements Runnable { public volatile boolean go = true; private boolean signal = false; @@ -313,7 +302,7 @@ public synchronized void signal() { public void run() { try { - SSLContext sc = SSLContext.getDefault(); + SSLContext sc = createServerSSLContext(); ServerSocketFactory fac = sc.getServerSocketFactory(); SSLServerSocket ssock = (SSLServerSocket) fac.createServerSocket(0); diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/ResumeChecksServer.java b/test/jdk/sun/security/ssl/SSLSessionImpl/ResumeChecksServer.java index 14faf95d701..ee7bc5f6918 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/ResumeChecksServer.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/ResumeChecksServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8206929 * @summary ensure that server only resumes a session if certain properties * of the session are compatible with the new connection + * @library /javax/net/ssl/templates * @run main/othervm -Djdk.tls.client.protocols=TLSv1.2 ResumeChecksServer BASIC * @run main/othervm -Djdk.tls.client.protocols=TLSv1.3 ResumeChecksServer BASIC * @run main/othervm ResumeChecksServer BASIC @@ -46,12 +47,7 @@ import java.net.*; import java.util.*; -public class ResumeChecksServer { - - static String pathToStores = "../../../../javax/net/ssl/etc"; - static String keyStoreFile = "keystore"; - static String trustStoreFile = "truststore"; - static String passwd = "passphrase"; +public class ResumeChecksServer extends SSLContextTemplate { enum TestMode { BASIC, @@ -64,23 +60,18 @@ enum TestMode { public static void main(String[] args) throws Exception { - TestMode mode = TestMode.valueOf(args[0]); - - String keyFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + keyStoreFile; - String trustFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + trustStoreFile; + new ResumeChecksServer(TestMode.valueOf(args[0])).run(); + } + private final TestMode testMode; - System.setProperty("javax.net.ssl.keyStore", keyFilename); - System.setProperty("javax.net.ssl.keyStorePassword", passwd); - System.setProperty("javax.net.ssl.trustStore", trustFilename); - System.setProperty("javax.net.ssl.trustStorePassword", passwd); + public ResumeChecksServer(TestMode testMode) { + this.testMode = testMode; + } + private void run() throws Exception { SSLSession secondSession = null; - SSLContext sslContext = SSLContext.getDefault(); + SSLContext sslContext = createServerSSLContext(); ServerSocketFactory fac = sslContext.getServerSocketFactory(); SSLServerSocket ssock = (SSLServerSocket) fac.createServerSocket(0); @@ -88,7 +79,7 @@ public static void main(String[] args) throws Exception { Client client = startClient(ssock.getLocalPort()); try { - connect(client, ssock, mode, false); + connect(client, ssock, testMode, false); } catch (Exception ex) { throw new RuntimeException(ex); } @@ -96,7 +87,7 @@ public static void main(String[] args) throws Exception { long secondStartTime = System.currentTimeMillis(); Thread.sleep(10); try { - secondSession = connect(client, ssock, mode, true); + secondSession = connect(client, ssock, testMode, true); } catch (SSLHandshakeException ex) { // this is expected } catch (Exception ex) { @@ -106,7 +97,7 @@ public static void main(String[] args) throws Exception { client.go = false; client.signal(); - switch (mode) { + switch (testMode) { case BASIC: // fail if session is not resumed if (secondSession.getCreationTime() > secondStartTime) { @@ -127,7 +118,7 @@ public static void main(String[] args) throws Exception { } break; default: - throw new RuntimeException("unknown mode: " + mode); + throw new RuntimeException("unknown mode: " + testMode); } } @@ -242,7 +233,7 @@ private static Client startClient(int port) { return client; } - private static class Client implements Runnable { + private static class Client extends SSLContextTemplate implements Runnable { public volatile boolean go = true; private boolean signal = false; @@ -276,7 +267,7 @@ public synchronized void signal() { public void run() { try { - SSLContext sc = SSLContext.getDefault(); + SSLContext sc = createClientSSLContext(); waitForSignal(); while (go) { diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/ClientSocketCloseHang.java b/test/jdk/sun/security/ssl/SSLSocketImpl/ClientSocketCloseHang.java index 249aab13291..e21cc314775 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/ClientSocketCloseHang.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/ClientSocketCloseHang.java @@ -34,7 +34,7 @@ import javax.net.ssl.*; import java.net.InetAddress; -public class ClientSocketCloseHang implements SSLContextTemplate { +public class ClientSocketCloseHang extends SSLContextTemplate { public static void main(String[] args) throws Exception { System.setProperty("jdk.tls.client.protocols", args[0]); diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java b/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java index 650c309887e..abad01099bc 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,240 +25,31 @@ * @test * @bug 4482446 * @summary java.net.SocketTimeoutException on 98, NT, 2000 for JSSE - * @run main/othervm ReuseAddr + * @library /javax/net/ssl/templates + * @run main ReuseAddr * * SunJSSE does not support dynamic system properties, no way to re-use * system properties in samevm/agentvm mode. * @author Brad Wetmore */ -import java.io.*; -import java.net.*; -import javax.net.ssl.*; +import java.net.ServerSocket; -public class ReuseAddr { +public class ReuseAddr extends SSLSocketTemplate { - /* - * ============================================================= - * Set the various variables needed for the tests, then - * specify what tests to run on each side. - */ + @Override + protected void doServerSide() throws Exception { + super.doServerSide(); - /* - * Should we run the client or server in a separate thread? - * Both sides can throw exceptions, but do you have a preference - * as to which side should be the main thread. - */ - static boolean separateServerThread = true; - - /* - * Where do we find the keystores? - */ - private final static String pathToStores = "../../../../javax/net/ssl/etc"; - static String keyStoreFile = "keystore"; - static String trustStoreFile = "truststore"; - static String passwd = "passphrase"; - - /* - * Is the server ready to serve? - */ - volatile static boolean serverReady = false; - - /* - * Turn on SSL debugging? - */ - static boolean debug = false; - - /* - * If the client or server is doing some kind of object creation - * that the other side depends on, and that thread prematurely - * exits, you may experience a hang. The test harness will - * terminate all hung threads after its timeout has expired, - * currently 3 minutes by default, but you might try to be - * smart about it.... - */ - - /* - * Define the server side of the test. - * - * If the server prematurely exits, serverReady will be set to true - * to avoid infinite hangs. - */ - void doServerSide() throws Exception { - SSLServerSocketFactory sslssf = - (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); - SSLServerSocket sslServerSocket = - (SSLServerSocket) sslssf.createServerSocket(serverPort); - serverPort = sslServerSocket.getLocalPort(); - - /* - * Signal Client, we're ready for his connect. - */ - serverReady = true; - - SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); - InputStream sslIS = sslSocket.getInputStream(); - OutputStream sslOS = sslSocket.getOutputStream(); - - sslIS.read(); - sslOS.write(85); - sslOS.flush(); - - sslSocket.close(); - - // Close original server socket - sslServerSocket.close(); - - // Try rebinding to same port - sslServerSocket = - (SSLServerSocket) sslssf.createServerSocket(serverPort); - sslServerSocket.close(); - } - - /* - * Define the client side of the test. - * - * If the server prematurely exits, serverReady will be set to true - * to avoid infinite hangs. - */ - void doClientSide() throws Exception { - - /* - * Wait for server to get started. - */ - while (!serverReady) { - Thread.sleep(50); + // Note that if this port is already used by another test, + // this test will fail. + System.out.println("Try rebinding to same port: " + serverPort); + try (ServerSocket server = new ServerSocket(serverPort)) { + System.out.println("Server port: " + server.getLocalPort()); } - - SSLSocketFactory sslsf = - (SSLSocketFactory) SSLSocketFactory.getDefault(); - SSLSocket sslSocket = (SSLSocket) - sslsf.createSocket("localhost", serverPort); - - InputStream sslIS = sslSocket.getInputStream(); - OutputStream sslOS = sslSocket.getOutputStream(); - - sslOS.write(280); - sslOS.flush(); - sslIS.read(); - - sslSocket.close(); } - /* - * ============================================================= - * The remainder is just support stuff - */ - - // use any free port by default - volatile int serverPort = 0; - - volatile Exception serverException = null; - volatile Exception clientException = null; - public static void main(String[] args) throws Exception { - String keyFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + keyStoreFile; - String trustFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + trustStoreFile; - - System.setProperty("javax.net.ssl.keyStore", keyFilename); - System.setProperty("javax.net.ssl.keyStorePassword", passwd); - System.setProperty("javax.net.ssl.trustStore", trustFilename); - System.setProperty("javax.net.ssl.trustStorePassword", passwd); - - if (debug) - System.setProperty("javax.net.debug", "all"); - - /* - * Start the tests. - */ - new ReuseAddr(); - } - - Thread clientThread = null; - Thread serverThread = null; - - /* - * Primary constructor, used to drive remainder of the test. - * - * Fork off the other side, then do your work. - */ - ReuseAddr() throws Exception { - if (separateServerThread) { - startServer(true); - startClient(false); - } else { - startClient(true); - startServer(false); - } - - /* - * Wait for other side to close down. - */ - if (separateServerThread) { - serverThread.join(); - } else { - clientThread.join(); - } - - /* - * When we get here, the test is pretty much over. - * - * If the main thread excepted, that propagates back - * immediately. If the other thread threw an exception, we - * should report back. - */ - if (serverException != null) - throw serverException; - if (clientException != null) - throw clientException; - } - - void startServer(boolean newThread) throws Exception { - if (newThread) { - serverThread = new Thread() { - public void run() { - try { - doServerSide(); - } catch (Exception e) { - /* - * Our server thread just died. - * - * Release the client, if not active already... - */ - System.err.println("Server died..."); - serverReady = true; - serverException = e; - } - } - }; - serverThread.start(); - } else { - doServerSide(); - } - } - - void startClient(boolean newThread) throws Exception { - if (newThread) { - clientThread = new Thread() { - public void run() { - try { - doClientSide(); - } catch (Exception e) { - /* - * Our client thread just died. - */ - System.err.println("Client died..."); - clientException = e; - } - } - }; - clientThread.start(); - } else { - doClientSide(); - } + new ReuseAddr().run(); } } diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketBruceForceClose.java b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketBruceForceClose.java deleted file mode 100644 index b220a3d434b..00000000000 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketBruceForceClose.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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. - */ - -// -// Please run in othervm mode. SunJSSE does not support dynamic system -// properties, no way to re-use system properties in samevm/agentvm mode. -// - -/* - * @test - * @bug 8209333 - * @summary Socket reset issue for TLS 1.3 socket close - * @library /javax/net/ssl/templates - * @run main/othervm SSLSocketBruceForceClose - */ - -import javax.net.ssl.*; -import java.io.*; -import java.net.InetAddress; - -public class SSLSocketBruceForceClose implements SSLContextTemplate { - - public static void main(String[] args) throws Exception { - for (int i = 0; i<= 10; i++) { - System.err.println("==================================="); - System.err.println("loop " + i); - System.err.println("==================================="); - new SSLSocketBruceForceClose().test(); - } - } - - private void test() throws Exception { - SSLServerSocket listenSocket = null; - SSLSocket serverSocket = null; - ClientSocket clientSocket = null; - try { - SSLServerSocketFactory serversocketfactory = - createServerSSLContext().getServerSocketFactory(); - listenSocket = - (SSLServerSocket)serversocketfactory.createServerSocket(0); - listenSocket.setNeedClientAuth(false); - listenSocket.setEnableSessionCreation(true); - listenSocket.setUseClientMode(false); - - - System.err.println("Starting client"); - clientSocket = new ClientSocket(listenSocket.getLocalPort()); - clientSocket.start(); - - System.err.println("Accepting client requests"); - serverSocket = (SSLSocket) listenSocket.accept(); - - System.err.println("Reading data from client"); - BufferedReader serverReader = new BufferedReader( - new InputStreamReader(serverSocket.getInputStream())); - String data = serverReader.readLine(); - System.err.println("Received data from client: " + data); - - System.err.println("Reading more data from client"); - data = serverReader.readLine(); - System.err.println("Received data from client: " + data); - } finally { - if (listenSocket != null) { - listenSocket.close(); - } - - if (serverSocket != null) { - serverSocket.close(); - } - } - - if (clientSocket != null && clientSocket.clientException != null) { - throw clientSocket.clientException; - } - } - - private class ClientSocket extends Thread{ - int serverPort = 0; - Exception clientException; - - public ClientSocket(int serverPort) { - this.serverPort = serverPort; - } - - @Override - public void run() { - SSLSocket clientSocket = null; - String clientData = "Hi, I am client"; - try { - System.err.println( - "Connecting to server at port " + serverPort); - SSLSocketFactory sslSocketFactory = - createClientSSLContext().getSocketFactory(); - clientSocket = (SSLSocket)sslSocketFactory.createSocket( - InetAddress.getLocalHost(), serverPort); - clientSocket.setSoLinger(true, 3); - clientSocket.setSoTimeout(1000); - - - System.err.println("Sending data to server ..."); - - BufferedWriter os = new BufferedWriter( - new OutputStreamWriter(clientSocket.getOutputStream())); - os.write(clientData, 0, clientData.length()); - os.newLine(); - os.flush(); - - System.err.println("Sending more data to server ..."); - os.write(clientData, 0, clientData.length()); - os.newLine(); - os.flush(); - } catch (Exception e) { - clientException = e; - } finally { - if (clientSocket != null) { - try{ - clientSocket.close(); - System.err.println("client socket closed"); - } catch (IOException ioe) { - clientException = ioe; - } - } - } - } - } -} - diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketBruteForceClose.java b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketBruteForceClose.java new file mode 100644 index 00000000000..bbc8a4f8bf5 --- /dev/null +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketBruteForceClose.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +// +// Please run in othervm mode. SunJSSE does not support dynamic system +// properties, no way to re-use system properties in samevm/agentvm mode. +// + +/* + * @test + * @bug 8209333 + * @summary Socket reset issue for TLS 1.3 socket close + * @library /javax/net/ssl/templates + * @run main/othervm SSLSocketBruteForceClose + */ + +import javax.net.ssl.*; +import java.io.*; +import java.net.SocketException; + +public class SSLSocketBruteForceClose extends SSLSocketTemplate { + + public static void main(String[] args) throws Exception { + for (int i = 0; i<= 10; i++) { + System.err.println("==================================="); + System.err.println("loop " + i); + System.err.println("==================================="); + new SSLSocketBruteForceClose().run(); + } + } + + @Override + protected void configureServerSocket(SSLServerSocket socket) { + socket.setNeedClientAuth(false); + socket.setEnableSessionCreation(true); + socket.setUseClientMode(false); + } + + @Override + protected void runServerApplication(SSLSocket socket) throws Exception { + System.err.println("Reading data from client"); + BufferedReader serverReader = new BufferedReader( + new InputStreamReader(socket.getInputStream())); + String data = serverReader.readLine(); + System.err.println("Received data from client: " + data); + + System.err.println("Reading more data from client"); + data = serverReader.readLine(); + System.err.println("Received data from client: " + data); + } + + @Override + protected void configureClientSocket(SSLSocket socket) { + try { + socket.setSoLinger(true, 3); + socket.setSoTimeout(1000); + } catch (SocketException exc) { + throw new RuntimeException("Could not configure client socket", exc); + } + } + + @Override + protected void runClientApplication(SSLSocket socket) throws Exception { + String clientData = "Hi, I am client"; + + System.err.println("Sending data to server ..."); + BufferedWriter os = new BufferedWriter( + new OutputStreamWriter(socket.getOutputStream())); + os.write(clientData, 0, clientData.length()); + os.newLine(); + os.flush(); + + System.err.println("Sending more data to server ..."); + os.write(clientData, 0, clientData.length()); + os.newLine(); + os.flush(); + + socket.close(); + System.err.println("client socket closed"); + } +} + diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketClose.java b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketClose.java index 47a06093e3f..2ca82ef514e 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketClose.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketClose.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * 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,123 +37,79 @@ import javax.net.ssl.*; import java.io.*; import java.net.InetAddress; +import java.net.SocketException; -public class SSLSocketClose implements SSLContextTemplate { +public class SSLSocketClose extends SSLSocketTemplate { public static void main(String[] args) throws Exception { for (int i = 0; i<= 10; i++) { - System.err.println("==================================="); - System.err.println("loop " + i); - System.err.println("==================================="); - new SSLSocketClose().test(); + System.out.println("==================================="); + System.out.println("loop " + i); + System.out.println("==================================="); + new SSLSocketClose().run(); } } - private void test() throws Exception { - SSLServerSocket listenSocket = null; - SSLSocket serverSocket = null; - ClientSocket clientSocket = null; - try { - SSLServerSocketFactory serversocketfactory = - createServerSSLContext().getServerSocketFactory(); - listenSocket = - (SSLServerSocket)serversocketfactory.createServerSocket(0); - listenSocket.setNeedClientAuth(false); - listenSocket.setEnableSessionCreation(true); - listenSocket.setUseClientMode(false); - - - System.err.println("Starting client"); - clientSocket = new ClientSocket(listenSocket.getLocalPort()); - clientSocket.start(); - - System.err.println("Accepting client requests"); - serverSocket = (SSLSocket) listenSocket.accept(); - - System.err.println("Reading data from client"); - BufferedReader serverReader = new BufferedReader( - new InputStreamReader(serverSocket.getInputStream())); - String data = serverReader.readLine(); - System.err.println("Received data from client: " + data); - - System.err.println("Sending data to client ..."); - String serverData = "Hi, I am server"; - BufferedWriter os = new BufferedWriter( - new OutputStreamWriter(serverSocket.getOutputStream())); - os.write(serverData, 0, serverData.length()); - os.newLine(); - os.flush(); - - System.err.println("Reading more data from client"); - data = serverReader.readLine(); - System.err.println("Received data from client: " + data); - } finally { - if (listenSocket != null) { - listenSocket.close(); - } - - if (serverSocket != null) { - serverSocket.close(); - } - } - - if (clientSocket != null && clientSocket.clientException != null) { - throw clientSocket.clientException; - } + @Override + protected void configureServerSocket(SSLServerSocket socket) { + socket.setNeedClientAuth(false); + socket.setEnableSessionCreation(true); + socket.setUseClientMode(false); } - private class ClientSocket extends Thread{ - int serverPort = 0; - Exception clientException; + @Override + protected void runServerApplication(SSLSocket socket) throws Exception { + System.out.println("Reading data from client"); + BufferedReader serverReader = new BufferedReader( + new InputStreamReader(socket.getInputStream())); + String data = serverReader.readLine(); + System.out.println("Received data from client: " + data); + + System.out.println("Sending data to client ..."); + String serverData = "Hi, I am server"; + BufferedWriter os = new BufferedWriter( + new OutputStreamWriter(socket.getOutputStream())); + os.write(serverData, 0, serverData.length()); + os.newLine(); + os.flush(); + + System.out.println("Reading more data from client"); + data = serverReader.readLine(); + System.out.println("Received data from client: " + data); + } - public ClientSocket(int serverPort) { - this.serverPort = serverPort; + @Override + protected void configureClientSocket(SSLSocket socket) { + try { + socket.setSoLinger(true, 3); + } catch (SocketException e) { + throw new RuntimeException("Could not configure client socket", e); } + } - @Override - public void run() { - SSLSocket clientSocket = null; - String clientData = "Hi, I am client"; - try { - System.err.println( - "Connecting to server at port " + serverPort); - SSLSocketFactory sslSocketFactory = - createClientSSLContext().getSocketFactory(); - clientSocket = (SSLSocket)sslSocketFactory.createSocket( - InetAddress.getLocalHost(), serverPort); - clientSocket.setSoLinger(true, 3); - - System.err.println("Sending data to server ..."); - - BufferedWriter os = new BufferedWriter( - new OutputStreamWriter(clientSocket.getOutputStream())); - os.write(clientData, 0, clientData.length()); - os.newLine(); - os.flush(); - - System.err.println("Reading data from server"); - BufferedReader is = new BufferedReader( - new InputStreamReader(clientSocket.getInputStream())); - String data = is.readLine(); - System.err.println("Received Data from server: " + data); - - System.err.println("Sending more data to server ..."); - os.write(clientData, 0, clientData.length()); - os.newLine(); - os.flush(); - } catch (Exception e) { - clientException = e; - } finally { - if (clientSocket != null) { - try{ - clientSocket.close(); - System.err.println("client socket closed"); - } catch (IOException ioe) { - clientException = ioe; - } - } - } - } + @Override + protected void runClientApplication(SSLSocket socket) throws Exception { + String clientData = "Hi, I am client"; + System.out.println("Sending data to server ..."); + + BufferedWriter os = new BufferedWriter( + new OutputStreamWriter(socket.getOutputStream())); + os.write(clientData, 0, clientData.length()); + os.newLine(); + os.flush(); + + System.out.println("Reading data from server"); + BufferedReader is = new BufferedReader( + new InputStreamReader(socket.getInputStream())); + String data = is.readLine(); + System.out.println("Received Data from server: " + data); + + System.out.println("Sending more data to server ..."); + os.write(clientData, 0, clientData.length()); + os.newLine(); + os.flush(); + + socket.close(); } } diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/SocketExceptionForSocketIssues.java b/test/jdk/sun/security/ssl/SSLSocketImpl/SocketExceptionForSocketIssues.java index dcaf6dab977..8a406ee65bb 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/SocketExceptionForSocketIssues.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/SocketExceptionForSocketIssues.java @@ -37,126 +37,84 @@ import javax.net.ssl.*; import java.io.*; import java.net.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; -public class SocketExceptionForSocketIssues implements SSLContextTemplate { +public class SocketExceptionForSocketIssues extends SSLSocketTemplate { + + private final CountDownLatch waitForClient = new CountDownLatch(1); public static void main(String[] args) throws Exception { - System.err.println("==================================="); - new SocketExceptionForSocketIssues().test(); + System.out.println("==================================="); + new SocketExceptionForSocketIssues().run(); + } + + @Override + protected void configureServerSocket(SSLServerSocket socket) { + socket.setNeedClientAuth(false); + socket.setEnableSessionCreation(true); + socket.setUseClientMode(false); } - private void test() throws Exception { - SSLServerSocket listenSocket = null; - SSLSocket serverSocket = null; - ClientSocket clientSocket = null; + @Override + protected void runServerApplication(SSLSocket socket) throws Exception { try { - SSLServerSocketFactory serversocketfactory = - createServerSSLContext().getServerSocketFactory(); - listenSocket = - (SSLServerSocket)serversocketfactory.createServerSocket(0); - listenSocket.setNeedClientAuth(false); - listenSocket.setEnableSessionCreation(true); - listenSocket.setUseClientMode(false); - - System.err.println("Starting client"); - clientSocket = new ClientSocket(listenSocket.getLocalPort()); - clientSocket.start(); - - System.err.println("Accepting client requests"); - serverSocket = (SSLSocket)listenSocket.accept(); - - if (!clientSocket.isDone) { - System.err.println("Waiting 3 seconds for client "); - Thread.sleep(3000); + if (!waitForClient.await(5, TimeUnit.SECONDS)) { + throw new RuntimeException("Client didn't complete within 5 seconds."); } - System.err.println("Sending data to client ..."); + System.out.println("Sending data to client ..."); String serverData = "Hi, I am server"; BufferedWriter os = new BufferedWriter( - new OutputStreamWriter(serverSocket.getOutputStream())); + new OutputStreamWriter(socket.getOutputStream())); os.write(serverData, 0, serverData.length()); os.newLine(); os.flush(); - } catch (SSLProtocolException | SSLHandshakeException sslhe) { - throw sslhe; + throw new RuntimeException("The expected SocketException was not thrown."); } catch (SocketException se) { // the expected exception, ignore it - System.err.println("server exception: " + se); - } finally { - if (listenSocket != null) { - listenSocket.close(); - } - - if (serverSocket != null) { - serverSocket.close(); - } + System.out.println("Caught expected SocketException: " + se); } + } - if (clientSocket != null && clientSocket.clientException != null) { - throw clientSocket.clientException; + @Override + protected void configureClientSocket(SSLSocket socket) { + try { + socket.setSoLinger(true, 3); + socket.setSoTimeout(100); + } catch (SocketException exc) { + throw new RuntimeException("Could not configure client socket.", exc); } } + @Override + protected void runClientApplication(SSLSocket socket) throws Exception { + try { + String clientData = "Hi, I am client"; + BufferedWriter os = new BufferedWriter( + new OutputStreamWriter(socket.getOutputStream())); + os.write(clientData, 0, clientData.length()); + os.newLine(); + os.flush(); + + System.out.println("Reading data from server"); + BufferedReader is = new BufferedReader( + new InputStreamReader(socket.getInputStream())); + String data = is.readLine(); + System.out.println("Received Data from server: " + data); + throw new RuntimeException("The expected client exception was not thrown."); - private class ClientSocket extends Thread{ - boolean isDone = false; - int serverPort = 0; - Exception clientException; + } catch (SSLProtocolException | SSLHandshakeException sslhe) { + System.err.println("Client had unexpected SSL exception: " + sslhe); + throw sslhe; - public ClientSocket(int serverPort) { - this.serverPort = serverPort; - } + } catch (SSLException | SocketTimeoutException ssle) { + // the expected exception, ignore it + System.out.println("Caught expected client exception: " + ssle); - @Override - public void run() { - SSLSocket clientSocket = null; - String clientData = "Hi, I am client"; - try { - System.err.println( - "Connecting to server at port " + serverPort); - SSLSocketFactory sslSocketFactory = - createClientSSLContext().getSocketFactory(); - clientSocket = (SSLSocket)sslSocketFactory.createSocket( - InetAddress.getLocalHost(), serverPort); - clientSocket.setSoLinger(true, 3); - clientSocket.setSoTimeout(100); - - - System.err.println("Sending data to server ..."); - - BufferedWriter os = new BufferedWriter( - new OutputStreamWriter(clientSocket.getOutputStream())); - os.write(clientData, 0, clientData.length()); - os.newLine(); - os.flush(); - - System.err.println("Reading data from server"); - BufferedReader is = new BufferedReader( - new InputStreamReader(clientSocket.getInputStream())); - String data = is.readLine(); - System.err.println("Received Data from server: " + data); - } catch (SSLProtocolException | SSLHandshakeException sslhe) { - clientException = sslhe; - System.err.println("unexpected client exception: " + sslhe); - } catch (SSLException | SocketTimeoutException ssle) { - // the expected exception, ignore it - System.err.println("expected client exception: " + ssle); - } catch (Exception e) { - clientException = e; - System.err.println("unexpected client exception: " + e); - } finally { - if (clientSocket != null) { - try { - clientSocket.close(); - System.err.println("client socket closed"); - } catch (IOException ioe) { - clientException = ioe; - } - } - - isDone = true; - } + } finally { + waitForClient.countDown(); } } } diff --git a/test/jdk/sun/security/ssl/SignatureScheme/AbstractCheckSignatureSchemes.java b/test/jdk/sun/security/ssl/SignatureScheme/AbstractCheckSignatureSchemes.java new file mode 100644 index 00000000000..df70db86fec --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/AbstractCheckSignatureSchemes.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * 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.nio.ByteBuffer; +import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLException; + +/** + * This is not a test. Actual tests are implemented by concrete subclasses. + * The abstract class AbstractCheckSignatureSchemes provides a base framework + * for checking TLS signature schemes. + */ + +public abstract class AbstractCheckSignatureSchemes extends SSLEngineTemplate { + + // Helper map to correlate integral SignatureScheme identifiers to + // their IANA string name counterparts. + protected static final Map sigSchemeMap = Map.ofEntries( + new SimpleImmutableEntry(0x0401, "rsa_pkcs1_sha256"), + new SimpleImmutableEntry(0x0501, "rsa_pkcs1_sha384"), + new SimpleImmutableEntry(0x0601, "rsa_pkcs1_sha512"), + new SimpleImmutableEntry(0x0403, "ecdsa_secp256r1_sha256"), + new SimpleImmutableEntry(0x0503, "ecdsa_secp384r1_sha384"), + new SimpleImmutableEntry(0x0603, "ecdsa_secp521r1_sha512"), + new SimpleImmutableEntry(0x0804, "rsa_pss_rsae_sha256"), + new SimpleImmutableEntry(0x0805, "rsa_pss_rsae_sha384"), + new SimpleImmutableEntry(0x0806, "rsa_pss_rsae_sha512"), + new SimpleImmutableEntry(0x0807, "ed25519"), + new SimpleImmutableEntry(0x0808, "ed448"), + new SimpleImmutableEntry(0x0809, "rsa_pss_pss_sha256"), + new SimpleImmutableEntry(0x080a, "rsa_pss_pss_sha384"), + new SimpleImmutableEntry(0x080b, "rsa_pss_pss_sha512"), + new SimpleImmutableEntry(0x0101, "rsa_md5"), + new SimpleImmutableEntry(0x0201, "rsa_pkcs1_sha1"), + new SimpleImmutableEntry(0x0202, "dsa_sha1"), + new SimpleImmutableEntry(0x0203, "ecdsa_sha1"), + new SimpleImmutableEntry(0x0301, "rsa_sha224"), + new SimpleImmutableEntry(0x0302, "dsa_sha224"), + new SimpleImmutableEntry(0x0303, "ecdsa_sha224"), + new SimpleImmutableEntry(0x0402, "rsa_pkcs1_sha256")); + + // Other useful TLS definitions for these tests + protected static final int TLS_HS_CLI_HELLO = 1; + protected static final int TLS_HS_CERT_REQ = 13; + protected static final int SIG_ALGS_EXT = 13; + protected static final int SIG_ALGS_CERT_EXT = 50; + + protected AbstractCheckSignatureSchemes() throws Exception { + super(); + } + + // Returns the protocol for test to use. + abstract String getProtocol(); + + protected boolean isDtls() { + return getProtocol().startsWith("DTLS"); + } + + @Override + protected SSLEngine configureClientEngine(SSLEngine clientEngine) { + clientEngine.setUseClientMode(true); + clientEngine.setEnabledProtocols(new String[]{getProtocol()}); + return clientEngine; + } + + @Override + protected SSLEngine configureServerEngine(SSLEngine serverEngine) { + serverEngine.setUseClientMode(false); + serverEngine.setWantClientAuth(true); + serverEngine.setEnabledProtocols(new String[]{getProtocol()}); + return serverEngine; + } + + @Override + protected ContextParameters getServerContextParameters() { + return new ContextParameters(getProtocol(), "PKIX", "NewSunX509"); + } + + @Override + protected ContextParameters getClientContextParameters() { + return new ContextParameters(getProtocol(), "PKIX", "NewSunX509"); + } + + protected ByteBuffer extractHandshakeMsg(ByteBuffer tlsRecord, int hsMsgId) + throws SSLException { + return extractHandshakeMsg(tlsRecord, hsMsgId, isDtls()); + } + + /** + * Parses the ClientHello message and extracts from it a list of + * SignatureScheme values in string form. It is assumed that the provided + * ByteBuffer has its position set at the first byte of the ClientHello + * message body (AFTER the handshake header) and contains the entire + * hello message. Upon successful completion of this method the ByteBuffer + * will have its position reset to the initial offset in the buffer. + * If an exception is thrown the position at the time of the exception + * will be preserved. + * + * @param data The ByteBuffer containing the ClientHello bytes. + * @param extCode Code of the TLS extension from which to extract + * signature schemes. + * @return A List of the signature schemes in string form. + */ + protected List getSigSchemesCliHello( + ByteBuffer data, int extCode) { + Objects.requireNonNull(data); + data.mark(); + + // Skip over the protocol version and client random + data.position(data.position() + 34); + + // Jump past the session ID (if there is one) + int sessLen = Byte.toUnsignedInt(data.get()); + if (sessLen != 0) { + data.position(data.position() + sessLen); + } + + // Skip DTLS-specific opaque cookie if any + if (isDtls()) { + int cookieLen = Byte.toUnsignedInt(data.get()); + if (cookieLen != 0) { + data.position(data.position() + cookieLen); + } + } + + // Jump past the cipher suites + int csLen = Short.toUnsignedInt(data.getShort()); + if (csLen != 0) { + data.position(data.position() + csLen); + } + + // ...and the compression + int compLen = Byte.toUnsignedInt(data.get()); + if (compLen != 0) { + data.position(data.position() + compLen); + } + + // Now for the fun part. Go through the extensions and look + // for the two status request exts. + List extSigAlgs = getSigSchemesFromExt(data, extCode); + + // We should be at the end of the ClientHello + data.reset(); + return extSigAlgs; + } + + /** + * Parses the CertificateRequest message and extracts from it a list of + * SignatureScheme values in string form. It is assumed that the provided + * ByteBuffer has its position set at the first byte of the + * CertificateRequest message body (AFTER the handshake header) and + * contains the entire CR message. Upon successful completion of this + * method the ByteBuffer will have its position reset to the initial + * offset in the buffer. + * If an exception is thrown the position at the time of the exception + * will be preserved. + * + * @param data The ByteBuffer containing the CertificateRequest bytes + * + * @return A List of the signature schemes in string form. If no + * signature_algorithms extension is present in the CertificateRequest + * then an empty list will be returned. + */ + protected List getSigSchemesCertReq(ByteBuffer data) { + Objects.requireNonNull(data); + data.mark(); + + // Jump past the certificate types + int certTypeLen = Byte.toUnsignedInt(data.get()); + if (certTypeLen != 0) { + data.position(data.position() + certTypeLen); + } + + // Collect the SignatureAndHashAlgorithms + List extSigAlgs = new ArrayList(); + int sigSchemeLen = Short.toUnsignedInt(data.getShort()); + for (int ssOff = 0; ssOff < sigSchemeLen; ssOff += 2) { + String schemeName = sigSchemeMap.get( + Short.toUnsignedInt(data.getShort())); + if (schemeName != null) { + extSigAlgs.add(schemeName); + } + } + + data.reset(); + return extSigAlgs; + } + + /** + * Gets signatures schemes from the given TLS extension. + * The buffer should be positioned at the start of the extension. + */ + protected List getSigSchemesFromExt( + ByteBuffer data, int extCode) { + + List extSigAlgs = new ArrayList<>(); + data.getShort(); // read length + + while (data.hasRemaining()) { + int extType = Short.toUnsignedInt(data.getShort()); + int extLen = Short.toUnsignedInt(data.getShort()); + if (extType == extCode) { + // Start processing signature algorithms + int sigSchemeLen = Short.toUnsignedInt(data.getShort()); + for (int ssOff = 0; ssOff < sigSchemeLen; ssOff += 2) { + String schemeName = sigSchemeMap.get( + Short.toUnsignedInt(data.getShort())); + if (schemeName != null) { + extSigAlgs.add(schemeName); + } + } + } else { + // Not the extension we're looking for. Skip past the + // extension data + data.position(data.position() + extLen); + } + } + + return extSigAlgs; + } +} diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureDTLS12.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureDTLS12.java new file mode 100644 index 00000000000..6c597cd2576 --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureDTLS12.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8340321 + * @summary Disable SHA-1 in TLS/DTLS 1.2 signatures. + * This test only covers DTLS 1.2. + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm DisableSHA1inHandshakeSignatureDTLS12 + */ + +public class DisableSHA1inHandshakeSignatureDTLS12 extends + DisableSHA1inHandshakeSignatureTLS12 { + + protected DisableSHA1inHandshakeSignatureDTLS12() throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + new DisableSHA1inHandshakeSignatureDTLS12().run(); + } + + @Override + protected String getProtocol() { + return "DTLSv1.2"; + } + + // No CertificateRequest in DTLS server flight. + @Override + protected void checkCertificateRequest() { + } +} diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureTLS12.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureTLS12.java new file mode 100644 index 00000000000..0389740b7fe --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureTLS12.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8340321 + * @summary Disable SHA-1 in TLS/DTLS 1.2 signatures. + * This test only covers TLS 1.2. + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm DisableSHA1inHandshakeSignatureTLS12 + */ + +import static jdk.test.lib.Asserts.assertFalse; +import static jdk.test.lib.Asserts.assertTrue; + +import java.util.List; + +public class DisableSHA1inHandshakeSignatureTLS12 extends + AbstractCheckSignatureSchemes { + + protected DisableSHA1inHandshakeSignatureTLS12() throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + new DisableSHA1inHandshakeSignatureTLS12().run(); + } + + @Override + protected String getProtocol() { + return "TLSv1.2"; + } + + // Run things in TLS handshake order. + protected void run() throws Exception { + + // Produce client_hello + clientEngine.wrap(clientOut, cTOs); + cTOs.flip(); + + checkClientHello(); + + // Consume client_hello. + serverEngine.unwrap(cTOs, serverIn); + runDelegatedTasks(serverEngine); + + // Produce server_hello. + serverEngine.wrap(serverOut, sTOc); + sTOc.flip(); + + checkCertificateRequest(); + } + + // Returns SHA-1 signature schemes supported for TLSv1.2 handshake + protected List getDisabledSignatureSchemes() { + return List.of( + "ecdsa_sha1", + "rsa_pkcs1_sha1", + "dsa_sha1" + ); + } + + protected void checkClientHello() throws Exception { + // Get signature_algorithms extension signature schemes. + List sigAlgsSS = getSigSchemesCliHello( + extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), + SIG_ALGS_EXT); + + // Should not be present in signature_algorithms extension. + getDisabledSignatureSchemes().forEach(ss -> + assertFalse(sigAlgsSS.contains(ss), + "Signature Scheme " + ss + + " present in ClientHello's signature_algorithms extension")); + + // Get signature_algorithms_cert extension signature schemes. + List sigAlgsCertSS = getSigSchemesCliHello( + extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), + SIG_ALGS_CERT_EXT); + + // Should be present in signature_algorithms_cert extension. + getDisabledSignatureSchemes().forEach(ss -> + assertTrue(sigAlgsCertSS.contains(ss), + "Signature Scheme " + ss + + " isn't present in ClientHello's" + + " signature_algorithms extension")); + } + + protected void checkCertificateRequest() throws Exception { + // Get CertificateRequest message signature schemes. + List sigAlgsCertSS = getSigSchemesCertReq( + extractHandshakeMsg(sTOc, TLS_HS_CERT_REQ)); + + // Should not be present in CertificateRequest message. + getDisabledSignatureSchemes().forEach(ss -> + assertFalse(sigAlgsCertSS.contains(ss), + "Signature Scheme " + ss + + " present in CertificateRequest")); + } +} diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureTLS13.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureTLS13.java new file mode 100644 index 00000000000..55f619460d4 --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureTLS13.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8340321 + * @summary Disable SHA-1 in TLS/DTLS 1.2 signatures. + * This test only covers TLS 1.3. + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm DisableSHA1inHandshakeSignatureTLS13 + */ + +import java.security.Security; +import java.util.List; + +public class DisableSHA1inHandshakeSignatureTLS13 extends + DisableSHA1inHandshakeSignatureTLS12 { + + protected DisableSHA1inHandshakeSignatureTLS13() throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + // SHA-1 algorithm MUST NOT be used in any TLSv1.3 handshake signatures. + // This is regardless of jdk.tls.disabledAlgorithms configuration. + Security.setProperty("jdk.tls.disabledAlgorithms", ""); + new DisableSHA1inHandshakeSignatureTLS13().run(); + } + + @Override + protected String getProtocol() { + return "TLSv1.3"; + } + + // Returns SHA-1 signature schemes NOT supported for TLSv1.3 handshake + // signatures, but supported for TLSv1.3 certificate signatures. + @Override + protected List getDisabledSignatureSchemes() { + return List.of("ecdsa_sha1", "rsa_pkcs1_sha1"); + } + + // TLSv1.3 sends CertificateRequest signature schemes in + // signature_algorithms and signature_algorithms_cert extensions. Same as + // ClientHello, but they are encrypted. So we skip CertificateRequest + // signature schemes verification for TLSv1.3. + @Override + protected void checkCertificateRequest() { + } +} diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeDTLS12.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeDTLS12.java new file mode 100644 index 00000000000..55f1002e894 --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeDTLS12.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8349583 + * @summary Add mechanism to disable signature schemes based on their TLS scope. + * This test only covers DTLS 1.2. + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm DisableSignatureSchemePerScopeDTLS12 + */ + +import java.security.Security; + +public class DisableSignatureSchemePerScopeDTLS12 + extends DisableSignatureSchemePerScopeTLS12 { + + protected DisableSignatureSchemePerScopeDTLS12() throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + Security.setProperty( + "jdk.tls.disabledAlgorithms", DISABLED_CONSTRAINTS); + new DisableSignatureSchemePerScopeDTLS12().run(); + } + + @Override + protected String getProtocol() { + return "DTLSv1.2"; + } + + // No CertificateRequest in DTLS server flight. + @Override + protected void checkCertificateRequest() { + } +} diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS12.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS12.java new file mode 100644 index 00000000000..e2ee9f0889a --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS12.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8349583 + * @summary Add mechanism to disable signature schemes based on their TLS scope. + * This test only covers TLS 1.2. + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm DisableSignatureSchemePerScopeTLS12 + */ + +import static jdk.test.lib.Asserts.assertFalse; +import static jdk.test.lib.Asserts.assertTrue; + +import java.security.Security; +import java.util.List; + +public class DisableSignatureSchemePerScopeTLS12 extends + AbstractCheckSignatureSchemes { + + // Disabled for Handshake scope. + protected static final String HANDSHAKE_DISABLED_SIG = "rsa_pss_rsae_sha384"; + + // Disabled for Certificate scope. + protected static final String CERTIFICATE_DISABLED_SIG = "ecdsa_secp384r1_sha384"; + + // jdk.tls.disabledAlgorithms value + // We differ from "HandshakeSignature" and "CertificateSignature" specified + // in java.security to check case-insensitive matching. + protected static final String DISABLED_CONSTRAINTS = + HANDSHAKE_DISABLED_SIG + " usage HandShakesignature, " + + CERTIFICATE_DISABLED_SIG + " usage certificateSignature"; + + protected DisableSignatureSchemePerScopeTLS12() throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + Security.setProperty( + "jdk.tls.disabledAlgorithms", DISABLED_CONSTRAINTS); + new DisableSignatureSchemePerScopeTLS12().run(); + } + + protected String getProtocol() { + return "TLSv1.2"; + } + + // Run things in TLS handshake order. + protected void run() throws Exception { + + // Produce client_hello + clientEngine.wrap(clientOut, cTOs); + cTOs.flip(); + + checkClientHello(); + + // Consume client_hello. + serverEngine.unwrap(cTOs, serverIn); + runDelegatedTasks(serverEngine); + + // Produce server_hello. + serverEngine.wrap(serverOut, sTOc); + sTOc.flip(); + + checkCertificateRequest(); + } + + protected void checkClientHello() throws Exception { + // --- Check signature_algorithms extension --- + + // Get signature_algorithms extension signature schemes. + List sigAlgsSS = getSigSchemesCliHello( + extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), + SIG_ALGS_EXT); + + // signature_algorithms extension MUST NOT contain disabled + // handshake signature scheme. + assertFalse(sigAlgsSS.contains(HANDSHAKE_DISABLED_SIG), + "Signature Scheme " + HANDSHAKE_DISABLED_SIG + + " present in ClientHello's signature_algorithms extension"); + + // signature_algorithms extension MUST contain disabled + // certificate signature scheme. + assertTrue(sigAlgsSS.contains(CERTIFICATE_DISABLED_SIG), + "Signature Scheme " + CERTIFICATE_DISABLED_SIG + + " isn't present in ClientHello's" + + " signature_algorithms extension"); + + // --- Check signature_algorithms_cert extension --- + + // Get signature_algorithms_cert extension signature schemes. + List sigAlgsCertSS = getSigSchemesCliHello( + extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), + SIG_ALGS_CERT_EXT); + + // signature_algorithms_cert extension MUST contain disabled + // handshake signature scheme. + assertTrue(sigAlgsCertSS.contains(HANDSHAKE_DISABLED_SIG), + "Signature Scheme " + HANDSHAKE_DISABLED_SIG + + " isn't present in ClientHello's" + + " signature_algorithms extension"); + + // signature_algorithms_cert extension MUST NOT contain disabled + // certificate signature scheme. + assertFalse(sigAlgsCertSS.contains(CERTIFICATE_DISABLED_SIG), + "Signature Scheme " + CERTIFICATE_DISABLED_SIG + + " present in ClientHello's signature_algorithms extension"); + } + + protected void checkCertificateRequest() throws Exception { + // Get CertificateRequest message signature schemes. + List sigAlgsCertSS = getSigSchemesCertReq( + extractHandshakeMsg(sTOc, TLS_HS_CERT_REQ)); + + // TLSv1.2 CertificateRequest message MUST NOT contain both: + // disabled handshake signature scheme and disabled + // certificate signature scheme + + assertFalse(sigAlgsCertSS.contains(HANDSHAKE_DISABLED_SIG), + "Signature Scheme " + HANDSHAKE_DISABLED_SIG + + " present in CertificateRequest"); + + assertFalse(sigAlgsCertSS.contains(CERTIFICATE_DISABLED_SIG), + "Signature Scheme " + CERTIFICATE_DISABLED_SIG + + " present in CertificateRequest"); + } +} diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java new file mode 100644 index 00000000000..5d5d445cb45 --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8349583 + * @summary Add mechanism to disable signature schemes based on their TLS scope. + * This test only covers TLS 1.3. + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm DisableSignatureSchemePerScopeTLS13 + */ + + +import static jdk.test.lib.Asserts.assertFalse; +import static jdk.test.lib.Asserts.assertTrue; + +import java.security.Security; +import java.util.List; + +public class DisableSignatureSchemePerScopeTLS13 + extends DisableSignatureSchemePerScopeTLS12 { + + // Signature schemes not supported in TLSv1.3 only for the handshake. + // This is regardless of jdk.tls.disabledAlgorithms configuration. + List NOT_SUPPORTED_FOR_HANDSHAKE = List.of( + "rsa_pkcs1_sha1", + "rsa_pkcs1_sha256", + "rsa_pkcs1_sha384", + "rsa_pkcs1_sha512" + ); + + protected DisableSignatureSchemePerScopeTLS13() throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + Security.setProperty( + "jdk.tls.disabledAlgorithms", DISABLED_CONSTRAINTS); + new DisableSignatureSchemePerScopeTLS13().run(); + } + + @Override + protected String getProtocol() { + return "TLSv1.3"; + } + + @Override + protected void checkClientHello() throws Exception { + super.checkClientHello(); + + // Get signature_algorithms extension signature schemes. + List sigAlgsSS = getSigSchemesCliHello( + extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), + SIG_ALGS_EXT); + + // Should not be present in signature_algorithms extension. + NOT_SUPPORTED_FOR_HANDSHAKE.forEach(ss -> + assertFalse(sigAlgsSS.contains(ss), + "Signature Scheme " + ss + + " present in ClientHello's signature_algorithms extension")); + + // Get signature_algorithms_cert extension signature schemes. + List sigAlgsCertSS = getSigSchemesCliHello( + extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), + SIG_ALGS_CERT_EXT); + + // Should be present in signature_algorithms_cert extension. + NOT_SUPPORTED_FOR_HANDSHAKE.forEach(ss -> + assertTrue(sigAlgsCertSS.contains(ss), + "Signature Scheme " + ss + + " isn't present in ClientHello's" + + " signature_algorithms extension")); + } + + // TLSv1.3 sends CertificateRequest signature schemes in + // signature_algorithms and signature_algorithms_cert extensions. Same as + // ClientHello, but they are encrypted. So we skip CertificateRequest + // signature schemes verification for TLSv1.3. + @Override + protected void checkCertificateRequest() { + } +} diff --git a/test/jdk/sun/security/ssl/SignatureScheme/MixingTLSUsageConstraintsWithNonTLS.java b/test/jdk/sun/security/ssl/SignatureScheme/MixingTLSUsageConstraintsWithNonTLS.java new file mode 100644 index 00000000000..3dc811ca66c --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/MixingTLSUsageConstraintsWithNonTLS.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8349583 + * @summary Add mechanism to disable signature schemes based on their TLS scope + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm MixingTLSUsageConstraintsWithNonTLS + */ + +import static jdk.test.lib.Asserts.assertEquals; +import static jdk.test.lib.Asserts.assertTrue; +import static jdk.test.lib.Utils.runAndCheckException; + +import java.security.Security; + +public class MixingTLSUsageConstraintsWithNonTLS extends SSLSocketTemplate { + + public static void main(String[] args) throws Exception { + Security.setProperty("jdk.tls.disabledAlgorithms", + "rsa_pkcs1_sha1 usage handshakeSignature certificateSignature TLSServer"); + + runAndCheckException( + () -> new MixingTLSUsageConstraintsWithNonTLS().run(), + e -> { + assertTrue(e instanceof ExceptionInInitializerError); + assertTrue( + e.getCause() instanceof IllegalArgumentException); + assertEquals(e.getCause().getMessage(), + "Can't mix TLS protocol specific constraints" + + " with other usage constraints"); + }); + } +} diff --git a/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java b/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java index f7eb7cf3e91..cfd550ad200 100644 --- a/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java +++ b/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java @@ -30,6 +30,8 @@ * @library /test/lib * /javax/net/ssl/templates * + * @build jdk.test.lib.Utils + * * @run main/othervm * -Djdk.tls.server.SignatureSchemes=ecdsa_secp384r1_sha384 * -Djdk.tls.client.SignatureSchemes=ecdsa_secp256r1_sha256,ecdsa_secp384r1_sha384 @@ -53,6 +55,7 @@ import javax.net.ssl.*; import java.nio.ByteBuffer; import java.util.*; +import jdk.test.lib.Utils; public class SigAlgosExtTestWithTLS12 extends SSLEngineTemplate { @@ -61,115 +64,7 @@ public class SigAlgosExtTestWithTLS12 extends SSLEngineTemplate { private static final boolean EXPECT_FAIL = Boolean.getBoolean("test.expectFail"); - private static final String[] CA_CERTS = new String[] { - // SHA256withECDSA, curve secp256r1 - // Validity - // Not Before: May 22 07:18:16 2018 GMT - // Not After : May 17 07:18:16 2038 GMT - // Subject Key Identifier: - // 60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86 - "-----BEGIN CERTIFICATE-----\n" + - "MIIBvjCCAWOgAwIBAgIJAIvFG6GbTroCMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" + - "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + - "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYTAlVT\n" + - "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTBZ\n" + - "MBMGByqGSM49AgEGCCqGSM49AwEHA0IABBz1WeVb6gM2mh85z3QlvaB/l11b5h0v\n" + - "LIzmkC3DKlVukZT+ltH2Eq1oEkpXuf7QmbM0ibrUgtjsWH3mULfmcWmjUDBOMB0G\n" + - "A1UdDgQWBBRgz71z//oaMNKk7NNJcUbvGjWghjAfBgNVHSMEGDAWgBRgz71z//oa\n" + - "MNKk7NNJcUbvGjWghjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQCG\n" + - "6wluh1r2/T6L31mZXRKf9JxeSf9pIzoLj+8xQeUChQIhAJ09wAi1kV8yePLh2FD9\n" + - "2YEHlSQUAbwwqCDEVB5KxaqP\n" + - "-----END CERTIFICATE-----", - - // SHA384withECDSA, curve secp384r1 - // Validity - // Not Before: Jun 24 08:15:06 2019 GMT - // Not After : Jun 19 08:15:06 2039 GMT - // Subject Key Identifier: - // 0a:93:a9:a0:bf:e7:d5:48:9d:4f:89:15:c6:51:98:80:05:51:4e:4e - "-----BEGIN CERTIFICATE-----\n" + - "MIICCDCCAY6gAwIBAgIUCpOpoL/n1UidT4kVxlGYgAVRTk4wCgYIKoZIzj0EAwMw\n" + - "OzELMAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0Ug\n" + - "VGVzdCBTZXJpdmNlMB4XDTE5MDYyNDA4MTUwNloXDTM5MDYxOTA4MTUwNlowOzEL\n" + - "MAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVz\n" + - "dCBTZXJpdmNlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAENVQN1wXWFdgC6u/dDdiC\n" + - "y+WtMTF66oL/0BSm+1ZqsogamzCryawOcHgiuXgWzx5CQ3LuOC+tDFyXpGfHuCvb\n" + - "dkzxPrP5n9NrR8/uRPe5l1KOUbchviU8z9cTP+LZxnZDo1MwUTAdBgNVHQ4EFgQU\n" + - "SktSFArR1p/5mXV0kyo0RxIVa/UwHwYDVR0jBBgwFoAUSktSFArR1p/5mXV0kyo0\n" + - "RxIVa/UwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjBZvoNmq3/v\n" + - "RD2gBTyvxjS9h0rsMRLHDnvul/KWngytwGPTOBo0Y8ixQXSjdKoc3rkCMQDkiNgx\n" + - "IDxuHedmrLQKIPnVcthTmwv7//jHiqGoKofwChMo2a1P+DQdhszmeHD/ARQ=\n" + - "-----END CERTIFICATE-----" - }; - - private static final String[] EE_CERTS = new String[] { - // SHA256withECDSA, curve secp256r1 - // Validity - // Not Before: May 22 07:18:16 2018 GMT - // Not After : May 17 07:18:16 2038 GMT - // Authority Key Identifier: - // 60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86 - "-----BEGIN CERTIFICATE-----\n" + - "MIIBqjCCAVCgAwIBAgIJAPLY8qZjgNRAMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" + - "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + - "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYTAlVT\n" + - "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTEY\n" + - "MBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\n" + - "QgAEb+9n05qfXnfHUb0xtQJNS4JeSi6IjOfW5NqchvKnfJey9VkJzR7QHLuOESdf\n" + - "xlR7q8YIWgih3iWLGfB+wxHiOqMjMCEwHwYDVR0jBBgwFoAUYM+9c//6GjDSpOzT\n" + - "SXFG7xo1oIYwCgYIKoZIzj0EAwIDSAAwRQIgWpRegWXMheiD3qFdd8kMdrkLxRbq\n" + - "1zj8nQMEwFTUjjQCIQDRIrAjZX+YXHN9b0SoWWLPUq0HmiFIi8RwMnO//wJIGQ==\n" + - "-----END CERTIFICATE-----", - - // SHA384withECDSA, curve secp384r1 - // Validity - // Not Before: Jun 24 08:15:06 2019 GMT - // Not After : Jun 19 08:15:06 2039 GMT - // Authority Key Identifier: - // 40:2D:AA:EE:66:AA:33:27:AD:9B:5D:52:9B:60:67:6A:2B:AD:52:D2 - "-----BEGIN CERTIFICATE-----\n" + - "MIICEjCCAZegAwIBAgIUS3F0AqAXWRg07CnbknJzxofyBQMwCgYIKoZIzj0EAwMw\n" + - "OzELMAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0Ug\n" + - "VGVzdCBTZXJpdmNlMB4XDTE5MDYyNDA4MTUwNloXDTM5MDYxOTA4MTUwNlowVTEL\n" + - "MAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVz\n" + - "dCBTZXJpdmNlMRgwFgYDVQQDDA9SZWdyZXNzaW9uIFRlc3QwdjAQBgcqhkjOPQIB\n" + - "BgUrgQQAIgNiAARqElz8b6T07eyKomIinhztV3/3XBk9bKGtJ0W+JOltjuhMmP/w\n" + - "G8ASSevpgqgpi6EzpBZaaJxE3zNfkNnxXOZmQi2Ypd1uK0zRdbEOKg0XOcTTZwEj\n" + - "iLjYmt3O0pwpklijQjBAMB0GA1UdDgQWBBRALaruZqozJ62bXVKbYGdqK61S0jAf\n" + - "BgNVHSMEGDAWgBRKS1IUCtHWn/mZdXSTKjRHEhVr9TAKBggqhkjOPQQDAwNpADBm\n" + - "AjEArVDFKf48xijN6huVUJzKCOP0zlWB5Js+DItIkZmLQuhciPLhLIB/rChf3Y4C\n" + - "xuP4AjEAmfLhQRI0O3pifpYzYSVh2G7/jHNG4eO+2dvgAcU+Lh2IIj/cpLaPFSvL\n" + - "J8FXY9Nj\n" + - "-----END CERTIFICATE-----" - }; - - private static final String[] EE_KEYS = new String[] { - "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgn5K03bpTLjEtFQRa\n" + - "JUtx22gtmGEvvSUSQdimhGthdtihRANCAARv72fTmp9ed8dRvTG1Ak1Lgl5KLoiM\n" + - "59bk2pyG8qd8l7L1WQnNHtAcu44RJ1/GVHurxghaCKHeJYsZ8H7DEeI6", - "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDASuI9EtK29APXPipkc\n" + - "qDA+qwlewMjv/OcjUJ77kP1Vz62oVF9iY9SRIyFIUju8wt+hZANiAARqElz8b6T0\n" + - "7eyKomIinhztV3/3XBk9bKGtJ0W+JOltjuhMmP/wG8ASSevpgqgpi6EzpBZaaJxE\n" + - "3zNfkNnxXOZmQi2Ypd1uK0zRdbEOKg0XOcTTZwEjiLjYmt3O0pwpklg=" - }; - - private static final String[] EE_ALGS = new String[] { - "EC", - "EC" - }; - - private static final String[] EE_ALIASES = new String[] { - "EC-SHA256", - "EC-SHA384" - }; - - private static final Map SIG_SCHEMES_MAP = Map.of( - 0x0403, "ecdsa_secp256r1_sha256", - 0x0503, "ecdsa_secp384r1_sha384"); - - private static final int TLS_HS_CLI_HELLO = 1; private static final int TLS_HS_CERT_REQ = 13; - private static final int HELLO_EXT_SIG_ALGS = 13; public SigAlgosExtTestWithTLS12() throws Exception { super(); @@ -178,36 +73,31 @@ public SigAlgosExtTestWithTLS12() throws Exception { /* * Create an instance of KeyManager for client use. */ - public KeyManager createClientKeyManager() throws Exception { - return SSLContextTemplate.createKeyManager( - EE_CERTS, - EE_KEYS, - EE_ALGS, - EE_ALIASES, - getServerContextParameters()); + @Override + protected KeyManager createClientKeyManager() throws Exception { + return createKeyManager( + new Cert[]{Cert.EE_ECDSA_SECP256R1, Cert.EE_ECDSA_SECP384R1}, + getClientContextParameters()); } @Override public TrustManager createClientTrustManager() throws Exception { - return SSLContextTemplate.createTrustManager( - CA_CERTS, + return createTrustManager( + new Cert[]{Cert.CA_ECDSA_SECP256R1, Cert.CA_ECDSA_SECP384R1}, getServerContextParameters()); } @Override public KeyManager createServerKeyManager() throws Exception { - return SSLContextTemplate.createKeyManager( - EE_CERTS, - EE_KEYS, - EE_ALGS, - EE_ALIASES, + return createKeyManager( + new Cert[]{Cert.EE_ECDSA_SECP256R1, Cert.EE_ECDSA_SECP384R1}, getServerContextParameters()); } @Override public TrustManager createServerTrustManager() throws Exception { - return SSLContextTemplate.createTrustManager( - CA_CERTS, + return createTrustManager( + new Cert[]{Cert.CA_ECDSA_SECP256R1, Cert.CA_ECDSA_SECP384R1}, getServerContextParameters()); } @@ -327,7 +217,7 @@ private static void twistCertReqMsg( // Slice the buffer such that it contains the entire // handshake message (less the handshake header). int bufPos = tlsRecord.position(); - ByteBuffer buf = slice(tlsRecord, bufPos, msgLen); + ByteBuffer buf = Utils.slice(tlsRecord, bufPos, msgLen); // Replace the signature scheme with an unknown value twistSigSchemesCertReq(buf, (short) 0x0000); @@ -345,18 +235,6 @@ private static void twistCertReqMsg( tlsRecord.reset(); } - /* Implementation of ByteBuffer.slice(int, int) for JDK11 */ - private static final ByteBuffer slice(ByteBuffer buffer, int index, int length) { - final int limit = buffer.limit(); - final int position = buffer.position(); - buffer.position(index); - buffer.limit(index + length); - ByteBuffer slice = buffer.slice(); - buffer.limit(limit); - buffer.position(position); - return slice; - } - /** * Replace the signature schemes in CertificateRequest message with an * alternative value. It is assumed that the provided ByteBuffer has its diff --git a/test/jdk/sun/security/ssl/SignatureScheme/Tls13NamedGroups.java b/test/jdk/sun/security/ssl/SignatureScheme/Tls13NamedGroups.java index fa876db5b3c..ed428df60bc 100644 --- a/test/jdk/sun/security/ssl/SignatureScheme/Tls13NamedGroups.java +++ b/test/jdk/sun/security/ssl/SignatureScheme/Tls13NamedGroups.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * 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,14 +37,7 @@ * @run main/othervm Tls13NamedGroups */ -import java.net.*; -import java.io.*; import javax.net.ssl.*; -import java.security.*; -import java.security.cert.*; -import java.security.spec.*; -import java.security.interfaces.*; -import java.util.Base64; public class Tls13NamedGroups extends SSLSocketTemplate { @@ -56,8 +49,10 @@ public static void main(String[] args) throws Exception { } @Override - protected SSLContext createServerSSLContext() throws Exception { - return generateSSLContext(); + public SSLContext createServerSSLContext() throws Exception { + return createSSLContext(new Cert[]{Cert.CA_ECDSA_SECP256R1}, + new Cert[]{Cert.EE_ECDSA_SECP256R1}, + new ContextParameters("TLSv1.3", "PKIX", "NewSunX509")); } @Override @@ -66,123 +61,9 @@ protected void configureServerSocket(SSLServerSocket socket) { } @Override - protected SSLContext createClientSSLContext() throws Exception { - return generateSSLContext(); - } - - /* - * ============================================================= - * The remainder is just support stuff - */ - - // Certificates and key used in the test. - // - // Trusted Certificate. - static String trustedCertStr = - // SHA256withECDSA, curve prime256v1 - // Validity - // Not Before: May 22 07:18:16 2018 GMT - // Not After : May 17 07:18:16 2038 GMT - // Subject Key Identifier: - // 60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86 - "-----BEGIN CERTIFICATE-----\n" + - "MIIBvjCCAWOgAwIBAgIJAIvFG6GbTroCMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" + - "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + - "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYTAlVT\n" + - "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTBZ\n" + - "MBMGByqGSM49AgEGCCqGSM49AwEHA0IABBz1WeVb6gM2mh85z3QlvaB/l11b5h0v\n" + - "LIzmkC3DKlVukZT+ltH2Eq1oEkpXuf7QmbM0ibrUgtjsWH3mULfmcWmjUDBOMB0G\n" + - "A1UdDgQWBBRgz71z//oaMNKk7NNJcUbvGjWghjAfBgNVHSMEGDAWgBRgz71z//oa\n" + - "MNKk7NNJcUbvGjWghjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQCG\n" + - "6wluh1r2/T6L31mZXRKf9JxeSf9pIzoLj+8xQeUChQIhAJ09wAi1kV8yePLh2FD9\n" + - "2YEHlSQUAbwwqCDEVB5KxaqP\n" + - "-----END CERTIFICATE-----"; - // -----BEGIN PRIVATE KEY----- - // MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/HcHdoLJCdq3haVd - // XZTSKP00YzM3xX97l98vGL/RI1KhRANCAAQc9VnlW+oDNpofOc90Jb2gf5ddW+Yd - // LyyM5pAtwypVbpGU/pbR9hKtaBJKV7n+0JmzNIm61ILY7Fh95lC35nFp - // -----END PRIVATE KEY----- - - // End entity certificate. - static String targetCertStr = - // SHA256withECDSA, curve prime256v1 - // Validity - // Not Before: May 22 07:18:16 2018 GMT - // Not After : May 17 07:18:16 2038 GMT - // Authority Key Identifier: - // 60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86 - "-----BEGIN CERTIFICATE-----\n" + - "MIIBqjCCAVCgAwIBAgIJAPLY8qZjgNRAMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" + - "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" + - "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYTAlVT\n" + - "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTEY\n" + - "MBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\n" + - "QgAEb+9n05qfXnfHUb0xtQJNS4JeSi6IjOfW5NqchvKnfJey9VkJzR7QHLuOESdf\n" + - "xlR7q8YIWgih3iWLGfB+wxHiOqMjMCEwHwYDVR0jBBgwFoAUYM+9c//6GjDSpOzT\n" + - "SXFG7xo1oIYwCgYIKoZIzj0EAwIDSAAwRQIgWpRegWXMheiD3qFdd8kMdrkLxRbq\n" + - "1zj8nQMEwFTUjjQCIQDRIrAjZX+YXHN9b0SoWWLPUq0HmiFIi8RwMnO//wJIGQ==\n" + - "-----END CERTIFICATE-----"; - - // Private key in the format of PKCS#8. - static String targetPrivateKey = - // - // EC private key related to cert endEntityCertStrs[0]. - // - "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgn5K03bpTLjEtFQRa\n" + - "JUtx22gtmGEvvSUSQdimhGthdtihRANCAARv72fTmp9ed8dRvTG1Ak1Lgl5KLoiM\n" + - "59bk2pyG8qd8l7L1WQnNHtAcu44RJ1/GVHurxghaCKHeJYsZ8H7DEeI6"; - - static char passphrase[] = "passphrase".toCharArray(); - - // Create the SSLContext instance. - private static SSLContext generateSSLContext() throws Exception { - - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - // create a key store - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(null, null); - - // import the trused cert - X509Certificate trusedCert = null; - ByteArrayInputStream is = - new ByteArrayInputStream(trustedCertStr.getBytes()); - trusedCert = (X509Certificate)cf.generateCertificate(is); - is.close(); - - ks.setCertificateEntry("Trusted EC Signer", trusedCert); - - // generate the private key. - PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - Base64.getMimeDecoder().decode(targetPrivateKey)); - KeyFactory kf = KeyFactory.getInstance("EC"); - ECPrivateKey priKey = - (ECPrivateKey)kf.generatePrivate(priKeySpec); - - // generate certificate chain - is = new ByteArrayInputStream(targetCertStr.getBytes()); - X509Certificate keyCert = (X509Certificate)cf.generateCertificate(is); - is.close(); - - X509Certificate[] chain = new X509Certificate[2]; - chain[0] = keyCert; - chain[1] = trusedCert; - - // import the key entry and the chain - ks.setKeyEntry("TheKey", priKey, passphrase, chain); - - // create SSL context - TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); - tmf.init(ks); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); - kmf.init(ks, passphrase); - - SSLContext ctx = SSLContext.getInstance("TLSv1.3"); - ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - ks = null; - - return ctx; + public SSLContext createClientSSLContext() throws Exception { + return createSSLContext(new Cert[]{Cert.CA_ECDSA_SECP256R1}, + new Cert[]{Cert.EE_ECDSA_SECP256R1}, + new ContextParameters("TLSv1.3", "PKIX", "NewSunX509")); } } diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/TooManyCAs.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/TooManyCAs.java index 9e44b1cdc94..41b7055e5fb 100644 --- a/test/jdk/sun/security/ssl/X509TrustManagerImpl/TooManyCAs.java +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/TooManyCAs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. * 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,18 +32,17 @@ import javax.net.ssl.*; import javax.security.auth.x500.X500Principal; import java.io.*; -import java.net.InetAddress; import java.net.Socket; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import java.util.Arrays; +import java.util.concurrent.CyclicBarrier; /** * Check if the connection can be established if the client or server trusts * more CAs such that it exceeds the size limit of the certificate_authorities * extension (2^16). */ -public class TooManyCAs implements SSLContextTemplate { +public class TooManyCAs extends SSLSocketTemplate { private static final String[][][] protocols = { {{"TLSv1.3"}, {"TLSv1.3"}}, @@ -55,44 +54,54 @@ public class TooManyCAs implements SSLContextTemplate { private final String[] serverProtocols; private final boolean needClientAuth; + /* + * Used to synchronize client and server; there were intermittent + * failures on Windows due to the connection being killed. + */ + private final CyclicBarrier barrier = new CyclicBarrier(2); + TooManyCAs(int index, boolean needClientAuth) { this.clientProtocols = protocols[index][0]; this.serverProtocols = protocols[index][1]; this.needClientAuth = needClientAuth; + + System.out.printf("Testing%n\tclient protocols: %s%n\t" + + "server protocols: %s%n\tneed client auth: %s%n", + String.join(", ", clientProtocols), + String.join(", ", serverProtocols), + needClientAuth); } - // Servers are configured before clients, increment test case after. - void configureClientSocket(SSLSocket clientSocket) { - System.err.print("Setting client protocol(s): "); - Arrays.stream(clientProtocols).forEachOrdered(System.err::print); - System.err.println(); + @Override + protected void configureClientSocket(SSLSocket clientSocket) { + System.out.println("Setting client protocol(s): " + + String.join(",", clientProtocols)); clientSocket.setEnabledProtocols(clientProtocols); } - void configureServerSocket(SSLServerSocket serverSocket) { - System.err.print("Setting server protocol(s): "); - Arrays.stream(serverProtocols).forEachOrdered(System.err::print); - System.err.println(); + @Override + protected void configureServerSocket(SSLServerSocket serverSocket) { + serverSocket.setNeedClientAuth(needClientAuth); + serverSocket.setEnableSessionCreation(true); + serverSocket.setUseClientMode(false); + + System.out.println("Setting server protocol(s): " + + String.join(",", serverProtocols)); serverSocket.setEnabledProtocols(serverProtocols); - if (needClientAuth) { - serverSocket.setNeedClientAuth(true); - } } @Override - public TrustManager createClientTrustManager() throws Exception { - TrustManager trustManager = - SSLContextTemplate.super.createClientTrustManager(); + protected TrustManager createClientTrustManager() throws Exception { + TrustManager trustManager = super.createClientTrustManager(); return new BogusX509TrustManager( (X509TrustManager)trustManager); } @Override - public TrustManager createServerTrustManager() throws Exception { - TrustManager trustManager = - SSLContextTemplate.super.createServerTrustManager(); + protected TrustManager createServerTrustManager() throws Exception { + TrustManager trustManager = super.createServerTrustManager(); return new BogusX509TrustManager( (X509TrustManager)trustManager); } @@ -107,104 +116,42 @@ public static void main(String[] args) throws Exception { } } - private void run() throws Exception { - SSLServerSocket listenSocket = null; - SSLSocket serverSocket = null; - ClientSocket clientSocket = null; + @Override + protected void runServerApplication(SSLSocket socket) throws Exception { try { - SSLServerSocketFactory serversocketfactory = - createServerSSLContext().getServerSocketFactory(); - listenSocket = - (SSLServerSocket)serversocketfactory.createServerSocket(0); - listenSocket.setNeedClientAuth(false); - listenSocket.setEnableSessionCreation(true); - listenSocket.setUseClientMode(false); - configureServerSocket(listenSocket); - - System.err.println("Starting client"); - clientSocket = new ClientSocket(listenSocket.getLocalPort()); - clientSocket.start(); - - System.err.println("Accepting client requests"); - serverSocket = (SSLSocket)listenSocket.accept(); - - if (!clientSocket.isDone) { - System.err.println("Waiting 3 seconds for client "); - Thread.sleep(3000); - } - - System.err.println("Sending data to client ..."); + System.out.println("Sending data to client ..."); String serverData = "Hi, I am server"; BufferedWriter os = new BufferedWriter( - new OutputStreamWriter(serverSocket.getOutputStream())); + new OutputStreamWriter(socket.getOutputStream())); os.write(serverData, 0, serverData.length()); os.newLine(); os.flush(); } finally { - if (listenSocket != null) { - listenSocket.close(); - } - - if (serverSocket != null) { - serverSocket.close(); - } - } - - if (clientSocket != null && clientSocket.clientException != null) { - throw clientSocket.clientException; + barrier.await(); + System.out.println("Server done"); } } - private class ClientSocket extends Thread{ - boolean isDone = false; - int serverPort = 0; - Exception clientException; + @Override + protected void runClientApplication(SSLSocket socket) throws Exception { + try { + String clientData = "Hi, I am client"; + System.out.println("Sending data to server ..."); - public ClientSocket(int serverPort) { - this.serverPort = serverPort; - } + BufferedWriter os = new BufferedWriter( + new OutputStreamWriter(socket.getOutputStream())); + os.write(clientData, 0, clientData.length()); + os.newLine(); + os.flush(); - @Override - public void run() { - SSLSocket clientSocket = null; - String clientData = "Hi, I am client"; - try { - System.err.println( - "Connecting to server at port " + serverPort); - SSLSocketFactory sslSocketFactory = - createClientSSLContext().getSocketFactory(); - clientSocket = (SSLSocket)sslSocketFactory.createSocket( - InetAddress.getLocalHost(), serverPort); - configureClientSocket(clientSocket); - - System.err.println("Sending data to server ..."); - - BufferedWriter os = new BufferedWriter( - new OutputStreamWriter(clientSocket.getOutputStream())); - os.write(clientData, 0, clientData.length()); - os.newLine(); - os.flush(); - - System.err.println("Reading data from server"); - BufferedReader is = new BufferedReader( - new InputStreamReader(clientSocket.getInputStream())); - String data = is.readLine(); - System.err.println("Received Data from server: " + data); - } catch (Exception e) { - clientException = e; - System.err.println("unexpected client exception: " + e); - } finally { - if (clientSocket != null) { - try { - clientSocket.close(); - System.err.println("client socket closed"); - } catch (IOException ioe) { - clientException = ioe; - } - } - - isDone = true; - } + System.out.println("Reading data from server"); + BufferedReader is = new BufferedReader( + new InputStreamReader(socket.getInputStream())); + String data = is.readLine(); + System.out.println("Received Data from server: " + data); + } finally { + barrier.await(); + System.out.println("client done."); } } @@ -273,7 +220,7 @@ public X509Certificate[] getAcceptedIssuers() { for (int i = 0; i < duplicated; i++) { System.arraycopy(trustedCerts, 0, returnedCAs, - i * trustedCerts.length + 0, trustedCerts.length); + i * trustedCerts.length, trustedCerts.length); } return returnedCAs; diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Chunghwa.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Chunghwa.java new file mode 100644 index 00000000000..8512640bb01 --- /dev/null +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Chunghwa.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * 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.net.ssl.X509TrustManager; +import java.io.File; +import java.security.Security; +import java.time.LocalDate; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Date; + +/* + * @test + * @bug 8369282 + * @summary Check that TLS Server certificates chaining back to distrusted + * Chunghwa root are invalid + * @library /test/lib + * @modules java.base/sun.security.validator + * @run main/othervm Chunghwa after policyOn invalid + * @run main/othervm Chunghwa after policyOff valid + * @run main/othervm Chunghwa before policyOn valid + * @run main/othervm Chunghwa before policyOff valid + */ + +public class Chunghwa { + + private static final String CERT_PATH = "chains" + File.separator + "chunghwa"; + + // The ePKI root has a test certificate chain stored in a file + // named "-chain.pem". + private static final String ROOT_TO_TEST = "chunghwaepkirootca"; + + // Date after the restrictions take effect + private static final ZonedDateTime DISTRUST_DATE = + LocalDate.of(2026, 03, 18).atStartOfDay(ZoneOffset.UTC); + + public static void main(String[] args) throws Exception { + + Distrust distrust = new Distrust(args); + + X509TrustManager[] tms = new X509TrustManager[]{ + distrust.getTMF("PKIX", null), + distrust.getTMF("SunX509", null) + }; + + Date notBefore = distrust.getNotBefore(DISTRUST_DATE); + distrust.testCertificateChain(CERT_PATH, notBefore, tms, ROOT_TO_TEST); + } +} diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/chunghwa/chunghwaepkirootca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/chunghwa/chunghwaepkirootca-chain.pem new file mode 100644 index 00000000000..fdaa6ee04df --- /dev/null +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/chunghwa/chunghwaepkirootca-chain.pem @@ -0,0 +1,50 @@ +Owner: CN=HiPKI Root CA - G1, + O="Chunghwa Telecom Co., Ltd.", C=TW +Issuer: OU=ePKI Root Certification Authority, + O="Chunghwa Telecom Co., Ltd.", C=TW +Serial number: 23fba648360e15e92ba78aedb67a0ae5 +Valid from: Wed Dec 20 19:11:23 MST 2023 until: Tue Dec 19 08:59:59 MST 2034 +Certificate fingerprints: + SHA1: 87:F1:DD:3B:8E:F1:E0:8C:A8:CA:CB:9B:CE:4E:26:5A:E4:4E:05:F2 + SHA256: 68:07:C9:72:35:C5:EC:60:90:26:9A:4B:5F:ED:FA:B4:69:86:E4:2F:4D:67:D2:ED:DD:CF:6E:45:CF:0D:FA:80 +Signature algorithm name: SHA256withRSA +Subject Public Key Algorithm: 4096-bit RSA key +Version: 3 + +-----BEGIN CERTIFICATE----- +MIIGjDCCBHSgAwIBAgIQI/umSDYOFekrp4rttnoK5TANBgkqhkiG9w0BAQsFADBe +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0yMzEyMjEwMjExMjNaFw0zNDEyMTkxNTU5NTlaME8xCzAJBgNVBAYTAlRXMSMw +IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQ +S0kgUm9vdCBDQSAtIEcxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA +9B5/UnMyDHPkvRN0o9QwqNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh +8Ge6zCFovkRTv4354twvVcg3Px+kwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux5 +5199QmQ5eiY29yTw1S+6lZgRZq2XNdZ1AYDgr/SEYYwNHl98h5ZeQa/rh+r4XfEu +iAU+TCK72h8q3VJGZDnzQs7ZngyzsHeXZJzA9KMuH5UHsBffMNsAGJZMoYFL3QRt +U6M9/Aes1MU3guvklQgZKILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfd +hSi8MEyr48KxRURHH+CKFgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXT +T3OUM3ECoWqj1jOXTyFjHluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK +9p/7qxj3ccC2HTHsOyDry+K49a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8 +b3ti6RZsR1pl8w4Rm0bZ/W3c1pzAtH2lsN0/Vm+h+fbkEkj9Bn8SV7apI09bA8Pg +cSojt/ewsTu8mL3WmKgMa/aOEmem8rJY5AIJEzypuxC00jBF8ez3ABHfZfjcK0NV +vxaXxA/VLGGEqnKG/uY6fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaOCAVMwggFPMB8G +A1UdIwQYMBaAFB4M97Zn8uGSJglFwFU5Lnc/QkqiMB0GA1UdDgQWBBTydxf6Xqj+ +9j1x1Wi6yUYMONivsDAOBgNVHQ8BAf8EBAMCAYYwQAYDVR0fBDkwNzA1oDOgMYYv +aHR0cDovL2VjYS5oaW5ldC5uZXQvcmVwb3NpdG9yeS9DUkxfU0hBMi9DQS5jcmww +gYIGCCsGAQUFBwEBBHYwdDA7BggrBgEFBQcwAoYvaHR0cDovL2VjYS5oaW5ldC5u +ZXQvcmVwb3NpdG9yeS9DZXJ0cy9lQ0FHMS5jcnQwNQYIKwYBBQUHMAGGKWh0dHA6 +Ly9vY3NwLmVjYS5oaW5ldC5uZXQvT0NTUC9vY3NwRzFzaGEyMBIGA1UdEwEB/wQI +MAYBAf8CAQEwIgYDVR0gBBswGTAIBgZngQwBAgIwDQYLKwYBBAGBtyNkAAMwDQYJ +KoZIhvcNAQELBQADggIBACY9pps8fqk3p8Xqv/qr26I1aFA4jOEG3VWd2bqn68Y9 +InOMZozTMVh7iOnOfat7mEqn/RNhikvR5MOV3qAeg4gwgNb1OMuGltwfXWGiuGeT +vhimsV6E2hhJFAmZyXtfuoV9vSrnr1a5pCWqhVYWSCvoAQ/8Kv0tATKbIe21CYXz +NIo7O9QBSXt0BiaP9+CVQtJAYYuy2MNAcXgzgL4rownrYYAixhPmkxQE0Dt1gVbW +s2htBLJGse0z1fJDblY0Zar4t2ly+kIScx5DhRrrd8XKMK0YvID9Ythb+ao8m7Wd +Kymqr36benGL3GsvmSypLPlqZtfEqVITFhXwQiL8ruxoL+3WfNQJ09x0iV4xaP+E +bZSLLVzIiyhU49YdFHaqKyAJQvzgF2Za3DOwQWlP7OngtUx0ScEGHsoo78AM+Y0T +eLFxmr82kuyH18wZkUT9bLZlot11P2aC8VTprBGr+jEAMJjpmEjSA83ja/ttmqgh +qjj29Jnw3Lgy91XIhzBFMxMYo+hhYeBRmBFWl5+Y5oxBgPVLZpDJvg2rKa8xdqim +KgvF0DMKHntE0hhVy7JfUCnKovNQ0pf0NodLfjpqcCS2GBZ1mNcsW2MG2uBPANcn +LRXmt7N4XX11mctQTADwt8yZZ+2HDrST4kghOz+FXgftrPBdtDtM0T6WJcHWR1uS +-----END CERTIFICATE----- diff --git a/test/lib/jdk/test/lib/Utils.java b/test/lib/jdk/test/lib/Utils.java index 201fcab8c8a..e2f06d3abf1 100644 --- a/test/lib/jdk/test/lib/Utils.java +++ b/test/lib/jdk/test/lib/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +32,7 @@ import java.net.URL; import java.net.URLClassLoader; import java.net.UnknownHostException; +import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -799,4 +800,26 @@ public static Path createTempDirectory(String prefix, FileAttribute... attrs) Path dir = Paths.get(System.getProperty("user.dir", ".")); return Files.createTempDirectory(dir, prefix); } + + /** + * Implementation of ByteBuffer.slice(int, int) for JDK11. + * @param buffer The ByteBuffer to operate with (read only). + * @param index The position in this buffer at which the content of the + * new buffer will start; must be non-negative and no + * larger than buffer.limit() + * @param length The number of elements the new buffer will contain; must + * be non-negative and no larger than buffer.limit() - index + * @return The new ByteBuffer. + */ + public static ByteBuffer slice(ByteBuffer buffer, int index, int length) { + final int limit = buffer.limit(); + final int position = buffer.position(); + buffer.position(index); + buffer.limit(index + length); + ByteBuffer slice = buffer.slice(); + buffer.limit(limit); + buffer.position(position); + return slice; + } + } diff --git a/test/lib/jdk/test/lib/containers/docker/DockerRunOptions.java b/test/lib/jdk/test/lib/containers/docker/DockerRunOptions.java index fc3b793c47a..1942ae734d9 100644 --- a/test/lib/jdk/test/lib/containers/docker/DockerRunOptions.java +++ b/test/lib/jdk/test/lib/containers/docker/DockerRunOptions.java @@ -65,22 +65,22 @@ public DockerRunOptions(String imageNameAndTag, String javaCmd, this.addJavaOpts("-XX:+ErrorFileToStderr"); } - public DockerRunOptions addDockerOpts(String... opts) { + public final DockerRunOptions addDockerOpts(String... opts) { Collections.addAll(dockerOpts, opts); return this; } - public DockerRunOptions addJavaOpts(String... opts) { + public final DockerRunOptions addJavaOpts(String... opts) { Collections.addAll(javaOpts, opts); return this; } - public DockerRunOptions addJavaOptsAppended(String... opts) { + public final DockerRunOptions addJavaOptsAppended(String... opts) { Collections.addAll(javaOptsAppended, opts); return this; } - public DockerRunOptions addClassOptions(String... opts) { + public final DockerRunOptions addClassOptions(String... opts) { Collections.addAll(classParams,opts); return this; }