diff --git a/source/build-aux/texinfo.tex b/source/build-aux/texinfo.tex
index faad184e345b058eda6fd880c4070a7950e419c5..3ebea93cb1d604c6b0fa7f1b95fcb6e5b1dda01a 100644
--- a/source/build-aux/texinfo.tex
+++ b/source/build-aux/texinfo.tex
@@ -3,7 +3,7 @@
 % Load plain if necessary, i.e., if running under initex.
 \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
 %
-\def\texinfoversion{2025-01-31.21}
+\def\texinfoversion{2025-03-22.08}
 %
 % Copyright 1985, 1986, 1988, 1990-2025 Free Software Foundation, Inc.
 %
@@ -287,7 +287,6 @@
 % Avoid "undefined control sequence" errors.
 \def\currentchapterdefs{}
 \def\currentsectiondefs{}
-\def\currentsection{}
 \def\prevchapterdefs{}
 \def\prevsectiondefs{}
 \def\currentcolordefs{}
@@ -980,18 +979,51 @@ where each line of input produces a line of output.}
 \newif\ifpdf
 \newif\ifpdfmakepagedest
 
+% when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1
+% can be set).  So we test for \relax and 0 as well as being undefined.
+\ifx\pdfoutput\thisisundefined
+\else
+  \ifx\pdfoutput\relax
+  \else
+    \ifcase\pdfoutput
+    \else
+      \pdftrue
+    \fi
+  \fi
+\fi
+
+\newif\ifxetex
+\ifx\XeTeXrevision\thisisundefined\else
+  \xetextrue
+\fi
+
 \newif\ifluatex
 \ifx\luatexversion\thisisundefined\else
   \luatextrue
+  \ifnum\luatexversion>84
+    \pdftrue
+  \fi
 \fi
 
+\newif\ifpdforxetex
+\ifpdf
+  \pdforxetextrue
+\fi
+\ifxetex
+  \pdforxetextrue
+\fi
+
+
+
+% Whether to use non-ASCII bytes in internal link targets.  Presently this
+% is almost always on.
+\newif\iftxiuseunicodedestname
+\txiuseunicodedestnametrue
+
 %
 % For LuaTeX
 %
 
-\newif\iftxiuseunicodedestname
-\txiuseunicodedestnamefalse % For pdfTeX etc.
-
 \ifluatex
   % Use Unicode destination names
   \txiuseunicodedestnametrue
@@ -1045,7 +1077,7 @@ where each line of input produces a line of output.}
     %
   \endgroup
   \def\pdfescapestring#1{\directlua{PDFescstr('\luaescapestring{#1}')}}
-  \ifnum\luatexversion>84
+  \ifpdf
     % For LuaTeX >= 0.85
     \def\pdfdest{\pdfextension dest}
     \let\pdfoutput\outputmode
@@ -1068,33 +1100,6 @@ where each line of input produces a line of output.}
   \fi
 \fi
 
-% when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1
-% can be set).  So we test for \relax and 0 as well as being undefined.
-\ifx\pdfoutput\thisisundefined
-\else
-  \ifx\pdfoutput\relax
-  \else
-    \ifcase\pdfoutput
-    \else
-      \pdftrue
-    \fi
-  \fi
-\fi
-
-\newif\ifxetex
-\ifx\XeTeXrevision\thisisundefined\else
-  \xetextrue
-\fi
-
-\newif\ifpdforxetex
-\pdforxetexfalse
-\ifpdf
-  \pdforxetextrue
-\fi
-\ifxetex
-  \pdforxetextrue
-\fi
-
 
 % Output page labels information.
 % See PDF reference v.1.7 p.594, section 8.3.1.
@@ -1388,9 +1393,6 @@ output) for that.)}
     \safewhatsit{\pdfdest name{\pdfdestname} xyz}%
   }
   %
-  % used to mark target names; must be expandable.
-  \def\pdfmkpgn#1{#1}
-  %
   % Adding outlines to PDF; macros for calculating structure of outlines
   % come from Petr Olsak
   \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0%
@@ -1416,7 +1418,7 @@ output) for that.)}
       \def\pdfdestname{#4}%
     \fi
     %
-    \pdfoutline goto name{\pdfmkpgn{\pdfdestname}}#2{\pdfoutlinetext}%
+    \pdfoutline goto name{\pdfdestname}#2{\pdfoutlinetext}%
   }
   %
   \def\pdfmakeoutlines{%
@@ -1427,15 +1429,18 @@ output) for that.)}
 	\def\thischapnum{##2}%
 	\def\thissecnum{0}%
 	\def\thissubsecnum{0}%
+	\def\indexlastsec{chap\thischapnum}%
       }%
       \def\numsecentry##1##2##3##4{%
 	\advancenumber{chap\thischapnum}%
 	\def\thissecnum{##2}%
 	\def\thissubsecnum{0}%
+	\def\indexlastsec{sec\thissecnum}%
       }%
       \def\numsubsecentry##1##2##3##4{%
 	\advancenumber{sec\thissecnum}%
 	\def\thissubsecnum{##2}%
+	\def\indexlastsec{subsec\thissecnum}%
       }%
       \def\numsubsubsecentry##1##2##3##4{%
 	\advancenumber{subsec\thissubsecnum}%
@@ -1443,7 +1448,13 @@ output) for that.)}
       \def\thischapnum{0}%
       \def\thissecnum{0}%
       \def\thissubsecnum{0}%
+      \let\indexlastsec\empty
       %
+      % Index initials are subsidiary to whatever sectioning command just
+      % occurred, usually @appendix or @chapter but occasionally a lower level.
+      \def\idxinitialentry##1##2##3##4{%
+        \expandafter\advancenumber\expandafter{\indexlastsec}%
+      }%
       % use \def rather than \let here because we redefine \chapentry et
       % al. a second time, below.
       \def\appentry{\numchapentry}%
@@ -1455,9 +1466,6 @@ output) for that.)}
       \def\unnsubsecentry{\numsubsecentry}%
       \def\unnsubsubsecentry{\numsubsubsecentry}%
       %
-      % Treat index initials like @section.  Note that this is the wrong
-      % level if the index is not at the level of @appendix or @chapter.
-      \def\idxinitialentry{\numsecentry}%
       \readdatafile{toc}%
       %
       % Read toc second time, this time actually producing the outlines.
@@ -1482,18 +1490,6 @@ output) for that.)}
       \def\idxinitialentry##1##2##3##4{%
         \dopdfoutline{##1}{}{idx.##1.##2}{##4}}%
       %
-      % PDF outlines are displayed using system fonts, instead of
-      % document fonts.  Therefore we cannot use special characters,
-      % since the encoding is unknown.  For example, the eogonek from
-      % Latin 2 (0xea) gets translated to a | character.  Info from
-      % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100.
-      %
-      % TODO this right, we have to translate 8-bit characters to
-      % their "best" equivalent, based on the @documentencoding.  Too
-      % much work for too little return.  Just use the ASCII equivalents
-      % we use for the index sort strings.
-      %
-      \indexnofonts
       \ifnodeseen\else \dopdfoutlinecontents \fi % for @contents at beginning
       \setupdatafile
       % We can have normal brace characters in the PDF outlines, unlike
@@ -1501,9 +1497,9 @@ output) for that.)}
       \def\{{\lbracecharliteral}%
       \def\}{\rbracecharliteral}%
       \catcode`\\=\active \otherbackslash
-      \input \tocreadfilename
+      \input \tocreadfilename\relax
+      \ifnodeseen \dopdfoutlinecontents \fi % for @contents at end
     \endgroup
-    \ifnodeseen \dopdfoutlinecontents \fi % for @contents at end
   }
   \def\dopdfoutlinecontents{%
     \expandafter\dopdfoutline\expandafter{\putwordTOC}{}{txi.CONTENTS}{}%
@@ -1541,7 +1537,7 @@ output) for that.)}
   %
   \def\pdflink#1{\pdflinkpage{#1}{#1}}%
   \def\pdflinkpage#1#2{%
-    \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}}
+    \startlink attr{/Border [0 0 0]} goto name{#1}
     \setcolor{\linkcolor}#2\endlink}
 \else
   % non-pdf mode
@@ -1644,18 +1640,20 @@ output) for that.)}
       % horizontal space being required in the PDF viewer.
       \def\partentry##1##2##3##4{}% ignore parts in the outlines
       \def\numchapentry##1##2##3##4{%
-        \dopdfoutline{##2 ##1}{1}{##3}{##4}}%
+        \dopdfoutline{##2 ##1}{1}{##3}{##4}%
+        \def\indexseclevel{2}}%
       \def\numsecentry##1##2##3##4{%
-        \dopdfoutline{##1}{2}{##3}{##4}}%
+        \dopdfoutline{##1}{2}{##3}{##4}%
+        \def\indexseclevel{3}}%
       \def\numsubsecentry##1##2##3##4{%
-        \dopdfoutline{##1}{3}{##3}{##4}}%
+        \dopdfoutline{##1}{3}{##3}{##4}%
+        \def\indexseclevel{4}}%
       \def\numsubsubsecentry##1##2##3##4{%
-        \dopdfoutline{##1}{4}{##3}{##4}}%
+        \dopdfoutline{##1}{4}{##3}{##4}%
+        \def\indexseclevel{5}}%
       %
-      % Note this is at the wrong level unless the index is in an @appendix
-      % or @chapter.
       \def\idxinitialentry##1##2##3##4{%
-         \dopdfoutline{##1}{2}{idx.##1.##2}{##4}}%
+         \dopdfoutline{##1}{\indexseclevel}{idx.##1.##2}{##4}}%
       %
       \let\appentry\numchapentry%
       \let\appsecentry\numsecentry%
@@ -1680,7 +1678,9 @@ output) for that.)}
       \def\{{\lbracecharliteral}%
       \def\}{\rbracecharliteral}%
       \catcode`\\=\active \otherbackslash
+      \xetexpreauxfile
       \input \tocreadfilename\relax
+      \xetexpostauxfile
       \ifnodeseen \dopdfoutlinecontents \fi % for @contents at end
     \endgroup
   }
@@ -5177,8 +5177,8 @@ $$%
   %
   \uccode`\1=`\{ \uppercase{\def\{{1}}%
   \uccode`\1=`\} \uppercase{\def\}{1}}%
-  \let\lbracechar\{%
-  \let\rbracechar\}%
+  \def\lbracechar##1{\{}%
+  \def\rbracechar##1{\}}%
   %
   %
   % We need to get rid of all macros, leaving only the arguments (if present).
@@ -5523,6 +5523,8 @@ $$%
   \tolerance = 9500
   \plainfrenchspacing
   \everypar = {}% don't want the \kern\-parindent from indentation suppression.
+  \let\entry\indexentry
+  \ifxetex\xetexpreauxfile\fi
   %
   % See comment in \requireopenindexfile.
   \def\indexname{#1}\ifx\indexname\indexisfl\def\indexname{f1}\fi
@@ -5548,6 +5550,7 @@ $$%
     \fi
   \fi
   \closein 1
+  \ifxetex\xetexpostauxfile\fi
 \endgroup}
 
 % Checked in @bye
@@ -5583,7 +5586,9 @@ might help (with 'rm \jobname.?? \jobname.??s')%
       }%
     \else
       \begindoublecolumns
+      \ifxetex\xetexpreauxfile\fi
       \input \jobname.\indexname s
+      \ifxetex\xetexpostauxfile\fi
       \enddoublecolumns
     \fi
   }{%
@@ -5594,11 +5599,39 @@ might help (with 'rm \jobname.?? \jobname.??s')%
     % should work because we (hopefully) don't otherwise use @ in index files.
     %\catcode`\@=12\relax
     \catcode`\@=0\relax
+    \ifxetex\xetexpreauxfile\fi
     \input \jobname.\indexname s
+    \ifxetex\xetexpostauxfile\fi
     \enddoublecolumns
   }%
 }
 
+\def\indexentry#1#2{%
+  \let\entrypagetarget\empty
+  \ifpdforxetex
+    % only link the index text to the page if no comma appears in the
+    % list of pages, i.e. there is only one page
+    \checkpagelistcomma{#2}\pagelistcomma
+    \expandafter\ifcase\pagelistcomma
+      \def\entrypagetarget{#2}%
+    \fi
+  \fi%
+  \entryinternal{#1}{#2}%
+}
+
+\def\checkpagelistcomma#1#2{%
+  \checkpagelistcommaxx#2#1,\finish
+}
+\def\checkpagelistcommaxx#1#2,#3\finish{%
+  \def\tmp{#3}%
+  \ifx\tmp\empty
+    \def#1{0\relax}
+  \else
+    \def#1{1\relax}
+  \fi
+}
+
+
 % These macros are used by the sorted index file itself.
 % Change them to control the appearance of the index.
 
@@ -5673,18 +5706,14 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 \def\doindexinitialentry#1{%
   \ifpdforxetex
     \global\advance\idxinitialno by 1
-    \def\indexlbrace{\{}
-    \def\indexrbrace{\}}
-    \def\indexbackslash{\realbackslash}
-    \def\indexatchar{\@}
+    \def\indexlbrace{\{}%
+    \def\indexrbrace{\}}%
+    \def\indexbackslash{\realbackslash}%
+    \def\indexatchar{\@}%
     \writetocentry{idxinitial}{\asis #1}{IDX\the\idxinitialno}%
     % The @asis removes a pair of braces around e.g. {@indexatchar} that
     % are output by texindex.
     %
-    \vbox to 0pt{}%
-    % This vbox fixes the \pdfdest location for double column formatting.
-    % Without it, the \pdfdest is output above topskip glue at the top
-    % of a column as this glue is not added until the first box.
     \pdfmkdest{idx.\asis #1.IDX\the\idxinitialno}%
   \fi
 }
@@ -5704,16 +5733,18 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 \newdimen\entrycontskip
 \entrycontskip=1em
 
-% for PDF output, whether to make the text of the entry a link to the page
-% number.  set for @contents and @shortcontents where there is only one
-% page number.
+% for PDF output, whether to make the text of the entry a link to the section.
+% set for @contents and @shortcontents.
 \newif\iflinkentrytext
 
-% \entry typesets a paragraph consisting of the text (#1), dot leaders, and
-% then page number (#2) flushed to the right margin.  It is used for index
-% and table of contents entries.  The paragraph is indented by \leftskip.
-% If \tocnodetarget is set, link text to the referenced node.
-\def\entry{%
+% \entryinternal typesets a paragraph consisting of the text (#1), dot
+% leaders, and then page number (#2) flushed to the right margin.  It is
+% used for index and table of contents entries.  The paragraph is indented
+% by \leftskip.
+% For PDF output, if \linkentrytexttrue and \tocnodetarget is set, link text
+% to the referenced node.  Else if \entrypagetarget is set, link text to the
+% page.
+\def\entryinternal{%
   \begingroup
     %
     % Start a new paragraph if necessary, so our assignments below can't
@@ -5761,7 +5792,11 @@ might help (with 'rm \jobname.?? \jobname.??s')%
             \endlink
           \fi
         \else
-          \unhbox\boxA
+          \ifx\entrypagetarget\empty
+            \unhbox\boxA
+          \else
+            \pdflinkpage{\entrypagetarget}{\unhbox\boxA}%
+          \fi
         \fi
       \else
         \unhbox\boxA
@@ -6433,6 +6468,10 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 \parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{}
   \suppressfirstparagraphindent}
 
+% @xrefname - give text with printed name for linking to node and allow
+% referencing node, but do not print any heading.
+\parseargdef\xrefname{\donoderef{Yomitfromtoc}{#1}}%
+
 % These macros generate a chapter, section, etc. heading only
 % (including whitespace, linebreaking, etc. around it),
 % given all the information in convenient, parsed form.
@@ -6554,11 +6593,6 @@ might help (with 'rm \jobname.?? \jobname.??s')%
     \chapfonts \rm
     \let\footnote=\errfootnoteheading % give better error message
     %
-    % Have to define \currentsection before calling \donoderef, because the
-    % xref code eventually uses it.  On the other hand, it has to be called
-    % after \pchapsepmacro, or the headline will change too soon.
-    \gdef\currentsection{#1}%
-    %
     % Only insert the separating space if we have a chapter/appendix
     % number, and don't print the unnumbered ``number''.
     \ifx\temptype\Ynothingkeyword
@@ -6585,7 +6619,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
     % been typeset.  If the destination for the pdf outline is after the
     % text, then jumping from the outline may wind up with the text not
     % being visible, for instance under high magnification.
-    \donoderef{#2}%
+    \donoderef{#2}{#1}%
     %
     % Typeset the actual heading.
     \nobreak % Avoid page breaks at the interline glue.
@@ -6701,21 +6735,17 @@ might help (with 'rm \jobname.?? \jobname.??s')%
     \ifx\temptype\Ynothingkeyword
       \setbox0 = \hbox{}%
       \def\toctype{unn}%
-      \gdef\currentsection{#1}%
     \else\ifx\temptype\Yomitfromtockeyword
-      % for @headings -- no section number, don't include in toc,
-      % and don't redefine \currentsection.
+      % for @headings -- no section number, don't include in toc.
       \setbox0 = \hbox{}%
       \def\toctype{omit}%
       \let\sectionlevel=\empty
     \else\ifx\temptype\Yappendixkeyword
       \setbox0 = \hbox{#4\enspace}%
       \def\toctype{app}%
-      \gdef\currentsection{#1}%
     \else
       \setbox0 = \hbox{#4\enspace}%
       \def\toctype{num}%
-      \gdef\currentsection{#1}%
     \fi\fi\fi
     %
     % Write the toc entry (before \donoderef).  See comments in \chapmacro.
@@ -6723,7 +6753,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
     %
     % Write the node reference (= pdf destination for pdftex).
     % Again, see comments in \chapmacro.
-    \donoderef{#3}%
+    \donoderef{#3}{#1}%
     %
     % Interline glue will be inserted when the vbox is completed.
     % That glue will be a valid breakpoint for the page, since it'll be
@@ -6955,6 +6985,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 %
 \def\contents{%
   \startcontents{\putwordTOC}{\contentsmkdest}%
+    \ifxetex\xetexpreauxfile\fi
     \openin 1 \tocreadfilename\space
     \ifeof 1 \else
       \findsecnowidths
@@ -6966,6 +6997,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
       \pdfmakeoutlines
     \fi
     \closein 1
+    \ifxetex\xetexpostauxfile\fi
   \endgroup
   \contentsendroman
 }
@@ -6999,11 +7031,13 @@ might help (with 'rm \jobname.?? \jobname.??s')%
     \let\numsubsubsecentry = \numsecentry
     \let\appsubsubsecentry = \numsecentry
     \let\unnsubsubsecentry = \numsecentry
+    \ifxetex\xetexpreauxfile\fi
     \openin 1 \tocreadfilename\space
     \ifeof 1 \else
       \readtocfile
     \fi
     \closein 1
+    \ifxetex\xetexpostauxfile\fi
     \vfill \eject
     \contentsalignmacro % in case @setchapternewpage odd is in effect
   \endgroup
@@ -7167,6 +7201,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 \extrasecnoskip=0pt
 
 \let\tocnodetarget\empty
+\let\entrypagetarget\empty
 
 % \tocentry{TITLE}{SEC NO}{NODE}{PAGE}
 %
@@ -7174,7 +7209,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
   \def\tocnodetarget{#3}%
   \def\secno{#2}%
   \ifx\empty\secno
-    \entry{#1}{#4}%
+    \entryinternal{#1}{#4}%
   \else
     \ifdim 0pt=\secnowidth
       \setbox0=\hbox{#2\hskip\labelspace\hskip\extrasecnoskip}%
@@ -7185,7 +7220,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
         #2\hskip\labelspace\hskip\extrasecnoskip\hfill}%
     \fi
     \entrycontskip=\wd0
-    \entry{\box0 #1}{#4}%
+    \entryinternal{\box0 #1}{#4}%
   \fi
 }
 \newdimen\labelspace
@@ -8170,18 +8205,11 @@ might help (with 'rm \jobname.?? \jobname.??s')%
   }
 \fi
 
-\let\E=\expandafter
-
 % Used at the time of macro expansion.
 % Argument is macro body with arguments substituted
 \def\scanmacro#1{%
   \newlinechar`\^^M
-  % expand the expansion of \eatleadingcr twice to maybe remove a leading
-  % newline (and \else and \fi tokens), then call \eatspaces on the result.
-  \def\xeatspaces##1{%
-    \E\E\E\E\E\E\E\eatspaces\E\E\E\E\E\E\E{\eatleadingcr##1%
-  }}%
-  \def\xempty##1{}%
+  \def\xeatspaces##1{\eatleadingcrthen\eatspaces{##1}}%
   %
   % Process the macro body under the current catcode regime.
   \scantokens{#1@comment}%
@@ -8234,10 +8262,12 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 \unbrace{\gdef\trim@@@ #1 } #2@{#1}
 }
 
-{\catcode`\^^M=\other%
-\gdef\eatleadingcr#1{\if\noexpand#1\noexpand^^M\else\E#1\fi}}%
-% Warning: this won't work for a delimited argument
-% or for an empty argument
+% Trim a single leading ^^M off a string, then call #1
+{\catcode`\^^M=\active \catcode`\Q=3%
+\gdef\eatleadingcrthen #1#2{\eatlcra #1Q#2Q^^MQ}%
+\gdef\eatlcra #1#2Q^^M{\eatlcrb #1#2Q}%
+\gdef\eatlcrb #1Q#2Q#3Q{#1{#2}}%
+}
 
 % Trim a single trailing ^^M off a string.
 {\catcode`\^^M=\other \catcode`\Q=3%
@@ -8373,6 +8403,10 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 % <parameter list> is #, then the preceding argument is delimited by
 % an opening brace, and that opening brace is not consumed.
 
+% Make @ a letter, so that we can make private-to-Texinfo macro names.
+\edef\texiatcatcode{\the\catcode`\@}
+\catcode `@=11\relax
+
 % Parse the optional {params} list to @macro or @rmacro.
 % Set \paramno to the number of arguments,
 % and \paramlist to a parameter text for the macro (e.g. #1,#2,#3 for a
@@ -8385,14 +8419,13 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 % That gets used by \mbodybackslash (above).
 %
 % If there are 10 or more arguments, a different technique is used: see
-% \parsemmanyargdef.
+% \parsemmanyargdef@@.
 %
 \def\parsemargdef#1;{%
   \paramno=0\def\paramlist{}%
   \let\hash\relax
   % \hash is redefined to `#' later to get it into definitions
   \let\xeatspaces\relax
-  \let\xempty\relax
   \parsemargdefxxx#1,;,%
   \ifnum\paramno<10\relax\else
     \paramno0\relax
@@ -8404,11 +8437,9 @@ might help (with 'rm \jobname.?? \jobname.??s')%
   \else \let\next=\parsemargdefxxx
     \advance\paramno by 1
     \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname
-        {\xeatspaces{\hash\the\paramno\noexpand\xempty{}}}%
+        {\xeatspaces{\hash\the\paramno}}%
     \edef\paramlist{\paramlist\hash\the\paramno,}%
   \fi\next}
-% the \xempty{} is to give \eatleadingcr an argument in the case of an
-% empty macro argument.
 
 % \parsemacbody, \parsermacbody
 %
@@ -8419,14 +8450,12 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 % body to be transformed.
 % Set \macrobody to the body of the macro, and call \macrodef.
 %
+\catcode `\@\texiatcatcode
 {\catcode`\ =\other\long\gdef\parsemacbody#1@end macro{%
 \xdef\macrobody{\eatcr{#1}}\endgroup\macrodef}}%
 {\catcode`\ =\other\long\gdef\parsermacbody#1@end rmacro{%
 \xdef\macrobody{\eatcr{#1}}\endgroup\macrodef}}%
-
-% Make @ a letter, so that we can make private-to-Texinfo macro names.
-\edef\texiatcatcode{\the\catcode`\@}
-\catcode `@=11\relax
+\catcode `\@=11\relax
 
 %%%%%%%%%%%%%% Code for > 10 arguments only   %%%%%%%%%%%%%%%%%%
 
@@ -8687,15 +8716,13 @@ might help (with 'rm \jobname.?? \jobname.??s')%
         \noexpand\expandafter
         \expandafter\noexpand\csname\the\macname @@\endcsname}%
       \expandafter\xdef\csname\the\macname @@\endcsname##1{%
-          \noexpand\passargtomacro
-          \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}%
+        \noexpand\passargtomacro
+        \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}%
       \expandafter\xdef\csname\the\macname @@@\endcsname##1{%
-          \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}%
-      \expandafter\expandafter
-      \expandafter\xdef
-      \expandafter\expandafter
-        \csname\the\macname @@@@\endcsname\paramlist{%
-          \endgroup\noexpand\scanmacro{\macrobody}}%
+        \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}%
+      \expandaftergroup{\expandafter\xdef\csname\the\macname @@@@\endcsname}%
+                       \paramlist{%
+        \endgroup\noexpand\scanmacro{\macrobody}}%
     \else % 10 or more:
       \expandafter\xdef\csname\the\macname\endcsname{%
         \noexpand\getargvals@{\the\macname}{\argl}%
@@ -8707,6 +8734,16 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 
 \catcode `\@\texiatcatcode\relax % end private-to-Texinfo catcodes
 
+% utility definition to avoid excessive use of \expandafter.  call
+% as \expandaftergroup{CONTENT}\WORD to expand \WORD exactly once and remove
+% braces around CONTENT.
+\def\expandaftergroup#1#2{%
+  \expandafter\expandaftergroupx\expandafter{#2}{#1}%
+}
+\def\expandaftergroupx#1#2{%
+  #2#1%
+}
+
 \def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}}
 
 
@@ -8876,9 +8913,8 @@ might help (with 'rm \jobname.?? \jobname.??s')%
     \expandafter\noexpand
     \csname\the\macname @@@\endcsname##1\noexpand\endlinemacro
   }
-  \expandafter\expandafter
-  \expandafter\xdef
-  \expandafter\expandafter\csname\the\macname @@@\endcsname\paramlist{%
+  \expandaftergroup{\expandafter\xdef\csname\the\macname @@@\endcsname}%
+                     \paramlist{%
     \newlinechar=13 % split \macrobody into lines
     \noexpand\scantokens{\macrobody}%
   }
@@ -8953,11 +8989,11 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 \let\lastnode=\empty
 
 % Write a cross-reference definition for the current node.  #1 is the
-% type (Ynumbered, Yappendix, Ynothing).
+% type (Ynumbered, Yappendix, Ynothing).  #2 is the section title.
 %
-\def\donoderef#1{%
+\def\donoderef#1#2{%
   \ifx\lastnode\empty\else
-    \setref{\lastnode}{#1}%
+    \setref{\lastnode}{#1}{#2}%
     \global\let\lastnode=\empty
     \setnodeseenonce
   \fi
@@ -8978,21 +9014,28 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 %
 \def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi}
 \def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi}
-\def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces}
-
-% \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an
-% anchor), which consists of three parts:
-% 1) NAME-title - the current sectioning name taken from \currentsection,
-%                 or the anchor name.
-% 2) NAME-snt   - section number and type, passed as the SNT arg, or
-%                 empty for anchors.
+\def\anchor#1{%
+  \savesf \setref{#1}{Yanchor}{#1}\restoresf \ignorespaces
+}
+
+% @namedanchor{NAME, XREFNAME} -- define xref target at arbitrary point
+% with label text for cross-references to it.
+\def\namedanchor#1{\donamedanchor#1\finish}%
+\def\donamedanchor#1,#2\finish{%
+  \savesf \setref{#1}{Yanchor}{\ignorespaces #2\unskip}\restoresf \ignorespaces
+}
+
+% \setref{NAME}{SNT}{TITLE} defines a cross-reference point NAME (a node
+% or an anchor), which consists of three parts:
+% 1) NAME-title - the current sectioning name
+% 2) NAME-snt   - section number and type, passed as the SNT arg.
 % 3) NAME-pg    - the page number.
 %
 % This is called from \donoderef, \anchor, and \dofloat.  In the case of
 % floats, there is an additional part, which is not written here:
 % 4) NAME-lof   - the text as it should appear in a @listoffloats.
 %
-\def\setref#1#2{%
+\def\setref#1#2#3{%
   \pdfmkdest{#1}%
   \iflinks
     {%
@@ -9004,7 +9047,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 	\write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef
 	  ##1}{##2}}% these are parameters of \writexrdef
       }%
-      \toks0 = \expandafter{\currentsection}%
+      \toks0 = {#3}%
       \immediate \writexrdef{title}{\the\toks0 }%
       \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc.
       \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, at \shipout
@@ -9058,15 +9101,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
   \setbox\infofilenamebox = \hbox{\infofilename\unskip}%
   %
   \startxreflink{#1}{#4}%
-  {%
-    % Have to otherify everything special to allow the \csname to
-    % include an _ in the xref name, etc.
-    \indexnofonts
-    \turnoffactive
-    \def\value##1{##1}%
-    \expandafter\global\expandafter\let\expandafter\Xthisreftitle
-      \csname XR#1-title\endcsname
-  }%
+  \getrefx{#1-title}\Xthisreftitle
   %
   % Float references are printed completely differently: "Figure 1.2"
   % instead of "[somenode], p.3".  \iffloat distinguishes them by
@@ -9099,21 +9134,23 @@ might help (with 'rm \jobname.?? \jobname.??s')%
       % Cross-manual reference with a printed manual name.
       %
       \crossmanualxref{\cite{\printedmanual\unskip}}%
-    %
     \else\ifdim \wd\infofilenamebox > 0pt
       % Cross-manual reference with only an info filename (arg 4), no
       % printed manual name (arg 5).  This is essentially the same as
       % the case above; we output the filename, since we have nothing else.
       %
       \crossmanualxref{\code{\infofilename\unskip}}%
-    %
     \else
       % Reference within this manual.
       %
-      % Only output a following space if the -snt ref is nonempty, as the ref
-      % will be empty for @unnumbered and @anchor.
-      \setbox2 = \hbox{\ignorespaces \refx{#1-snt}}%
-      \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi
+      % Only output a following space if the -snt ref is nonempty, as is
+      % the case for @unnumbered and @anchor.
+      \getrefx{#1-snt}\tmp
+      \ifx\tmp\empty\else
+        \ifx\tmp\Yanchor\else
+          \tmp\space
+        \fi
+      \fi
       %
       % output the `[mynode]' via the macro below so it can be overridden.
       \xrefprintnodename\printedrefname
@@ -9169,7 +9206,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
         \else
           % Otherwise just copy the Info node name.
           \def\printedrefname{\ignorespaces #1}%
-        \fi%
+        \fi
       \fi
     \fi
   \fi
@@ -9201,7 +9238,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
        \ifnum\filenamelength>0
          goto file{\the\filename.pdf} name{\pdfdestname}%
        \else
-         goto name{\pdfmkpgn{\pdfdestname}}%
+         goto name{\pdfdestname}%
        \fi
      \else % XeTeX
        \ifnum\filenamelength>0
@@ -9281,6 +9318,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 %
 \def\Ynothing{}
 \def\Yomitfromtoc{}
+\def\Yanchor{\isanchor} \let\isanchor\relax
 \def\Ynumbered{%
   \ifnum\secno=0
     \putwordChapter@tie \the\chapno
@@ -9307,14 +9345,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 
 % \refx{NAME} - reference a cross-reference string named NAME.
 \def\refx#1{%
-  \requireauxfile
-  {%
-    \indexnofonts
-    \turnoffactive
-    \def\value##1{##1}%
-    \expandafter\global\expandafter\let\expandafter\thisrefX
-      \csname XR#1\endcsname
-  }%
+  \getrefx{#1}\thisrefX
   \ifx\thisrefX\relax
     % If not defined, say something at least.
     \angleleft un\-de\-fined\angleright
@@ -9335,6 +9366,17 @@ might help (with 'rm \jobname.?? \jobname.??s')%
   \fi
 }
 
+% Set #2 to xref string #1
+\def\getrefx#1#2{%
+  \requireauxfile
+  {%
+    \indexnofonts
+    \turnoffactive
+    \def\value##1{##1}%
+    \expandafter\global\expandafter\let\expandafter#2\csname XR#1\endcsname
+  }%
+}
+
 % This is the macro invoked by entries in the aux file.  Define a control
 % sequence for a cross-reference target (we prepend XR to the control sequence
 % name to avoid collisions).  The value is the page number.  If this is a float
@@ -9399,12 +9441,14 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 % Read the last existing aux file, if any.  No error if none exists.
 %
 \def\tryauxfile{%
+  \ifxetex\xetexpreauxfile\fi
   \openin 1 \jobname.aux
   \ifeof 1 \else
     \readdatafile{aux}%
     \global\havexrefstrue
   \fi
   \closein 1
+  \ifxetex\xetexpostauxfile\fi
 }
 
 \def\setupdatafile{%
@@ -9790,14 +9834,15 @@ might help (with 'rm \jobname.?? \jobname.??s')%
       \global\advance\floatno by 1
       %
       {%
-        % This magic value for \currentsection is output by \setref as the
-        % XREFLABEL-title value.  \xrefX uses it to distinguish float
+        % This magic value for the third argument of \setref is output as
+        % the XREFLABEL-title value.  \xrefX uses it to distinguish float
         % labels (which have a completely different output format) from
         % node and anchor labels.  And \xrdef uses it to construct the
         % lists of floats.
         %
-        \edef\currentsection{\floatmagic=\safefloattype}%
-        \setref{\floatlabel}{Yfloat}%
+        \edef\tmp{\noexpand\setref{\floatlabel}{Yfloat}%
+                  {\floatmagic=\safefloattype}}%
+        \tmp
       }%
     \fi
     %
@@ -9919,7 +9964,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 
 % #1 is the control sequence we are passed; we expand into a conditional
 % which is true if #1 represents a float ref.  That is, the magic
-% \currentsection value which we \setref above.
+% value which we passed to \setref above.
 %
 \def\iffloat#1{\expandafter\doiffloat#1==\finish}
 %
@@ -9976,6 +10021,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
   \toksA = \expandafter{\csname XR#1-lof\endcsname}%
   %
   % use the same \entry macro we use to generate the TOC and index.
+  \let\entry\entryinternal
   \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}%
   \writeentry
 }}
@@ -10071,17 +10117,24 @@ directory should work if nowhere else does.}
   \fi
 \fi
 
+\let\xetexpreauxfile\relax
+\let\xetexpostauxfile\relax
+
 % Set I/O by bytes instead of UTF-8 sequence for XeTeX and LuaTex
 % for non-UTF-8 (byte-wise) encodings.
 %
 \def\setbytewiseio{%
   \ifxetex
-    \XeTeXdefaultencoding "bytes"  % For subsequent files to be read
-    \XeTeXinputencoding "bytes"  % For document root file
-    % Unfortunately, there seems to be no corresponding XeTeX command for
-    % output encoding.  This is a problem for auxiliary index and TOC files.
-    % The only solution would be perhaps to write out @U{...} sequences in
-    % place of non-ASCII characters.
+    % For document root file
+    \XeTeXinputencoding "bytes"
+    %
+    % Setting for subsequent files to be read with @include.
+    \XeTeXdefaultencoding "bytes"
+    %
+    % Use UTF-8 for reading auxiliary index and TOC files, which are
+    % always output in UTF-8 with XeTeX.
+    \def\xetexpreauxfile{\XeTeXdefaultencoding "UTF-8"}%
+    \def\xetexpostauxfile{\XeTeXdefaultencoding "bytes"}%
   \fi
 
   \ifluatex
@@ -10713,12 +10766,12 @@ directory should work if nowhere else does.}
 
 % Suppress ligature creation from adjacent characters.
 \ifluatex
-  \def\nolig{{}}
-\else
   % Braces do not suppress ligature creation in LuaTeX, e.g. in of{}fice
   % to suppress the "ff" ligature.  Using a kern appears to be the only
   % workaround.
   \def\nolig{\kern0pt{}}
+\else
+  \def\nolig{{}}
 \fi
 
 % https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_M
diff --git a/source/configure b/source/configure
index 5c27356634e90ed6e6292bcfd1dd65bde829318c..330d813b53a51663c64559fe45f71d9ca65b248b 100755
--- a/source/configure
+++ b/source/configure
@@ -813,6 +813,23 @@ enable_native_texlive_build
 enable_multiplatform
 enable_cxx_runtime_hack
 enable_libtool_hack
+enable_autosp
+enable_axodraw2
+enable_devnag
+enable_lacheck
+enable_m_tx
+enable_pmx
+enable_ps2eps
+enable_t1utils
+enable_texdoctk
+enable_tpic2pdftex
+enable_vlna
+enable_xindy
+enable_xindy_rules
+enable_xindy_docs
+with_clisp_runtime
+enable_xml2pmx
+enable_xpdfopen
 enable_web2c
 with_banner_add
 with_editor
@@ -860,16 +877,88 @@ enable_tektronixwin
 enable_unitermwin
 enable_web_progs
 enable_synctex
+enable_afm2pl
+enable_bibtex_x
+enable_bibtex8
+enable_bibtexu
+enable_chktex
+enable_cjkutils
+enable_detex
+enable_dtl
+enable_dvi2tty
+enable_dvidvi
+enable_dviljk
+enable_dviout_util
+enable_dvipdfm_x
+enable_dvipng
+enable_debug
+enable_timing
+with_gs
+enable_dvipos
+enable_dvipsk
+enable_dvisvgm
+enable_gregorio
+enable_gsftopk
+enable_lcdf_typetools
+enable_cfftot1
+enable_mmafm
+enable_mmpfb
+enable_otfinfo
+enable_otftotfm
+enable_t1dotlessj
+enable_t1lint
+enable_t1rawafm
+enable_t1reencode
+enable_t1testpage
+enable_ttftotype42
+enable_updmap
+enable_makeindexk
+enable_makejvf
+enable_mendexk
+enable_musixtnt
+enable_ps2pk
+enable_psutils
+enable_seetexk
+enable_tex4htk
+enable_ttf2pk2
+enable_ttfdump
+enable_upmendex
+enable_xdvik
+with_xdvi_x_toolkit
 enable_texlive
 enable_linked_scripts
 with_system_harfbuzz
+with_system_icu
+with_system_teckit
 with_system_graphite2
 with_system_zziplib
+with_system_mpfi
+with_mpfi_includes
+with_mpfi_libdir
+with_system_mpfr
+with_mpfr_includes
+with_mpfr_libdir
+with_system_gmp
+with_gmp_includes
+with_gmp_libdir
+with_system_cairo
+with_system_pixman
+with_system_gd
+with_gd_includes
+with_gd_libdir
+with_system_potrace
+with_potrace_includes
+with_potrace_libdir
+with_system_freetype2
 with_system_libpng
+with_system_libpaper
+with_libpaper_includes
+with_libpaper_libdir
 with_system_luajit
 with_system_zlib
 with_zlib_includes
 with_zlib_libdir
+with_system_ptexenc
 with_system_kpathsea
 enable_mktexmf_default
 enable_mktexpk_default
@@ -1552,6 +1641,22 @@ Optional Features:
                           lib/PLATFORM
   --enable-cxx-runtime-hack  link C++ runtime statically
   --enable-libtool-hack   ignore libtool dependency_libs
+  --disable-autosp        do not build the autosp package
+  --disable-axodraw2      do not build the axodraw2 package
+  --disable-devnag        do not build the devnag package
+  --disable-lacheck       do not build the lacheck package
+  --disable-m-tx          do not build the m-tx package
+  --disable-pmx           do not build the pmx package
+  --disable-ps2eps        do not build the ps2eps package
+  --disable-t1utils       do not build the t1utils package
+  --disable-texdoctk      do not build the texdoctk package
+  --disable-tpic2pdftex   do not build the tpic2pdftex package
+  --disable-vlna          do not build the vlna package
+  --enable-xindy          build the xindy package
+  --enable-xindy-rules      build and install make-rules package
+  --enable-xindy-docs       build and install documentation
+  --disable-xml2pmx       do not build the xml2pmx package
+  --disable-xpdfopen      do not build the xpdfopen package
   --disable-web2c         do not build the web2c (TeX & Co.) package
   --enable-auto-core        cause TeX&MF to dump core, given a certain
                             filename
@@ -1599,6 +1704,57 @@ Optional Features:
   --enable-unitermwin         include Uniterm window support
   --disable-web-progs       do not build WEB programs bibtex ... weave
   --disable-synctex         do not build the SyncTeX library and tool
+  --disable-afm2pl        do not build the afm2pl package
+  --disable-bibtex-x      do not build the bibtex-x package
+  --disable-bibtex8         do not build the bibtex8 program
+  --disable-bibtexu         do not build the bibtexu program
+  --disable-chktex        do not build the chktex package
+  --disable-cjkutils      do not build the cjkutils package
+  --disable-detex         do not build the detex package
+  --disable-dtl           do not build the dtl package
+  --disable-dvi2tty       do not build the dvi2tty package
+  --disable-dvidvi        do not build the dvidvi package
+  --disable-dviljk        do not build the dviljk package
+  --disable-dviout-util   do not build the dviout-util package
+  --disable-dvipdfm-x     do not build the dvipdfm-x package
+  --disable-dvipng        do not build the dvipng package
+  --disable-debug           Compile without debug (-d) option
+  --enable-timing           Output execution time of dvipng
+  --disable-dvipos        do not build the dvipos package
+  --disable-dvipsk        do not build the dvipsk package
+  --disable-dvisvgm       do not build the dvisvgm package
+  --disable-gregorio      do not build the gregorio package
+  --disable-gsftopk       do not build the gsftopk package
+  --disable-lcdf-typetools
+                          do not build the lcdf-typetools package
+  --disable-cfftot1         do not build the cfftot1 program
+  --disable-mmafm           do not build the mmafm program
+  --disable-mmpfb           do not build the mmpfb program
+  --disable-otfinfo         do not build the otfinfo program
+  --disable-otftotfm        do not build the otftotfm program
+  --disable-t1dotlessj      do not build the t1dotlessj program
+  --disable-t1lint          do not build the t1lint program
+  --disable-t1rawafm        do not build the t1rawafm program
+  --disable-t1reencode      do not build the t1reencode program
+  --disable-t1testpage      do not build the t1testpage program
+  --disable-ttftotype42     do not build the ttftotype42 program
+  --disable-auto-cfftot1    disable running cfftot1 from otftotfm
+  --disable-auto-t1dotlessj disable running t1dotlessj from otftotfm
+  --disable-auto-ttftotype42
+                            disable running ttftotype42 from otftotfm
+  --disable-auto-updmap     disable running updmap from otftotfm
+  --disable-makeindexk    do not build the makeindexk package
+  --disable-makejvf       do not build the makejvf package
+  --disable-mendexk       do not build the mendexk package
+  --disable-musixtnt      do not build the musixtnt package
+  --disable-ps2pk         do not build the ps2pk package
+  --disable-psutils       do not build the psutils package
+  --disable-seetexk       do not build the seetexk package
+  --disable-tex4htk       do not build the tex4htk package
+  --disable-ttf2pk2       do not build the ttf2pk2 package
+  --disable-ttfdump       do not build the ttfdump package
+  --disable-upmendex      do not build the upmendex package
+  --disable-xdvik         do not build the xdvik package
   --disable-texlive       do not build the texlive (TeX Live scripts) package
   --disable-linked-scripts  do not install the linked scripts
   --disable-mktexmf-default   do not run mktexmf if MF source missing
@@ -1636,24 +1792,68 @@ Optional Features:
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-clisp-runtime=PATH
+                          pathname of clisp runtime to install for `xindy',
+                          `default' to derive from clisp, or `system' to use
+                          installed version
   --with-banner-add=STR   add STR to version string appended to banner lines
   --with-editor=CMD       invoke CMD from the `e' option [vi +%d '%s'] or
                           [texworks --position=%d "%s"]
   --with-mf-x-toolkit     use X toolkit for METAFONT
+  --with-gs=/PATH/TO/gs   Hard-wire the location of GhostScript
+  --with-xdvi-x-toolkit=KIT
+                          Use toolkit KIT (xaw/motif/xaw3d/neXtaw) for xdvi
+                          [default: Xaw]
   --with-system-harfbuzz  use installed harfbuzz headers and library (requires
                           pkg-config)
+  --with-system-icu       use installed ICU headers and libraries (requires
+                          pkg-config or icu-config)
+  --with-system-teckit    use installed teckit headers and library (requires
+                          pkg-config)
   --with-system-graphite2 use installed graphite2 headers and library
                           (requires pkg-config)
   --with-system-zziplib   use installed zziplib headers and library (requires
                           pkg-config)
+  --with-system-mpfi      use installed mpfi headers and library
+  --with-mpfi-includes=DIR
+                          mpfi headers installed in DIR
+  --with-mpfi-libdir=DIR  mpfi library installed in DIR
+  --with-system-mpfr      use installed mpfr headers and library
+  --with-mpfr-includes=DIR
+                          mpfr headers installed in DIR
+  --with-mpfr-libdir=DIR  mpfr library installed in DIR
+  --with-system-gmp       use installed gmp headers and library
+  --with-gmp-includes=DIR gmp headers installed in DIR
+  --with-gmp-libdir=DIR   gmp library installed in DIR
+  --with-system-cairo     use installed cairo headers and library (requires
+                          pkg-config)
+  --with-system-pixman    use installed pixman headers and library (requires
+                          pkg-config)
+  --with-system-gd        use installed gd headers and library
+  --with-gd-includes=DIR  gd headers installed in DIR
+  --with-gd-libdir=DIR    gd library installed in DIR
+  --with-system-potrace   use installed potrace headers and library
+  --with-potrace-includes=DIR
+                          potrace headers installed in DIR
+  --with-potrace-libdir=DIR
+                          potrace library installed in DIR
+  --with-system-freetype2 use installed freetype2 headers and library
+                          (requires freetype-config)
   --with-system-libpng    use installed libpng headers and library (requires
                           pkg-config)
+  --with-system-libpaper  use installed libpaper headers and library
+  --with-libpaper-includes=DIR
+                          libpaper headers installed in DIR
+  --with-libpaper-libdir=DIR
+                          libpaper library installed in DIR
   --with-system-luajit    use installed luajit headers and library (requires
                           pkg-config)
   --with-system-zlib      use installed zlib headers and library
   --with-zlib-includes=DIR
                           zlib headers installed in DIR
   --with-zlib-libdir=DIR  zlib library installed in DIR
+  --with-system-ptexenc   use installed ptexenc headers and library (requires
+                          pkg-config)
   --with-system-kpathsea  use installed kpathsea headers and library (requires
                           pkg-config)
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
@@ -5065,6 +5265,333 @@ printf "%s\n" "$as_me: $host -> \`--disable-mfluajit-nowin'" >&6;}
 esac ;;
 esac
 
+## utils/autosp/ac/withenable.ac: configure.ac fragment for Tl subdir
+## configure options and TL libraries required for autosp.
+# Check whether --enable-autosp was given.
+if test ${enable_autosp+y}
+then :
+  enableval=$enable_autosp;
+fi
+case $enable_autosp in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_autosp=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-autosp=$enable_autosp'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-autosp=$enable_autosp'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-autosp=$enable_autosp'"
+    ;;
+esac
+
+## utils/axodraw2/ac/withenable.ac: configure.ac fragment for TL subdir
+## configure options and TL libraries for axodraw2.
+# Check whether --enable-axodraw2 was given.
+if test ${enable_axodraw2+y}
+then :
+  enableval=$enable_axodraw2;
+fi
+case $enable_axodraw2 in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_axodraw2=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-axodraw2=$enable_axodraw2'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-axodraw2=$enable_axodraw2'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-axodraw2=$enable_axodraw2'"
+    ;;
+esac
+
+## utils/devnag/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/devnag/
+## configure options and TL libraries required for devnag
+# Check whether --enable-devnag was given.
+if test ${enable_devnag+y}
+then :
+  enableval=$enable_devnag;
+fi
+case $enable_devnag in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_devnag=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-devnag=$enable_devnag'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-devnag=$enable_devnag'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-devnag=$enable_devnag'"
+    ;;
+esac
+
+## utils/lacheck/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/lacheck/
+## configure options and TL libraries required for lacheck
+# Check whether --enable-lacheck was given.
+if test ${enable_lacheck+y}
+then :
+  enableval=$enable_lacheck;
+fi
+case $enable_lacheck in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_lacheck=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-lacheck=$enable_lacheck'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-lacheck=$enable_lacheck'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-lacheck=$enable_lacheck'"
+    ;;
+esac
+
+## utils/m-tx/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/m-tx/
+## configure options and TL libraries required for mtx
+# Check whether --enable-m-tx was given.
+if test ${enable_m_tx+y}
+then :
+  enableval=$enable_m_tx;
+fi
+case $enable_m_tx in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_m_tx=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-m-tx=$enable_m_tx'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-m-tx=$enable_m_tx'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-m-tx=$enable_m_tx'"
+    ;;
+esac
+
+## utils/pmx/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/pmx/
+## configure options and TL libraries required for pmx
+# Check whether --enable-pmx was given.
+if test ${enable_pmx+y}
+then :
+  enableval=$enable_pmx;
+fi
+case $enable_pmx in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_pmx=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-pmx=$enable_pmx'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-pmx=$enable_pmx'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-pmx=$enable_pmx'"
+    ;;
+esac
+
+## utils/ps2eps/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/ps2eps/
+## configure options and TL libraries required for ps2eps
+# Check whether --enable-ps2eps was given.
+if test ${enable_ps2eps+y}
+then :
+  enableval=$enable_ps2eps;
+fi
+case $enable_ps2eps in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_ps2eps=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-ps2eps=$enable_ps2eps'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-ps2eps=$enable_ps2eps'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-ps2eps=$enable_ps2eps'"
+    ;;
+esac
+
+## utils/t1utils/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/t1utils/
+## configure options and TL libraries required for t1utils
+# Check whether --enable-t1utils was given.
+if test ${enable_t1utils+y}
+then :
+  enableval=$enable_t1utils;
+fi
+case $enable_t1utils in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_t1utils=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-t1utils=$enable_t1utils'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-t1utils=$enable_t1utils'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-t1utils=$enable_t1utils'"
+    ;;
+esac
+
+## utils/texdoctk/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/texdoctk/
+## configure options and TL libraries required for texdoctk
+# Check whether --enable-texdoctk was given.
+if test ${enable_texdoctk+y}
+then :
+  enableval=$enable_texdoctk;
+fi
+case $enable_texdoctk in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_texdoctk=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-texdoctk=$enable_texdoctk'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-texdoctk=$enable_texdoctk'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-texdoctk=$enable_texdoctk'"
+    ;;
+esac
+
+## utils/tpic2pdftex/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/tpic2pdftex/
+## configure options and TL libraries required for tpic2pdftex
+# Check whether --enable-tpic2pdftex was given.
+if test ${enable_tpic2pdftex+y}
+then :
+  enableval=$enable_tpic2pdftex;
+fi
+case $enable_tpic2pdftex in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_tpic2pdftex=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-tpic2pdftex=$enable_tpic2pdftex'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-tpic2pdftex=$enable_tpic2pdftex'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-tpic2pdftex=$enable_tpic2pdftex'"
+    ;;
+esac
+
+## utils/vlna/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/vlna/
+## configure options and TL libraries required for vlna
+# Check whether --enable-vlna was given.
+if test ${enable_vlna+y}
+then :
+  enableval=$enable_vlna;
+fi
+case $enable_vlna in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_vlna=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-vlna=$enable_vlna'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-vlna=$enable_vlna'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-vlna=$enable_vlna'"
+    ;;
+esac
+
+## utils/xindy/ac/withenable.ac: configure.ac fragment for TL subdir
+## configure options and TL libraries required for xindy.
+# Check whether --enable-xindy was given.
+if test ${enable_xindy+y}
+then :
+  enableval=$enable_xindy;
+fi
+case $enable_xindy in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_xindy=no
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-xindy=$enable_xindy'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-xindy=$enable_xindy'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-xindy=$enable_xindy'"
+    ;;
+esac
+
+## utils/xindy/ac/xindy.ac: configure.ac fragment for the TeX Live subdirectory utils/xindy/
+## configure options for xindy
+# Check whether --enable-xindy-rules was given.
+if test ${enable_xindy_rules+y}
+then :
+  enableval=$enable_xindy_rules;
+fi
+# Check whether --enable-xindy-docs was given.
+if test ${enable_xindy_docs+y}
+then :
+  enableval=$enable_xindy_docs;
+fi
+
+# Check whether --with-clisp-runtime was given.
+if test ${with_clisp_runtime+y}
+then :
+  withval=$with_clisp_runtime;
+fi
+
+## utils/xindy/ac/clisp.ac: configure.ac fragment for the TeX Live subdirectory utils/xindy/
+## configure checks for xindy and clisp
+case $with_clisp_runtime in #(
+  default) :
+     ;; #(
+  system) :
+    if test "x$enable_native_texlive_build" = xyes
+then :
+  as_fn_error $? "you can not use the installed clisp for a native TeX Live build" "$LINENO" 5
+fi ;; #(
+  "") :
+    if test "x$enable_native_texlive_build" = xyes
+then :
+  with_clisp_runtime=default
+else case e in #(
+  e) with_clisp_runtime=system ;;
+esac
+fi
+               { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--with-clisp-runtime=$with_clisp_runtime'" >&5
+printf "%s\n" "$as_me: Assuming \`--with-clisp-runtime=$with_clisp_runtime'" >&6;}
+               ac_configure_args="$ac_configure_args '--with-clisp-runtime=$with_clisp_runtime'" ;; #(
+  *) :
+    if test ! -f "$with_clisp_runtime"
+then :
+  as_fn_error $? "no such file: \"$with_clisp_runtime\"" "$LINENO" 5
+fi ;;
+esac
+
+## utils/xml2pmx/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/xml2pmx/
+## configure options and TL libraries required for xml2pmx
+# Check whether --enable-xml2pmx was given.
+if test ${enable_xml2pmx+y}
+then :
+  enableval=$enable_xml2pmx;
+fi
+case $enable_xml2pmx in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_xml2pmx=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-xml2pmx=$enable_xml2pmx'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-xml2pmx=$enable_xml2pmx'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-xml2pmx=$enable_xml2pmx'"
+    ;;
+esac
+
+## utils/xpdfopen/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/xpdfopen/
+## configure options and TL libraries required for xpdfopen
+# Check whether --enable-xpdfopen was given.
+if test ${enable_xpdfopen+y}
+then :
+  enableval=$enable_xpdfopen;
+fi
+if test "x$with_x" = xno
+then :
+  case $enable_xpdfopen in #(
+  "") :
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \`--without-x' -> \`--disable-xpdfopen'" >&5
+printf "%s\n" "$as_me: \`--without-x' -> \`--disable-xpdfopen'" >&6;}
+                      enable_xpdfopen=no
+                      ac_configure_args="$ac_configure_args '--disable-xpdfopen'" ;; #(
+  yes) :
+    as_fn_error $? "Sorry, incompatible options \`--without-x' and \`--enable-xpdfopen'" "$LINENO" 5 ;; #(
+  *) :
+     ;;
+esac
+fi
+case $enable_xpdfopen in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_xpdfopen=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-xpdfopen=$enable_xpdfopen'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-xpdfopen=$enable_xpdfopen'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-xpdfopen=$enable_xpdfopen'"
+    ;;
+esac
+
 
 ## texk/web2c/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/web2c/
 ## configure options and TL libraries required for web2c
@@ -5579,475 +6106,1919 @@ then :
 fi
 
 
-## texk/texlive/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/texlive/
-## configure options and TL libraries required for texlive
-# Check whether --enable-texlive was given.
-if test ${enable_texlive+y}
+## texk/afm2pl/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/afm2pl/
+## configure options and TL libraries required for afm2pl
+# Check whether --enable-afm2pl was given.
+if test ${enable_afm2pl+y}
 then :
-  enableval=$enable_texlive;
+  enableval=$enable_afm2pl;
 fi
-case $enable_texlive in #(
+case $enable_afm2pl in #(
   yes|no) :
      ;; #(
   *) :
 
-   enable_texlive=$enable_all_pkgs
-     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-texlive=$enable_texlive'" >&5
-printf "%s\n" "$as_me: Assuming \`--enable-texlive=$enable_texlive'" >&6;}
-     ac_configure_args="$ac_configure_args '--enable-texlive=$enable_texlive'"
+   enable_afm2pl=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-afm2pl=$enable_afm2pl'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-afm2pl=$enable_afm2pl'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-afm2pl=$enable_afm2pl'"
     ;;
 esac
 
-## texk/texlive/ac/texlive.ac: configure.ac fragment for the TeX Live subdirectory texk/texlive/
-## configure options for texlive
-# Check whether --enable-linked-scripts was given.
-if test ${enable_linked_scripts+y}
+test "x$enable_afm2pl" = xno || {
+  need_kpathsea=yes
+}
+
+## texk/bibtex-x/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/bibtex-x/
+## configure options and TL libraries required for bibtex-x
+# Check whether --enable-bibtex-x was given.
+if test ${enable_bibtex_x+y}
 then :
-  enableval=$enable_linked_scripts;
+  enableval=$enable_bibtex_x;
 fi
+case $enable_bibtex_x in #(
+  yes|no) :
+     ;; #(
+  *) :
 
+   enable_bibtex_x=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-bibtex-x=$enable_bibtex_x'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-bibtex-x=$enable_bibtex_x'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-bibtex-x=$enable_bibtex_x'"
+    ;;
+esac
 
-## libs/pplib/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/pplib/
-## configure options and TL libraries required for pplib
-
-test "x$need_pplib" = xyes && {
-  need_zlib=yes
+test "x$enable_bibtex_x" = xno || {
+  need_kpathsea=yes
 }
 
-## libs/harfbuzz/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/harfbuzz/
-## configure options and TL libraries required for harfbuzz
-
-# Check whether --with-system-harfbuzz was given.
-if test ${with_system_harfbuzz+y}
+## texk/bibtex-x/ac/bibtex-x.ac: configure.ac fragment for the TeX Live subdirectory texk/bibtex-x/
+## configure options for bibtex-x
+# Check whether --enable-bibtex8 was given.
+if test ${enable_bibtex8+y}
 then :
-  withval=$with_system_harfbuzz;
-fi
-if test "x$with_system_harfbuzz" = x; then
-  if test -f $srcdir/libs/harfbuzz/configure; then
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`harfbuzz' headers and library from TL tree" >&5
-printf "%s\n" "$as_me: Assuming \`harfbuzz' headers and library from TL tree" >&6;}
-    with_system_harfbuzz=no
-  else
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`harfbuzz' headers and library" >&5
-printf "%s\n" "$as_me: Assuming installed \`harfbuzz' headers and library" >&6;}
-    with_system_harfbuzz=yes
-  fi
-  ac_configure_args="$ac_configure_args '--with-system-harfbuzz=$with_system_harfbuzz'"
-elif test "x$with_system_harfbuzz" = xyes; then
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`harfbuzz' headers and library" >&5
-printf "%s\n" "$as_me: Using installed \`harfbuzz' headers and library" >&6;}
-else
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`harfbuzz' headers and library from TL tree" >&5
-printf "%s\n" "$as_me: Using \`harfbuzz' headers and library from TL tree" >&6;}
-  if test "x$with_system_harfbuzz" != xno; then
-    with_system_harfbuzz=no
-    ac_configure_args="$ac_configure_args '--without-system-harfbuzz'"
-  fi
+  enableval=$enable_bibtex8;
 fi
-if test "x$with_system_harfbuzz" = xyes; then
-  if test "x$with_system_graphite2" = x; then
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`graphite2' headers and library" >&5
-printf "%s\n" "$as_me:   ->  installed \`graphite2' headers and library" >&6;}
-    with_system_graphite2=yes
-    ac_configure_args="$ac_configure_args '--with-system-graphite2'"
-  elif test "x$with_system_graphite2" != xyes; then
-    as_fn_error $? "Sorry, \`--with-system-harfbuzz' requires \`--with-system-graphite2'" "$LINENO" 5
-  fi
-  if test "x$with_system_icu" = x; then
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`icu' headers and library" >&5
-printf "%s\n" "$as_me:   ->  installed \`icu' headers and library" >&6;}
-    with_system_icu=yes
-    ac_configure_args="$ac_configure_args '--with-system-icu'"
-  elif test "x$with_system_icu" != xyes; then
-    as_fn_error $? "Sorry, \`--with-system-harfbuzz' requires \`--with-system-icu'" "$LINENO" 5
-  fi
+
+case $enable_bibtex8 in #(
+  yes | no) :
+     ;; #(
+  *) :
+    enable_bibtex8=yes ;;
+esac
+# Check whether --enable-bibtexu was given.
+if test ${enable_bibtexu+y}
+then :
+  enableval=$enable_bibtexu;
 fi
 
-test "x$need_harfbuzz" = xyes && {
-  need_graphite2=yes
-  need_icu=yes
-}
+case $enable_bibtexu in #(
+  yes | no) :
+     ;; #(
+  *) :
+    enable_bibtexu=yes ;;
+esac
 
-## libs/graphite2/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/graphite2/
-## configure options and TL libraries required for graphite2
+test "x$enable_bibtex_x:$enable_bibtexu" = xyes:yes && need_icu=yes
 
-# Check whether --with-system-graphite2 was given.
-if test ${with_system_graphite2+y}
+## texk/chktex/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/chktex/
+## configure options and TL libraries required for chktex
+# Check whether --enable-chktex was given.
+if test ${enable_chktex+y}
 then :
-  withval=$with_system_graphite2;
-fi
-if test "x$with_system_graphite2" = x; then
-  if test -f $srcdir/libs/graphite2/configure; then
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`graphite2' headers and library from TL tree" >&5
-printf "%s\n" "$as_me: Assuming \`graphite2' headers and library from TL tree" >&6;}
-    with_system_graphite2=no
-  else
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`graphite2' headers and library" >&5
-printf "%s\n" "$as_me: Assuming installed \`graphite2' headers and library" >&6;}
-    with_system_graphite2=yes
-  fi
-  ac_configure_args="$ac_configure_args '--with-system-graphite2=$with_system_graphite2'"
-elif test "x$with_system_graphite2" = xyes; then
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`graphite2' headers and library" >&5
-printf "%s\n" "$as_me: Using installed \`graphite2' headers and library" >&6;}
-else
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`graphite2' headers and library from TL tree" >&5
-printf "%s\n" "$as_me: Using \`graphite2' headers and library from TL tree" >&6;}
-  if test "x$with_system_graphite2" != xno; then
-    with_system_graphite2=no
-    ac_configure_args="$ac_configure_args '--without-system-graphite2'"
-  fi
+  enableval=$enable_chktex;
 fi
+case $enable_chktex in #(
+  yes|no) :
+     ;; #(
+  *) :
 
-## libs/zziplib/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/zziplib/
-## configure options and TL libraries required for zziplib
+   enable_chktex=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-chktex=$enable_chktex'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-chktex=$enable_chktex'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-chktex=$enable_chktex'"
+    ;;
+esac
 
-# Check whether --with-system-zziplib was given.
-if test ${with_system_zziplib+y}
+test "x$enable_chktex" = xno || {
+  need_kpathsea=yes
+}
+
+## texk/cjkutils/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/cjkutils/
+## configure options and TL libraries required for cjkutils
+# Check whether --enable-cjkutils was given.
+if test ${enable_cjkutils+y}
 then :
-  withval=$with_system_zziplib;
-fi
-if test "x$with_system_zziplib" = x; then
-  if test -f $srcdir/libs/zziplib/configure; then
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`zziplib' headers and library from TL tree" >&5
-printf "%s\n" "$as_me: Assuming \`zziplib' headers and library from TL tree" >&6;}
-    with_system_zziplib=no
-  else
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`zziplib' headers and library" >&5
-printf "%s\n" "$as_me: Assuming installed \`zziplib' headers and library" >&6;}
-    with_system_zziplib=yes
-  fi
-  ac_configure_args="$ac_configure_args '--with-system-zziplib=$with_system_zziplib'"
-elif test "x$with_system_zziplib" = xyes; then
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`zziplib' headers and library" >&5
-printf "%s\n" "$as_me: Using installed \`zziplib' headers and library" >&6;}
-else
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`zziplib' headers and library from TL tree" >&5
-printf "%s\n" "$as_me: Using \`zziplib' headers and library from TL tree" >&6;}
-  if test "x$with_system_zziplib" != xno; then
-    with_system_zziplib=no
-    ac_configure_args="$ac_configure_args '--without-system-zziplib'"
-  fi
-fi
-if test "x$with_system_zziplib" = xyes; then
-  if test "x$with_system_zlib" = x; then
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`zlib' headers and library" >&5
-printf "%s\n" "$as_me:   ->  installed \`zlib' headers and library" >&6;}
-    with_system_zlib=yes
-    ac_configure_args="$ac_configure_args '--with-system-zlib'"
-  elif test "x$with_system_zlib" != xyes; then
-    as_fn_error $? "Sorry, \`--with-system-zziplib' requires \`--with-system-zlib'" "$LINENO" 5
-  fi
+  enableval=$enable_cjkutils;
 fi
+case $enable_cjkutils in #(
+  yes|no) :
+     ;; #(
+  *) :
 
-test "x$need_zziplib" = xyes && {
-  need_zlib=yes
-}
+   enable_cjkutils=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-cjkutils=$enable_cjkutils'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-cjkutils=$enable_cjkutils'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-cjkutils=$enable_cjkutils'"
+    ;;
+esac
 
-## libs/libpng/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/libpng/
-## configure options and TL libraries required for libpng
+test "x$enable_cjkutils" = xno || {
+  need_kpathsea=yes
+}
 
-# Check whether --with-system-libpng was given.
-if test ${with_system_libpng+y}
+## texk/detex/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/detex/
+## configure options and TL libraries required for detex
+# Check whether --enable-detex was given.
+if test ${enable_detex+y}
 then :
-  withval=$with_system_libpng;
+  enableval=$enable_detex;
 fi
-if test "x$with_system_libpng" = x; then
-  if test -f $srcdir/libs/libpng/configure; then
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`libpng' headers and library from TL tree" >&5
-printf "%s\n" "$as_me: Assuming \`libpng' headers and library from TL tree" >&6;}
-    with_system_libpng=no
-  else
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`libpng' headers and library" >&5
-printf "%s\n" "$as_me: Assuming installed \`libpng' headers and library" >&6;}
-    with_system_libpng=yes
-  fi
-  ac_configure_args="$ac_configure_args '--with-system-libpng=$with_system_libpng'"
-elif test "x$with_system_libpng" = xyes; then
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`libpng' headers and library" >&5
-printf "%s\n" "$as_me: Using installed \`libpng' headers and library" >&6;}
-else
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`libpng' headers and library from TL tree" >&5
-printf "%s\n" "$as_me: Using \`libpng' headers and library from TL tree" >&6;}
-  if test "x$with_system_libpng" != xno; then
-    with_system_libpng=no
-    ac_configure_args="$ac_configure_args '--without-system-libpng'"
-  fi
+case $enable_detex in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_detex=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-detex=$enable_detex'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-detex=$enable_detex'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-detex=$enable_detex'"
+    ;;
+esac
+
+test "x$enable_detex" = xno || {
+  need_kpathsea=yes
+}
+
+## texk/dtl/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/dtl/
+## configure options and TL libraries required for dtl
+# Check whether --enable-dtl was given.
+if test ${enable_dtl+y}
+then :
+  enableval=$enable_dtl;
 fi
-if test "x$with_system_libpng" = xyes; then
-  if test "x$with_system_zlib" = x; then
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`zlib' headers and library" >&5
-printf "%s\n" "$as_me:   ->  installed \`zlib' headers and library" >&6;}
-    with_system_zlib=yes
-    ac_configure_args="$ac_configure_args '--with-system-zlib'"
-  elif test "x$with_system_zlib" != xyes; then
-    as_fn_error $? "Sorry, \`--with-system-libpng' requires \`--with-system-zlib'" "$LINENO" 5
-  fi
+case $enable_dtl in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_dtl=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-dtl=$enable_dtl'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-dtl=$enable_dtl'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-dtl=$enable_dtl'"
+    ;;
+esac
+
+test "x$enable_dtl" = xno || {
+  need_kpathsea=yes
+}
+
+## texk/dvi2tty/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/dvi2tty/
+## configure options and TL libraries required for dvi2tty
+# Check whether --enable-dvi2tty was given.
+if test ${enable_dvi2tty+y}
+then :
+  enableval=$enable_dvi2tty;
 fi
+case $enable_dvi2tty in #(
+  yes|no) :
+     ;; #(
+  *) :
 
-test "x$need_libpng" = xyes && {
-  need_zlib=yes
+   enable_dvi2tty=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-dvi2tty=$enable_dvi2tty'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-dvi2tty=$enable_dvi2tty'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-dvi2tty=$enable_dvi2tty'"
+    ;;
+esac
+
+test "x$enable_dvi2tty" = xno || {
+  need_ptexenc=yes
 }
 
-## libs/luajit/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/luajit/
-## configure options and TL libraries required for luajit
+## texk/dvidvi/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/dvidvi/
+## configure options and TL libraries required for dvidvi
+# Check whether --enable-dvidvi was given.
+if test ${enable_dvidvi+y}
+then :
+  enableval=$enable_dvidvi;
+fi
+case $enable_dvidvi in #(
+  yes|no) :
+     ;; #(
+  *) :
 
-# Check whether --with-system-luajit was given.
-if test ${with_system_luajit+y}
+   enable_dvidvi=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-dvidvi=$enable_dvidvi'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-dvidvi=$enable_dvidvi'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-dvidvi=$enable_dvidvi'"
+    ;;
+esac
+
+test "x$enable_dvidvi" = xno || {
+  need_kpathsea=yes
+}
+
+## texk/dviljk/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/dviljk/
+## configure options and TL libraries required for dviljk
+# Check whether --enable-dviljk was given.
+if test ${enable_dviljk+y}
 then :
-  withval=$with_system_luajit;
+  enableval=$enable_dviljk;
 fi
-if test "x$with_system_luajit" = x; then
-  if test -f $srcdir/libs/luajit/configure; then
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`luajit' headers and library from TL tree" >&5
-printf "%s\n" "$as_me: Assuming \`luajit' headers and library from TL tree" >&6;}
-    with_system_luajit=no
-  else
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`luajit' headers and library" >&5
-printf "%s\n" "$as_me: Assuming installed \`luajit' headers and library" >&6;}
-    with_system_luajit=yes
-  fi
-  ac_configure_args="$ac_configure_args '--with-system-luajit=$with_system_luajit'"
-elif test "x$with_system_luajit" = xyes; then
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`luajit' headers and library" >&5
-printf "%s\n" "$as_me: Using installed \`luajit' headers and library" >&6;}
-else
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`luajit' headers and library from TL tree" >&5
-printf "%s\n" "$as_me: Using \`luajit' headers and library from TL tree" >&6;}
-  if test "x$with_system_luajit" != xno; then
-    with_system_luajit=no
-    ac_configure_args="$ac_configure_args '--without-system-luajit'"
-  fi
+case $enable_dviljk in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_dviljk=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-dviljk=$enable_dviljk'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-dviljk=$enable_dviljk'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-dviljk=$enable_dviljk'"
+    ;;
+esac
+
+test "x$enable_dviljk" = xno || {
+  need_kpathsea=yes
+}
+
+## texk/dviout-util/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/dviout-util/
+## configure options and TL libraries required for dviout-util
+# Check whether --enable-dviout-util was given.
+if test ${enable_dviout_util+y}
+then :
+  enableval=$enable_dviout_util;
 fi
+case $enable_dviout_util in #(
+  yes|no) :
+     ;; #(
+  *) :
 
-## libs/lua53/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/lua53/
-## configure options and TL libraries required for lua53
+   enable_dviout_util=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-dviout-util=$enable_dviout_util'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-dviout-util=$enable_dviout_util'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-dviout-util=$enable_dviout_util'"
+    ;;
+esac
 
-## libs/zlib/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/zlib/
-## configure options and TL libraries required for zlib
+test "x$enable_dviout_util" = xno || {
+  need_ptexenc=yes
+}
 
-# Check whether --with-system-zlib was given.
-if test ${with_system_zlib+y}
+## texk/dvipdfm-x/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/dvipdfm-x/
+## configure options and TL libraries required for dvipdfm-x
+# Check whether --enable-dvipdfm-x was given.
+if test ${enable_dvipdfm_x+y}
 then :
-  withval=$with_system_zlib;
+  enableval=$enable_dvipdfm_x;
 fi
+case $enable_dvipdfm_x in #(
+  yes|no) :
+     ;; #(
+  *) :
 
-# Check whether --with-zlib-includes was given.
-if test ${with_zlib_includes+y}
+   enable_dvipdfm_x=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-dvipdfm-x=$enable_dvipdfm_x'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-dvipdfm-x=$enable_dvipdfm_x'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-dvipdfm-x=$enable_dvipdfm_x'"
+    ;;
+esac
+
+test "x$enable_dvipdfm_x" = xno || {
+  need_kpathsea=yes
+  need_libpng=yes
+  need_libpaper=yes
+}
+
+## texk/dvipng/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/dvipng/
+## configure options and TL libraries required for dvipng
+# Check whether --enable-dvipng was given.
+if test ${enable_dvipng+y}
 then :
-  withval=$with_zlib_includes;
+  enableval=$enable_dvipng;
 fi
+case $enable_dvipng in #(
+  yes|no) :
+     ;; #(
+  *) :
 
-# Check whether --with-zlib-libdir was given.
-if test ${with_zlib_libdir+y}
+   enable_dvipng=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-dvipng=$enable_dvipng'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-dvipng=$enable_dvipng'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-dvipng=$enable_dvipng'"
+    ;;
+esac
+
+test "x$enable_dvipng" = xno || {
+  need_kpathsea=yes
+  need_gd=yes
+}
+
+## texk/dvipng/ac/dvipng.ac: configure.ac fragment for the TeX Live subdirectory texk/dvipng/
+## configure options for dvipng
+# Check whether --enable-debug was given.
+if test ${enable_debug+y}
 then :
-  withval=$with_zlib_libdir;
+  enableval=$enable_debug;
 fi
-if test "x$with_system_zlib" = x; then
-  if test -f $srcdir/libs/zlib/configure; then
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`zlib' headers and library from TL tree" >&5
-printf "%s\n" "$as_me: Assuming \`zlib' headers and library from TL tree" >&6;}
-    with_system_zlib=no
-  else
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`zlib' headers and library" >&5
-printf "%s\n" "$as_me: Assuming installed \`zlib' headers and library" >&6;}
-    with_system_zlib=yes
-  fi
-  ac_configure_args="$ac_configure_args '--with-system-zlib=$with_system_zlib'"
-elif test "x$with_system_zlib" = xyes; then
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`zlib' headers and library" >&5
-printf "%s\n" "$as_me: Using installed \`zlib' headers and library" >&6;}
-else
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`zlib' headers and library from TL tree" >&5
-printf "%s\n" "$as_me: Using \`zlib' headers and library from TL tree" >&6;}
-  if test "x$with_system_zlib" != xno; then
-    with_system_zlib=no
-    ac_configure_args="$ac_configure_args '--without-system-zlib'"
-  fi
+
+# Check whether --enable-timing was given.
+if test ${enable_timing+y}
+then :
+  enableval=$enable_timing;
 fi
 
 
-## texk/kpathsea/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/kpathsea/
-## configure options and TL libraries required for kpathsea
+# Check whether --with-gs was given.
+if test ${with_gs+y}
+then :
+  withval=$with_gs;
+fi
 
-# Check whether --with-system-kpathsea was given.
-if test ${with_system_kpathsea+y}
+
+## texk/dvipos/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/dvipos/
+## configure options and TL libraries required for dvipos
+# Check whether --enable-dvipos was given.
+if test ${enable_dvipos+y}
 then :
-  withval=$with_system_kpathsea;
+  enableval=$enable_dvipos;
 fi
-if test "x$with_system_kpathsea" = x; then
-  if test -f $srcdir/texk/kpathsea/configure; then
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`kpathsea' headers and library from TL tree" >&5
-printf "%s\n" "$as_me: Assuming \`kpathsea' headers and library from TL tree" >&6;}
-    with_system_kpathsea=no
-  else
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`kpathsea' headers and library" >&5
-printf "%s\n" "$as_me: Assuming installed \`kpathsea' headers and library" >&6;}
-    with_system_kpathsea=yes
-  fi
-  ac_configure_args="$ac_configure_args '--with-system-kpathsea=$with_system_kpathsea'"
-elif test "x$with_system_kpathsea" = xyes; then
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`kpathsea' headers and library" >&5
-printf "%s\n" "$as_me: Using installed \`kpathsea' headers and library" >&6;}
-else
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`kpathsea' headers and library from TL tree" >&5
-printf "%s\n" "$as_me: Using \`kpathsea' headers and library from TL tree" >&6;}
-  if test "x$with_system_kpathsea" != xno; then
-    with_system_kpathsea=no
-    ac_configure_args="$ac_configure_args '--without-system-kpathsea'"
-  fi
+case $enable_dvipos in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_dvipos=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-dvipos=$enable_dvipos'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-dvipos=$enable_dvipos'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-dvipos=$enable_dvipos'"
+    ;;
+esac
+
+test "x$enable_dvipos" = xno || {
+  need_kpathsea=yes
+}
+
+## texk/dvipsk/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/dvipsk/
+## configure options and TL libraries required for dvipsk
+# Check whether --enable-dvipsk was given.
+if test ${enable_dvipsk+y}
+then :
+  enableval=$enable_dvipsk;
 fi
+case $enable_dvipsk in #(
+  yes|no) :
+     ;; #(
+  *) :
 
-## texk/kpathsea/ac/mktex.ac: configure.ac fragment for the TeX Live
-## subdirectory texk/kpathsea.
-## configure defaults for mktexfmt & Co.
-# Check whether --enable-mktexmf-default was given.
-if test ${enable_mktexmf_default+y}
+   enable_dvipsk=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-dvipsk=$enable_dvipsk'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-dvipsk=$enable_dvipsk'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-dvipsk=$enable_dvipsk'"
+    ;;
+esac
+
+test "x$enable_dvipsk" = xno || {
+  need_kpathsea=yes
+}
+
+# texk/dvisvgm/ac/withenable.ac: configure.ac fragment
+## configure options and TL libraries required for dvisvgm
+# Check whether --enable-dvisvgm was given.
+if test ${enable_dvisvgm+y}
 then :
-  enableval=$enable_mktexmf_default;
+  enableval=$enable_dvisvgm;
 fi
-# Check whether --enable-mktexpk-default was given.
-if test ${enable_mktexpk_default+y}
+case $enable_dvisvgm in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_dvisvgm=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-dvisvgm=$enable_dvisvgm'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-dvisvgm=$enable_dvisvgm'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-dvisvgm=$enable_dvisvgm'"
+    ;;
+esac
+
+test "x$enable_dvisvgm" = xno || {
+  need_kpathsea=yes
+  need_potrace=yes
+  need_freetype2=yes
+  need_zlib=yes
+}
+
+## texk/gregorio/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/gregorio/
+## configure options and TL libraries required for gregorio
+# Check whether --enable-gregorio was given.
+if test ${enable_gregorio+y}
 then :
-  enableval=$enable_mktexpk_default;
+  enableval=$enable_gregorio;
 fi
-# Check whether --enable-mktextfm-default was given.
-if test ${enable_mktextfm_default+y}
+case $enable_gregorio in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_gregorio=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-gregorio=$enable_gregorio'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-gregorio=$enable_gregorio'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-gregorio=$enable_gregorio'"
+    ;;
+esac
+
+test "x$enable_gregorio" = xno || {
+  need_kpathsea=yes
+}
+
+## texk/gsftopk/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/gsftopk/
+## configure options and TL libraries required for gsftopk
+# Check whether --enable-gsftopk was given.
+if test ${enable_gsftopk+y}
 then :
-  enableval=$enable_mktextfm_default;
+  enableval=$enable_gsftopk;
 fi
-# Check whether --enable-mkocp-default was given.
-if test ${enable_mkocp_default+y}
+case $enable_gsftopk in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_gsftopk=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-gsftopk=$enable_gsftopk'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-gsftopk=$enable_gsftopk'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-gsftopk=$enable_gsftopk'"
+    ;;
+esac
+
+test "x$enable_gsftopk" = xno || {
+  need_kpathsea=yes
+}
+
+## texk/lcdf-typetools/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/lcdf-typetools/
+## configure options and TL libraries required for lcdf-typetools
+# Check whether --enable-lcdf-typetools was given.
+if test ${enable_lcdf_typetools+y}
 then :
-  enableval=$enable_mkocp_default;
+  enableval=$enable_lcdf_typetools;
 fi
-# Check whether --enable-mkofm-default was given.
-if test ${enable_mkofm_default+y}
+case $enable_lcdf_typetools in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_lcdf_typetools=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-lcdf-typetools=$enable_lcdf_typetools'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-lcdf-typetools=$enable_lcdf_typetools'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-lcdf-typetools=$enable_lcdf_typetools'"
+    ;;
+esac
+
+test "x$enable_lcdf_typetools" = xno || {
+  need_kpathsea=yes
+}
+
+# Define configure options for lcdf-typetools.  Extracted from configure.ac
+# for ease of building TeX Live.
+#
+#
+# Check whether --enable-cfftot1 was given.
+if test ${enable_cfftot1+y}
 then :
-  enableval=$enable_mkofm_default;
+  enableval=$enable_cfftot1;
 fi
-# Check whether --enable-mktexfmt-default was given.
-if test ${enable_mktexfmt_default+y}
+# Check whether --enable-mmafm was given.
+if test ${enable_mmafm+y}
 then :
-  enableval=$enable_mktexfmt_default;
+  enableval=$enable_mmafm;
 fi
-# Check whether --enable-mktextex-default was given.
-if test ${enable_mktextex_default+y}
+# Check whether --enable-mmpfb was given.
+if test ${enable_mmpfb+y}
 then :
-  enableval=$enable_mktextex_default;
+  enableval=$enable_mmpfb;
+fi
+# Check whether --enable-otfinfo was given.
+if test ${enable_otfinfo+y}
+then :
+  enableval=$enable_otfinfo;
+fi
+# Check whether --enable-otftotfm was given.
+if test ${enable_otftotfm+y}
+then :
+  enableval=$enable_otftotfm;
+fi
+# Check whether --enable-t1dotlessj was given.
+if test ${enable_t1dotlessj+y}
+then :
+  enableval=$enable_t1dotlessj;
+fi
+# Check whether --enable-t1lint was given.
+if test ${enable_t1lint+y}
+then :
+  enableval=$enable_t1lint;
+fi
+# Check whether --enable-t1rawafm was given.
+if test ${enable_t1rawafm+y}
+then :
+  enableval=$enable_t1rawafm;
+fi
+# Check whether --enable-t1reencode was given.
+if test ${enable_t1reencode+y}
+then :
+  enableval=$enable_t1reencode;
+fi
+# Check whether --enable-t1testpage was given.
+if test ${enable_t1testpage+y}
+then :
+  enableval=$enable_t1testpage;
+fi
+# Check whether --enable-ttftotype42 was given.
+if test ${enable_ttftotype42+y}
+then :
+  enableval=$enable_ttftotype42;
 fi
 
+#
+# Check whether --enable-cfftot1 was given.
+if test ${enable_cfftot1+y}
+then :
+  enableval=$enable_cfftot1;
+fi
+# Check whether --enable-t1dotlessj was given.
+if test ${enable_t1dotlessj+y}
+then :
+  enableval=$enable_t1dotlessj;
+fi
+# Check whether --enable-ttftotype42 was given.
+if test ${enable_ttftotype42+y}
+then :
+  enableval=$enable_ttftotype42;
+fi
+# Check whether --enable-updmap was given.
+if test ${enable_updmap+y}
+then :
+  enableval=$enable_updmap;
+fi
 
 
-# end of kpse_setup macro.
-echo 'tldbg:KPSE_SETUP done (toplevel=)' >&5
-
+## texk/makeindexk/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/makeindexk/
+## configure options and TL libraries required for makeindexk
+# Check whether --enable-makeindexk was given.
+if test ${enable_makeindexk+y}
+then :
+  enableval=$enable_makeindexk;
+fi
+case $enable_makeindexk in #(
+  yes|no) :
+     ;; #(
+  *) :
 
-am__api_version='1.17'
+   enable_makeindexk=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-makeindexk=$enable_makeindexk'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-makeindexk=$enable_makeindexk'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-makeindexk=$enable_makeindexk'"
+    ;;
+esac
 
+test "x$enable_makeindexk" = xno || {
+  need_kpathsea=yes
+}
 
-  # Find a good install program.  We prefer a C program (faster),
-# so one script is as good as another.  But avoid the broken or
-# incompatible versions:
-# SysV /etc/install, /usr/sbin/install
-# SunOS /usr/etc/install
-# IRIX /sbin/install
-# AIX /bin/install
-# AmigaOS /C/install, which installs bootblocks on floppy discs
-# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
-# AFS /usr/afsws/bin/install, which mishandles nonexistent args
-# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
-# OS/2's system install, which has a completely different semantic
-# ./install, which can be erroneously created by make from ./install.sh.
-# Reject install programs that cannot install multiple files.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
-printf %s "checking for a BSD-compatible install... " >&6; }
-if test -z "$INSTALL"; then
-if test ${ac_cv_path_install+y}
+## texk/makejvf/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/makejvf/
+## configure options and TL libraries required for makejvf
+# Check whether --enable-makejvf was given.
+if test ${enable_makejvf+y}
 then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  case $as_dir in #(((
-    '') as_dir=./ ;;
-    */) ;;
-    *) as_dir=$as_dir/ ;;
-  esac
-    # Account for fact that we put trailing slashes in our PATH walk.
-case $as_dir in #((
-  ./ | /[cC]/* | \
-  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
-  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
-  /usr/ucb/* ) ;;
-  *)
-    # OSF1 and SCO ODT 3.0 have their own names for install.
-    # Don't use installbsd from OSF since it installs stuff as root
-    # by default.
-    for ac_prog in ginstall scoinst install; do
-      for ac_exec_ext in '' $ac_executable_extensions; do
-	if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then
-	  if test $ac_prog = install &&
-	    grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
-	    # AIX install.  It has an incompatible calling convention.
-	    :
-	  elif test $ac_prog = install &&
-	    grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
-	    # program-specific install script used by HP pwplus--don't use.
-	    :
-	  else
-	    rm -rf conftest.one conftest.two conftest.dir
-	    echo one > conftest.one
-	    echo two > conftest.two
-	    mkdir conftest.dir
-	    if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" &&
-	      test -s conftest.one && test -s conftest.two &&
-	      test -s conftest.dir/conftest.one &&
-	      test -s conftest.dir/conftest.two
-	    then
-	      ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c"
-	      break 3
-	    fi
-	  fi
-	fi
-      done
-    done
+  enableval=$enable_makejvf;
+fi
+case $enable_makejvf in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_makejvf=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-makejvf=$enable_makejvf'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-makejvf=$enable_makejvf'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-makejvf=$enable_makejvf'"
     ;;
 esac
 
-  done
-IFS=$as_save_IFS
+test "x$enable_makejvf" = xno || {
+  need_ptexenc=yes
+}
 
-rm -rf conftest.one conftest.two conftest.dir
- ;;
-esac
-fi
-  if test ${ac_cv_path_install+y}; then
-    INSTALL=$ac_cv_path_install
-  else
-    # As a last resort, use the slow shell script.  Don't cache a
-    # value for INSTALL within a source directory, because that will
-    # break other packages using the cache if that directory is
-    # removed, or if the value is a relative name.
-    INSTALL=$ac_install_sh
-  fi
+## texk/mendexk/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/mendexk/
+## configure options and TL libraries required for mendexk
+# Check whether --enable-mendexk was given.
+if test ${enable_mendexk+y}
+then :
+  enableval=$enable_mendexk;
 fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
-printf "%s\n" "$INSTALL" >&6; }
-
-# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
-# It thinks the first close brace ends the variable substitution.
-test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+case $enable_mendexk in #(
+  yes|no) :
+     ;; #(
+  *) :
 
-test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+   enable_mendexk=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-mendexk=$enable_mendexk'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-mendexk=$enable_mendexk'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-mendexk=$enable_mendexk'"
+    ;;
+esac
 
-test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+test "x$enable_mendexk" = xno || {
+  need_ptexenc=yes
+}
 
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether sleep supports fractional seconds" >&5
-printf %s "checking whether sleep supports fractional seconds... " >&6; }
-if test ${am_cv_sleep_fractional_seconds+y}
+## texk/musixtnt/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/musixtnt/
+## configure options and TL libraries required for musixtnt
+# Check whether --enable-musixtnt was given.
+if test ${enable_musixtnt+y}
+then :
+  enableval=$enable_musixtnt;
+fi
+case $enable_musixtnt in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_musixtnt=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-musixtnt=$enable_musixtnt'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-musixtnt=$enable_musixtnt'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-musixtnt=$enable_musixtnt'"
+    ;;
+esac
+
+test "x$enable_musixtnt" = xno || {
+  need_kpathsea=yes
+}
+
+## texk/ps2pk/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/ps2pk/
+## configure options and TL libraries required for ps2pk
+# Check whether --enable-ps2pk was given.
+if test ${enable_ps2pk+y}
+then :
+  enableval=$enable_ps2pk;
+fi
+case $enable_ps2pk in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_ps2pk=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-ps2pk=$enable_ps2pk'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-ps2pk=$enable_ps2pk'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-ps2pk=$enable_ps2pk'"
+    ;;
+esac
+
+test "x$enable_ps2pk" = xno || {
+  need_kpathsea=yes
+}
+
+## texk/psutils/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/psutils/
+## configure options and TL libraries required for psutils
+# Check whether --enable-psutils was given.
+if test ${enable_psutils+y}
+then :
+  enableval=$enable_psutils;
+fi
+case $enable_psutils in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_psutils=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-psutils=$enable_psutils'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-psutils=$enable_psutils'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-psutils=$enable_psutils'"
+    ;;
+esac
+
+test "x$enable_psutils" = xno || {
+  need_kpathsea=yes
+  need_libpaper=yes
+}
+
+## texk/seetexk/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/seetexk/
+## configure options and TL libraries required for seetexk
+# Check whether --enable-seetexk was given.
+if test ${enable_seetexk+y}
+then :
+  enableval=$enable_seetexk;
+fi
+case $enable_seetexk in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_seetexk=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-seetexk=$enable_seetexk'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-seetexk=$enable_seetexk'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-seetexk=$enable_seetexk'"
+    ;;
+esac
+
+test "x$enable_seetexk" = xno || {
+  need_kpathsea=yes
+}
+
+## texk/tex4htk/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/tex4htk/
+## configure options and TL libraries required for tex4htk
+# Check whether --enable-tex4htk was given.
+if test ${enable_tex4htk+y}
+then :
+  enableval=$enable_tex4htk;
+fi
+case $enable_tex4htk in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_tex4htk=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-tex4htk=$enable_tex4htk'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-tex4htk=$enable_tex4htk'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-tex4htk=$enable_tex4htk'"
+    ;;
+esac
+
+test "x$enable_tex4htk" = xno || {
+  need_kpathsea=yes
+}
+
+## texk/ttf2pk2/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/ttf2pk2/
+## configure options and TL libraries required for ttf2pk
+# Check whether --enable-ttf2pk2 was given.
+if test ${enable_ttf2pk2+y}
+then :
+  enableval=$enable_ttf2pk2;
+fi
+case $enable_ttf2pk2 in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_ttf2pk2=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-ttf2pk2=$enable_ttf2pk2'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-ttf2pk2=$enable_ttf2pk2'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-ttf2pk2=$enable_ttf2pk2'"
+    ;;
+esac
+
+test "x$enable_ttf2pk2" = xno || {
+  need_kpathsea=yes
+  need_freetype2=yes
+}
+
+## texk/ttfdump/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/ttfdump/
+## configure options and TL libraries required for ttfdump
+# Check whether --enable-ttfdump was given.
+if test ${enable_ttfdump+y}
+then :
+  enableval=$enable_ttfdump;
+fi
+case $enable_ttfdump in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_ttfdump=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-ttfdump=$enable_ttfdump'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-ttfdump=$enable_ttfdump'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-ttfdump=$enable_ttfdump'"
+    ;;
+esac
+
+test "x$enable_ttfdump" = xno || {
+  need_kpathsea=yes
+}
+
+## texk/upmendex/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/upmendex/
+## configure options and TL libraries required for upmendex
+# Check whether --enable-upmendex was given.
+if test ${enable_upmendex+y}
+then :
+  enableval=$enable_upmendex;
+fi
+case $enable_upmendex in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_upmendex=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-upmendex=$enable_upmendex'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-upmendex=$enable_upmendex'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-upmendex=$enable_upmendex'"
+    ;;
+esac
+
+test "x$enable_upmendex" = xno || {
+  need_kpathsea=yes
+  need_icu=yes
+}
+
+## texk/xdvik/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/xdvik/
+## configure options and TL libraries required for xdvik
+# Check whether --enable-xdvik was given.
+if test ${enable_xdvik+y}
+then :
+  enableval=$enable_xdvik;
+fi
+if test "x$with_x" = xno
+then :
+  case $enable_xdvik in #(
+  "") :
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \`--without-x' -> \`--disable-xdvik'" >&5
+printf "%s\n" "$as_me: \`--without-x' -> \`--disable-xdvik'" >&6;}
+                      enable_xdvik=no
+                      ac_configure_args="$ac_configure_args '--disable-xdvik'" ;; #(
+  yes) :
+    as_fn_error $? "Sorry, incompatible options \`--without-x' and \`--enable-xdvik'" "$LINENO" 5 ;; #(
+  *) :
+     ;;
+esac
+fi
+case $enable_xdvik in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_xdvik=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-xdvik=$enable_xdvik'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-xdvik=$enable_xdvik'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-xdvik=$enable_xdvik'"
+    ;;
+esac
+
+test "x$enable_xdvik" = xno || {
+  need_kpathsea=yes
+  need_freetype2=yes
+}
+
+## texk/xdvik/ac/xdvik.ac: configure.ac fragment for the TeX Live subdirectory texk/xdvik/
+## configure options for xdvik
+
+# Check whether --with-xdvi-x-toolkit was given.
+if test ${with_xdvi_x_toolkit+y}
+then :
+  withval=$with_xdvi_x_toolkit;
+fi
+
+
+## texk/texlive/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/texlive/
+## configure options and TL libraries required for texlive
+# Check whether --enable-texlive was given.
+if test ${enable_texlive+y}
+then :
+  enableval=$enable_texlive;
+fi
+case $enable_texlive in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_texlive=$enable_all_pkgs
+     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-texlive=$enable_texlive'" >&5
+printf "%s\n" "$as_me: Assuming \`--enable-texlive=$enable_texlive'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-texlive=$enable_texlive'"
+    ;;
+esac
+
+## texk/texlive/ac/texlive.ac: configure.ac fragment for the TeX Live subdirectory texk/texlive/
+## configure options for texlive
+# Check whether --enable-linked-scripts was given.
+if test ${enable_linked_scripts+y}
+then :
+  enableval=$enable_linked_scripts;
+fi
+
+
+## libs/pplib/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/pplib/
+## configure options and TL libraries required for pplib
+
+test "x$need_pplib" = xyes && {
+  need_zlib=yes
+}
+
+## libs/harfbuzz/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/harfbuzz/
+## configure options and TL libraries required for harfbuzz
+
+# Check whether --with-system-harfbuzz was given.
+if test ${with_system_harfbuzz+y}
+then :
+  withval=$with_system_harfbuzz;
+fi
+if test "x$with_system_harfbuzz" = x; then
+  if test -f $srcdir/libs/harfbuzz/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`harfbuzz' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`harfbuzz' headers and library from TL tree" >&6;}
+    with_system_harfbuzz=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`harfbuzz' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`harfbuzz' headers and library" >&6;}
+    with_system_harfbuzz=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-harfbuzz=$with_system_harfbuzz'"
+elif test "x$with_system_harfbuzz" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`harfbuzz' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`harfbuzz' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`harfbuzz' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`harfbuzz' headers and library from TL tree" >&6;}
+  if test "x$with_system_harfbuzz" != xno; then
+    with_system_harfbuzz=no
+    ac_configure_args="$ac_configure_args '--without-system-harfbuzz'"
+  fi
+fi
+if test "x$with_system_harfbuzz" = xyes; then
+  if test "x$with_system_graphite2" = x; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`graphite2' headers and library" >&5
+printf "%s\n" "$as_me:   ->  installed \`graphite2' headers and library" >&6;}
+    with_system_graphite2=yes
+    ac_configure_args="$ac_configure_args '--with-system-graphite2'"
+  elif test "x$with_system_graphite2" != xyes; then
+    as_fn_error $? "Sorry, \`--with-system-harfbuzz' requires \`--with-system-graphite2'" "$LINENO" 5
+  fi
+  if test "x$with_system_icu" = x; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`icu' headers and library" >&5
+printf "%s\n" "$as_me:   ->  installed \`icu' headers and library" >&6;}
+    with_system_icu=yes
+    ac_configure_args="$ac_configure_args '--with-system-icu'"
+  elif test "x$with_system_icu" != xyes; then
+    as_fn_error $? "Sorry, \`--with-system-harfbuzz' requires \`--with-system-icu'" "$LINENO" 5
+  fi
+fi
+
+test "x$need_harfbuzz" = xyes && {
+  need_graphite2=yes
+  need_icu=yes
+}
+
+## libs/icu/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/icu/
+## configure options and TL libraries required for icu (modified for XeTeX)
+
+# Check whether --with-system-icu was given.
+if test ${with_system_icu+y}
+then :
+  withval=$with_system_icu;
+fi
+if test "x$with_system_icu" = x; then
+  if test -f $srcdir/libs/icu/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`icu' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`icu' headers and library from TL tree" >&6;}
+    with_system_icu=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`icu' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`icu' headers and library" >&6;}
+    with_system_icu=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-icu=$with_system_icu'"
+elif test "x$with_system_icu" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`icu' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`icu' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`icu' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`icu' headers and library from TL tree" >&6;}
+  if test "x$with_system_icu" != xno; then
+    with_system_icu=no
+    ac_configure_args="$ac_configure_args '--without-system-icu'"
+  fi
+fi
+
+## libs/teckit/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/teckit/
+## configure options and TL libraries required for teckit
+
+# Check whether --with-system-teckit was given.
+if test ${with_system_teckit+y}
+then :
+  withval=$with_system_teckit;
+fi
+if test "x$with_system_teckit" = x; then
+  if test -f $srcdir/libs/teckit/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`teckit' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`teckit' headers and library from TL tree" >&6;}
+    with_system_teckit=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`teckit' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`teckit' headers and library" >&6;}
+    with_system_teckit=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-teckit=$with_system_teckit'"
+elif test "x$with_system_teckit" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`teckit' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`teckit' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`teckit' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`teckit' headers and library from TL tree" >&6;}
+  if test "x$with_system_teckit" != xno; then
+    with_system_teckit=no
+    ac_configure_args="$ac_configure_args '--without-system-teckit'"
+  fi
+fi
+if test "x$with_system_teckit" = xyes; then
+  if test "x$with_system_zlib" = x; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`zlib' headers and library" >&5
+printf "%s\n" "$as_me:   ->  installed \`zlib' headers and library" >&6;}
+    with_system_zlib=yes
+    ac_configure_args="$ac_configure_args '--with-system-zlib'"
+  elif test "x$with_system_zlib" != xyes; then
+    as_fn_error $? "Sorry, \`--with-system-teckit' requires \`--with-system-zlib'" "$LINENO" 5
+  fi
+fi
+
+test "x$need_teckit" = xyes && {
+  need_zlib=yes
+}
+
+## libs/graphite2/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/graphite2/
+## configure options and TL libraries required for graphite2
+
+# Check whether --with-system-graphite2 was given.
+if test ${with_system_graphite2+y}
+then :
+  withval=$with_system_graphite2;
+fi
+if test "x$with_system_graphite2" = x; then
+  if test -f $srcdir/libs/graphite2/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`graphite2' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`graphite2' headers and library from TL tree" >&6;}
+    with_system_graphite2=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`graphite2' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`graphite2' headers and library" >&6;}
+    with_system_graphite2=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-graphite2=$with_system_graphite2'"
+elif test "x$with_system_graphite2" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`graphite2' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`graphite2' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`graphite2' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`graphite2' headers and library from TL tree" >&6;}
+  if test "x$with_system_graphite2" != xno; then
+    with_system_graphite2=no
+    ac_configure_args="$ac_configure_args '--without-system-graphite2'"
+  fi
+fi
+
+## libs/zziplib/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/zziplib/
+## configure options and TL libraries required for zziplib
+
+# Check whether --with-system-zziplib was given.
+if test ${with_system_zziplib+y}
+then :
+  withval=$with_system_zziplib;
+fi
+if test "x$with_system_zziplib" = x; then
+  if test -f $srcdir/libs/zziplib/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`zziplib' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`zziplib' headers and library from TL tree" >&6;}
+    with_system_zziplib=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`zziplib' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`zziplib' headers and library" >&6;}
+    with_system_zziplib=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-zziplib=$with_system_zziplib'"
+elif test "x$with_system_zziplib" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`zziplib' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`zziplib' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`zziplib' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`zziplib' headers and library from TL tree" >&6;}
+  if test "x$with_system_zziplib" != xno; then
+    with_system_zziplib=no
+    ac_configure_args="$ac_configure_args '--without-system-zziplib'"
+  fi
+fi
+if test "x$with_system_zziplib" = xyes; then
+  if test "x$with_system_zlib" = x; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`zlib' headers and library" >&5
+printf "%s\n" "$as_me:   ->  installed \`zlib' headers and library" >&6;}
+    with_system_zlib=yes
+    ac_configure_args="$ac_configure_args '--with-system-zlib'"
+  elif test "x$with_system_zlib" != xyes; then
+    as_fn_error $? "Sorry, \`--with-system-zziplib' requires \`--with-system-zlib'" "$LINENO" 5
+  fi
+fi
+
+test "x$need_zziplib" = xyes && {
+  need_zlib=yes
+}
+
+## libs/xpdf/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/xpdf/
+## configure options and TL libraries required for xpdf
+: "kpse_xpdf_options - no-op"
+if test "x$with_system_xpdf" = x; then
+  if test -f $srcdir/libs/xpdf/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`xpdf' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`xpdf' headers and library from TL tree" >&6;}
+    with_system_xpdf=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`xpdf' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`xpdf' headers and library" >&6;}
+    with_system_xpdf=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-xpdf=$with_system_xpdf'"
+elif test "x$with_system_xpdf" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`xpdf' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`xpdf' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`xpdf' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`xpdf' headers and library from TL tree" >&6;}
+  if test "x$with_system_xpdf" != xno; then
+    with_system_xpdf=no
+    ac_configure_args="$ac_configure_args '--without-system-xpdf'"
+  fi
+fi
+
+## libs/mpfi/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/mpfi/
+## configure options and TL libraries required for mpfi
+
+# Check whether --with-system-mpfi was given.
+if test ${with_system_mpfi+y}
+then :
+  withval=$with_system_mpfi;
+fi
+
+# Check whether --with-mpfi-includes was given.
+if test ${with_mpfi_includes+y}
+then :
+  withval=$with_mpfi_includes;
+fi
+
+# Check whether --with-mpfi-libdir was given.
+if test ${with_mpfi_libdir+y}
+then :
+  withval=$with_mpfi_libdir;
+fi
+if test "x$with_system_mpfi" = x; then
+  if test -f $srcdir/libs/mpfi/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`mpfi' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`mpfi' headers and library from TL tree" >&6;}
+    with_system_mpfi=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`mpfi' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`mpfi' headers and library" >&6;}
+    with_system_mpfi=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-mpfi=$with_system_mpfi'"
+elif test "x$with_system_mpfi" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`mpfi' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`mpfi' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`mpfi' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`mpfi' headers and library from TL tree" >&6;}
+  if test "x$with_system_mpfi" != xno; then
+    with_system_mpfi=no
+    ac_configure_args="$ac_configure_args '--without-system-mpfi'"
+  fi
+fi
+if test "x$with_system_mpfi" = xyes; then
+  if test "x$with_system_mpfr" = x; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`mpfr' headers and library" >&5
+printf "%s\n" "$as_me:   ->  installed \`mpfr' headers and library" >&6;}
+    with_system_mpfr=yes
+    ac_configure_args="$ac_configure_args '--with-system-mpfr'"
+  elif test "x$with_system_mpfr" != xyes; then
+    as_fn_error $? "Sorry, \`--with-system-mpfi' requires \`--with-system-mpfr'" "$LINENO" 5
+  fi
+  if test "x$with_system_gmp" = x; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`gmp' headers and library" >&5
+printf "%s\n" "$as_me:   ->  installed \`gmp' headers and library" >&6;}
+    with_system_gmp=yes
+    ac_configure_args="$ac_configure_args '--with-system-gmp'"
+  elif test "x$with_system_gmp" != xyes; then
+    as_fn_error $? "Sorry, \`--with-system-mpfi' requires \`--with-system-gmp'" "$LINENO" 5
+  fi
+fi
+
+test "x$need_mpfi" = xyes && {
+  need_mpfr=yes
+  need_gmp=yes
+}
+
+## libs/mpfr/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/mpfr/
+## configure options and TL libraries required for mpfr
+
+# Check whether --with-system-mpfr was given.
+if test ${with_system_mpfr+y}
+then :
+  withval=$with_system_mpfr;
+fi
+
+# Check whether --with-mpfr-includes was given.
+if test ${with_mpfr_includes+y}
+then :
+  withval=$with_mpfr_includes;
+fi
+
+# Check whether --with-mpfr-libdir was given.
+if test ${with_mpfr_libdir+y}
+then :
+  withval=$with_mpfr_libdir;
+fi
+if test "x$with_system_mpfr" = x; then
+  if test -f $srcdir/libs/mpfr/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`mpfr' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`mpfr' headers and library from TL tree" >&6;}
+    with_system_mpfr=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`mpfr' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`mpfr' headers and library" >&6;}
+    with_system_mpfr=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-mpfr=$with_system_mpfr'"
+elif test "x$with_system_mpfr" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`mpfr' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`mpfr' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`mpfr' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`mpfr' headers and library from TL tree" >&6;}
+  if test "x$with_system_mpfr" != xno; then
+    with_system_mpfr=no
+    ac_configure_args="$ac_configure_args '--without-system-mpfr'"
+  fi
+fi
+if test "x$with_system_mpfr" = xyes; then
+  if test "x$with_system_gmp" = x; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`gmp' headers and library" >&5
+printf "%s\n" "$as_me:   ->  installed \`gmp' headers and library" >&6;}
+    with_system_gmp=yes
+    ac_configure_args="$ac_configure_args '--with-system-gmp'"
+  elif test "x$with_system_gmp" != xyes; then
+    as_fn_error $? "Sorry, \`--with-system-mpfr' requires \`--with-system-gmp'" "$LINENO" 5
+  fi
+fi
+
+test "x$need_mpfr" = xyes && {
+  need_gmp=yes
+}
+
+## libs/gmp/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/gmp/
+## configure options and TL libraries required for gmp
+
+# Check whether --with-system-gmp was given.
+if test ${with_system_gmp+y}
+then :
+  withval=$with_system_gmp;
+fi
+
+# Check whether --with-gmp-includes was given.
+if test ${with_gmp_includes+y}
+then :
+  withval=$with_gmp_includes;
+fi
+
+# Check whether --with-gmp-libdir was given.
+if test ${with_gmp_libdir+y}
+then :
+  withval=$with_gmp_libdir;
+fi
+if test "x$with_system_gmp" = x; then
+  if test -f $srcdir/libs/gmp/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`gmp' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`gmp' headers and library from TL tree" >&6;}
+    with_system_gmp=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`gmp' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`gmp' headers and library" >&6;}
+    with_system_gmp=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-gmp=$with_system_gmp'"
+elif test "x$with_system_gmp" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`gmp' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`gmp' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`gmp' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`gmp' headers and library from TL tree" >&6;}
+  if test "x$with_system_gmp" != xno; then
+    with_system_gmp=no
+    ac_configure_args="$ac_configure_args '--without-system-gmp'"
+  fi
+fi
+
+## libs/cairo/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/cairo/
+## configure options and TL libraries required for cairo
+
+# Check whether --with-system-cairo was given.
+if test ${with_system_cairo+y}
+then :
+  withval=$with_system_cairo;
+fi
+if test "x$with_system_cairo" = x; then
+  if test -f $srcdir/libs/cairo/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`cairo' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`cairo' headers and library from TL tree" >&6;}
+    with_system_cairo=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`cairo' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`cairo' headers and library" >&6;}
+    with_system_cairo=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-cairo=$with_system_cairo'"
+elif test "x$with_system_cairo" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`cairo' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`cairo' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`cairo' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`cairo' headers and library from TL tree" >&6;}
+  if test "x$with_system_cairo" != xno; then
+    with_system_cairo=no
+    ac_configure_args="$ac_configure_args '--without-system-cairo'"
+  fi
+fi
+if test "x$with_system_cairo" = xyes; then
+  if test "x$with_system_pixman" = x; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`pixman' headers and library" >&5
+printf "%s\n" "$as_me:   ->  installed \`pixman' headers and library" >&6;}
+    with_system_pixman=yes
+    ac_configure_args="$ac_configure_args '--with-system-pixman'"
+  elif test "x$with_system_pixman" != xyes; then
+    as_fn_error $? "Sorry, \`--with-system-cairo' requires \`--with-system-pixman'" "$LINENO" 5
+  fi
+fi
+
+test "x$need_cairo" = xyes && {
+  need_pixman=yes
+}
+
+## libs/pixman/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/pixman/
+## configure options and TL libraries required for pixman
+
+# Check whether --with-system-pixman was given.
+if test ${with_system_pixman+y}
+then :
+  withval=$with_system_pixman;
+fi
+if test "x$with_system_pixman" = x; then
+  if test -f $srcdir/libs/pixman/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`pixman' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`pixman' headers and library from TL tree" >&6;}
+    with_system_pixman=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`pixman' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`pixman' headers and library" >&6;}
+    with_system_pixman=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-pixman=$with_system_pixman'"
+elif test "x$with_system_pixman" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`pixman' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`pixman' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`pixman' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`pixman' headers and library from TL tree" >&6;}
+  if test "x$with_system_pixman" != xno; then
+    with_system_pixman=no
+    ac_configure_args="$ac_configure_args '--without-system-pixman'"
+  fi
+fi
+
+## libs/gd/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/gd/
+## configure options and TL libraries required for gd
+
+# Check whether --with-system-gd was given.
+if test ${with_system_gd+y}
+then :
+  withval=$with_system_gd;
+fi
+
+# Check whether --with-gd-includes was given.
+if test ${with_gd_includes+y}
+then :
+  withval=$with_gd_includes;
+fi
+
+# Check whether --with-gd-libdir was given.
+if test ${with_gd_libdir+y}
+then :
+  withval=$with_gd_libdir;
+fi
+if test "x$with_system_gd" = x; then
+  if test -f $srcdir/libs/gd/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`gd' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`gd' headers and library from TL tree" >&6;}
+    with_system_gd=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`gd' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`gd' headers and library" >&6;}
+    with_system_gd=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-gd=$with_system_gd'"
+elif test "x$with_system_gd" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`gd' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`gd' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`gd' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`gd' headers and library from TL tree" >&6;}
+  if test "x$with_system_gd" != xno; then
+    with_system_gd=no
+    ac_configure_args="$ac_configure_args '--without-system-gd'"
+  fi
+fi
+if test "x$with_system_gd" = xyes; then
+  if test "x$with_system_libpng" = x; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`libpng' headers and library" >&5
+printf "%s\n" "$as_me:   ->  installed \`libpng' headers and library" >&6;}
+    with_system_libpng=yes
+    ac_configure_args="$ac_configure_args '--with-system-libpng'"
+  elif test "x$with_system_libpng" != xyes; then
+    as_fn_error $? "Sorry, \`--with-system-gd' requires \`--with-system-libpng'" "$LINENO" 5
+  fi
+  if test "x$with_system_freetype2" = x; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`freetype2' headers and library" >&5
+printf "%s\n" "$as_me:   ->  installed \`freetype2' headers and library" >&6;}
+    with_system_freetype2=yes
+    ac_configure_args="$ac_configure_args '--with-system-freetype2'"
+  elif test "x$with_system_freetype2" != xyes; then
+    as_fn_error $? "Sorry, \`--with-system-gd' requires \`--with-system-freetype2'" "$LINENO" 5
+  fi
+fi
+
+test "x$need_gd" = xyes && {
+  need_libpng=yes
+  need_freetype2=yes
+}
+
+## libs/potrace/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/potrace/
+## configure options and TL libraries required for potrace
+
+# Check whether --with-system-potrace was given.
+if test ${with_system_potrace+y}
+then :
+  withval=$with_system_potrace;
+fi
+
+# Check whether --with-potrace-includes was given.
+if test ${with_potrace_includes+y}
+then :
+  withval=$with_potrace_includes;
+fi
+
+# Check whether --with-potrace-libdir was given.
+if test ${with_potrace_libdir+y}
+then :
+  withval=$with_potrace_libdir;
+fi
+if test "x$with_system_potrace" = x; then
+  if test -f $srcdir/libs/potrace/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`potrace' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`potrace' headers and library from TL tree" >&6;}
+    with_system_potrace=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`potrace' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`potrace' headers and library" >&6;}
+    with_system_potrace=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-potrace=$with_system_potrace'"
+elif test "x$with_system_potrace" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`potrace' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`potrace' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`potrace' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`potrace' headers and library from TL tree" >&6;}
+  if test "x$with_system_potrace" != xno; then
+    with_system_potrace=no
+    ac_configure_args="$ac_configure_args '--without-system-potrace'"
+  fi
+fi
+
+## libs/freetype2/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/freetype2/
+## configure options and TL libraries required for freetype2
+
+# Check whether --with-system-freetype2 was given.
+if test ${with_system_freetype2+y}
+then :
+  withval=$with_system_freetype2;
+fi
+if test "x$with_system_freetype2" = x; then
+  if test -f $srcdir/libs/freetype2/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`freetype2' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`freetype2' headers and library from TL tree" >&6;}
+    with_system_freetype2=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`freetype2' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`freetype2' headers and library" >&6;}
+    with_system_freetype2=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-freetype2=$with_system_freetype2'"
+elif test "x$with_system_freetype2" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`freetype2' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`freetype2' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`freetype2' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`freetype2' headers and library from TL tree" >&6;}
+  if test "x$with_system_freetype2" != xno; then
+    with_system_freetype2=no
+    ac_configure_args="$ac_configure_args '--without-system-freetype2'"
+  fi
+fi
+if test "x$with_system_freetype2" = xyes; then
+  if test "x$with_system_zlib" = x; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`zlib' headers and library" >&5
+printf "%s\n" "$as_me:   ->  installed \`zlib' headers and library" >&6;}
+    with_system_zlib=yes
+    ac_configure_args="$ac_configure_args '--with-system-zlib'"
+  elif test "x$with_system_zlib" != xyes; then
+    as_fn_error $? "Sorry, \`--with-system-freetype2' requires \`--with-system-zlib'" "$LINENO" 5
+  fi
+fi
+
+test "x$need_freetype2" = xyes && {
+  need_zlib=yes
+}
+
+## libs/libpng/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/libpng/
+## configure options and TL libraries required for libpng
+
+# Check whether --with-system-libpng was given.
+if test ${with_system_libpng+y}
+then :
+  withval=$with_system_libpng;
+fi
+if test "x$with_system_libpng" = x; then
+  if test -f $srcdir/libs/libpng/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`libpng' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`libpng' headers and library from TL tree" >&6;}
+    with_system_libpng=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`libpng' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`libpng' headers and library" >&6;}
+    with_system_libpng=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-libpng=$with_system_libpng'"
+elif test "x$with_system_libpng" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`libpng' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`libpng' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`libpng' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`libpng' headers and library from TL tree" >&6;}
+  if test "x$with_system_libpng" != xno; then
+    with_system_libpng=no
+    ac_configure_args="$ac_configure_args '--without-system-libpng'"
+  fi
+fi
+if test "x$with_system_libpng" = xyes; then
+  if test "x$with_system_zlib" = x; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`zlib' headers and library" >&5
+printf "%s\n" "$as_me:   ->  installed \`zlib' headers and library" >&6;}
+    with_system_zlib=yes
+    ac_configure_args="$ac_configure_args '--with-system-zlib'"
+  elif test "x$with_system_zlib" != xyes; then
+    as_fn_error $? "Sorry, \`--with-system-libpng' requires \`--with-system-zlib'" "$LINENO" 5
+  fi
+fi
+
+test "x$need_libpng" = xyes && {
+  need_zlib=yes
+}
+
+## libs/libpaper/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/libpaper/
+## configure options and TL libraries required for libpaper
+
+# Check whether --with-system-libpaper was given.
+if test ${with_system_libpaper+y}
+then :
+  withval=$with_system_libpaper;
+fi
+
+# Check whether --with-libpaper-includes was given.
+if test ${with_libpaper_includes+y}
+then :
+  withval=$with_libpaper_includes;
+fi
+
+# Check whether --with-libpaper-libdir was given.
+if test ${with_libpaper_libdir+y}
+then :
+  withval=$with_libpaper_libdir;
+fi
+if test "x$with_system_libpaper" = x; then
+  if test -f $srcdir/libs/libpaper/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`libpaper' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`libpaper' headers and library from TL tree" >&6;}
+    with_system_libpaper=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`libpaper' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`libpaper' headers and library" >&6;}
+    with_system_libpaper=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-libpaper=$with_system_libpaper'"
+elif test "x$with_system_libpaper" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`libpaper' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`libpaper' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`libpaper' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`libpaper' headers and library from TL tree" >&6;}
+  if test "x$with_system_libpaper" != xno; then
+    with_system_libpaper=no
+    ac_configure_args="$ac_configure_args '--without-system-libpaper'"
+  fi
+fi
+
+## libs/luajit/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/luajit/
+## configure options and TL libraries required for luajit
+
+# Check whether --with-system-luajit was given.
+if test ${with_system_luajit+y}
+then :
+  withval=$with_system_luajit;
+fi
+if test "x$with_system_luajit" = x; then
+  if test -f $srcdir/libs/luajit/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`luajit' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`luajit' headers and library from TL tree" >&6;}
+    with_system_luajit=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`luajit' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`luajit' headers and library" >&6;}
+    with_system_luajit=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-luajit=$with_system_luajit'"
+elif test "x$with_system_luajit" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`luajit' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`luajit' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`luajit' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`luajit' headers and library from TL tree" >&6;}
+  if test "x$with_system_luajit" != xno; then
+    with_system_luajit=no
+    ac_configure_args="$ac_configure_args '--without-system-luajit'"
+  fi
+fi
+
+## libs/lua53/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/lua53/
+## configure options and TL libraries required for lua53
+
+## libs/zlib/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory libs/zlib/
+## configure options and TL libraries required for zlib
+
+# Check whether --with-system-zlib was given.
+if test ${with_system_zlib+y}
+then :
+  withval=$with_system_zlib;
+fi
+
+# Check whether --with-zlib-includes was given.
+if test ${with_zlib_includes+y}
+then :
+  withval=$with_zlib_includes;
+fi
+
+# Check whether --with-zlib-libdir was given.
+if test ${with_zlib_libdir+y}
+then :
+  withval=$with_zlib_libdir;
+fi
+if test "x$with_system_zlib" = x; then
+  if test -f $srcdir/libs/zlib/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`zlib' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`zlib' headers and library from TL tree" >&6;}
+    with_system_zlib=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`zlib' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`zlib' headers and library" >&6;}
+    with_system_zlib=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-zlib=$with_system_zlib'"
+elif test "x$with_system_zlib" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`zlib' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`zlib' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`zlib' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`zlib' headers and library from TL tree" >&6;}
+  if test "x$with_system_zlib" != xno; then
+    with_system_zlib=no
+    ac_configure_args="$ac_configure_args '--without-system-zlib'"
+  fi
+fi
+
+
+## texk/ptexenc/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/ptexenc/
+## configure options and TL libraries required for ptexenc
+
+# Check whether --with-system-ptexenc was given.
+if test ${with_system_ptexenc+y}
+then :
+  withval=$with_system_ptexenc;
+fi
+if test "x$with_system_ptexenc" = x; then
+  if test -f $srcdir/texk/ptexenc/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`ptexenc' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`ptexenc' headers and library from TL tree" >&6;}
+    with_system_ptexenc=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`ptexenc' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`ptexenc' headers and library" >&6;}
+    with_system_ptexenc=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-ptexenc=$with_system_ptexenc'"
+elif test "x$with_system_ptexenc" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`ptexenc' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`ptexenc' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`ptexenc' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`ptexenc' headers and library from TL tree" >&6;}
+  if test "x$with_system_ptexenc" != xno; then
+    with_system_ptexenc=no
+    ac_configure_args="$ac_configure_args '--without-system-ptexenc'"
+  fi
+fi
+if test "x$with_system_ptexenc" = xyes; then
+  if test "x$with_system_kpathsea" = x; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}:   ->  installed \`kpathsea' headers and library" >&5
+printf "%s\n" "$as_me:   ->  installed \`kpathsea' headers and library" >&6;}
+    with_system_kpathsea=yes
+    ac_configure_args="$ac_configure_args '--with-system-kpathsea'"
+  elif test "x$with_system_kpathsea" != xyes; then
+    as_fn_error $? "Sorry, \`--with-system-ptexenc' requires \`--with-system-kpathsea'" "$LINENO" 5
+  fi
+fi
+
+test "x$need_ptexenc" = xyes && {
+  need_kpathsea=yes
+}
+
+## texk/kpathsea/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory texk/kpathsea/
+## configure options and TL libraries required for kpathsea
+
+# Check whether --with-system-kpathsea was given.
+if test ${with_system_kpathsea+y}
+then :
+  withval=$with_system_kpathsea;
+fi
+if test "x$with_system_kpathsea" = x; then
+  if test -f $srcdir/texk/kpathsea/configure; then
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming \`kpathsea' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Assuming \`kpathsea' headers and library from TL tree" >&6;}
+    with_system_kpathsea=no
+  else
+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Assuming installed \`kpathsea' headers and library" >&5
+printf "%s\n" "$as_me: Assuming installed \`kpathsea' headers and library" >&6;}
+    with_system_kpathsea=yes
+  fi
+  ac_configure_args="$ac_configure_args '--with-system-kpathsea=$with_system_kpathsea'"
+elif test "x$with_system_kpathsea" = xyes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using installed \`kpathsea' headers and library" >&5
+printf "%s\n" "$as_me: Using installed \`kpathsea' headers and library" >&6;}
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using \`kpathsea' headers and library from TL tree" >&5
+printf "%s\n" "$as_me: Using \`kpathsea' headers and library from TL tree" >&6;}
+  if test "x$with_system_kpathsea" != xno; then
+    with_system_kpathsea=no
+    ac_configure_args="$ac_configure_args '--without-system-kpathsea'"
+  fi
+fi
+
+## texk/kpathsea/ac/mktex.ac: configure.ac fragment for the TeX Live
+## subdirectory texk/kpathsea.
+## configure defaults for mktexfmt & Co.
+# Check whether --enable-mktexmf-default was given.
+if test ${enable_mktexmf_default+y}
+then :
+  enableval=$enable_mktexmf_default;
+fi
+# Check whether --enable-mktexpk-default was given.
+if test ${enable_mktexpk_default+y}
+then :
+  enableval=$enable_mktexpk_default;
+fi
+# Check whether --enable-mktextfm-default was given.
+if test ${enable_mktextfm_default+y}
+then :
+  enableval=$enable_mktextfm_default;
+fi
+# Check whether --enable-mkocp-default was given.
+if test ${enable_mkocp_default+y}
+then :
+  enableval=$enable_mkocp_default;
+fi
+# Check whether --enable-mkofm-default was given.
+if test ${enable_mkofm_default+y}
+then :
+  enableval=$enable_mkofm_default;
+fi
+# Check whether --enable-mktexfmt-default was given.
+if test ${enable_mktexfmt_default+y}
+then :
+  enableval=$enable_mktexfmt_default;
+fi
+# Check whether --enable-mktextex-default was given.
+if test ${enable_mktextex_default+y}
+then :
+  enableval=$enable_mktextex_default;
+fi
+
+
+
+# end of kpse_setup macro.
+echo 'tldbg:KPSE_SETUP done (toplevel=)' >&5
+
+
+am__api_version='1.17'
+
+
+  # Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+printf %s "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if test ${ac_cv_path_install+y}
+then :
+  printf %s "(cached) " >&6
+else case e in #(
+  e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  case $as_dir in #(((
+    '') as_dir=./ ;;
+    */) ;;
+    *) as_dir=$as_dir/ ;;
+  esac
+    # Account for fact that we put trailing slashes in our PATH walk.
+case $as_dir in #((
+  ./ | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    rm -rf conftest.one conftest.two conftest.dir
+	    echo one > conftest.one
+	    echo two > conftest.two
+	    mkdir conftest.dir
+	    if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" &&
+	      test -s conftest.one && test -s conftest.two &&
+	      test -s conftest.dir/conftest.one &&
+	      test -s conftest.dir/conftest.two
+	    then
+	      ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c"
+	      break 3
+	    fi
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+ ;;
+esac
+fi
+  if test ${ac_cv_path_install+y}; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+printf "%s\n" "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether sleep supports fractional seconds" >&5
+printf %s "checking whether sleep supports fractional seconds... " >&6; }
+if test ${am_cv_sleep_fractional_seconds+y}
 then :
   printf %s "(cached) " >&6
 else case e in #(
@@ -22806,6 +24777,12 @@ printf %s "checking for TeX specific libraries to build... " >&6; }
 echo 'tldbg:_KPSE_RECURSE called: list=texlibs, text=TeX specific libraries, cond=test "x$with_system_[]Kpse_pkg" != xyes && test "x$need_[]Kpse_pkg" = xyes, prefix=texk/.' >&5
 MAKE_SUBDIRS=
 CONF_SUBDIRS=
+if test -x $srcdir/texk/ptexenc/configure; then
+  test "x$with_system_ptexenc" != xyes && test "x$need_ptexenc" = xyes && MAKE_SUBDIRS="texk/ptexenc $MAKE_SUBDIRS"
+  CONF_SUBDIRS="texk/ptexenc $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/texk/ptexenc/configure' >&5
+fi
 if test -x $srcdir/texk/kpathsea/configure; then
   test "x$with_system_kpathsea" != xyes && test "x$need_kpathsea" = xyes && MAKE_SUBDIRS="texk/kpathsea $MAKE_SUBDIRS"
   CONF_SUBDIRS="texk/kpathsea $CONF_SUBDIRS"
@@ -23373,17 +25350,63 @@ esac
 else
   ICU_CONFIG="$ac_cv_prog_ICU_CONFIG"
 fi
-if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
-set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_PKG_CONFIG+y}
+then :
+  printf %s "(cached) " >&6
+else case e in #(
+  e) if test -n "$PKG_CONFIG"; then
+  ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  case $as_dir in #(((
+    '') as_dir=./ ;;
+    */) ;;
+    *) as_dir=$as_dir/ ;;
+  esac
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+    ac_cv_prog_PKG_CONFIG="${ac_tool_prefix}pkg-config"
+    printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_prog_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+printf "%s\n" "$PKG_CONFIG" >&6; }
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_PKG_CONFIG"; then
+  ac_ct_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_PKG_CONFIG+y}
+if test ${ac_cv_prog_ac_ct_PKG_CONFIG+y}
 then :
   printf %s "(cached) " >&6
 else case e in #(
-  e) if test -n "$PKG_CONFIG"; then
-  ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test.
+  e) if test -n "$ac_ct_PKG_CONFIG"; then
+  ac_cv_prog_ac_ct_PKG_CONFIG="$ac_ct_PKG_CONFIG" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -23396,7 +25419,7 @@ do
   esac
     for ac_exec_ext in '' $ac_executable_extensions; do
   if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
-    ac_cv_prog_PKG_CONFIG="${ac_tool_prefix}pkg-config"
+    ac_cv_prog_ac_ct_PKG_CONFIG="pkg-config"
     printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -23407,120 +25430,391 @@ IFS=$as_save_IFS
 fi ;;
 esac
 fi
-PKG_CONFIG=$ac_cv_prog_PKG_CONFIG
-if test -n "$PKG_CONFIG"; then
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
-printf "%s\n" "$PKG_CONFIG" >&6; }
+ac_ct_PKG_CONFIG=$ac_cv_prog_ac_ct_PKG_CONFIG
+if test -n "$ac_ct_PKG_CONFIG"; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_PKG_CONFIG" >&5
+printf "%s\n" "$ac_ct_PKG_CONFIG" >&6; }
 else
   { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
 printf "%s\n" "no" >&6; }
 fi
-
-
+
+  if test "x$ac_ct_PKG_CONFIG" = x; then
+    PKG_CONFIG="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_ct_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_prog_PKG_CONFIG"
+fi
+if $ICU_CONFIG --version >/dev/null 2>&1; then
+  ICU_INCLUDES=`$ICU_CONFIG --cppflags`
+  ICU_LIBS=`$ICU_CONFIG --ldflags-searchpath --ldflags-libsonly --ldflags-system`
+elif $PKG_CONFIG --libs icu-uc icu-io >/dev/null 2>&1; then
+  ICU_INCLUDES=`$PKG_CONFIG --cflags icu-uc icu-io`
+  ICU_LIBS=`$PKG_CONFIG --libs icu-uc icu-io`
+elif test "x$need_icu:$with_system_icu" = xyes:yes; then
+  as_fn_error $? "did not find either pkg-config or icu-config; one is required for system icu library support" "$LINENO" 5
+fi
+
+if $PKG_CONFIG harfbuzz; then
+  HARFBUZZ_INCLUDES=`$PKG_CONFIG harfbuzz --cflags`
+  HARFBUZZ_LIBS=`$PKG_CONFIG harfbuzz --libs`
+elif test "x$need_harfbuzz:$with_system_harfbuzz" = xyes:yes; then
+  as_fn_error $? "did not find harfbuzz" "$LINENO" 5
+fi
+
+if $PKG_CONFIG luajit; then
+  LUAJIT_INCLUDES=`$PKG_CONFIG luajit --cflags`
+  LUAJIT_LIBS=`$PKG_CONFIG luajit --libs`
+elif test "x$need_luajit:$with_system_luajit" = xyes:yes; then
+  as_fn_error $? "did not find luajit" "$LINENO" 5
+fi
+
+
+
+
+
+
+## texk/kpathsea/ac/kpathsea.ac: configure.ac fragment for the TeX Live subdirectory texk/kpathsea/
+## basic check of system kpathsea
+if test "x$need_kpathsea:$with_system_kpathsea" = xyes:yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`kpathsea' library" >&5
+printf %s "checking requested system \`kpathsea' library... " >&6; }
+  CPPFLAGS="$KPATHSEA_INCLUDES $CPPFLAGS"
+  LIBS="$KPATHSEA_LIBS $LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <kpathsea/kpathsea.h>
+#include <kpathsea/version.h>
+int
+main (void)
+{
+const char *version = kpathsea_version_string;
+kpse_set_program_name("prog", "name");
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+  syslib_used=yes kpse_res=ok
+else case e in #(
+  e) syslib_status=no kpse_res=failed ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+    conftest$ac_exeext conftest.$ac_ext
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $kpse_res" >&5
+printf "%s\n" "$kpse_res" >&6; }
+fi
+
+## texk/ptexenc/ac/ptexenc.ac: configure.ac fragment for the TeX Live subdirectory texk/ptexenc/
+## basic check of system ptexenc
+if test "x$need_ptexenc:$with_system_ptexenc" = xyes:yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`ptexenc' library" >&5
+printf %s "checking requested system \`ptexenc' library... " >&6; }
+  CPPFLAGS="$PTEXENC_INCLUDES $CPPFLAGS"
+  LIBS="$PTEXENC_LIBS $LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ptexenc/ptexenc.h>
+int
+main (void)
+{
+const char *version = ptexenc_version_string;
+set_enc_string("prog", "name");
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+  syslib_used=yes kpse_res=ok
+else case e in #(
+  e) syslib_status=no kpse_res=failed ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+    conftest$ac_exeext conftest.$ac_ext
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $kpse_res" >&5
+printf "%s\n" "$kpse_res" >&6; }
+fi
+
+## libs/zlib/ac/zlib.ac: configure.ac fragment for the TeX Live subdirectory libs/zlib/
+## basic check of system zlib
+if test "x$need_zlib:$with_system_zlib" = xyes:yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`zlib' library" >&5
+printf %s "checking requested system \`zlib' library... " >&6; }
+  CPPFLAGS="$ZLIB_INCLUDES $CPPFLAGS"
+  LIBS="$ZLIB_LIBS $LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <zlib.h>
+int
+main (void)
+{
+z_stream stream;
+const char *version = zlibVersion();
+deflate(&stream, 0);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+  syslib_used=yes kpse_res=ok
+else case e in #(
+  e) syslib_status=no kpse_res=failed ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+    conftest$ac_exeext conftest.$ac_ext
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $kpse_res" >&5
+printf "%s\n" "$kpse_res" >&6; }
+fi
+
+## libs/luajit/ac/luajit.ac: configure.ac fragment for the TeX Live subdirectory libs/luajit/
+## basic check of system luajit
+if test "x$need_luajit:$with_system_luajit" = xyes:yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`luajit' library" >&5
+printf %s "checking requested system \`luajit' library... " >&6; }
+  CPPFLAGS="$LUAJIT_INCLUDES $CPPFLAGS"
+  LIBS="$LUAJIT_LIBS $LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <luajit.h>
+int
+main (void)
+{
+const char *v = LUAJIT_VERSION;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+  syslib_used=yes kpse_res=ok
+else case e in #(
+  e) syslib_status=no kpse_res=failed ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+    conftest$ac_exeext conftest.$ac_ext
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $kpse_res" >&5
+printf "%s\n" "$kpse_res" >&6; }
+fi
+
+## libs/libpaper/ac/libpaper.ac: configure.ac fragment for the TeX Live subdirectory libs/libpaper/
+## basic check of system libpaper
+if test "x$need_libpaper:$with_system_libpaper" = xyes:yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`libpaper' library" >&5
+printf %s "checking requested system \`libpaper' library... " >&6; }
+  CPPFLAGS="$LIBPAPER_INCLUDES $CPPFLAGS"
+  LIBS="$LIBPAPER_LIBS $LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <paper.h>
+int
+main (void)
+{
+const char *v = defaultpapername();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+  syslib_used=yes kpse_res=ok
+else case e in #(
+  e) syslib_status=no kpse_res=failed ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+    conftest$ac_exeext conftest.$ac_ext
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $kpse_res" >&5
+printf "%s\n" "$kpse_res" >&6; }
+fi
+
+## libs/libpng/ac/libpng.ac: configure.ac fragment for the TeX Live subdirectory libs/libpng/
+## basic check of system libpng
+if test "x$need_libpng:$with_system_libpng" = xyes:yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`libpng' library" >&5
+printf %s "checking requested system \`libpng' library... " >&6; }
+  CPPFLAGS="$LIBPNG_INCLUDES $CPPFLAGS"
+  LIBS="$LIBPNG_LIBS $LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <png.h>
+int
+main (void)
+{
+png_structp png; png_voidp io; png_rw_ptr fn;
+png_set_read_fn(png, io, fn);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+  syslib_used=yes kpse_res=ok
+else case e in #(
+  e) syslib_status=no kpse_res=failed ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+    conftest$ac_exeext conftest.$ac_ext
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $kpse_res" >&5
+printf "%s\n" "$kpse_res" >&6; }
+fi
+
+## libs/freetype2/ac/freetype2.ac: configure.ac fragment for the TeX Live subdirectory libs/freetype2/
+## basic check of system freetype2
+if test "x$need_freetype2:$with_system_freetype2" = xyes:yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`freetype2' library" >&5
+printf %s "checking requested system \`freetype2' library... " >&6; }
+  CPPFLAGS="$FREETYPE2_INCLUDES $CPPFLAGS"
+  LIBS="$FREETYPE2_LIBS $LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ft2build.h>
+#include FT_FREETYPE_H
+int
+main (void)
+{
+FT_Library library; FT_Init_FreeType(&library);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+  syslib_used=yes kpse_res=ok
+else case e in #(
+  e) syslib_status=no kpse_res=failed ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+    conftest$ac_exeext conftest.$ac_ext
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $kpse_res" >&5
+printf "%s\n" "$kpse_res" >&6; }
 fi
-if test -z "$ac_cv_prog_PKG_CONFIG"; then
-  ac_ct_PKG_CONFIG=$PKG_CONFIG
-  # Extract the first word of "pkg-config", so it can be a program name with args.
-set dummy pkg-config; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_PKG_CONFIG+y}
+
+## libs/potrace/ac/potrace.ac: configure.ac fragment for the TeX Live subdirectory libs/potrace/
+## basic check of system potrace
+if test "x$need_potrace:$with_system_potrace" = xyes:yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`potrace' library" >&5
+printf %s "checking requested system \`potrace' library... " >&6; }
+  CPPFLAGS="$POTRACE_INCLUDES $CPPFLAGS"
+  LIBS="$POTRACE_LIBS $LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <potracelib.h>
+int
+main (void)
+{
+potrace_state_t st;
+const char *version = potrace_version();
+potrace_state_free(&st);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
 then :
-  printf %s "(cached) " >&6
+  syslib_used=yes kpse_res=ok
 else case e in #(
-  e) if test -n "$ac_ct_PKG_CONFIG"; then
-  ac_cv_prog_ac_ct_PKG_CONFIG="$ac_ct_PKG_CONFIG" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  case $as_dir in #(((
-    '') as_dir=./ ;;
-    */) ;;
-    *) as_dir=$as_dir/ ;;
-  esac
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_PKG_CONFIG="pkg-config"
-    printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi ;;
+  e) syslib_status=no kpse_res=failed ;;
 esac
 fi
-ac_ct_PKG_CONFIG=$ac_cv_prog_ac_ct_PKG_CONFIG
-if test -n "$ac_ct_PKG_CONFIG"; then
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_PKG_CONFIG" >&5
-printf "%s\n" "$ac_ct_PKG_CONFIG" >&6; }
-else
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+    conftest$ac_exeext conftest.$ac_ext
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $kpse_res" >&5
+printf "%s\n" "$kpse_res" >&6; }
 fi
 
-  if test "x$ac_ct_PKG_CONFIG" = x; then
-    PKG_CONFIG="false"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
+## libs/gd/ac/gd.ac: configure.ac fragment for the TeX Live subdirectory libs/gd/
+## basic check of system gd
+if test "x$need_gd:$with_system_gd" = xyes:yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`gd' library" >&5
+printf %s "checking requested system \`gd' library... " >&6; }
+  CPPFLAGS="$GD_INCLUDES $CPPFLAGS"
+  LIBS="$GD_LIBS $LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <gd.h>
+int
+main (void)
+{
+gdImageCreate(1, 2);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+  syslib_used=yes kpse_res=ok
+else case e in #(
+  e) syslib_status=no kpse_res=failed ;;
 esac
-    PKG_CONFIG=$ac_ct_PKG_CONFIG
-  fi
-else
-  PKG_CONFIG="$ac_cv_prog_PKG_CONFIG"
 fi
-if $ICU_CONFIG --version >/dev/null 2>&1; then
-  ICU_INCLUDES=`$ICU_CONFIG --cppflags`
-  ICU_LIBS=`$ICU_CONFIG --ldflags-searchpath --ldflags-libsonly --ldflags-system`
-elif $PKG_CONFIG --libs icu-uc icu-io >/dev/null 2>&1; then
-  ICU_INCLUDES=`$PKG_CONFIG --cflags icu-uc icu-io`
-  ICU_LIBS=`$PKG_CONFIG --libs icu-uc icu-io`
-elif test "x$need_icu:$with_system_icu" = xyes:yes; then
-  as_fn_error $? "did not find either pkg-config or icu-config; one is required for system icu library support" "$LINENO" 5
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+    conftest$ac_exeext conftest.$ac_ext
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $kpse_res" >&5
+printf "%s\n" "$kpse_res" >&6; }
 fi
 
-if $PKG_CONFIG harfbuzz; then
-  HARFBUZZ_INCLUDES=`$PKG_CONFIG harfbuzz --cflags`
-  HARFBUZZ_LIBS=`$PKG_CONFIG harfbuzz --libs`
-elif test "x$need_harfbuzz:$with_system_harfbuzz" = xyes:yes; then
-  as_fn_error $? "did not find harfbuzz" "$LINENO" 5
+## libs/pixman/ac/pixman.ac: configure.ac fragment for the TeX Live subdirectory libs/pixman/
+## basic check of system pixman
+if test "x$need_pixman:$with_system_pixman" = xyes:yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`pixman' library" >&5
+printf %s "checking requested system \`pixman' library... " >&6; }
+  CPPFLAGS="$PIXMAN_INCLUDES $CPPFLAGS"
+  LIBS="$PIXMAN_LIBS $LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <pixman.h>
+int
+main (void)
+{
+const char *s = pixman_version_string();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+  syslib_used=yes kpse_res=ok
+else case e in #(
+  e) syslib_status=no kpse_res=failed ;;
+esac
 fi
-
-if $PKG_CONFIG luajit; then
-  LUAJIT_INCLUDES=`$PKG_CONFIG luajit --cflags`
-  LUAJIT_LIBS=`$PKG_CONFIG luajit --libs`
-elif test "x$need_luajit:$with_system_luajit" = xyes:yes; then
-  as_fn_error $? "did not find luajit" "$LINENO" 5
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+    conftest$ac_exeext conftest.$ac_ext
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $kpse_res" >&5
+printf "%s\n" "$kpse_res" >&6; }
 fi
 
-
-
-
-
-
-## texk/kpathsea/ac/kpathsea.ac: configure.ac fragment for the TeX Live subdirectory texk/kpathsea/
-## basic check of system kpathsea
-if test "x$need_kpathsea:$with_system_kpathsea" = xyes:yes; then
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`kpathsea' library" >&5
-printf %s "checking requested system \`kpathsea' library... " >&6; }
-  CPPFLAGS="$KPATHSEA_INCLUDES $CPPFLAGS"
-  LIBS="$KPATHSEA_LIBS $LIBS"
+## libs/cairo/ac/cairo.ac: configure.ac fragment for the TeX Live subdirectory libs/cairo/
+## basic check of system cairo
+if test "x$need_cairo:$with_system_cairo" = xyes:yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`cairo' library" >&5
+printf %s "checking requested system \`cairo' library... " >&6; }
+  CPPFLAGS="$CAIRO_INCLUDES $CPPFLAGS"
+  LIBS="$CAIRO_LIBS $LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-#include <kpathsea/kpathsea.h>
-#include <kpathsea/version.h>
+#include <cairo.h>
 int
 main (void)
 {
-const char *version = kpathsea_version_string;
-kpse_set_program_name("prog", "name");
+const char *s = cairo_version_string();
   ;
   return 0;
 }
@@ -23538,22 +25832,20 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \
 printf "%s\n" "$kpse_res" >&6; }
 fi
 
-## libs/zlib/ac/zlib.ac: configure.ac fragment for the TeX Live subdirectory libs/zlib/
-## basic check of system zlib
-if test "x$need_zlib:$with_system_zlib" = xyes:yes; then
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`zlib' library" >&5
-printf %s "checking requested system \`zlib' library... " >&6; }
-  CPPFLAGS="$ZLIB_INCLUDES $CPPFLAGS"
-  LIBS="$ZLIB_LIBS $LIBS"
+## libs/gmp/ac/gmp.ac: configure.ac fragment for the TeX Live subdirectory libs/gmp/
+## basic check of system gmp
+if test "x$need_gmp:$with_system_gmp" = xyes:yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`gmp' library" >&5
+printf %s "checking requested system \`gmp' library... " >&6; }
+  CPPFLAGS="$GMP_INCLUDES $CPPFLAGS"
+  LIBS="$GMP_LIBS $LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-#include <zlib.h>
+#include <gmp.h>
 int
 main (void)
 {
-z_stream stream;
-const char *version = zlibVersion();
-deflate(&stream, 0);
+const char *s = gmp_version;
   ;
   return 0;
 }
@@ -23571,20 +25863,20 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \
 printf "%s\n" "$kpse_res" >&6; }
 fi
 
-## libs/luajit/ac/luajit.ac: configure.ac fragment for the TeX Live subdirectory libs/luajit/
-## basic check of system luajit
-if test "x$need_luajit:$with_system_luajit" = xyes:yes; then
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`luajit' library" >&5
-printf %s "checking requested system \`luajit' library... " >&6; }
-  CPPFLAGS="$LUAJIT_INCLUDES $CPPFLAGS"
-  LIBS="$LUAJIT_LIBS $LIBS"
+## libs/mpfr/ac/mpfr.ac: configure.ac fragment for the TeX Live subdirectory libs/mpfr/
+## basic check of system mpfr
+if test "x$need_mpfr:$with_system_mpfr" = xyes:yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`mpfr' library" >&5
+printf %s "checking requested system \`mpfr' library... " >&6; }
+  CPPFLAGS="$MPFR_INCLUDES $CPPFLAGS"
+  LIBS="$MPFR_LIBS $LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-#include <luajit.h>
+#include <mpfr.h>
 int
 main (void)
 {
-const char *v = LUAJIT_VERSION;
+const char *s = mpfr_get_version();
   ;
   return 0;
 }
@@ -23602,26 +25894,31 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \
 printf "%s\n" "$kpse_res" >&6; }
 fi
 
-## libs/libpng/ac/libpng.ac: configure.ac fragment for the TeX Live subdirectory libs/libpng/
-## basic check of system libpng
-if test "x$need_libpng:$with_system_libpng" = xyes:yes; then
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`libpng' library" >&5
-printf %s "checking requested system \`libpng' library... " >&6; }
-  CPPFLAGS="$LIBPNG_INCLUDES $CPPFLAGS"
-  LIBS="$LIBPNG_LIBS $LIBS"
+## libs/xpdf/ac/xpdf.ac: configure.ac fragment for the TeX Live subdirectory libs/xpdf/
+## basic check of system xpdf (a.k.a. poppler, no longer supported in
+## TL sources)
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test "x$need_xpdf:$with_system_xpdf" = xyes:yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`xpdf' library" >&5
+printf %s "checking requested system \`xpdf' library... " >&6; }
+  CPPFLAGS="$XPDF_INCLUDES $CPPFLAGS"
+  LIBS="$XPDF_LIBS $LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-#include <png.h>
+#include <GfxFont.h>
 int
 main (void)
 {
-png_structp png; png_voidp io; png_rw_ptr fn;
-png_set_read_fn(png, io, fn);
+GfxFont *gfxFont; gfxFont->isOk();
   ;
   return 0;
 }
 _ACEOF
-if ac_fn_c_try_link "$LINENO"
+if ac_fn_cxx_try_link "$LINENO"
 then :
   syslib_used=yes kpse_res=ok
 else case e in #(
@@ -23633,6 +25930,11 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \
   { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $kpse_res" >&5
 printf "%s\n" "$kpse_res" >&6; }
 fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 ## libs/zziplib/ac/zziplib.ac: configure.ac fragment for the TeX Live subdirectory libs/zziplib/
 ## basic check of system zziplib
@@ -23697,6 +25999,89 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \
 printf "%s\n" "$kpse_res" >&6; }
 fi
 
+## libs/teckit/ac/teckit.ac: configure.ac fragment for the TeX Live subdirectory libs/teckit/
+## basic check of system teckit
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test "x$need_teckit:$with_system_teckit" = xyes:yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`teckit' library" >&5
+printf %s "checking requested system \`teckit' library... " >&6; }
+  CPPFLAGS="$TECKIT_INCLUDES $CPPFLAGS"
+  LIBS="$TECKIT_LIBS $LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <teckit/TECkit_Engine.h>
+int
+main (void)
+{
+TECkit_Converter converter; TECkit_DisposeConverter(converter);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"
+then :
+  syslib_used=yes kpse_res=ok
+else case e in #(
+  e) syslib_status=no kpse_res=failed ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+    conftest$ac_exeext conftest.$ac_ext
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $kpse_res" >&5
+printf "%s\n" "$kpse_res" >&6; }
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+## libs/icu/ac/icu.ac: configure.ac fragment for the TeX Live subdirectory libs/icu/
+## basic check of system icu
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test "x$need_icu:$with_system_icu" = xyes:yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking requested system \`icu' library" >&5
+printf %s "checking requested system \`icu' library... " >&6; }
+  CPPFLAGS="$ICU_INCLUDES $CPPFLAGS"
+  LIBS="$ICU_LIBS $LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <unicode/ustring.h>
+int
+main (void)
+{
+UErrorCode code; const UChar *src; UChar *dst;
+u_strToLower(dst, -1, src, -1, NULL, &code);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"
+then :
+  syslib_used=yes kpse_res=ok
+else case e in #(
+  e) syslib_status=no kpse_res=failed ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+    conftest$ac_exeext conftest.$ac_ext
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $kpse_res" >&5
+printf "%s\n" "$kpse_res" >&6; }
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
 ## libs/harfbuzz/ac/harfbuzz.ac: configure.ac fragment for the TeX Live subdirectory libs/harfbuzz/
 ## basic check of system harfbuzz
 if test "x$need_harfbuzz:$with_system_harfbuzz" = xyes:yes; then
diff --git a/source/libs/README b/source/libs/README
index be663eb9ba978280a78869013660987d57378dad..21a75a336a2fe1e3bb1d37761d3660ae1bc4e7a7 100644
--- a/source/libs/README
+++ b/source/libs/README
@@ -1,4 +1,4 @@
-$Id: README 74540 2025-03-08 22:22:06Z kakuto $
+$Id: README 74729 2025-03-24 00:38:36Z kakuto $
 Public domain.  Originally created by Karl Berry, 2005.
 
 Libraries we compile for TeX Live.
@@ -28,7 +28,7 @@ graphite2 1.3.14 - checked 10apr20
   https://sourceforge.net/projects/silgraphite/files/graphite2/
   (requires C++11)
 
-harfbuzz 10.4.0 - checked 09mar25
+harfbuzz 11.0.0 - checked 24mar25
   https://github.com/harfbuzz/harfbuzz/releases/latest
 
 icu 76.1 - checked 27oct24 (requires C++17, e.g., g++13)
@@ -52,7 +52,7 @@ luajit 2.1.0-beta3 - checked 20jun17
 mpfi 1.5.4 - checked 1feb24
   https://perso.ens-lyon.fr/nathalie.revol/software.html#download
   
-mpfr 4.2.1 - checked 1feb24
+mpfr 4.2.2 - checked 21mar25
   https://ftp.gnu.org/gnu/mpfr/
 
 pixman 0.42.2 - no longer checked
diff --git a/source/libs/harfbuzz/ChangeLog b/source/libs/harfbuzz/ChangeLog
index 49a13b5b4c265a5bfabdfaaeb1d0270504542ee5..ed247d02c3ce5f8e297e4aab223c28e684633ca5 100644
--- a/source/libs/harfbuzz/ChangeLog
+++ b/source/libs/harfbuzz/ChangeLog
@@ -1,3 +1,8 @@
+2025-03-24  Akira Kakuto  <kakuto@jcom.zaq.ne.jp>
+
+	Import harfbuzz-11.0.0.
+	* version.ac, include/Makefile.am: Adjusted.
+
 2025-03-09  Akira Kakuto  <kakuto@jcom.zaq.ne.jp>
 
 	Import harfbuzz-10.4.0.
diff --git a/source/libs/harfbuzz/TLpatches/ChangeLog b/source/libs/harfbuzz/TLpatches/ChangeLog
index 32f6c06d46a584ee8a9c0a2e70716046831e53aa..fd8309b60b6b7829fff70dd2b8b97120b1456ec5 100644
--- a/source/libs/harfbuzz/TLpatches/ChangeLog
+++ b/source/libs/harfbuzz/TLpatches/ChangeLog
@@ -1,3 +1,8 @@
+2025-03-24  Akira Kakuto  <kakuto@jcom.zaq.ne.jp>
+
+	Imported harfbuzz-11.0.0 source tree from:
+	https://github.com/harfbuzz/harfbuzz/releases/download/11.0.0/
+
 2025-03-09  Akira Kakuto  <kakuto@jcom.zaq.ne.jp>
 
 	Imported harfbuzz-10.4.0 source tree from:
diff --git a/source/libs/harfbuzz/TLpatches/TL-Changes b/source/libs/harfbuzz/TLpatches/TL-Changes
index 91b5aa9434eed3bf92759ba782d9264e9eacc50e..7f26b1d211ec2dd78c5ede5fb07657f4c4bc6ac0 100644
--- a/source/libs/harfbuzz/TLpatches/TL-Changes
+++ b/source/libs/harfbuzz/TLpatches/TL-Changes
@@ -1,5 +1,5 @@
-Changes applied to the harfbuzz-10.4.0/ tree as obtained from:
-	https://github.com/harfbuzz/harfbuzz/releases/download/10.4.0/
+Changes applied to the harfbuzz-11.0.0/ tree as obtained from:
+	https://github.com/harfbuzz/harfbuzz/releases/download/11.0.0/
 
 Removed:
 	.clang-format
diff --git a/source/libs/harfbuzz/configure b/source/libs/harfbuzz/configure
index 43d9ee0e231f31dafaa39453c59e97e41f29cd57..8ae6a92113812fa594e59739552b0729dd5d5a68 100755
--- a/source/libs/harfbuzz/configure
+++ b/source/libs/harfbuzz/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.72 for harfbuzz (TeX Live) 10.4.0.
+# Generated by GNU Autoconf 2.72 for harfbuzz (TeX Live) 11.0.0.
 #
 # Report bugs to <tex-k@tug.org>.
 #
@@ -604,8 +604,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='harfbuzz (TeX Live)'
 PACKAGE_TARNAME='harfbuzz--tex-live-'
-PACKAGE_VERSION='10.4.0'
-PACKAGE_STRING='harfbuzz (TeX Live) 10.4.0'
+PACKAGE_VERSION='11.0.0'
+PACKAGE_STRING='harfbuzz (TeX Live) 11.0.0'
 PACKAGE_BUGREPORT='tex-k@tug.org'
 PACKAGE_URL=''
 
@@ -1341,7 +1341,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-'configure' configures harfbuzz (TeX Live) 10.4.0 to adapt to many kinds of systems.
+'configure' configures harfbuzz (TeX Live) 11.0.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1413,7 +1413,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of harfbuzz (TeX Live) 10.4.0:";;
+     short | recursive ) echo "Configuration of harfbuzz (TeX Live) 11.0.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1518,7 +1518,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-harfbuzz (TeX Live) configure 10.4.0
+harfbuzz (TeX Live) configure 11.0.0
 generated by GNU Autoconf 2.72
 
 Copyright (C) 2023 Free Software Foundation, Inc.
@@ -2075,7 +2075,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by harfbuzz (TeX Live) $as_me 10.4.0, which was
+It was created by harfbuzz (TeX Live) $as_me 11.0.0, which was
 generated by GNU Autoconf 2.72.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -5252,7 +5252,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='harfbuzz--tex-live-'
- VERSION='10.4.0'
+ VERSION='11.0.0'
 
 
 # Some tools Automake needs.
@@ -5440,10 +5440,10 @@ WARNING_CFLAGS=$kpse_cv_warning_cflags
 echo 'tldbg:KPSE_BASIC done (pkg=harfbuzz, amopt=no-define)' >&5
 
 
-HB_VERSION_MAJOR=10
-HB_VERSION_MINOR=4
+HB_VERSION_MAJOR=11
+HB_VERSION_MINOR=0
 HB_VERSION_MICRO=0
-HB_VERSION=10.4.0
+HB_VERSION=11.0.0
 
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
@@ -9292,7 +9292,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by harfbuzz (TeX Live) $as_me 10.4.0, which was
+This file was extended by harfbuzz (TeX Live) $as_me 11.0.0, which was
 generated by GNU Autoconf 2.72.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -9360,7 +9360,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-harfbuzz (TeX Live) config.status 10.4.0
+harfbuzz (TeX Live) config.status 11.0.0
 configured by $0, generated by GNU Autoconf 2.72,
   with options \\"\$ac_cs_config\\"
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/CMakeLists.txt b/source/libs/harfbuzz/harfbuzz-src/CMakeLists.txt
index 3b4f5aa61e868e6a42e81d7582ae639c2b7db691..203f2396c7a4479878aaf56dfffc0b89d922be23 100644
--- a/source/libs/harfbuzz/harfbuzz-src/CMakeLists.txt
+++ b/source/libs/harfbuzz/harfbuzz-src/CMakeLists.txt
@@ -233,7 +233,7 @@ if (HB_HAVE_FREETYPE AND NOT TARGET freetype)
   set (CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${FREETYPE_INCLUDE_DIRS})
   set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${FREETYPE_LIBRARIES})
 
-  check_funcs(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var)
+  check_funcs(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var FT_Get_Transform)
 endif ()
 
 if (HB_HAVE_FREETYPE)
diff --git a/source/libs/harfbuzz/harfbuzz-src/NEWS b/source/libs/harfbuzz/harfbuzz-src/NEWS
index 4e7dbe0d925334055743b0633523b9ced2af9a45..363bcaf827946268e56c58fe01b9976648f3baf5 100644
--- a/source/libs/harfbuzz/harfbuzz-src/NEWS
+++ b/source/libs/harfbuzz/harfbuzz-src/NEWS
@@ -1,3 +1,64 @@
+Overview of changes leading to 11.0.0
+Monday, March 24, 2025
+====================================
+- There are three new font-functions implementations (integrations) in this
+  release:
+  * `hb-coretext` has gained one, calling into the CoreText library,
+  * `hb-directwrite` has gained one, calling into the DirectWrite library.
+  * `hb-fontations` has gained one, calling into the Skrifa Rust library.
+  All three are mostly useful for performance and correctness testing, but some
+  clients might find them useful.
+  An API is added to use them from a single API by providing a backend name
+  string:
+  * `hb_font_set_funcs_using()`
+- Several new APIs are added, to load a font-face using different
+  "face-loaders", and a single entry point to them all using a loader name
+  string:
+  * `hb_ft_face_create_from_file_or_fail()` and
+    `hb_ft_face_create_from_blob_or_fail()`
+  * `hb_coretext_face_create_from_file_or_fail()` and
+    `hb_coretext_face_create_from_blob_or_fail()`
+  * `hb_directwrite_face_create_from_file_or_fail()` and
+    `hb_directwrite_face_create_from_blob_or_fail()`
+  * `hb_face_create_from_file_or_fail_using()`
+- All drawing and painting operations using the default, `hb-ot` functions have
+  become memory allocation-free.
+- Several performance optimizations have been implemented.
+- Application of the `trak` table during shaping has been improved.
+- The `directwrite` shaper now supports font variations, and correctly applies
+  user features.
+- The `hb-directwrite` API and shaper has graduated from experimental.
+- Various bug fixes and other improvements.
+
+- New API:
++hb_malloc
++hb_calloc
++hb_realloc
++hb_free
++hb_face_list_loaders
++hb_face_create_or_fail_using
++hb_face_create_from_file_or_fail_using
++hb_font_list_funcs
++hb_font_set_funcs_using
++hb_coretext_face_create_from_blob_or_fail
++hb_directwrite_face_create_from_file_or_fail
++hb_directwrite_face_create_from_blob_or_fail
++hb_directwrite_font_create
++hb_directwrite_font_get_dw_font_face
++hb_directwrite_font_set_funcs
++hb_fontations_font_set_funcs
++hb_ft_face_create_from_blob_or_fail
++hb_paint_push_font_transform
++hb_paint_push_inverse_font_transform
++HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES
++HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE
++HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES
++HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS
+
+- Deprecated API:
++hb_directwrite_font_get_dw_font
+
+
 Overview of changes leading to 10.4.0
 Saturday, March 1, 2025
 ====================================
diff --git a/source/libs/harfbuzz/harfbuzz-src/README.md b/source/libs/harfbuzz/harfbuzz-src/README.md
index 02c1554bd19271970f8b0bb5ab99352d7adcec35..f94a83b54b60718b34d71cb10ffb93edbe381a99 100644
--- a/source/libs/harfbuzz/harfbuzz-src/README.md
+++ b/source/libs/harfbuzz/harfbuzz-src/README.md
@@ -51,6 +51,8 @@ For custom configurations, see [CONFIG.md](CONFIG.md).
 
 For testing and profiling, see [TESTING.md](TESTING.md).
 
+For cross-compiling to Windows from Linux or macOS, see [README.mingw.md](README.mingw.md).
+
 To get a better idea of where HarfBuzz stands in the text rendering stack you
 may want to read [State of Text Rendering 2024][6].
 Here are a few presentation slides about HarfBuzz at the
diff --git a/source/libs/harfbuzz/harfbuzz-src/README.mingw.md b/source/libs/harfbuzz/harfbuzz-src/README.mingw.md
new file mode 100644
index 0000000000000000000000000000000000000000..aada0f79339dded0993c8657f9e598ffe24d3b65
--- /dev/null
+++ b/source/libs/harfbuzz/harfbuzz-src/README.mingw.md
@@ -0,0 +1,211 @@
+Most HarfBuzz developers do so on Linux or macOS. However, HarfBuzz is a
+cross-platform library and it is important to ensure that it works on Windows
+as well. In particular, we use this workflow to develop and test the HarfBuzz
+Uniscribe shaper and DirectWrite shaper and font backend, all from Linux or
+macOS.
+
+This document provides instructions for cross-compiling HarfBuzz on Linux or
+macOS, for Windows, using the MinGW toolchain, and running tests and utilties
+under Wine.
+
+We then discuss using native Windows Uniscribe or DirectWrite DLLs, which
+allows you to test HarfBuzz's shaping against the Microsoft shaping engines
+instead of those provided by Wine.
+
+This document assumes that you are familiar with building HarfBuzz on Linux or
+macOS.
+
+You can build for 32bit or 64bit Windows. If your intention is to use a native
+Uniscribe usp10.dll from Windows 7 or before, you would need to build for 32bit.
+If you want to use a native DirectWrite DLL from Windows 10 or later, you would
+need to build for 64bit.
+
+We suggest you read to the end of this document before starting, as it provides
+a few different ways to build and test HarfBuzz for Windows.
+
+1. Install Wine.
+
+  - Fedora: `dnf install wine`.
+  - Ubuntu, 32bit: `apt install wine wine32`.
+  - Ubuntu, 64bit: `apt install wine wine64`.
+  - Mac: `brew install wine-stable`.
+
+2. Install the `mingw-w64` cross-compiler.
+
+  - Fedora, 32bit: `dnf install mingw32-gcc-c++`
+  - Fedora, 64bit: `dnf install mingw64-gcc-c++`
+  - Ubuntu, 32bit: `apt install g++-mingw-w64-i686`
+  - Ubuntu, 64bit: `apt install g++-mingw-w64-x86-64`
+  - Mac: `brew install mingw-w64`
+
+3. Install dependencies.
+
+First, make sure you do not have the mingw32 harfbuzz package, as that will
+override our own build:
+
+  - Fedora, 32bit: `dnf remove mingw32-harfbuzz`
+  - Fedora, 64bit: `dnf remove mingw64-harfbuzz`
+
+Then install the actual dependencies:
+
+  - Fedora, 32bit: `dnf install mingw32-glib2 mingw32-cairo mingw32-freetype`
+  - Fedora, 64bit: `dnf install mingw64-glib2 mingw64-cairo mingw64-freetype`
+
+If you cannot find these packages for your distribution, or you are on macOS,
+you can skip to the next step, as meson will automatically download and build
+the dependencies for you.
+
+4. If you are familiar with `meson`, you can use the cross-compile files we
+provide to find your way around. But we do not recommend this way. Read until
+the end of this section before deciding which one to use.
+
+  - 32bit: `meson --cross-file=.ci/win32-cross-file.txt build-win -Dglib-enabled -Dcairo=enabled -Dgdi=enabled -Ddirectwrite=enabled`
+  - 64bit: `meson --cross-file=.ci/win64-cross-file.txt build-win -Dglib-enabled -Dcairo=enabled -Dgdi=enabled -Ddirectwrite=enabled`
+
+In which case, you will proceed to run `ninja` as usual to build:
+
+  - `ninja -C build-win`
+
+Or you can simply invoke the scripts we provide for our Continuous Integration
+system, to configure and build HarfBuzz for you. This is the easiest way to
+build HarfBuzz for Windows and how we build our Windows binaries:
+
+  - 32bit: `./.ci/build-win.sh 32 && ln -s build-win32 build-win`
+  - 64bit: `./.ci/build-win.sh 64 && ln -s build-win64 build-win`
+
+This might take a while, since, if you do not have the dependencies installed,
+meson will download and build them for you.
+
+5. If everything succeeds, you should have the `hb-shape.exe`, `hb-view.exe`,
+`hb-subset.exe`, and `hb-info.exe` executables in `build-win/util`.
+
+6. Configure your wine to find system mingw libraries. While there, set it also
+to find the built HarfBuzz DLLs:
+
+  - Fedora, 32bit: `export WINEPATH="$HOME/harfbuzz/build-win/src;/usr/i686-w64-mingw32/sys-root/mingw/bin"`
+  - Fedora, 64bit: `export WINEPATH="$HOME/harfbuzz/build-win/src;/usr/x86_64-w64-mingw32/sys-root/mingw/bin"`
+  - Other systems: `export WINEPATH="$HOME/harfbuzz/build-win/src"`
+
+Adjust for the path where you have built HarfBuzz.  You might want to add this
+to your `.bashrc` or `.zshrc` file.
+
+Alternatively, can skip this step if commands are run through the `meson devenv`
+command, which we will introduce in the next step. I personally find it more
+convenient to set the `WINEPATH` variable, as it allows me to run the executables
+directly from the shell.
+
+7. Run the `hb-shape` executable under Wine:
+
+  - `wine build-win/util/hb-shape.exe perf/fonts/Roboto-Regular.ttf Test`
+
+Or using `meson devenv to do the same:
+
+  - `meson devenv -C build-win util/hb-shape.exe $PWD/perf/fonts/Roboto-Regular.ttf Test`
+
+You probably will get lots of Wine warnings, but if all works fine, you
+should see:
+```
+[gid57=0+1123|gid74=1+1086|gid88=2+1057|gid89=3+670]
+```
+
+You can make Wine less verbose, without hiding all errors, by setting:
+
+  - `export WINEDEBUG=fixme-all,warn-all,err-plugplay,err-seh,err-rpc,err-ntoskrnl,err-winediag,err-systray,err-hid`
+
+Add this to your `.bashrc` or `.zshrc` file as well.
+
+Next, let's try some non-Latin text. Unfortunately, the command-line parsing of
+our cross-compiled glib is not quite Unicode-aware, at least when run under
+Wine. So you will need to find some other way to feed Unicode text to the
+shaper. There are three different ways you can try:
+
+  - `echo حرف | wine build-win/util/hb-shape.exe perf/fonts/Amiri-Regular.ttf`
+  - `wine build-win/util/hb-shape.exe perf/fonts/Amiri-Regular.ttf -u 062D,0631,0641`
+  - `wine build-win/util/hb-shape.exe perf/fonts/Amiri-Regular.ttf --text-file harf.txt`
+
+To get the Unicode codepoints for a string, you can use the `hb-unicode-decode`
+utility:
+```
+$ test/shape/hb-unicode-decode حرف
+U+062D,U+0631,U+0641
+```
+
+8. Next, let's try the `hb-view` utility. By default, `hb-view` outputs ANSI text,
+which Wine will not display correctly. You can use the `-o` option to redirect the
+output to a file, or just redirect the output using the shell, which will produce
+a PNG file.
+
+  - `wine build-win/util/hb-view.exe perf/fonts/Roboto-Regular.ttf Test > test.png`
+
+7. As noted, if your Linux has `binfmt_misc` enabled, you can run the executables
+directly. If not, you can modify the cross-file to use the `exe_wrapper` option as
+specified before.
+
+  - `build-win/util/hb-shape.exe perf/fonts/Roboto-Regular.ttf Test`
+
+If that does not work, you can use the `wine` command as shown above.
+
+10. You can try running the test suite. If on Linux with `binfmt_misc` enabled, you
+can run the tests directly:
+
+  - `ninja -C build-win test`
+
+For other situations, use `meson devenv`:
+
+  - `meson devenv -C build-win ninja test`
+
+This might take a couple of minutes to run. Running under Wine is expensive, so
+be patient.
+
+If all goes well, tests should run. If all is well, you should probably see about
+400 tests pass, some skipped, but none failing.
+
+11. In the above testing situation, the `directwrite` test will be disabled
+automatically upon detection of running under Wine. The reason the `directwrite`
+test would otherwise fails is that we are running against the Wine-provided
+DirectWrite DLL, which is an incomplete reimplementation of the DirectWrite API
+by Wine, and not the real thing.
+
+If you want to test the Uniscribe or DirectWrite shapers against the real
+Uniscribe / DirectWrite, you can follow the instructions below.
+
+11. Old Uniscribe: Assuming a 32bit build for now.
+
+Bring a 32bit version of `usp10.dll` for yourself from
+`C:\Windows\SysWOW64\usp10.dll` of your 64bit Windows installation,
+or `C:\Windows\System32\usp10.dll` for 32bit Windows installation.
+
+You want one from Windows 7 or earlier.  One that is not just a proxy for
+`TextShaping.dll`.  Rule of thumb, your `usp10.dll` should have a size more
+than 500kb.
+
+Put the file in `~/.wine/drive_c/windows/syswow64/` so wine can find it.
+
+You can now tell wine to use the native `usp10.dll`:
+
+  - `export WINEDLLOVERRIDES="usp10=n"`
+  - `wine build-win/util/hb-shape.exe perf/fonts/Roboto-Regular.ttf Test --shaper=uniscribe`
+
+12. DirectWrite and new Uniscribe: You can use the same method to test the
+DirectWrite shaper against the native DirectWrite DLL. Try with a 64bit build
+this time.
+
+Bring `TextShaping.dll`, `DWrite.dll`, and `usp10.dll` from your 64bit Windows
+installation (`C:\Windows\System32`) to `~/.wine/drive_c/windows/system32/`.
+
+You want the ones from Windows 10 or later. You might have some luck downloading
+them from the internet, but be careful with the source. I had success with the
+DLLs from [https://dllme.com](dllme.com), but I cannot vouch for the site.
+
+You can now tell wine to use the native DirectWrite:
+
+  - `export WINEDLLOVERRIDES="textshaping,dwrite,usp10=n"`
+  - `wine build-win/util/hb-shape.exe perf/fonts/Roboto-Regular.ttf Test --shaper=directwrite`
+
+If all works well, you should be able to rerun the tests and see all pass this time.
+
+13. For some old instructions on how to test HarfBuzz's native Indic shaper against
+Uniscribe, see: https://github.com/harfbuzz/harfbuzz/issues/3671
+
+14. That's it! If you made it this far, you are now able to develop and test
+HarfBuzz on Windows, from Linux or macOS. Enjoy!
diff --git a/source/libs/harfbuzz/harfbuzz-src/RELEASING.md b/source/libs/harfbuzz/harfbuzz-src/RELEASING.md
index e510022a29e42a52717d3868e047e567b7639aa4..a8a6705f295b291aa68cd7d5cd47410d350d18ef 100644
--- a/source/libs/harfbuzz/harfbuzz-src/RELEASING.md
+++ b/source/libs/harfbuzz/harfbuzz-src/RELEASING.md
@@ -17,7 +17,7 @@
 
 - [ ] Based on severity of changes, decide whether it's a minor or micro release number bump.
 
-- [ ] Search for 'XSince: REPLACEME' on the repository and replace it with the chosen version for the release, e.g. 'Since: 1.4.7'.
+- [ ] Search for 'REPLACEME' on the repository and replace it with the chosen version for the release, e.g. 'Since: 1.4.7'.
 
 - [ ] Make sure you have correct date and new version at the top of NEWS file.
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/meson.build b/source/libs/harfbuzz/harfbuzz-src/meson.build
index 1460c2a9de7ddc3bac4cb7a7ced7d51f9350f675..91c94bf0a356b1f3cc8439cbadc6bc20d4b7fb05 100644
--- a/source/libs/harfbuzz/harfbuzz-src/meson.build
+++ b/source/libs/harfbuzz/harfbuzz-src/meson.build
@@ -1,11 +1,12 @@
-project('harfbuzz', 'c', 'cpp',
+project('harfbuzz', ['c', 'cpp'],
   meson_version: '>= 0.55.0',
-  version: '10.4.0',
+  version: '11.0.0',
   default_options: [
     'cpp_eh=none',          # Just to support msvc, we are passing -fno-exceptions also anyway
     # 'cpp_rtti=false',     # Do NOT enable, wraps inherit it and ICU needs RTTI
     'cpp_std=c++11',
     'wrap_mode=nofallback', # Use --wrap-mode=default to revert, https://github.com/harfbuzz/harfbuzz/pull/2548
+    'buildtype=debugoptimized',
   ],
 )
 
@@ -102,44 +103,36 @@ check_funcs = [
 
 m_dep = cpp.find_library('m', required: false)
 
-if meson.version().version_compare('>=0.60.0')
+# Painful hack to handle multiple dependencies but also respect options
+if get_option('freetype').disabled()
+  freetype_dep = dependency('', required: false)
+else
   # Sadly, FreeType's versioning schemes are different between pkg-config and CMake
-  # pkg-config: freetype2, cmake: Freetype
+
+  # Try pkg-config name
   freetype_dep = dependency('freetype2',
                             version: freetype_min_version,
                             method: 'pkg-config',
                             required: false,
                             allow_fallback: false)
   if not freetype_dep.found()
-    freetype_dep = dependency('FreeType',
+    # Try cmake name
+    freetype_dep = dependency('Freetype',
                               version: freetype_min_version_actual,
                               method: 'cmake',
-                              required: get_option('freetype'),
-                              default_options: ['harfbuzz=disabled'],
-                              allow_fallback: true)
-  endif
-else
-  # painful hack to handle multiple dependencies but also respect options
-  freetype_opt = get_option('freetype')
-  # we want to handle enabled manually after fallbacks, but also handle disabled normally
-  if freetype_opt.enabled()
-    freetype_opt = false
-  endif
-  # try pkg-config name
-  freetype_dep = dependency('freetype2', version: freetype_min_version, method: 'pkg-config', required: freetype_opt)
-  # when disabled, leave it not-found
-  if not freetype_dep.found() and not get_option('freetype').disabled()
-    # Try cmake name
-    freetype_dep = dependency('Freetype', version: freetype_min_version_actual, method: 'cmake', required: false)
-    # Subproject fallback, `allow_fallback: true` means the fallback will be
-    # tried even if the freetype option is set to `auto`.
+                              required: false,
+                              allow_fallback: false)
+    # Subproject fallback
     if not freetype_dep.found()
-      freetype_dep = dependency('freetype2',
-                                version: freetype_min_version,
-                                method: 'pkg-config',
+      freetype_proj = subproject('freetype2',
+                                version: freetype_min_version_actual,
                                 required: get_option('freetype'),
-                                default_options: ['harfbuzz=disabled'],
-                                allow_fallback: true)
+                                default_options: ['harfbuzz=disabled'])
+      if freetype_proj.found()
+        freetype_dep = freetype_proj.get_variable('freetype_dep')
+      else
+        freetype_dep = dependency('', required: false)
+      endif
     endif
   endif
 endif
@@ -227,16 +220,18 @@ endif
 
 chafa_dep = dependency('chafa', version: chafa_min_version, required: get_option('chafa'))
 
+fontations_dep_found = false
+if get_option('fontations').enabled()
+  add_languages(['rust'], native: false, required : true)
+  fontations_dep_found = true
+endif
+
 conf = configuration_data()
 incconfig = include_directories('.')
 
 add_project_arguments('-DHAVE_CONFIG_H', language: ['c', 'cpp'])
 
-warn_cflags = [
-  '-Wno-non-virtual-dtor',
-]
-
-cpp_args = cpp.get_supported_arguments(warn_cflags)
+cpp_args = []
 
 if glib_dep.found()
   conf.set('HAVE_GLIB', 1)
@@ -272,6 +267,10 @@ if chafa_dep.found()
   conf.set('HAVE_CHAFA', 1)
 endif
 
+if fontations_dep_found
+  conf.set('HAVE_FONTATIONS', 1)
+endif
+
 if wasm_dep.found()
   conf.set('HAVE_WASM', 1)
   conf.set('HB_WASM_MODULE_DIR', '"'+get_option('prefix')+'/'+get_option('libdir')+'/harfbuzz/wasm"')
@@ -315,7 +314,7 @@ endif
 gdi_uniscribe_deps = []
 # GDI (Uniscribe) (Windows)
 if host_machine.system() == 'windows' and not get_option('gdi').disabled()
-  if (get_option('directwrite').enabled() and
+  if (get_option('gdi').enabled() and
       not (cpp.has_header('usp10.h') and cpp.has_header('windows.h')))
     error('GDI/Uniscribe was enabled explicitly, but required headers are missing.')
   endif
@@ -335,10 +334,9 @@ endif
 
 # DirectWrite (Windows)
 if host_machine.system() == 'windows' and not get_option('directwrite').disabled()
-  if get_option('directwrite').enabled() and not cpp.has_header('dwrite_1.h')
+  if get_option('directwrite').enabled() and not cpp.has_header('dwrite_3.h')
     error('DirectWrite was enabled explicitly, but required header is missing.')
   endif
-
   conf.set('HAVE_DIRECTWRITE', 1)
 endif
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/meson_options.txt b/source/libs/harfbuzz/harfbuzz-src/meson_options.txt
index c53cf45fcb41e2e632dd15b584dd2abb3613a0ab..86258f89d0d1edbf24d0fd2d2641394fc5ae1d45 100644
--- a/source/libs/harfbuzz/harfbuzz-src/meson_options.txt
+++ b/source/libs/harfbuzz/harfbuzz-src/meson_options.txt
@@ -15,10 +15,12 @@ option('graphite2', type: 'feature', value: 'disabled',
   description: 'Enable Graphite2 complementary shaper')
 option('freetype', type: 'feature', value: 'auto',
   description: 'Enable freetype interop helpers')
+option('fontations', type: 'feature', value: 'disabled',
+  description: 'Enabled fontations font functions')
 option('gdi', type: 'feature', value: 'disabled',
   description: 'Enable GDI helpers and Uniscribe shaper backend (Windows only)')
 option('directwrite', type: 'feature', value: 'disabled',
-  description: 'Enable DirectWrite shaper backend on Windows (experimental)')
+  description: 'Enable DirectWrite shaper backend on Windows')
 option('coretext', type: 'feature', value: 'disabled',
   description: 'Enable CoreText shaper backend on macOS')
 option('wasm', type: 'feature', value: 'disabled',
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Color/COLR/COLR.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Color/COLR/COLR.hh
index cf10e894a410065418737cf8d602de0028ff55f9..16cd96e32d2eceb7b4a3cca6a0d6dd9432598608 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Color/COLR/COLR.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Color/COLR/COLR.hh
@@ -47,6 +47,11 @@ namespace OT {
 struct hb_paint_context_t;
 }
 
+struct hb_colr_scratch_t
+{
+  hb_paint_extents_context_t paint_extents;
+};
+
 namespace OT {
 
 struct COLR;
@@ -90,7 +95,8 @@ public:
     font (font_),
     palette (
 #ifndef HB_NO_COLOR
-	     font->face->table.CPAL->get_palette_colors (palette_)
+	     // https://github.com/harfbuzz/harfbuzz/issues/5116
+	     font->face->table.CPAL->get_palette_colors (palette_ < font->face->table.CPAL->get_palette_count () ? palette_ : 0)
 #endif
     ),
     foreground (foreground_),
@@ -932,9 +938,9 @@ struct PaintGlyph
   void paint_glyph (hb_paint_context_t *c) const
   {
     TRACE_PAINT (this);
-    c->funcs->push_inverse_root_transform (c->data, c->font);
+    c->funcs->push_inverse_font_transform (c->data, c->font);
     c->funcs->push_clip_glyph (c->data, gid, c->font);
-    c->funcs->push_root_transform (c->data, c->font);
+    c->funcs->push_font_transform (c->data, c->font);
     c->recurse (this+paint);
     c->funcs->pop_transform (c->data);
     c->funcs->pop_clip (c->data);
@@ -1511,10 +1517,12 @@ struct PaintComposite
   void paint_glyph (hb_paint_context_t *c) const
   {
     TRACE_PAINT (this);
+    c->funcs->push_group (c->data);
     c->recurse (this+backdrop);
     c->funcs->push_group (c->data);
     c->recurse (this+src);
     c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode);
+    c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
   }
 
   HBUINT8		format; /* format = 32 */
@@ -2079,6 +2087,8 @@ struct COLR
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
 
+  bool has_data () const { return has_v0_data () || version; }
+
   bool has_v0_data () const { return numBaseGlyphs; }
   bool has_v1_data () const
   {
@@ -2112,7 +2122,53 @@ struct COLR
   {
     accelerator_t (hb_face_t *face)
     { colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
-    ~accelerator_t () { this->colr.destroy (); }
+
+    ~accelerator_t ()
+    {
+      auto *scratch = cached_scratch.get_relaxed ();
+      if (scratch)
+      {
+	scratch->~hb_colr_scratch_t ();
+	hb_free (scratch);
+      }
+
+      colr.destroy ();
+    }
+
+
+    bool has_data () const { return colr->has_data (); }
+
+#ifndef HB_NO_PAINT
+    bool
+    get_extents (hb_font_t *font,
+		 hb_codepoint_t glyph,
+		 hb_glyph_extents_t *extents) const
+    {
+      if (unlikely (!has_data ())) return false;
+
+      hb_colr_scratch_t *scratch = acquire_scratch ();
+      if (unlikely (!scratch)) return true;
+      bool ret = colr->get_extents (font, glyph, extents, *scratch);
+      release_scratch (scratch);
+      return ret;
+    }
+
+    bool paint_glyph (hb_font_t *font,
+		      hb_codepoint_t glyph,
+		      hb_paint_funcs_t *funcs, void *data,
+		      unsigned int palette_index,
+		      hb_color_t foreground,
+		      bool clip = true) const
+    {
+      if (unlikely (!has_data ())) return false;
+
+      hb_colr_scratch_t *scratch = acquire_scratch ();
+      if (unlikely (!scratch)) return true;
+      bool ret = colr->paint_glyph (font, glyph, funcs, data, palette_index, foreground, clip, *scratch);
+      release_scratch (scratch);
+      return ret;
+    }
+#endif
 
     bool is_valid () { return colr.get_blob ()->length; }
 
@@ -2148,7 +2204,33 @@ struct COLR
     { return colr->get_delta_set_index_map_ptr (); }
 
     private:
+
+    hb_colr_scratch_t *acquire_scratch () const
+    {
+      hb_colr_scratch_t *scratch = cached_scratch.get_acquire ();
+
+      if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
+      {
+	scratch = (hb_colr_scratch_t *) hb_calloc (1, sizeof (hb_colr_scratch_t));
+	if (unlikely (!scratch))
+	  return nullptr;
+      }
+
+      return scratch;
+    }
+    void release_scratch (hb_colr_scratch_t *scratch) const
+    {
+      if (!cached_scratch.cmpexch (nullptr, scratch))
+      {
+	scratch->~hb_colr_scratch_t ();
+	hb_free (scratch);
+      }
+    }
+
+    public:
     hb_blob_ptr_t<COLR> colr;
+    private:
+    hb_atomic_t<hb_colr_scratch_t *> cached_scratch;
   };
 
   void closure_glyphs (hb_codepoint_t glyph,
@@ -2520,7 +2602,10 @@ struct COLR
 
 #ifndef HB_NO_PAINT
   bool
-  get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
+  get_extents (hb_font_t *font,
+	       hb_codepoint_t glyph,
+	       hb_glyph_extents_t *extents,
+	       hb_colr_scratch_t &scratch) const
   {
 
     ItemVarStoreInstancer instancer (get_var_store_ptr (),
@@ -2534,10 +2619,10 @@ struct COLR
     }
 
     auto *extents_funcs = hb_paint_extents_get_funcs ();
-    hb_paint_extents_context_t extents_data;
-    bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0));
+    scratch.paint_extents.clear ();
+    bool ret = paint_glyph (font, glyph, extents_funcs, &scratch.paint_extents, 0, HB_COLOR(0,0,0,0), true, scratch);
 
-    hb_extents_t e = extents_data.get_extents ();
+    auto e = scratch.paint_extents.get_extents ();
     if (e.is_void ())
     {
       extents->x_bearing = 0;
@@ -2547,6 +2632,7 @@ struct COLR
     }
     else
     {
+      // Ugh. We need to undo the synthetic slant here. Leave it for now. :-(.
       extents->x_bearing = e.xmin;
       extents->y_bearing = e.ymax;
       extents->width = e.xmax - e.xmin;
@@ -2583,7 +2669,12 @@ struct COLR
 
 #ifndef HB_NO_PAINT
   bool
-  paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
+  paint_glyph (hb_font_t *font,
+	       hb_codepoint_t glyph,
+	       hb_paint_funcs_t *funcs, void *data,
+	       unsigned int palette_index, hb_color_t foreground,
+	       bool clip,
+	       hb_colr_scratch_t &scratch) const
   {
     ItemVarStoreInstancer instancer (get_var_store_ptr (),
 				     get_delta_set_index_map_ptr (),
@@ -2609,6 +2700,7 @@ struct COLR
 	  if (get_clip (glyph, &extents, instancer))
 	  {
 	    font->scale_glyph_extents (&extents);
+	    font->synthetic_glyph_extents (&extents);
 	    c.funcs->push_clip_rectangle (c.data,
 					  extents.x_bearing,
 					  extents.y_bearing + extents.height,
@@ -2618,15 +2710,16 @@ struct COLR
 	  else
 	  {
 	    auto *extents_funcs = hb_paint_extents_get_funcs ();
-	    hb_paint_extents_context_t extents_data;
+	    scratch.paint_extents.clear ();
 
 	    paint_glyph (font, glyph,
-			 extents_funcs, &extents_data,
+			 extents_funcs, &scratch.paint_extents,
 			 palette_index, foreground,
-			 false);
+			 false,
+			 scratch);
 
-	    hb_extents_t extents = extents_data.get_extents ();
-	    is_bounded = extents_data.is_bounded ();
+	    auto extents = scratch.paint_extents.get_extents ();
+	    is_bounded = scratch.paint_extents.is_bounded ();
 
 	    c.funcs->push_clip_rectangle (c.data,
 					  extents.xmin,
@@ -2636,7 +2729,7 @@ struct COLR
 	  }
 	}
 
-	c.funcs->push_root_transform (c.data, font);
+	c.funcs->push_font_transform (c.data, font);
 
 	if (is_bounded)
 	  c.recurse (*paint);
@@ -2714,9 +2807,7 @@ void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
       return;
 
     const Paint &paint = paint_offset_lists.get_paint (i);
-    c->funcs->push_group (c->data);
     c->recurse (paint);
-    c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
   }
 }
 
@@ -2728,7 +2819,7 @@ void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
   if (unlikely (!node.visit (gid)))
     return;
 
-  c->funcs->push_inverse_root_transform (c->data, c->font);
+  c->funcs->push_inverse_font_transform (c->data, c->font);
   if (c->funcs->color_glyph (c->data, gid, c->font))
   {
     c->funcs->pop_transform (c->data);
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Var/VARC/VARC.cc b/source/libs/harfbuzz/harfbuzz-src/src/OT/Var/VARC/VARC.cc
index 3b9eec4fb3be4a34542fd02602ff9773f6ed93d2..5b43f187f10e706c7392682d0ca58e1b9415f508 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Var/VARC/VARC.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Var/VARC/VARC.cc
@@ -126,24 +126,18 @@ hb_transforming_pen_get_funcs ()
   return static_transforming_pen_funcs.get_unconst ();
 }
 
-
 hb_ubytes_t
-VarComponent::get_path_at (hb_font_t *font,
+VarComponent::get_path_at (const hb_varc_context_t &c,
 			   hb_codepoint_t parent_gid,
-			   hb_draw_session_t &draw_session,
 			   hb_array_t<const int> coords,
 			   hb_transform_t total_transform,
 			   hb_ubytes_t total_record,
-			   hb_decycler_t *decycler,
-			   signed *edges_left,
-			   signed depth_left,
-			   hb_glyf_scratch_t &scratch,
 			   VarRegionList::cache_t *cache) const
 {
   const unsigned char *end = total_record.arrayZ + total_record.length;
   const unsigned char *record = total_record.arrayZ;
 
-  auto &VARC = *font->face->table.VARC->table;
+  auto &VARC = *c.font->face->table.VARC->table;
   auto &varStore = &VARC+VARC.varStore;
 
 #define READ_UINT32VAR(name) \
@@ -193,9 +187,9 @@ VarComponent::get_path_at (hb_font_t *font,
 
   // Axis values
 
-  auto &axisIndices = scratch.axisIndices;
+  auto &axisIndices = c.scratch.axisIndices;
   axisIndices.clear ();
-  auto &axisValues = scratch.axisValues;
+  auto &axisValues = c.scratch.axisValues;
   axisValues.clear ();
   if (flags & (unsigned) flags_t::HAVE_AXES)
   {
@@ -222,7 +216,7 @@ VarComponent::get_path_at (hb_font_t *font,
    * 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<int> (font->coords, font->num_coords);
+    component_coords = hb_array<int> (c.font->coords, c.font->num_coords);
 
   // Transform
 
@@ -316,14 +310,18 @@ VarComponent::get_path_at (hb_font_t *font,
       transform.scaleY = transform.scaleX;
 
     total_transform.transform (transform.to_transform ());
-    total_transform.scale (font->x_mult ? 1.f / font->x_multf : 0.f,
-			   font->y_mult ? 1.f / font->y_multf : 0.f);
+    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;
 
-    VARC.get_path_at (font, gid,
-		      draw_session, component_coords, total_transform,
+    c.depth_left--;
+    VARC.get_path_at (c, gid,
+		      component_coords, total_transform,
 		      parent_gid,
-		      decycler, edges_left, depth_left - 1,
-		      scratch);
+		      same_coords ? cache : nullptr);
+    c.depth_left++;
   }
 
 #undef PROCESS_TRANSFORM_COMPONENTS
@@ -333,16 +331,12 @@ VarComponent::get_path_at (hb_font_t *font,
 }
 
 bool
-VARC::get_path_at (hb_font_t *font,
+VARC::get_path_at (const hb_varc_context_t &c,
 		   hb_codepoint_t glyph,
-		   hb_draw_session_t &draw_session,
 		   hb_array_t<const int> coords,
 		   hb_transform_t transform,
 		   hb_codepoint_t parent_glyph,
-		   hb_decycler_t *decycler,
-		   signed *edges_left,
-		   signed depth_left,
-		   hb_glyf_scratch_t &scratch) const
+		   VarRegionList::cache_t *parent_cache) const
 {
   // Don't recurse on the same glyph.
   unsigned idx = glyph == parent_glyph ?
@@ -350,50 +344,69 @@ VARC::get_path_at (hb_font_t *font,
 		 (this+coverage).get_coverage (glyph);
   if (idx == NOT_COVERED)
   {
-    // 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,
-					   draw_session.funcs,
-					   draw_session.draw_data,
-					   &draw_session.st};
-    hb_draw_session_t transformer_session {transformer_funcs, &context};
-    hb_draw_session_t &shape_draw_session = transform.is_identity () ? draw_session : transformer_session;
-
-    if (!font->face->table.glyf->get_path_at (font, glyph, shape_draw_session, coords, scratch))
+    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))
 #ifndef HB_NO_CFF
-    if (!font->face->table.cff2->get_path_at (font, glyph, shape_draw_session, coords))
-    if (!font->face->table.cff1->get_path (font, glyph, shape_draw_session)) // Doesn't have variations
+      if (!c.font->face->table.cff2->get_path_at (c.font, glyph, shape_draw_session, coords))
+      if (!c.font->face->table.cff1->get_path (c.font, glyph, shape_draw_session)) // Doesn't have variations
 #endif
-      return false;
+	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 (depth_left <= 0)
+  if (c.depth_left <= 0)
     return true;
 
-  if (*edges_left <= 0)
+  if (c.edges_left <= 0)
     return true;
-  (*edges_left)--;
+  (c.edges_left)--;
 
-  hb_decycler_node_t node (*decycler);
+  hb_decycler_node_t node (c.decycler);
   if (unlikely (!node.visit (glyph)))
     return true;
 
   hb_ubytes_t record = (this+glyphRecords)[idx];
 
   float static_cache[sizeof (void *) * 16];
-  VarRegionList::cache_t *cache = (this+varStore).create_cache (hb_array (static_cache));
+  VarRegionList::cache_t *cache = parent_cache ?
+				  parent_cache :
+				  (this+varStore).create_cache (hb_array (static_cache));
 
-  transform.scale (font->x_multf, font->y_multf);
+  transform.scale (c.font->x_multf, c.font->y_multf);
 
-  VarCompositeGlyph::get_path_at (font, glyph,
-				  draw_session, coords, transform,
+  VarCompositeGlyph::get_path_at (c,
+				  glyph,
+				  coords, transform,
 				  record,
-				  decycler, edges_left, depth_left,
-				  scratch,
 				  cache);
 
-  (this+varStore).destroy_cache (cache, hb_array (static_cache));
+  if (cache != parent_cache)
+    (this+varStore).destroy_cache (cache, hb_array (static_cache));
 
   return true;
 }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Var/VARC/VARC.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Var/VARC/VARC.hh
index 30e54b6bd2a41611a2d1a065092286bb051cafe9..22cfbb8ca8145a84f47991cb7c36a13dc47ca18e 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Var/VARC/VARC.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Var/VARC/VARC.hh
@@ -21,6 +21,24 @@ namespace OT {
 
 #ifndef HB_NO_VAR_COMPOSITES
 
+struct hb_varc_scratch_t
+{
+  hb_vector_t<unsigned> axisIndices;
+  hb_vector_t<float> axisValues;
+  hb_glyf_scratch_t glyf_scratch;
+};
+
+struct hb_varc_context_t
+{
+  hb_font_t *font;
+  hb_draw_session_t *draw_session;
+  hb_extents_t *extents;
+  mutable hb_decycler_t decycler;
+  mutable signed edges_left;
+  mutable signed depth_left;
+  hb_varc_scratch_t &scratch;
+};
+
 struct VarComponent
 {
   enum class flags_t : uint32_t
@@ -44,41 +62,32 @@ struct VarComponent
   };
 
   HB_INTERNAL hb_ubytes_t
-  get_path_at (hb_font_t *font,
+  get_path_at (const hb_varc_context_t &c,
 	       hb_codepoint_t parent_gid,
-	       hb_draw_session_t &draw_session,
 	       hb_array_t<const int> coords,
 	       hb_transform_t transform,
 	       hb_ubytes_t record,
-	       hb_decycler_t *decycler,
-	       signed *edges_left,
-	       signed depth_left,
-	       hb_glyf_scratch_t &scratch,
 	       VarRegionList::cache_t *cache = nullptr) const;
 };
 
 struct VarCompositeGlyph
 {
   static void
-  get_path_at (hb_font_t *font,
-	       hb_codepoint_t glyph,
-	       hb_draw_session_t &draw_session,
+  get_path_at (const hb_varc_context_t &c,
+	       hb_codepoint_t gid,
 	       hb_array_t<const int> coords,
 	       hb_transform_t transform,
 	       hb_ubytes_t record,
-	       hb_decycler_t *decycler,
-	       signed *edges_left,
-	       signed depth_left,
-	       hb_glyf_scratch_t &scratch,
-	       VarRegionList::cache_t *cache = nullptr)
+	       VarRegionList::cache_t *cache)
   {
     while (record)
     {
       const VarComponent &comp = * (const VarComponent *) (record.arrayZ);
-      record = comp.get_path_at (font, glyph,
-				 draw_session, coords, transform,
+      record = comp.get_path_at (c,
+				 gid,
+				 coords, transform,
 				 record,
-				 decycler, edges_left, depth_left, scratch, cache);
+				 cache);
     }
   }
 };
@@ -92,36 +101,47 @@ struct VARC
   static constexpr hb_tag_t tableTag = HB_TAG ('V', 'A', 'R', 'C');
 
   HB_INTERNAL bool
-  get_path_at (hb_font_t *font,
-	       hb_codepoint_t glyph,
-	       hb_draw_session_t &draw_session,
+  get_path_at (const hb_varc_context_t &c,
+	       hb_codepoint_t gid,
 	       hb_array_t<const int> coords,
-	       hb_transform_t transform,
-	       hb_codepoint_t parent_glyph,
-	       hb_decycler_t *decycler,
-	       signed *edges_left,
-	       signed depth_left,
-	       hb_glyf_scratch_t &scratch) const;
+	       hb_transform_t transform = HB_TRANSFORM_IDENTITY,
+	       hb_codepoint_t parent_gid = HB_CODEPOINT_INVALID,
+	       VarRegionList::cache_t *parent_cache = nullptr) const;
 
   bool
   get_path (hb_font_t *font,
 	    hb_codepoint_t gid,
 	    hb_draw_session_t &draw_session,
-	    hb_glyf_scratch_t &scratch) const
+	    hb_varc_scratch_t &scratch) const
   {
-    hb_decycler_t decycler;
-    signed edges = HB_MAX_GRAPH_EDGE_COUNT;
-
-    return get_path_at (font,
-			gid,
-			draw_session,
-			hb_array (font->coords, font->num_coords),
-			HB_TRANSFORM_IDENTITY,
-			HB_CODEPOINT_INVALID,
-			&decycler,
-			&edges,
-			HB_MAX_NESTING_LEVEL,
-			scratch);
+    hb_varc_context_t c {font,
+			 &draw_session,
+			 nullptr,
+			 hb_decycler_t {},
+			 HB_MAX_GRAPH_EDGE_COUNT,
+			 HB_MAX_NESTING_LEVEL,
+			 scratch};
+
+    return get_path_at (c, gid,
+			hb_array (font->coords, font->num_coords));
+  }
+
+  bool
+  get_extents (hb_font_t *font,
+	       hb_codepoint_t gid,
+	       hb_extents_t *extents,
+	       hb_varc_scratch_t &scratch) const
+  {
+    hb_varc_context_t c {font,
+			 nullptr,
+			 extents,
+			 hb_decycler_t {},
+			 HB_MAX_GRAPH_EDGE_COUNT,
+			 HB_MAX_NESTING_LEVEL,
+			 scratch};
+
+    return get_path_at (c, gid,
+			hb_array (font->coords, font->num_coords));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -150,7 +170,7 @@ struct VARC
       auto *scratch = cached_scratch.get_relaxed ();
       if (scratch)
       {
-	scratch->~hb_glyf_scratch_t ();
+	scratch->~hb_varc_scratch_t ();
 	hb_free (scratch);
       }
 
@@ -162,34 +182,60 @@ struct VARC
     {
       if (!table->has_data ()) return false;
 
-      hb_glyf_scratch_t *scratch;
+      auto *scratch = acquire_scratch ();
+      if (unlikely (!scratch)) return true;
+      bool ret = table->get_path (font, gid, draw_session, *scratch);
+      release_scratch (scratch);
+      return ret;
+    }
+
+    bool
+    get_extents (hb_font_t *font,
+		 hb_codepoint_t gid,
+		 hb_glyph_extents_t *extents) const
+    {
+      if (!table->has_data ()) return false;
+
+      hb_extents_t f_extents;
+
+      auto *scratch = acquire_scratch ();
+      if (unlikely (!scratch)) return true;
+      bool ret = table->get_extents (font, gid, &f_extents, *scratch);
+      release_scratch (scratch);
+
+      if (ret)
+	*extents = f_extents.to_glyph_extents (font->x_scale < 0, font->y_scale < 0);
+
+      return ret;
+    }
+
+    private:
 
-      // Borrow the cached strach buffer.
+    hb_varc_scratch_t *acquire_scratch () const
+    {
+      hb_varc_scratch_t *scratch = cached_scratch.get_acquire ();
+
+      if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
       {
-	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;
-	}
+	scratch = (hb_varc_scratch_t *) hb_calloc (1, sizeof (hb_varc_scratch_t));
+	if (unlikely (!scratch))
+	  return nullptr;
       }
 
-      bool ret = table->get_path (font, gid, draw_session, *scratch);
-
-      // Put it back.
+      return scratch;
+    }
+    void release_scratch (hb_varc_scratch_t *scratch) const
+    {
       if (!cached_scratch.cmpexch (nullptr, scratch))
       {
-        scratch->~hb_glyf_scratch_t ();
+	scratch->~hb_varc_scratch_t ();
 	hb_free (scratch);
       }
-
-      return ret;
     }
 
     private:
     hb_blob_ptr_t<VARC> table;
-    hb_atomic_ptr_t<hb_glyf_scratch_t> cached_scratch;
+    hb_atomic_t<hb_varc_scratch_t *> cached_scratch;
   };
 
   bool has_data () const { return version.major != 0; }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/glyf.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/glyf.hh
index fe4ae7b8c542cd71a1ff34fdd0b40f61b6d0692a..b136b150282681787dfb8e16ca5186f5ec058053 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/glyf.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/glyf.hh
@@ -429,16 +429,27 @@ struct glyf_accelerator_t
   }
 
   public:
-  bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
+
+  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)); }
+
+  bool get_extents_at (hb_font_t *font,
+		       hb_codepoint_t gid,
+		       hb_glyph_extents_t *extents,
+		       hb_array_t<const int> coords) const
   {
     if (unlikely (gid >= num_glyphs)) return false;
 
 #ifndef HB_NO_VAR
-    if (font->num_coords)
+    if (coords)
     {
       hb_glyf_scratch_t scratch;
-      return get_points (font, gid, points_aggregator_t (font, extents, nullptr, true),
-			 hb_array (font->coords, font->num_coords),
+      return get_points (font,
+			 gid,
+			 points_aggregator_t (font, extents, nullptr, true),
+			 coords,
 			 scratch);
     }
 #endif
@@ -532,7 +543,7 @@ struct glyf_accelerator_t
   unsigned int num_glyphs;
   hb_blob_ptr_t<loca> loca_table;
   hb_blob_ptr_t<glyf> glyf_table;
-  hb_atomic_ptr_t<hb_glyf_scratch_t> cached_scratch;
+  hb_atomic_t<hb_glyf_scratch_t *> cached_scratch;
 };
 
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/addTable.py b/source/libs/harfbuzz/harfbuzz-src/src/addTable.py
index 103f292dd6a4d70aacfe84b5ef5bb565fa3762b7..8ceda7ae8f0b3ed69355568f170b31f00b9ba070 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/addTable.py
+++ b/source/libs/harfbuzz/harfbuzz-src/src/addTable.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+
 import sys
 from fontTools.ttLib import TTFont
 from fontTools.ttLib.tables.DefaultTable import DefaultTable
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/check-symbols.py b/source/libs/harfbuzz/harfbuzz-src/src/check-symbols.py
index 91bf8b0671a350efffee1e8f7fed7edd706084bb..d0ea303e32bd0b239801e0390dcc623c0184ed36 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/check-symbols.py
+++ b/source/libs/harfbuzz/harfbuzz-src/src/check-symbols.py
@@ -7,18 +7,26 @@ os.environ['LC_ALL'] = 'C' # otherwise 'nm' prints in wrong order
 builddir = os.getenv ('builddir', os.path.dirname (__file__))
 libs = os.getenv ('libs', '.libs')
 
-IGNORED_SYMBOLS = '|'.join(['_fini', '_init', '_fdata', '_ftext', '_fbss',
+IGNORED_SYMBOLS = ['_fini', '_init', '_fdata', '_ftext', '_fbss',
 	'__bss_start', '__bss_start__', '__bss_end__', '_edata', '_end', '_bss_end__',
 	'__end__', '__gcov_.*', 'llvm_.*', 'flush_fn_list', 'writeout_fn_list', 'mangle_path',
-	'lprofDirMode', 'reset_fn_list'])
+	'lprofDirMode', 'reset_fn_list']
+
+# Rust
+IGNORED_SYMBOLS += [
+    'rust_eh_personality',
+    '_ZN3std9panicking11EMPTY_PANIC.*', # 'std::panicking::EMPTY_PANIC::.*'
+    '_ZN3std3sys3pal4unix4args3imp15ARGV_INIT_ARRAY.*', # 'std::sys::pal::unix::args::imp::ARGV_INIT_ARRAY::.*'
+    '_ZN17compiler_builtins4math4libm7generic4sqrt9RSQRT_TAB.*', # 'compiler_builtins::math::libm::generic::sqrt::RSQRT_TAB::.*'
+]
+
+IGNORED_SYMBOLS = '|'.join (IGNORED_SYMBOLS)
 
 nm = os.getenv ('NM', shutil.which ('nm'))
 if not nm:
 	print ('check-symbols.py: \'nm\' not found; skipping test')
 	sys.exit (77)
 
-cxxfilt = shutil.which ('c++filt')
-
 tested = False
 stat = 0
 
@@ -34,12 +42,6 @@ for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject'
 				    for s in re.findall (r'^.+ [BCDGIRSTu] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE)
 				    if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)]
 
-		# run again c++filt also if is available
-		if cxxfilt:
-			EXPORTED_SYMBOLS = subprocess.check_output (
-				[cxxfilt], input='\n'.join (EXPORTED_SYMBOLS).encode ()
-			).decode ('utf-8').splitlines ()
-
 		prefix = (symprefix + os.path.basename (so)).replace ('libharfbuzz', 'hb').replace ('-', '_').split ('.')[0]
 
 		print ('Checking that %s does not expose internal symbols' % so)
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/fontations/Cargo.lock b/source/libs/harfbuzz/harfbuzz-src/src/fontations/Cargo.lock
new file mode 100644
index 0000000000000000000000000000000000000000..b4cbe2d6e6f31add166476d7d0c1deb5fbb59a5e
--- /dev/null
+++ b/source/libs/harfbuzz/harfbuzz-src/src/fontations/Cargo.lock
@@ -0,0 +1,95 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "bytemuck"
+version = "1.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540"
+dependencies = [
+ "bytemuck_derive",
+]
+
+[[package]]
+name = "bytemuck_derive"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "font-types"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d868ec188a98bb014c606072edd47e52e7ab7297db943b0b28503121e1d037bd"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
+name = "harfbuzz_fontations"
+version = "0.0.0"
+dependencies = [
+ "read-fonts",
+ "skrifa",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.94"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.39"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "read-fonts"
+version = "0.27.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f14974c88fb4fd0a7203719f98020209248c9dbebaf9d10d860337797a905097"
+dependencies = [
+ "bytemuck",
+ "font-types",
+]
+
+[[package]]
+name = "skrifa"
+version = "0.29.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c0ca53de9bb9bee1720c727606275148463cd938eb6bde249dcedeec4967747"
+dependencies = [
+ "bytemuck",
+ "read-fonts",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.99"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/fontations/Cargo.toml b/source/libs/harfbuzz/harfbuzz-src/src/fontations/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..e239a26c347ff4856bd6929aa0fcf9cdf2f6bdb7
--- /dev/null
+++ b/source/libs/harfbuzz/harfbuzz-src/src/fontations/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "harfbuzz_fontations"
+edition = "2021"
+
+[dependencies]
+read-fonts = "0.27"
+skrifa = "0.29.2"
+
+[lib]
+name = "harfbuzz_fontations"
+path = "lib.rs"
+crate-type = ["staticlib"]
+
+[profile.release]
+strip = true
+lto = "fat"
+panic = "abort"
+overflow-checks = false
+codegen-units = 1
+
+[profile.debugoptimized]
+inherits = "release"
+debug = true
+codegen-units = 16
+strip = false
+
+[profile.dev]
+lto = "fat"
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/fontations/lib.rs b/source/libs/harfbuzz/harfbuzz-src/src/fontations/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..44ef1b133138aea008c133d3f438aec2c0be1cc5
--- /dev/null
+++ b/source/libs/harfbuzz/harfbuzz-src/src/fontations/lib.rs
@@ -0,0 +1,944 @@
+#![allow(non_camel_case_types)]
+#![allow(non_upper_case_globals)]
+include!(concat!(env!("OUT_DIR"), "/hb.rs"));
+
+use std::alloc::{GlobalAlloc, Layout};
+use std::collections::HashMap;
+use std::mem::transmute;
+use std::os::raw::c_void;
+use std::ptr::null_mut;
+use std::sync::atomic::{AtomicPtr, AtomicU32, Ordering};
+use std::sync::{Mutex, OnceLock};
+
+use read_fonts::tables::cpal::ColorRecord;
+use read_fonts::TableProvider;
+use skrifa::charmap::Charmap;
+use skrifa::charmap::MapVariant::Variant;
+use skrifa::color::{
+    Brush, ColorGlyphCollection, ColorPainter, ColorStop, CompositeMode, Extend, Transform,
+};
+use skrifa::font::FontRef;
+use skrifa::instance::{Location, NormalizedCoord, Size};
+use skrifa::metrics::{BoundingBox, GlyphMetrics};
+use skrifa::outline::pen::OutlinePen;
+use skrifa::outline::DrawSettings;
+use skrifa::OutlineGlyphCollection;
+use skrifa::{GlyphId, GlyphNames, MetadataProvider};
+
+struct MyAllocator;
+
+unsafe impl GlobalAlloc for MyAllocator {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        assert!(layout.align() <= 2 * std::mem::size_of::<*mut u8>());
+        hb_malloc(layout.size()) as *mut u8
+    }
+
+    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+        assert!(layout.align() <= 2 * std::mem::size_of::<*mut u8>());
+        hb_calloc(layout.size(), 1) as *mut u8
+    }
+
+    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+        assert!(layout.align() <= 2 * std::mem::size_of::<*mut u8>());
+        hb_realloc(ptr as *mut c_void, new_size) as *mut u8
+    }
+
+    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+        assert!(layout.align() <= 2 * std::mem::size_of::<*mut u8>());
+        hb_free(ptr as *mut c_void);
+    }
+}
+
+#[global_allocator]
+static GLOBAL: MyAllocator = MyAllocator;
+
+// A struct for storing your “fontations” data
+#[repr(C)]
+struct FontationsData<'a> {
+    face_blob: *mut hb_blob_t,
+    font: *mut hb_font_t,
+    font_ref: FontRef<'a>,
+    char_map: Charmap<'a>,
+    outline_glyphs: OutlineGlyphCollection<'a>,
+    color_glyphs: ColorGlyphCollection<'a>,
+    glyph_names: GlyphNames<'a>,
+    glyph_from_names: OnceLock<HashMap<String, hb_codepoint_t>>,
+    size: Size,
+
+    // Mutex for the below
+    mutex: Mutex<()>,
+    serial: AtomicU32,
+    x_mult: f32,
+    y_mult: f32,
+    location: Location,
+    glyph_metrics: Option<GlyphMetrics<'a>>,
+}
+
+impl FontationsData<'_> {
+    unsafe fn from_hb_font(font: *mut hb_font_t) -> Self {
+        let face_index = hb_face_get_index(hb_font_get_face(font));
+        let face_blob = hb_face_reference_blob(hb_font_get_face(font));
+        let blob_length = hb_blob_get_length(face_blob);
+        let blob_data = hb_blob_get_data(face_blob, null_mut());
+        let face_data = std::slice::from_raw_parts(blob_data as *const u8, blob_length as usize);
+
+        let font_ref = FontRef::from_index(face_data, face_index).unwrap();
+
+        let char_map = Charmap::new(&font_ref);
+
+        let outline_glyphs = font_ref.outline_glyphs();
+
+        let color_glyphs = font_ref.color_glyphs();
+
+        let glyph_names = font_ref.glyph_names();
+
+        let upem = hb_face_get_upem(hb_font_get_face(font));
+
+        let mut data = FontationsData {
+            face_blob,
+            font,
+            font_ref,
+            char_map,
+            outline_glyphs,
+            color_glyphs,
+            glyph_names,
+            glyph_from_names: OnceLock::new(),
+            size: Size::new(upem as f32),
+            mutex: Mutex::new(()),
+            x_mult: 1.0,
+            y_mult: 1.0,
+            serial: AtomicU32::new(u32::MAX),
+            location: Location::default(),
+            glyph_metrics: None,
+        };
+
+        data.check_for_updates();
+
+        data
+    }
+
+    unsafe fn _check_for_updates(&mut self) {
+        let font_serial = hb_font_get_serial(self.font);
+        let serial = self.serial.load(Ordering::Relaxed);
+        if serial == font_serial {
+            return;
+        }
+
+        let _lock = self.mutex.lock().unwrap();
+
+        let mut x_scale: i32 = 0;
+        let mut y_scale: i32 = 0;
+        hb_font_get_scale(self.font, &mut x_scale, &mut y_scale);
+        let upem = hb_face_get_upem(hb_font_get_face(self.font));
+        self.x_mult = x_scale as f32 / upem as f32;
+        self.y_mult = y_scale as f32 / upem as f32;
+
+        let mut num_coords: u32 = 0;
+        let coords = hb_font_get_var_coords_normalized(self.font, &mut num_coords);
+        let coords = if coords.is_null() {
+            &[]
+        } else {
+            std::slice::from_raw_parts(coords, num_coords as usize)
+        };
+        let all_zeros = coords.iter().all(|&x| x == 0);
+        // if all zeros, use Location::default()
+        // otherwise, use the provided coords.
+        // This currently doesn't seem to have a perf effect on fontations, but it's a good idea to
+        // check if the coords are all zeros before creating a Location.
+        self.location = if all_zeros {
+            Location::default()
+        } else {
+            let mut location = Location::new(num_coords as usize);
+            let coords_mut = location.coords_mut();
+            coords_mut
+                .iter_mut()
+                .zip(coords.iter().map(|v| NormalizedCoord::from_bits(*v as i16)))
+                .for_each(|(dest, source)| *dest = source);
+            location
+        };
+
+        let location = transmute::<&Location, &Location>(&self.location);
+        self.glyph_metrics = Some(self.font_ref.glyph_metrics(self.size, location));
+
+        self.serial.store(font_serial, Ordering::Release);
+    }
+    fn check_for_updates(&mut self) {
+        unsafe { self._check_for_updates() }
+    }
+}
+
+extern "C" fn _hb_fontations_data_destroy(font_data: *mut c_void) {
+    let data = unsafe { Box::from_raw(font_data as *mut FontationsData) };
+
+    unsafe {
+        hb_blob_destroy(data.face_blob);
+    }
+}
+
+fn struct_at_offset<T: Copy>(first: *const T, index: u32, stride: u32) -> T {
+    unsafe { *((first as *const u8).offset((index * stride) as isize) as *const T) }
+}
+
+fn struct_at_offset_mut<T: Copy>(first: *mut T, index: u32, stride: u32) -> &'static mut T {
+    unsafe { &mut *((first as *mut u8).offset((index * stride) as isize) as *mut T) }
+}
+
+extern "C" fn _hb_fontations_get_nominal_glyphs(
+    _font: *mut hb_font_t,
+    font_data: *mut ::std::os::raw::c_void,
+    count: ::std::os::raw::c_uint,
+    first_unicode: *const hb_codepoint_t,
+    unicode_stride: ::std::os::raw::c_uint,
+    first_glyph: *mut hb_codepoint_t,
+    glyph_stride: ::std::os::raw::c_uint,
+    _user_data: *mut ::std::os::raw::c_void,
+) -> ::std::os::raw::c_uint {
+    let data = unsafe { &*(font_data as *const FontationsData) };
+    let char_map = &data.char_map;
+
+    for i in 0..count {
+        let unicode = struct_at_offset(first_unicode, i, unicode_stride);
+        let Some(glyph) = char_map.map(unicode) else {
+            return i;
+        };
+        let glyph_id = glyph.to_u32() as hb_codepoint_t;
+        *struct_at_offset_mut(first_glyph, i, glyph_stride) = glyph_id;
+    }
+
+    count
+}
+extern "C" fn _hb_fontations_get_variation_glyph(
+    _font: *mut hb_font_t,
+    font_data: *mut ::std::os::raw::c_void,
+    unicode: hb_codepoint_t,
+    variation_selector: hb_codepoint_t,
+    glyph: *mut hb_codepoint_t,
+    _user_data: *mut ::std::os::raw::c_void,
+) -> hb_bool_t {
+    let data = unsafe { &*(font_data as *const FontationsData) };
+    let char_map = &data.char_map;
+
+    match char_map.map_variant(unicode, variation_selector) {
+        Some(Variant(glyph_id)) => {
+            unsafe { *glyph = glyph_id.to_u32() as hb_codepoint_t };
+            true as hb_bool_t
+        }
+        _ => false as hb_bool_t,
+    }
+}
+
+extern "C" fn _hb_fontations_get_glyph_h_advances(
+    _font: *mut hb_font_t,
+    font_data: *mut ::std::os::raw::c_void,
+    count: ::std::os::raw::c_uint,
+    first_glyph: *const hb_codepoint_t,
+    glyph_stride: ::std::os::raw::c_uint,
+    first_advance: *mut hb_position_t,
+    advance_stride: ::std::os::raw::c_uint,
+    _user_data: *mut ::std::os::raw::c_void,
+) {
+    let data = unsafe { &mut *(font_data as *mut FontationsData) };
+    data.check_for_updates();
+
+    let glyph_metrics = &data.glyph_metrics.as_ref().unwrap();
+
+    for i in 0..count {
+        let glyph = struct_at_offset(first_glyph, i, glyph_stride);
+        let glyph_id = GlyphId::new(glyph);
+        let advance = (glyph_metrics.advance_width(glyph_id).unwrap_or_default() * data.x_mult)
+            .round() as i32;
+        *struct_at_offset_mut(first_advance, i, advance_stride) = advance as hb_position_t;
+    }
+}
+extern "C" fn _hb_fontations_get_glyph_extents(
+    _font: *mut hb_font_t,
+    font_data: *mut ::std::os::raw::c_void,
+    glyph: hb_codepoint_t,
+    extents: *mut hb_glyph_extents_t,
+    _user_data: *mut ::std::os::raw::c_void,
+) -> hb_bool_t {
+    let data = unsafe { &mut *(font_data as *mut FontationsData) };
+    data.check_for_updates();
+
+    let glyph_metrics = &data.glyph_metrics.as_ref().unwrap();
+
+    let glyph_id = GlyphId::new(glyph);
+    let glyph_extents = glyph_metrics.bounds(glyph_id);
+    let Some(glyph_extents) = glyph_extents else {
+        return false as hb_bool_t;
+    };
+
+    let x_bearing = (glyph_extents.x_min * data.x_mult).round() as hb_position_t;
+    let width = (glyph_extents.x_max * data.x_mult).round() as hb_position_t - x_bearing;
+    let y_bearing = (glyph_extents.y_max * data.y_mult).round() as hb_position_t;
+    let height = (glyph_extents.y_min * data.y_mult).round() as hb_position_t - y_bearing;
+
+    unsafe {
+        *extents = hb_glyph_extents_t {
+            x_bearing,
+            y_bearing,
+            width,
+            height,
+        };
+    }
+
+    true as hb_bool_t
+}
+
+extern "C" fn _hb_fontations_get_font_h_extents(
+    _font: *mut hb_font_t,
+    font_data: *mut ::std::os::raw::c_void,
+    extents: *mut hb_font_extents_t,
+    _user_data: *mut ::std::os::raw::c_void,
+) -> hb_bool_t {
+    let data = unsafe { &mut *(font_data as *mut FontationsData) };
+    data.check_for_updates();
+
+    let font_ref = &data.font_ref;
+    let size = &data.size;
+    let location = &data.location;
+    let metrics = font_ref.metrics(*size, location);
+
+    unsafe {
+        (*extents).ascender = (metrics.ascent * data.y_mult).round() as hb_position_t;
+        (*extents).descender = (metrics.descent * data.y_mult).round() as hb_position_t;
+        (*extents).line_gap = (metrics.leading * data.y_mult).round() as hb_position_t;
+    }
+
+    true as hb_bool_t
+}
+
+struct HbPen {
+    x_mult: f32,
+    y_mult: f32,
+    draw_state: *mut hb_draw_state_t,
+    draw_funcs: *mut hb_draw_funcs_t,
+    draw_data: *mut c_void,
+}
+
+impl OutlinePen for HbPen {
+    fn move_to(&mut self, x: f32, y: f32) {
+        unsafe {
+            hb_draw_move_to(
+                self.draw_funcs,
+                self.draw_data,
+                self.draw_state,
+                x * self.x_mult,
+                y * self.y_mult,
+            );
+        }
+    }
+    fn line_to(&mut self, x: f32, y: f32) {
+        unsafe {
+            hb_draw_line_to(
+                self.draw_funcs,
+                self.draw_data,
+                self.draw_state,
+                x * self.x_mult,
+                y * self.y_mult,
+            );
+        }
+    }
+    fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) {
+        unsafe {
+            hb_draw_quadratic_to(
+                self.draw_funcs,
+                self.draw_data,
+                self.draw_state,
+                x1 * self.x_mult,
+                y1 * self.y_mult,
+                x * self.x_mult,
+                y * self.y_mult,
+            );
+        }
+    }
+    fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
+        unsafe {
+            hb_draw_cubic_to(
+                self.draw_funcs,
+                self.draw_data,
+                self.draw_state,
+                x1 * self.x_mult,
+                y1 * self.y_mult,
+                x2 * self.x_mult,
+                y2 * self.y_mult,
+                x * self.x_mult,
+                y * self.y_mult,
+            );
+        }
+    }
+    fn close(&mut self) {
+        unsafe {
+            hb_draw_close_path(self.draw_funcs, self.draw_data, self.draw_state);
+        }
+    }
+}
+
+extern "C" fn _hb_fontations_draw_glyph(
+    font: *mut hb_font_t,
+    font_data: *mut ::std::os::raw::c_void,
+    glyph: hb_codepoint_t,
+    draw_funcs: *mut hb_draw_funcs_t,
+    draw_data: *mut ::std::os::raw::c_void,
+    _user_data: *mut ::std::os::raw::c_void,
+) {
+    let data = unsafe { &mut *(font_data as *mut FontationsData) };
+    data.check_for_updates();
+
+    let size = &data.size;
+    let location = &data.location;
+    let outline_glyphs = &data.outline_glyphs;
+
+    // Create an outline-glyph
+    let glyph_id = GlyphId::new(glyph);
+    let Some(outline_glyph) = outline_glyphs.get(glyph_id) else {
+        return;
+    };
+    let draw_settings = DrawSettings::unhinted(*size, location);
+    // Allocate zero bytes for the draw_state_t on the stack.
+    let mut draw_state: hb_draw_state_t = unsafe { std::mem::zeroed::<hb_draw_state_t>() };
+
+    let slant = unsafe { hb_font_get_synthetic_slant(font) };
+    let mut x_scale: i32 = 0;
+    let mut y_scale: i32 = 0;
+    unsafe {
+        hb_font_get_scale(font, &mut x_scale, &mut y_scale);
+    }
+    let slant = if y_scale != 0 {
+        slant as f32 * x_scale as f32 / y_scale as f32
+    } else {
+        0.
+    };
+    draw_state.slant_xy = slant;
+
+    let mut pen = HbPen {
+        x_mult: data.x_mult,
+        y_mult: data.y_mult,
+        draw_state: &mut draw_state,
+        draw_funcs,
+        draw_data,
+    };
+
+    let _ = outline_glyph.draw(draw_settings, &mut pen);
+}
+
+struct HbColorPainter<'a> {
+    font: *mut hb_font_t,
+    paint_funcs: *mut hb_paint_funcs_t,
+    paint_data: *mut c_void,
+    color_records: &'a [ColorRecord],
+    foreground: hb_color_t,
+}
+
+impl HbColorPainter<'_> {
+    fn lookup_color(&self, color_index: u16, alpha: f32) -> hb_color_t {
+        if color_index == 0xFFFF {
+            // Apply alpha to foreground color
+            return ((self.foreground & 0xFFFFFF00)
+                | (((self.foreground & 0xFF) as f32 * alpha).round() as u32))
+                as hb_color_t;
+        }
+
+        let c = self.color_records.get(color_index as usize);
+        if c.is_some() {
+            let c = c.unwrap();
+            (((c.blue as u32) << 24)
+                | ((c.green as u32) << 16)
+                | ((c.red as u32) << 8)
+                | ((c.alpha as f32 * alpha).round() as u32)) as hb_color_t
+        } else {
+            0 as hb_color_t
+        }
+    }
+
+    fn make_color_line(&self, color_line: &ColorLineData) -> hb_color_line_t {
+        let mut cl = unsafe { std::mem::zeroed::<hb_color_line_t>() };
+        cl.data = color_line as *const ColorLineData as *mut ::std::os::raw::c_void;
+        cl.get_color_stops = Some(_hb_fontations_get_color_stops);
+        cl.get_extend = Some(_hb_fontations_get_extend);
+        cl
+    }
+}
+
+struct ColorLineData<'a> {
+    painter: &'a HbColorPainter<'a>,
+    color_stops: &'a [ColorStop],
+    extend: Extend,
+}
+extern "C" fn _hb_fontations_get_color_stops(
+    _color_line: *mut hb_color_line_t,
+    color_line_data: *mut ::std::os::raw::c_void,
+    start: ::std::os::raw::c_uint,
+    count_out: *mut ::std::os::raw::c_uint,
+    color_stops_out: *mut hb_color_stop_t,
+    _user_data: *mut ::std::os::raw::c_void,
+) -> ::std::os::raw::c_uint {
+    let color_line_data = unsafe { &*(color_line_data as *const ColorLineData) };
+    let color_stops = &color_line_data.color_stops;
+    if count_out.is_null() {
+        return color_stops.len() as u32;
+    }
+    let count = unsafe { *count_out };
+    for i in 0..count {
+        let Some(stop) = color_stops.get(start as usize + i as usize) else {
+            unsafe {
+                *count_out = i;
+            };
+            break;
+        };
+        unsafe {
+            *(color_stops_out.offset(i as isize)) = hb_color_stop_t {
+                offset: stop.offset,
+                color: color_line_data
+                    .painter
+                    .lookup_color(stop.palette_index, stop.alpha),
+                is_foreground: (stop.palette_index == 0xFFFF) as hb_bool_t,
+            };
+        }
+    }
+    color_stops.len() as u32
+}
+extern "C" fn _hb_fontations_get_extend(
+    _color_line: *mut hb_color_line_t,
+    color_line_data: *mut ::std::os::raw::c_void,
+    _user_data: *mut ::std::os::raw::c_void,
+) -> hb_paint_extend_t {
+    let color_line_data = unsafe { &*(color_line_data as *const ColorLineData) };
+    color_line_data.extend as hb_paint_extend_t // They are the same
+}
+
+pub fn _hb_fontations_unreduce_anchors(
+    x0: f32,
+    y0: f32,
+    x1: f32,
+    y1: f32,
+) -> (f32, f32, f32, f32, f32, f32) {
+    /* Returns (x0, y0, x1, y1, x2, y2) such that the original
+     * `_hb_cairo_reduce_anchors` would produce (xx0, yy0, xx1, yy1)
+     * as outputs.
+     * The OT spec has the following wording; we just need to
+     * invert that operation here:
+     *
+     * Note: An implementation can derive a single vector, from p₀ to a point p₃, by computing the
+     * orthogonal projection of the vector from p₀ to p₁ onto a line perpendicular to line p₀p₂ and
+     * passing through p₀ to obtain point p₃. The linear gradient defined using p₀, p₁ and p₂ as
+     * described above is functionally equivalent to a linear gradient defined by aligning stop
+     * offset 0 to p₀ and aligning stop offset 1.0 to p₃, with each color projecting on either side
+     * of that line in a perpendicular direction. This specification uses three points, p₀, p₁ and
+     * p₂, as that provides greater flexibility in controlling the placement and rotation of the
+     * gradient, as well as variations thereof.
+     */
+
+    let dx = x1 - x0;
+    let dy = y1 - y0;
+
+    (x0, y0, x1, y1, x0 + dy, y0 - dx)
+}
+
+impl ColorPainter for HbColorPainter<'_> {
+    fn push_transform(&mut self, transform: Transform) {
+        unsafe {
+            hb_paint_push_transform(
+                self.paint_funcs,
+                self.paint_data,
+                transform.xx,
+                transform.yx,
+                transform.xy,
+                transform.yy,
+                transform.dx,
+                transform.dy,
+            );
+        }
+    }
+    fn pop_transform(&mut self) {
+        unsafe {
+            hb_paint_pop_transform(self.paint_funcs, self.paint_data);
+        }
+    }
+    fn fill_glyph(
+        &mut self,
+        glyph_id: GlyphId,
+        brush_transform: Option<Transform>,
+        brush: Brush<'_>,
+    ) {
+        unsafe {
+            hb_paint_push_inverse_font_transform(self.paint_funcs, self.paint_data, self.font);
+        }
+        self.push_clip_glyph(glyph_id);
+        unsafe {
+            hb_paint_push_font_transform(self.paint_funcs, self.paint_data, self.font);
+        }
+        if let Some(wrap_in_transform) = brush_transform {
+            self.push_transform(wrap_in_transform);
+            self.fill(brush);
+            self.pop_transform();
+        } else {
+            self.fill(brush);
+        }
+        self.pop_transform();
+        self.pop_clip();
+        self.pop_transform();
+    }
+    fn push_clip_glyph(&mut self, glyph_id: GlyphId) {
+        unsafe {
+            hb_paint_push_clip_glyph(
+                self.paint_funcs,
+                self.paint_data,
+                glyph_id.to_u32() as hb_codepoint_t,
+                self.font,
+            );
+        }
+    }
+    fn push_clip_box(&mut self, bbox: BoundingBox) {
+        unsafe {
+            hb_paint_push_clip_rectangle(
+                self.paint_funcs,
+                self.paint_data,
+                bbox.x_min,
+                bbox.y_min,
+                bbox.x_max,
+                bbox.y_max,
+            );
+        }
+    }
+    fn pop_clip(&mut self) {
+        unsafe {
+            hb_paint_pop_clip(self.paint_funcs, self.paint_data);
+        }
+    }
+    fn fill(&mut self, brush: Brush) {
+        match brush {
+            Brush::Solid {
+                palette_index: color_index,
+                alpha,
+            } => {
+                let is_foreground = color_index == 0xFFFF;
+                unsafe {
+                    hb_paint_color(
+                        self.paint_funcs,
+                        self.paint_data,
+                        is_foreground as hb_bool_t,
+                        self.lookup_color(color_index, alpha),
+                    );
+                }
+            }
+            Brush::LinearGradient {
+                color_stops,
+                extend,
+                p0,
+                p1,
+            } => {
+                let color_stops = ColorLineData {
+                    painter: self,
+                    color_stops,
+                    extend,
+                };
+                let mut color_line = self.make_color_line(&color_stops);
+
+                let (x0, y0, x1, y1, x2, y2) =
+                    _hb_fontations_unreduce_anchors(p0.x, p0.y, p1.x, p1.y);
+
+                unsafe {
+                    hb_paint_linear_gradient(
+                        self.paint_funcs,
+                        self.paint_data,
+                        &mut color_line,
+                        x0,
+                        y0,
+                        x1,
+                        y1,
+                        x2,
+                        y2,
+                    );
+                }
+            }
+            Brush::RadialGradient {
+                color_stops,
+                extend,
+                c0,
+                r0,
+                c1,
+                r1,
+            } => {
+                let color_stops = ColorLineData {
+                    painter: self,
+                    color_stops,
+                    extend,
+                };
+                let mut color_line = self.make_color_line(&color_stops);
+                unsafe {
+                    hb_paint_radial_gradient(
+                        self.paint_funcs,
+                        self.paint_data,
+                        &mut color_line,
+                        c0.x,
+                        c0.y,
+                        r0,
+                        c1.x,
+                        c1.y,
+                        r1,
+                    );
+                }
+            }
+            Brush::SweepGradient {
+                color_stops,
+                extend,
+                c0,
+                start_angle,
+                end_angle,
+            } => {
+                let color_stops = ColorLineData {
+                    painter: self,
+                    color_stops,
+                    extend,
+                };
+                let mut color_line = self.make_color_line(&color_stops);
+                // Skrifa has this gem, so we swap end_angle and start_angle
+                // when passing to our API:
+                //
+                //  * Convert angles and stops from counter-clockwise to clockwise
+                //  * for the shader if the gradient is not already reversed due to
+                //  * start angle being larger than end angle.
+                //
+                //  Undo that.
+                let (start_angle, end_angle) = (360. - start_angle, 360. - end_angle);
+                let start_angle = start_angle.to_radians();
+                let end_angle = end_angle.to_radians();
+                unsafe {
+                    hb_paint_sweep_gradient(
+                        self.paint_funcs,
+                        self.paint_data,
+                        &mut color_line,
+                        c0.x,
+                        c0.y,
+                        start_angle,
+                        end_angle,
+                    );
+                }
+            }
+        }
+    }
+    fn push_layer(&mut self, _mode: CompositeMode) {
+        unsafe {
+            hb_paint_push_group(self.paint_funcs, self.paint_data);
+        }
+    }
+    fn pop_layer_with_mode(&mut self, mode: CompositeMode) {
+        let mode = mode as hb_paint_composite_mode_t; // They are the same
+        unsafe {
+            hb_paint_pop_group(self.paint_funcs, self.paint_data, mode);
+        }
+    }
+}
+
+extern "C" fn _hb_fontations_paint_glyph(
+    font: *mut hb_font_t,
+    font_data: *mut ::std::os::raw::c_void,
+    glyph: hb_codepoint_t,
+    paint_funcs: *mut hb_paint_funcs_t,
+    paint_data: *mut ::std::os::raw::c_void,
+    palette_index: ::std::os::raw::c_uint,
+    foreground: hb_color_t,
+    _user_data: *mut ::std::os::raw::c_void,
+) {
+    let data = unsafe { &mut *(font_data as *mut FontationsData) };
+    data.check_for_updates();
+
+    let font_ref = &data.font_ref;
+    let location = &data.location;
+    let color_glyphs = &data.color_glyphs;
+
+    // Create an color-glyph
+    let glyph_id = GlyphId::new(glyph);
+    let Some(color_glyph) = color_glyphs.get(glyph_id) else {
+        return;
+    };
+
+    let cpal = font_ref.cpal();
+    let color_records = if cpal.is_err() {
+        unsafe { std::slice::from_raw_parts(std::ptr::NonNull::dangling().as_ptr(), 0) }
+    } else {
+        let cpal = cpal.unwrap();
+        let num_entries = cpal.num_palette_entries().into();
+        let color_records = cpal.color_records_array();
+        let start_index = cpal.color_record_indices().get(palette_index as usize);
+        let start_index = if start_index.is_some() {
+            start_index
+        } else {
+            // https://github.com/harfbuzz/harfbuzz/issues/5116
+            cpal.color_record_indices().first()
+        };
+
+        if let (Some(Ok(color_records)), Some(start_index)) = (color_records, start_index) {
+            let start_index: usize = start_index.get().into();
+            let color_records = &color_records[start_index..start_index + num_entries];
+            unsafe { std::slice::from_raw_parts(color_records.as_ptr(), num_entries) }
+        } else {
+            unsafe { std::slice::from_raw_parts(std::ptr::NonNull::dangling().as_ptr(), 0) }
+        }
+    };
+
+    let mut painter = HbColorPainter {
+        font,
+        paint_funcs,
+        paint_data,
+        color_records,
+        foreground,
+    };
+    unsafe {
+        hb_paint_push_font_transform(paint_funcs, paint_data, font);
+    }
+    let _ = color_glyph.paint(location, &mut painter);
+}
+
+extern "C" fn _hb_fontations_glyph_name(
+    _font: *mut hb_font_t,
+    font_data: *mut ::std::os::raw::c_void,
+    glyph: hb_codepoint_t,
+    name: *mut ::std::os::raw::c_char,
+    size: ::std::os::raw::c_uint,
+    _user_data: *mut ::std::os::raw::c_void,
+) -> hb_bool_t {
+    let data = unsafe { &mut *(font_data as *mut FontationsData) };
+
+    let glyph_name = data.glyph_names.get(GlyphId::new(glyph));
+    match glyph_name {
+        None => false as hb_bool_t,
+        Some(glyph_name) => {
+            let glyph_name = glyph_name.as_str();
+            // Copy the glyph name into the buffer, up to size-1 bytes
+            let len = glyph_name.len().min(size as usize - 1);
+            unsafe {
+                std::ptr::copy_nonoverlapping(glyph_name.as_ptr(), name as *mut u8, len);
+                *name.add(len) = 0;
+            }
+            true as hb_bool_t
+        }
+    }
+}
+
+extern "C" fn _hb_fontations_glyph_from_name(
+    _font: *mut hb_font_t,
+    font_data: *mut ::std::os::raw::c_void,
+    name: *const ::std::os::raw::c_char,
+    len: ::std::os::raw::c_int,
+    glyph: *mut hb_codepoint_t,
+    _user_data: *mut ::std::os::raw::c_void,
+) -> hb_bool_t {
+    let data = unsafe { &mut *(font_data as *mut FontationsData) };
+
+    let name = unsafe { std::slice::from_raw_parts(name as *const u8, len as usize) };
+    let name = std::str::from_utf8(name).unwrap_or_default();
+
+    let glyph_from_names = data.glyph_from_names.get_or_init(|| {
+        data.glyph_names
+            .iter()
+            .map(|(gid, name)| (name.to_string(), gid.to_u32()))
+            .collect()
+    });
+    let glyph_id = glyph_from_names.get(name);
+
+    match glyph_id {
+        None => false as hb_bool_t,
+        Some(glyph_id) => {
+            unsafe {
+                *glyph = *glyph_id;
+            }
+            true as hb_bool_t
+        }
+    }
+}
+
+fn _hb_fontations_font_funcs_get() -> *mut hb_font_funcs_t {
+    static static_ffuncs: AtomicPtr<hb_font_funcs_t> = AtomicPtr::new(null_mut());
+
+    loop {
+        let mut ffuncs = static_ffuncs.load(Ordering::Acquire);
+
+        if !ffuncs.is_null() {
+            return ffuncs;
+        }
+
+        ffuncs = unsafe { hb_font_funcs_create() };
+
+        unsafe {
+            hb_font_funcs_set_nominal_glyphs_func(
+                ffuncs,
+                Some(_hb_fontations_get_nominal_glyphs),
+                null_mut(),
+                None,
+            );
+            hb_font_funcs_set_variation_glyph_func(
+                ffuncs,
+                Some(_hb_fontations_get_variation_glyph),
+                null_mut(),
+                None,
+            );
+            hb_font_funcs_set_glyph_h_advances_func(
+                ffuncs,
+                Some(_hb_fontations_get_glyph_h_advances),
+                null_mut(),
+                None,
+            );
+            hb_font_funcs_set_glyph_extents_func(
+                ffuncs,
+                Some(_hb_fontations_get_glyph_extents),
+                null_mut(),
+                None,
+            );
+            hb_font_funcs_set_font_h_extents_func(
+                ffuncs,
+                Some(_hb_fontations_get_font_h_extents),
+                null_mut(),
+                None,
+            );
+            hb_font_funcs_set_draw_glyph_func(
+                ffuncs,
+                Some(_hb_fontations_draw_glyph),
+                null_mut(),
+                None,
+            );
+            hb_font_funcs_set_paint_glyph_func(
+                ffuncs,
+                Some(_hb_fontations_paint_glyph),
+                null_mut(),
+                None,
+            );
+            hb_font_funcs_set_glyph_name_func(
+                ffuncs,
+                Some(_hb_fontations_glyph_name),
+                null_mut(),
+                None,
+            );
+            hb_font_funcs_set_glyph_from_name_func(
+                ffuncs,
+                Some(_hb_fontations_glyph_from_name),
+                null_mut(),
+                None,
+            );
+        }
+
+        if (static_ffuncs.compare_exchange(null_mut(), ffuncs, Ordering::SeqCst, Ordering::Relaxed))
+            == Ok(null_mut())
+        {
+            return ffuncs;
+        } else {
+            unsafe {
+                hb_font_funcs_destroy(ffuncs);
+            }
+        }
+    }
+}
+
+/// # Safety
+///
+/// This function is unsafe because it connects with the HarfBuzz API.
+#[no_mangle]
+pub unsafe extern "C" fn hb_fontations_font_set_funcs(font: *mut hb_font_t) {
+    let ffuncs = _hb_fontations_font_funcs_get();
+
+    let data = FontationsData::from_hb_font(font);
+    let data_ptr = Box::into_raw(Box::new(data)) as *mut c_void;
+
+    hb_font_set_funcs(font, ffuncs, data_ptr, Some(_hb_fontations_data_destroy));
+}
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/fontations/meson.build b/source/libs/harfbuzz/harfbuzz-src/src/fontations/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..7f26f3570a3a18d5f7bf50b66bbb372e37d4054c
--- /dev/null
+++ b/source/libs/harfbuzz/harfbuzz-src/src/fontations/meson.build
@@ -0,0 +1,105 @@
+rust = import('unstable-rust')
+
+hb_rs = rust.bindgen(
+  input : '../hb.h',
+  output : 'hb.rs',
+  include_directories: incsrc,
+  args : ['--allowlist-function=hb_.*',
+          '--allowlist-type=hb_.*',
+          '--no-copy=hb_.*',
+          ],
+)
+
+cargo = find_program('cargo')
+rustfmt = find_program('rustfmt')
+
+rust_flags = ''
+cargo_args = [
+  '--package', 'harfbuzz_fontations',
+  '--lib',
+  '--target-dir', meson.current_build_dir(),
+  '--manifest-path', meson.current_source_dir() / 'Cargo.toml',
+  '-Z', 'build-std=std,panic_abort',
+  '-Z', 'build-std-features=panic_immediate_abort',
+]
+
+buildtype = get_option('buildtype')
+if buildtype == 'release' or buildtype == 'debugoptimized'
+  cargo_args += ['--profile', buildtype]
+endif
+
+opt_level = get_option('optimization')
+rust_flags += ' -C opt-level=' + opt_level
+
+harfbuzz_fontations = custom_target(
+  'harfbuzz_fontations',
+  input: ['lib.rs', 'Cargo.toml', 'Cargo.lock'],
+  output: ['libharfbuzz_fontations.a'],
+  depends: [hb_rs],
+  env: ['OUT_DIR=' + meson.current_build_dir(),
+        'RUSTFLAGS=' + rust_flags,
+  ],
+  command: [
+    cargo, 'build',
+    ] + cargo_args + [
+    '-Z', 'unstable-options',
+    '--artifact-dir', meson.current_build_dir(),
+  ],
+  install: true,
+  install_dir: join_paths(get_option('prefix'), 'lib'),
+)
+
+harfbuzz_fontations_dep = declare_dependency(
+  link_with: harfbuzz_fontations,
+)
+
+clippy_fix = run_target(
+  'clippy-fix',
+  env: ['OUT_DIR=' + meson.current_build_dir()],
+  depends: [hb_rs, harfbuzz_fontations],
+  command: [
+    cargo, 'clippy',
+    ] + cargo_args + [
+    '--allow-dirty', '--fix',
+  ],
+)
+if get_option('tests').enabled() and cargo.found()
+  test(
+    'clippy',
+    cargo,
+    env: ['OUT_DIR=' + meson.current_build_dir()],
+    depends: [hb_rs, harfbuzz_fontations],
+    args: [
+      'clippy',
+      ] + cargo_args + [
+      '--', '-D', 'warnings',
+    ],
+    timeout: 120,
+  )
+endif
+
+rustfmt_fix = run_target(
+  'rustfmt-fix',
+  env: ['OUT_DIR=' + meson.current_build_dir()],
+  depends: [hb_rs],
+  command: [
+    rustfmt,
+    '--edition', '2021',
+    '--',
+    meson.current_source_dir() / 'lib.rs',
+  ],
+)
+if get_option('tests').enabled() and rustfmt.found()
+  test(
+    'rustfmt',
+    rustfmt,
+    env: ['OUT_DIR=' + meson.current_build_dir()],
+    depends: [hb_rs],
+    args: [
+      '--check',
+      '--edition', '2021',
+      '--',
+      meson.current_source_dir() / 'lib.rs',
+    ],
+  )
+endif
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/gen-ragel-artifacts.py b/source/libs/harfbuzz/harfbuzz-src/src/gen-ragel-artifacts.py
index 8bbb375bfb80a5467554490d7f360f7d74f0993a..84bd7b22e8c9d847653281796531d288c79ae4c5 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/gen-ragel-artifacts.py
+++ b/source/libs/harfbuzz/harfbuzz-src/src/gen-ragel-artifacts.py
@@ -19,7 +19,9 @@ outdir = os.path.dirname (OUTPUT)
 shutil.copy (INPUT, outdir)
 rl = os.path.basename (INPUT)
 hh = rl.replace ('.rl', '.hh')
-subprocess.Popen (ragel.split() + ['-e', '-F1', '-o', hh, rl], cwd=outdir).wait ()
+ret = subprocess.Popen (ragel.split() + ['-e', '-F1', '-o', hh, rl], cwd=outdir).wait ()
+if ret:
+    sys.exit (ret)
 
 # copy it also to src/
 shutil.copyfile (os.path.join (outdir, hh), os.path.join (CURRENT_SOURCE_DIR, hh))
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/harfbuzz.cc b/source/libs/harfbuzz/harfbuzz-src/src/harfbuzz.cc
index 9ff800daa7f10acc48051c6c1cac5bab9d610c77..985797df492e6adf05f8d119886050236d4921aa 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/harfbuzz.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/harfbuzz.cc
@@ -8,6 +8,9 @@
 #include "hb-common.cc"
 #include "hb-coretext-font.cc"
 #include "hb-coretext-shape.cc"
+#include "hb-coretext.cc"
+#include "hb-directwrite-font.cc"
+#include "hb-directwrite-shape.cc"
 #include "hb-directwrite.cc"
 #include "hb-draw.cc"
 #include "hb-face-builder.cc"
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-common.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-common.hh
index d2626b45f8e5178eb6d69de63ec11377c71a7654..640778e454f674a8687357a0e2ec9b306799f35f 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-common.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-common.hh
@@ -29,6 +29,8 @@
 
 #include "hb-aat-layout.hh"
 #include "hb-aat-map.hh"
+#include "hb-ot-layout-common.hh"
+#include "hb-ot-layout-gdef-table.hh"
 #include "hb-open-type.hh"
 #include "hb-cache.hh"
 #include "hb-bit-set.hh"
@@ -48,6 +50,61 @@ struct ankr;
 using hb_aat_class_cache_t = hb_cache_t<15, 8, 7>;
 static_assert (sizeof (hb_aat_class_cache_t) == 256, "");
 
+struct hb_aat_scratch_t
+{
+  hb_aat_scratch_t () = default;
+  hb_aat_scratch_t (const hb_aat_scratch_t &) = delete;
+
+  hb_aat_scratch_t (hb_aat_scratch_t &&o)
+  {
+    buffer_glyph_set.set_relaxed (o.buffer_glyph_set.get_relaxed ());
+    o.buffer_glyph_set.set_relaxed (nullptr);
+  }
+  hb_aat_scratch_t & operator = (hb_aat_scratch_t &&o)
+  {
+    buffer_glyph_set.set_relaxed (o.buffer_glyph_set.get_relaxed ());
+    o.buffer_glyph_set.set_relaxed (nullptr);
+    return *this;
+  }
+  ~hb_aat_scratch_t ()
+  {
+    auto *s = buffer_glyph_set.get_relaxed ();
+    if (unlikely (!s))
+      return;
+    s->fini ();
+    hb_free (s);
+  }
+
+  hb_bit_set_t *create_buffer_glyph_set () const
+  {
+    hb_bit_set_t *s = buffer_glyph_set.get_acquire ();
+    if (s && buffer_glyph_set.cmpexch (s, nullptr))
+      return s;
+
+    s = (hb_bit_set_t *) hb_calloc (1, sizeof (hb_bit_set_t));
+    if (unlikely (!s))
+      return nullptr;
+    s->init ();
+
+    return s;
+  }
+  void destroy_buffer_glyph_set (hb_bit_set_t *s) const
+  {
+    if (unlikely (!s))
+      return;
+    if (buffer_glyph_set.cmpexch (nullptr, s))
+      return;
+    s->fini ();
+    hb_free (s);
+  }
+
+  mutable hb_atomic_t<hb_bit_set_t *> buffer_glyph_set;
+};
+
+enum { DELETED_GLYPH = 0xFFFF };
+
+#define HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED HB_BUFFER_SCRATCH_FLAG_SHAPER0
+
 struct hb_aat_apply_context_t :
        hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
 {
@@ -64,10 +121,11 @@ struct hb_aat_apply_context_t :
   hb_buffer_t *buffer;
   hb_sanitize_context_t sanitizer;
   const ankr *ankr_table;
-  const OT::GDEF *gdef_table;
+  const OT::GDEF &gdef;
+  bool has_glyph_classes;
   const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
   bool using_buffer_glyph_set = false;
-  hb_bit_set_t buffer_glyph_set;
+  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;
@@ -90,15 +148,15 @@ struct hb_aat_apply_context_t :
 
   void setup_buffer_glyph_set ()
   {
-    using_buffer_glyph_set = buffer->len >= 4;
+    using_buffer_glyph_set = buffer->len >= 4 && buffer_glyph_set;
 
-    if (using_buffer_glyph_set)
-      buffer->collect_codepoints (buffer_glyph_set);
+    if (likely (using_buffer_glyph_set))
+      buffer->collect_codepoints (*buffer_glyph_set);
   }
   bool buffer_intersects_machine () const
   {
-    if (using_buffer_glyph_set)
-      return buffer_glyph_set.intersects (*machine_glyph_set);
+    if (likely (using_buffer_glyph_set))
+      return buffer_glyph_set->intersects (*machine_glyph_set);
 
     // Faster for shorter buffers.
     for (unsigned i = 0; i < buffer->len; i++)
@@ -106,6 +164,66 @@ struct hb_aat_apply_context_t :
 	return true;
     return false;
   }
+
+  template <typename T>
+  HB_NODISCARD bool output_glyphs (unsigned int count,
+				   const T *glyphs)
+  {
+    if (likely (using_buffer_glyph_set))
+      buffer_glyph_set->add_array (glyphs, count);
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (glyphs[i] == DELETED_GLYPH)
+      {
+        buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
+	_hb_glyph_info_set_aat_deleted (&buffer->cur());
+      }
+      else
+      {
+#ifndef HB_NO_OT_LAYOUT
+	if (has_glyph_classes)
+	  _hb_glyph_info_set_glyph_props (&buffer->cur(),
+					  gdef.get_glyph_props (glyphs[i]));
+#endif
+      }
+      if (unlikely (!buffer->output_glyph (glyphs[i]))) return false;
+    }
+    return true;
+  }
+
+  HB_NODISCARD bool replace_glyph (hb_codepoint_t glyph)
+  {
+    if (glyph == DELETED_GLYPH)
+      return delete_glyph ();
+
+    if (likely (using_buffer_glyph_set))
+      buffer_glyph_set->add (glyph);
+#ifndef HB_NO_OT_LAYOUT
+    if (has_glyph_classes)
+      _hb_glyph_info_set_glyph_props (&buffer->cur(),
+				      gdef.get_glyph_props (glyph));
+#endif
+    return buffer->replace_glyph (glyph);
+  }
+
+  HB_NODISCARD bool delete_glyph ()
+  {
+    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
+    _hb_glyph_info_set_aat_deleted (&buffer->cur());
+    return buffer->replace_glyph (DELETED_GLYPH);
+  }
+
+  void replace_glyph_inplace (unsigned i, hb_codepoint_t glyph)
+  {
+    buffer->info[i].codepoint = glyph;
+    if (likely (using_buffer_glyph_set))
+      buffer_glyph_set->add (glyph);
+#ifndef HB_NO_OT_LAYOUT
+    if (has_glyph_classes)
+      _hb_glyph_info_set_glyph_props (&buffer->info[i],
+				      gdef.get_glyph_props (glyph));
+#endif
+  }
 };
 
 
@@ -113,8 +231,6 @@ struct hb_aat_apply_context_t :
  * Lookup Table
  */
 
-enum { DELETED_GLYPH = 0xFFFF };
-
 template <typename T> struct Lookup;
 
 template <typename T>
@@ -179,6 +295,7 @@ struct LookupSegmentSingle
   template <typename set_t, typename filter_t>
   void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
   {
+    if (first == DELETED_GLYPH) return;
     if (!filter (value)) return;
     glyphs.add_range (first, last);
   }
@@ -268,6 +385,7 @@ struct LookupSegmentArray
   template <typename set_t, typename filter_t>
   void collect_glyphs_filtered (set_t &glyphs, const void *base, const filter_t &filter) const
   {
+    if (first == DELETED_GLYPH) return;
     const auto &values = base+valuesZ;
     for (hb_codepoint_t i = first; i <= last; i++)
       if (filter (values[i - first]))
@@ -368,6 +486,7 @@ struct LookupSingle
   template <typename set_t, typename filter_t>
   void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
   {
+    if (glyph == DELETED_GLYPH) return;
     if (!filter (value)) return;
     glyphs.add (glyph);
   }
@@ -746,6 +865,10 @@ struct StateTable
     }
 
     // And glyphs in those classes.
+
+    if (filter (CLASS_DELETED_GLYPH))
+      glyphs.add (DELETED_GLYPH);
+
     (this+classTable).collect_glyphs_filtered (glyphs, num_glyphs, filter);
   }
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh
index 4b980ca896f40fee55d9b85f3d686db69158d76d..e5b17ba1d4113195420238b8140dc56332a04463 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh
@@ -185,6 +185,9 @@ struct Format1Entry<true>
     DEFINE_SIZE_STATIC (2);
   };
 
+  static bool initiateAction (const Entry<EntryData> &entry)
+  { return entry.flags & Push; }
+
   static bool performAction (const Entry<EntryData> &entry)
   { return entry.data.kernActionIndex != 0xFFFF; }
 
@@ -325,8 +328,9 @@ struct KerxSubTableFormat1
 	    }
 	    else if (buffer->info[idx].mask & kern_mask)
 	    {
-	      o.x_advance += c->font->em_scale_x (v);
-	      o.x_offset += c->font->em_scale_x (v);
+	      auto scaled = c->font->em_scale_x (v);
+	      o.x_advance += scaled;
+	      o.x_offset += scaled;
 	    }
 	  }
 	  else
@@ -394,10 +398,8 @@ struct KerxSubTableFormat1
   template <typename set_t>
   void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
   {
-    set_t set;
-    machine.collect_glyphs (set, num_glyphs);
-    left_set.union_ (set);
-    right_set.union_ (set);
+    machine.collect_initial_glyphs (left_set, num_glyphs, *this);
+    //machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
   }
 
   protected:
@@ -671,10 +673,8 @@ struct KerxSubTableFormat4
   template <typename set_t>
   void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
   {
-    set_t set;
-    machine.collect_glyphs (set, num_glyphs);
-    left_set.union_ (set);
-    right_set.union_ (set);
+    machine.collect_initial_glyphs (left_set, num_glyphs, *this);
+    //machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
   }
 
   protected:
@@ -921,7 +921,18 @@ struct KerxSubTable
  * The 'kerx' Table
  */
 
-using kern_accelerator_data_t = hb_vector_t<hb_pair_t<hb_bit_set_t, hb_bit_set_t>>;
+struct kern_subtable_accelerator_data_t
+{
+  hb_bit_set_t left_set;
+  hb_bit_set_t right_set;
+  mutable hb_aat_class_cache_t class_cache;
+};
+
+struct kern_accelerator_data_t
+{
+  hb_vector_t<kern_subtable_accelerator_data_t> subtable_accels;
+  hb_aat_scratch_t scratch;
+};
 
 template <typename T>
 struct KerxTable
@@ -985,6 +996,8 @@ struct KerxTable
   {
     c->buffer->unsafe_to_concat ();
 
+    c->setup_buffer_glyph_set ();
+
     typedef typename T::SubTable SubTable;
 
     bool ret = false;
@@ -996,12 +1009,25 @@ struct KerxTable
     {
       bool reverse;
 
+      auto &subtable_accel = accel_data.subtable_accels[i];
+
       if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation))
 	goto skip;
 
       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->machine_class_cache = &subtable_accel.class_cache;
+
+      if (!c->buffer_intersects_machine ())
+      {
+	(void) c->buffer->message (c->font, "skipped subtable %u because no glyph matches", c->lookup_index);
+	goto skip;
+      }
+
       reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
 		HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
 
@@ -1028,9 +1054,6 @@ struct KerxTable
       if (reverse)
 	c->buffer->reverse ();
 
-      c->left_set = &accel_data[i].first;
-      c->right_set = &accel_data[i].second;
-
       {
 	/* See comment in sanitize() for conditional here. */
 	hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr);
@@ -1106,9 +1129,13 @@ struct KerxTable
     unsigned int count = thiz()->tableCount;
     for (unsigned int i = 0; i < count; i++)
     {
-      hb_bit_set_t left_set, right_set;
-      st->collect_glyphs (left_set, right_set, num_glyphs);
-      accel_data.push (hb_pair (left_set, right_set));
+      auto &subtable_accel = *accel_data.subtable_accels.push ();
+      if (unlikely (accel_data.subtable_accels.in_error ()))
+	  return accel_data;
+
+      st->collect_glyphs (subtable_accel.left_set, subtable_accel.right_set, num_glyphs);
+      subtable_accel.class_cache.clear ();
+
       st = &StructAfter<SubTable> (*st);
     }
 
@@ -1137,6 +1164,7 @@ struct KerxTable
 
     hb_blob_ptr_t<T> table;
     kern_accelerator_data_t accel_data;
+    hb_aat_scratch_t scratch;
   };
 };
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh
index 617a239fe49732161ca7587c24fc28e028a5e66b..663e47991d411e4aa2c02e3033823eb7a3605f41 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh
@@ -30,8 +30,6 @@
 #include "hb-open-type.hh"
 #include "hb-aat-layout-common.hh"
 #include "hb-ot-layout.hh"
-#include "hb-ot-layout-common.hh"
-#include "hb-ot-layout-gdef-table.hh"
 #include "hb-aat-map.hh"
 
 /*
@@ -178,12 +176,6 @@ struct RearrangementSubtable
 
     StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
 
-    if (!c->buffer_intersects_machine ())
-    {
-      (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
-      return_trace (false);
-    }
-
     driver.drive (&dc, c);
 
     return_trace (dc.ret);
@@ -242,9 +234,7 @@ struct ContextualSubtable
 	ret (false),
 	c (c_),
 	table (table_),
-	gdef (*c->gdef_table),
 	mark_set (false),
-	has_glyph_classes (gdef.has_glyph_classes ()),
 	mark (0),
 	subs (table+table->substitutionTables) {}
 
@@ -281,12 +271,7 @@ struct ContextualSubtable
       if (replacement)
       {
 	buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
-	hb_codepoint_t glyph = *replacement;
-	buffer->info[mark].codepoint = glyph;
-	c->buffer_glyph_set.add (glyph);
-	if (has_glyph_classes)
-	  _hb_glyph_info_set_glyph_props (&buffer->info[mark],
-					  gdef.get_glyph_props (*replacement));
+	c->replace_glyph_inplace (mark, *replacement);
 	ret = true;
       }
 
@@ -312,12 +297,7 @@ struct ContextualSubtable
       }
       if (replacement)
       {
-	hb_codepoint_t glyph = *replacement;
-	buffer->info[idx].codepoint = glyph;
-	c->buffer_glyph_set.add (glyph);
-	if (has_glyph_classes)
-	  _hb_glyph_info_set_glyph_props (&buffer->info[idx],
-					  gdef.get_glyph_props (*replacement));
+	c->replace_glyph_inplace (idx, *replacement);
 	ret = true;
       }
 
@@ -333,9 +313,7 @@ struct ContextualSubtable
     hb_aat_apply_context_t *c;
     const ContextualSubtable *table;
     private:
-    const OT::GDEF &gdef;
     bool mark_set;
-    bool has_glyph_classes;
     unsigned int mark;
     const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false> &subs;
   };
@@ -348,12 +326,6 @@ struct ContextualSubtable
 
     StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
 
-    if (!c->buffer_intersects_machine ())
-    {
-      (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
-      return_trace (false);
-    }
-
     driver.drive (&dc, c);
 
     return_trace (dc.ret);
@@ -581,7 +553,7 @@ struct LigatureSubtable
 	    hb_codepoint_t lig = ligatureData;
 
 	    DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
-	    if (unlikely (!buffer->replace_glyph (lig))) return;
+	    if (unlikely (!c->replace_glyph (lig))) return;
 
 	    unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
 	    /* Now go and delete all subsequent components. */
@@ -589,8 +561,7 @@ struct LigatureSubtable
 	    {
 	      DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
 	      if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
-	      _hb_glyph_info_set_default_ignorable (&buffer->cur());
-	      if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
+	      if (!c->delete_glyph ()) return;
 	    }
 
 	    if (unlikely (!buffer->move_to (lig_end))) return;
@@ -624,12 +595,6 @@ struct LigatureSubtable
 
     StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
 
-    if (!c->buffer_intersects_machine ())
-    {
-      (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
-      return_trace (false);
-    }
-
     driver.drive (&dc, c);
 
     return_trace (dc.ret);
@@ -665,15 +630,6 @@ struct NoncontextualSubtable
   {
     TRACE_APPLY (this);
 
-    if (!c->buffer_intersects_machine ())
-    {
-      (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
-      return_trace (false);
-    }
-
-    const OT::GDEF &gdef (*c->gdef_table);
-    bool has_glyph_classes = gdef.has_glyph_classes ();
-
     bool ret = false;
     unsigned int num_glyphs = c->face->get_num_glyphs ();
 
@@ -703,12 +659,7 @@ struct NoncontextualSubtable
       const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
       if (replacement)
       {
-	hb_codepoint_t glyph = *replacement;
-	info[i].codepoint = glyph;
-	c->buffer_glyph_set.add (glyph);
-	if (has_glyph_classes)
-	  _hb_glyph_info_set_glyph_props (&info[i],
-					  gdef.get_glyph_props (*replacement));
+	c->replace_glyph_inplace (i, *replacement);
 	ret = true;
       }
     }
@@ -850,9 +801,7 @@ struct InsertionSubtable
 	if (buffer->idx < buffer->len && !before)
 	  if (unlikely (!buffer->copy_glyph ())) return;
 	/* TODO We ignore KashidaLike setting. */
-	if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
-	for (unsigned int i = 0; i < count; i++)
-	  c->buffer_glyph_set.add (glyphs[i]);
+	if (unlikely (!c->output_glyphs (count, glyphs))) return;
 	ret = true;
 	if (buffer->idx < buffer->len && !before)
 	  buffer->skip_glyph ();
@@ -881,7 +830,8 @@ struct InsertionSubtable
 	if (buffer->idx < buffer->len && !before)
 	  if (unlikely (!buffer->copy_glyph ())) return;
 	/* TODO We ignore KashidaLike setting. */
-	if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
+	if (unlikely (!c->output_glyphs (count, glyphs))) return;
+	ret = true;
 	if (buffer->idx < buffer->len && !before)
 	  buffer->skip_glyph ();
 
@@ -921,12 +871,6 @@ struct InsertionSubtable
 
     StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
 
-    if (!c->buffer_intersects_machine ())
-    {
-      (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
-      return_trace (false);
-    }
-
     driver.drive (&dc, c);
 
     return_trace (dc.ret);
@@ -1224,6 +1168,7 @@ struct Chain
       if (hb_none (hb_iter (c->range_flags) |
 		   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;
@@ -1233,6 +1178,12 @@ struct Chain
 	  bool (coverage & ChainSubtable<Types>::Vertical))
 	goto skip;
 
+      if (!c->buffer_intersects_machine ())
+      {
+	(void) c->buffer->message (c->font, "skipped chainsubtable %u because no glyph matches", c->lookup_index);
+	goto skip;
+      }
+
       /* Buffer contents is always in logical direction.  Determine if
        * we need to reverse before applying this subtable.  We reverse
        * back after if we did reverse indeed.
@@ -1376,7 +1327,7 @@ struct mortmorx
 
       this->chain_count = table->get_chain_count ();
 
-      this->accels = (hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *) hb_calloc (this->chain_count, sizeof (*accels));
+      this->accels = (hb_atomic_t<hb_aat_layout_chain_accelerator_t *> *) hb_calloc (this->chain_count, sizeof (*accels));
       if (unlikely (!this->accels))
       {
 	this->chain_count = 0;
@@ -1423,7 +1374,8 @@ struct mortmorx
 
     hb_blob_ptr_t<T> table;
     unsigned int chain_count;
-    hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *accels;
+    hb_atomic_t<hb_aat_layout_chain_accelerator_t *> *accels;
+    hb_aat_scratch_t scratch;
   };
 
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-trak-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-trak-table.hh
index 508606037ad2443de95e38b2402130565397c71d..24c212c2c165e66116dca24792eeff1d4faaa240 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-trak-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-trak-table.hh
@@ -142,9 +142,9 @@ struct TrackData
     unsigned j = count - 1;
 
     // Find the two entries that track is between.
-    while (i + 1 < count && trackTable[i + 1].get_track_value () < track)
+    while (i + 1 < count && trackTable[i + 1].get_track_value () <= track)
       i++;
-    while (j > 0 && trackTable[j - 1].get_track_value () > track)
+    while (j > 0 && trackTable[j - 1].get_track_value () >= track)
       j--;
 
     // Exact match.
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout.cc
index 9fe77a575958de9245ad1df63c18722ccf51e917..374554466829ad5e860ac907cf3702f4b6b7ae87 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout.cc
@@ -58,13 +58,14 @@ AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *p
 						       buffer (buffer_),
 						       sanitizer (),
 						       ankr_table (&Null (AAT::ankr)),
-						       gdef_table (
+						       gdef (
 #ifndef HB_NO_OT_LAYOUT
-							 face->table.GDEF->table
+							 *face->table.GDEF->table
 #else
-							 &Null (GDEF)
+							 Null (GDEF)
 #endif
 						       ),
+						       has_glyph_classes (gdef.has_glyph_classes ()),
 						       lookup_index (0)
 {
   sanitizer.init (blob);
@@ -203,7 +204,7 @@ hb_aat_layout_find_feature_mapping (hb_tag_t tag)
 #endif
 
 
-#ifndef HB_NO_AAT
+#ifndef HB_NO_AAT_SHAPE
 
 /*
  * mort/morx/kerx/trak
@@ -287,11 +288,14 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
 			  const hb_feature_t *features,
 			  unsigned num_features)
 {
-  hb_aat_map_builder_t builder (font->face, plan->props);
-  for (unsigned i = 0; i < num_features; i++)
-    builder.add_feature (features[i]);
   hb_aat_map_t map;
-  builder.compile (map);
+  if (num_features)
+  {
+    hb_aat_map_builder_t builder (font->face, plan->props);
+    for (unsigned i = 0; i < num_features; i++)
+      builder.add_feature (features[i]);
+    builder.compile (map);
+  }
 
   {
     auto &accel = *font->face->table.morx;
@@ -300,7 +304,10 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
     {
       AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
       if (!buffer->message (font, "start table morx")) return;
-      morx.apply (&c, map, accel);
+      c.buffer_glyph_set = accel.scratch.create_buffer_glyph_set ();
+      morx.apply (&c, num_features ? map : plan->aat_map, accel);
+      accel.scratch.destroy_buffer_glyph_set (c.buffer_glyph_set);
+      c.buffer_glyph_set = nullptr;
       (void) buffer->message (font, "end table morx");
       return;
     }
@@ -313,34 +320,24 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
     {
       AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
       if (!buffer->message (font, "start table mort")) return;
-      mort.apply (&c, map, accel);
+      mort.apply (&c, num_features ? map : plan->aat_map, accel);
       (void) buffer->message (font, "end table mort");
       return;
     }
   }
 }
 
-void
-hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer)
-{
-  unsigned int count = buffer->len;
-  hb_glyph_info_t *info = buffer->info;
-  hb_glyph_position_t *pos = buffer->pos;
-  for (unsigned int i = 0; i < count; i++)
-    if (unlikely (info[i].codepoint == AAT::DELETED_GLYPH))
-      pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
-}
-
 static bool
 is_deleted_glyph (const hb_glyph_info_t *info)
 {
-  return info->codepoint == AAT::DELETED_GLYPH;
+  return _hb_glyph_info_is_aat_deleted (info);
 }
 
 void
 hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
 {
-  buffer->delete_glyphs_inplace (is_deleted_glyph);
+  if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED)
+    buffer->delete_glyphs_inplace (is_deleted_glyph);
 }
 
 /**
@@ -371,8 +368,11 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
 
   AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
   if (!buffer->message (font, "start table kerx")) return;
+  c.buffer_glyph_set = accel.scratch.create_buffer_glyph_set ();
   c.set_ankr_table (font->face->table.ankr.get ());
   accel.apply (&c);
+  accel.scratch.destroy_buffer_glyph_set (c.buffer_glyph_set);
+  c.buffer_glyph_set = nullptr;
   (void) buffer->message (font, "end table kerx");
 }
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout.hh
index c5d6ecb10b0c47ccbacab77f88b6451d38d6bd64..0e4ae6e7b3c0cc92fd2d91a29ef43672460182c3 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout.hh
@@ -60,9 +60,6 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
 			  const hb_feature_t *features,
 			  unsigned num_features);
 
-HB_INTERNAL void
-hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer);
-
 HB_INTERNAL void
 hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer);
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-map.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-map.cc
index 1a0dee022bb17bba14c0195e2b8a8a531bdd55f4..0b85c901e8eb8ba516645b4b125da6c9101d2b18 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-map.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-map.cc
@@ -85,6 +85,11 @@ void
 hb_aat_map_builder_t::compile (hb_aat_map_t  &m)
 {
   /* Compute active features per range, and compile each. */
+  if (!features.length)
+  {
+    hb_aat_layout_compile_map (this, &m);
+    return;
+  }
 
   /* Sort features by start/end events. */
   hb_vector_t<feature_event_t> feature_events;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-atomic.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-atomic.hh
index 121c463a56bd2fc73ca8fa3c57c2a36a717e1a80..e92ccbca109cc875df79912f19a64097b73d35de 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-atomic.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-atomic.hh
@@ -149,62 +149,47 @@ static inline void _hb_compiler_memory_r_barrier () {}
 #define hb_atomic_ptr_impl_get_relaxed(P)	(*(P))
 #endif
 #ifndef hb_atomic_int_impl_set
-inline void hb_atomic_int_impl_set (int *AI, int v)	{ _hb_memory_w_barrier (); *AI = v; }
-inline void hb_atomic_int_impl_set (short *AI, short v)	{ _hb_memory_w_barrier (); *AI = v; }
+template <typename T>
+inline void hb_atomic_int_impl_set (T *AI, T v)	{ _hb_memory_w_barrier (); *AI = v; }
 #endif
 #ifndef hb_atomic_int_impl_get
-inline int hb_atomic_int_impl_get (const int *AI)	{ int v = *AI; _hb_memory_r_barrier (); return v; }
-inline short hb_atomic_int_impl_get (const short *AI)	{ short v = *AI; _hb_memory_r_barrier (); return v; }
+template <typename T>
+inline T hb_atomic_int_impl_get (const T *AI)	{ T v = *AI; _hb_memory_r_barrier (); return v; }
 #endif
 #ifndef hb_atomic_ptr_impl_get
 inline void *hb_atomic_ptr_impl_get (void ** const P)	{ void *v = *P; _hb_memory_r_barrier (); return v; }
 #endif
 
 
-struct hb_atomic_short_t
+template <typename T>
+struct hb_atomic_t
 {
-  hb_atomic_short_t () = default;
-  constexpr hb_atomic_short_t (short v) : v (v) {}
+  hb_atomic_t () = default;
+  constexpr hb_atomic_t (T v) : v (v) {}
 
-  hb_atomic_short_t& operator = (short v_) { set_relaxed (v_); return *this; }
-  operator short () const { return get_relaxed (); }
+  hb_atomic_t& operator = (T v_) { set_relaxed (v_); return *this; }
+  operator T () const { return get_relaxed (); }
 
-  void set_relaxed (short v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
-  void set_release (short v_) { hb_atomic_int_impl_set (&v, v_); }
-  short get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
-  short get_acquire () const { return hb_atomic_int_impl_get (&v); }
-  short inc () { return hb_atomic_int_impl_add (&v,  1); }
-  short dec () { return hb_atomic_int_impl_add (&v, -1); }
+  void set_relaxed (T v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
+  void set_release (T v_) { hb_atomic_int_impl_set (&v, v_); }
+  T get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
+  T get_acquire () const { return hb_atomic_int_impl_get (&v); }
+  T inc () { return hb_atomic_int_impl_add (&v,  1); }
+  T dec () { return hb_atomic_int_impl_add (&v, -1); }
 
-  short v = 0;
-};
-
-struct hb_atomic_int_t
-{
-  hb_atomic_int_t () = default;
-  constexpr hb_atomic_int_t (int v) : v (v) {}
+  int operator ++ (int) { return inc (); }
+  int operator -- (int) { return dec (); }
+  long operator |= (long v_) { set_relaxed (get_relaxed () | v_); return *this; }
 
-  hb_atomic_int_t& operator = (int v_) { set_relaxed (v_); return *this; }
-  operator int () const { return get_relaxed (); }
-
-  void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
-  void set_release (int v_) { hb_atomic_int_impl_set (&v, v_); }
-  int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
-  int get_acquire () const { return hb_atomic_int_impl_get (&v); }
-  int inc () { return hb_atomic_int_impl_add (&v,  1); }
-  int dec () { return hb_atomic_int_impl_add (&v, -1); }
-
-  int v = 0;
+  T v = 0;
 };
 
-template <typename P>
-struct hb_atomic_ptr_t
+template <typename T>
+struct hb_atomic_t<T*>
 {
-  typedef hb_remove_pointer<P> T;
-
-  hb_atomic_ptr_t () = default;
-  constexpr hb_atomic_ptr_t (T* v) : v (v) {}
-  hb_atomic_ptr_t (const hb_atomic_ptr_t &other) = delete;
+  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_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-set.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-set.hh
index 4607b884d5b3c109c71544452bb10eaa8c8da7b8..ec462c7d415d9c1d05da45cbffe56d5ed6e588b7 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-set.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-set.hh
@@ -77,7 +77,7 @@ struct hb_bit_set_t
 
   bool successful = true; /* Allocations successful */
   mutable unsigned int population = 0;
-  mutable hb_atomic_int_t last_page_lookup = 0;
+  mutable hb_atomic_t<unsigned> last_page_lookup = 0;
   hb_sorted_vector_t<page_map_t> page_map;
   hb_vector_t<page_t> pages;
 
@@ -88,7 +88,7 @@ struct hb_bit_set_t
   {
     if (unlikely (!successful)) return false;
 
-    if (pages.length < count && count <= 2)
+    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) ||
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-vector.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-vector.hh
new file mode 100644
index 0000000000000000000000000000000000000000..58084e59a3d7e1c9acf8891d6bb27c391438fb79
--- /dev/null
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-vector.hh
@@ -0,0 +1,195 @@
+/*
+ *  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_BIT_VECTOR_HH
+#define HB_BIT_VECTOR_HH
+
+#include "hb.hh"
+
+#include "hb-atomic.hh"
+
+struct hb_min_max_t
+{
+  void add (hb_codepoint_t v) { min_v = hb_min (min_v, v); max_v = hb_max (max_v, v); }
+  void add_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    min_v = hb_min (min_v, a);
+    max_v = hb_max (max_v, b);
+  }
+
+  template <typename set_t>
+  void union_ (const set_t &set)
+  {
+    hb_codepoint_t set_min = set.get_min ();
+    if (unlikely (set_min == HB_CODEPOINT_INVALID))
+      return;
+    hb_codepoint_t set_max = set.get_max ();
+    min_v = hb_min (min_v, set_min);
+    max_v = hb_max (max_v, set_max);
+  }
+
+  hb_codepoint_t get_min () const { return min_v; }
+  hb_codepoint_t get_max () const { return max_v; }
+
+  private:
+  hb_codepoint_t min_v = HB_CODEPOINT_INVALID;
+  hb_codepoint_t max_v = 0;
+};
+
+template <bool atomic = false>
+struct hb_bit_vector_t
+{
+  using int_t = uint64_t;
+  using elt_t = typename std::conditional<atomic, hb_atomic_t<int_t>, int_t>::type;
+
+  hb_bit_vector_t () = delete;
+  hb_bit_vector_t (const hb_bit_vector_t &other) = delete;
+  hb_bit_vector_t &operator= (const hb_bit_vector_t &other) = delete;
+
+  // Move
+  hb_bit_vector_t (hb_bit_vector_t &&other)
+		: min_v (other.min_v), max_v (other.max_v), count (other.count), elts (other.elts)
+  {
+    other.min_v = other.max_v = other.count = 0;
+    other.elts = nullptr;
+  }
+  hb_bit_vector_t &operator= (hb_bit_vector_t &&other)
+  {
+    hb_swap (min_v, other.min_v);
+    hb_swap (max_v, other.max_v);
+    hb_swap (count, other.count);
+    hb_swap (elts, other.elts);
+    return *this;
+  }
+
+  hb_bit_vector_t (unsigned min_v, unsigned max_v)
+    : min_v (min_v), max_v (max_v)
+  {
+    if (unlikely (min_v >= max_v))
+    {
+      min_v = max_v = count = 0;
+      return;
+    }
+
+    unsigned num = (max_v - min_v + sizeof (int_t) * 8) / (sizeof (int_t) * 8);
+    elts = (elt_t *) hb_calloc (num, sizeof (int_t));
+    if (unlikely (!elts))
+    {
+      min_v = max_v = count = 0;
+      return;
+    }
+
+    count = max_v - min_v + 1;
+  }
+  ~hb_bit_vector_t ()
+  {
+    hb_free (elts);
+  }
+
+  void add (hb_codepoint_t g) { elt (g) |= mask (g); }
+  void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
+  void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); }
+  bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
+  bool has (hb_codepoint_t g) const { return get (g); }
+  bool may_have (hb_codepoint_t g) const { return get (g); }
+
+  bool operator [] (hb_codepoint_t g) const { return get (g); }
+  bool operator () (hb_codepoint_t g) const { return get (g); }
+
+  void add_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    if (unlikely (!count || a > b || a < min_v || b > max_v))
+      return;
+
+    elt_t *la = &elt (a);
+    elt_t *lb = &elt (b);
+    if (la == lb)
+      *la |= (mask (b) << 1) - mask(a);
+    else
+    {
+      *la |= ~(mask (a) - 1llu);
+      la++;
+
+      hb_memset (la, 0xff, (char *) lb - (char *) la);
+
+      *lb |= ((mask (b) << 1) - 1llu);
+    }
+  }
+  void del_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    if (unlikely (!count || a > b || a < min_v || b > max_v))
+      return;
+
+    elt_t *la = &elt (a);
+    elt_t *lb = &elt (b);
+    if (la == lb)
+      *la &= ~((mask (b) << 1llu) - mask(a));
+    else
+    {
+      *la &= mask (a) - 1;
+      la++;
+
+      hb_memset (la, 0, (char *) lb - (char *) la);
+
+      *lb &= ~((mask (b) << 1) - 1llu);
+    }
+  }
+  void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
+  { if (v) add_range (a, b); else del_range (a, b); }
+
+  template <typename set_t>
+  void union_ (const set_t &set)
+  {
+    for (hb_codepoint_t g : set)
+      add (g);
+  }
+
+  static const unsigned int ELT_BITS = sizeof (elt_t) * 8;
+  static constexpr unsigned ELT_MASK = ELT_BITS - 1;
+
+  static constexpr elt_t zero = 0;
+
+  elt_t &elt (hb_codepoint_t g)
+  {
+    g -= min_v;
+    if (unlikely (g >= count))
+      return Crap(elt_t);
+    return elts[g / ELT_BITS];
+  }
+  const elt_t& elt (hb_codepoint_t g) const
+  {
+    g -= min_v;
+    if (unlikely (g >= count))
+      return Null(elt_t);
+    return elts[g / ELT_BITS];
+  }
+
+  static constexpr int_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); }
+
+  hb_codepoint_t min_v = 0, max_v = 0, count = 0;
+  elt_t *elts = nullptr;
+};
+
+
+#endif /* HB_BIT_VECTOR_HH */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-json.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-json.hh
index 471bbb93fdbdf665275eae9ff0b7710fa446e2d0..b5bb3f4b29afb8abfe98c26b3910416e253a0e77 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-json.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-json.hh
@@ -34,57 +34,66 @@
 
 #line 36 "hb-buffer-deserialize-json.hh"
 static const unsigned char _deserialize_json_trans_keys[] = {
-	0u, 0u, 9u, 123u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 
-	9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 
-	48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 
-	9u, 125u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 
-	34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 
-	9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, 
-	9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 
-	9u, 93u, 9u, 123u, 0u, 0u, 0
+	0u, 0u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 
+	9u, 125u, 9u, 125u, 9u, 93u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 
+	9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 
+	120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 
+	9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 
+	9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, 9u, 125u, 
+	34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 123u, 
+	9u, 123u, 9u, 123u, 0
 };
 
 static const char _deserialize_json_key_spans[] = {
-	0, 115, 115, 26, 21, 2, 1, 50, 
-	49, 10, 117, 117, 117, 1, 50, 49, 
-	10, 117, 117, 1, 1, 50, 49, 117, 
-	117, 2, 1, 50, 49, 10, 117, 117, 
-	1, 50, 49, 10, 117, 117, 1, 1, 
-	50, 49, 117, 117, 1, 50, 49, 59, 
-	117, 59, 117, 117, 1, 50, 49, 117, 
-	85, 115, 0
+	0, 26, 21, 2, 1, 50, 49, 10, 
+	117, 117, 85, 117, 1, 50, 49, 10, 
+	117, 117, 1, 1, 50, 49, 117, 117, 
+	2, 1, 50, 49, 10, 117, 117, 1, 
+	50, 49, 10, 117, 117, 1, 1, 50, 
+	49, 117, 117, 1, 50, 49, 59, 117, 
+	59, 117, 117, 1, 50, 49, 117, 115, 
+	115, 115
 };
 
 static const short _deserialize_json_index_offsets[] = {
-	0, 0, 116, 232, 259, 281, 284, 286, 
-	337, 387, 398, 516, 634, 752, 754, 805, 
-	855, 866, 984, 1102, 1104, 1106, 1157, 1207, 
-	1325, 1443, 1446, 1448, 1499, 1549, 1560, 1678, 
-	1796, 1798, 1849, 1899, 1910, 2028, 2146, 2148, 
-	2150, 2201, 2251, 2369, 2487, 2489, 2540, 2590, 
-	2650, 2768, 2828, 2946, 3064, 3066, 3117, 3167, 
-	3285, 3371, 3487
+	0, 0, 27, 49, 52, 54, 105, 155, 
+	166, 284, 402, 488, 606, 608, 659, 709, 
+	720, 838, 956, 958, 960, 1011, 1061, 1179, 
+	1297, 1300, 1302, 1353, 1403, 1414, 1532, 1650, 
+	1652, 1703, 1753, 1764, 1882, 2000, 2002, 2004, 
+	2055, 2105, 2223, 2341, 2343, 2394, 2444, 2504, 
+	2622, 2682, 2800, 2918, 2920, 2971, 3021, 3139, 
+	3255, 3371
 };
 
 static const char _deserialize_json_indicies[] = {
 	0, 0, 0, 0, 0, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	0, 1, 1, 1, 1, 1, 1, 1, 
+	0, 1, 2, 1, 3, 1, 4, 5, 
+	1, 6, 7, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	8, 1, 9, 10, 1, 11, 1, 11, 
+	11, 11, 11, 11, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 11, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	12, 1, 12, 12, 12, 12, 12, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 2, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 12, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 13, 1, 
+	1, 14, 15, 15, 15, 15, 15, 15, 
+	15, 15, 15, 1, 16, 17, 17, 17, 
+	17, 17, 17, 17, 17, 17, 1, 18, 
+	18, 18, 18, 18, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 18, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 3, 1, 2, 2, 2, 
-	2, 2, 1, 1, 1, 1, 1, 1, 
+	1, 1, 19, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 2, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -93,66 +102,66 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 20, 1, 21, 21, 21, 
+	21, 21, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 21, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 3, 
-	1, 4, 4, 4, 4, 4, 1, 1, 
+	0, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	4, 1, 5, 1, 6, 1, 7, 8, 
-	1, 9, 10, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	11, 1, 12, 13, 1, 14, 1, 14, 
-	14, 14, 14, 14, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 14, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	15, 1, 15, 15, 15, 15, 15, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 15, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 16, 1, 
-	1, 17, 18, 18, 18, 18, 18, 18, 
-	18, 18, 18, 1, 19, 20, 20, 20, 
-	20, 20, 20, 20, 20, 20, 1, 21, 
-	21, 21, 21, 21, 1, 1, 1, 1, 
+	1, 22, 1, 22, 22, 22, 22, 22, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 21, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 22, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 23, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 23, 
+	1, 18, 18, 18, 18, 18, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	18, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 19, 1, 1, 1, 
+	17, 17, 17, 17, 17, 17, 17, 17, 
+	17, 17, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 23, 1, 24, 24, 24, 
-	24, 24, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 24, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	4, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 20, 1, 24, 
+	1, 24, 24, 24, 24, 24, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	24, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 25, 1, 25, 25, 25, 25, 
+	25, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 25, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 25, 1, 21, 21, 21, 21, 21, 
+	26, 1, 1, 27, 28, 28, 28, 28, 
+	28, 28, 28, 28, 28, 1, 29, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	1, 31, 31, 31, 31, 31, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 21, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 22, 1, 
-	1, 1, 20, 20, 20, 20, 20, 20, 
-	20, 20, 20, 20, 1, 1, 1, 1, 
+	31, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 32, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -160,86 +169,86 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 23, 
-	1, 26, 1, 26, 26, 26, 26, 26, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 26, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 33, 1, 31, 
+	31, 31, 31, 31, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 31, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 27, 1, 27, 27, 
-	27, 27, 27, 1, 1, 1, 1, 1, 
+	1, 1, 32, 1, 1, 1, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 27, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 28, 1, 1, 29, 30, 30, 
-	30, 30, 30, 30, 30, 30, 30, 1, 
-	31, 32, 32, 32, 32, 32, 32, 32, 
-	32, 32, 1, 33, 33, 33, 33, 33, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 33, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 34, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 33, 1, 34, 1, 35, 
+	1, 35, 35, 35, 35, 35, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	35, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 36, 1, 36, 36, 36, 36, 
+	36, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 35, 
-	1, 33, 33, 33, 33, 33, 1, 1, 
+	1, 1, 1, 36, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 37, 38, 38, 38, 38, 
+	38, 38, 38, 38, 38, 1, 39, 39, 
+	39, 39, 39, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	33, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 34, 1, 1, 1, 
-	32, 32, 32, 32, 32, 32, 32, 32, 
-	32, 32, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 39, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 40, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 35, 1, 36, 
-	1, 37, 1, 37, 37, 37, 37, 37, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 37, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 41, 1, 39, 39, 39, 39, 
+	39, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 38, 1, 38, 38, 
-	38, 38, 38, 1, 1, 1, 1, 1, 
+	1, 1, 1, 39, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 40, 
+	1, 1, 1, 42, 42, 42, 42, 42, 
+	42, 42, 42, 42, 42, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 38, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 39, 40, 40, 
-	40, 40, 40, 40, 40, 40, 40, 1, 
-	41, 41, 41, 41, 41, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 41, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 42, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	41, 1, 43, 44, 1, 45, 1, 45, 
+	45, 45, 45, 45, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 45, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	46, 1, 46, 46, 46, 46, 46, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 43, 1, 41, 41, 
-	41, 41, 41, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 41, 1, 1, 
+	1, 46, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 47, 1, 
+	1, 48, 49, 49, 49, 49, 49, 49, 
+	49, 49, 49, 1, 50, 51, 51, 51, 
+	51, 51, 51, 51, 51, 51, 1, 52, 
+	52, 52, 52, 52, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 42, 1, 1, 1, 44, 44, 44, 
-	44, 44, 44, 44, 44, 44, 44, 1, 
+	1, 1, 1, 1, 1, 1, 52, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 53, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -247,43 +256,43 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 43, 1, 45, 46, 1, 47, 
-	1, 47, 47, 47, 47, 47, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	47, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 54, 1, 52, 52, 52, 
+	52, 52, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 52, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 48, 1, 48, 48, 48, 48, 
-	48, 1, 1, 1, 1, 1, 1, 1, 
+	53, 1, 1, 1, 51, 51, 51, 51, 
+	51, 51, 51, 51, 51, 51, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 48, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	49, 1, 1, 50, 51, 51, 51, 51, 
-	51, 51, 51, 51, 51, 1, 52, 53, 
-	53, 53, 53, 53, 53, 53, 53, 53, 
-	1, 54, 54, 54, 54, 54, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	54, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 55, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 54, 1, 55, 1, 55, 55, 55, 
+	55, 55, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 55, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 56, 1, 
+	56, 56, 56, 56, 56, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 56, 1, 54, 
-	54, 54, 54, 54, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 56, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 54, 1, 
+	1, 1, 1, 1, 57, 1, 1, 58, 
+	59, 59, 59, 59, 59, 59, 59, 59, 
+	59, 1, 60, 61, 61, 61, 61, 61, 
+	61, 61, 61, 61, 1, 62, 62, 62, 
+	62, 62, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 55, 1, 1, 1, 53, 53, 
-	53, 53, 53, 53, 53, 53, 53, 53, 
+	1, 1, 1, 1, 62, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	63, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -291,42 +300,42 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 56, 1, 57, 1, 57, 
-	57, 57, 57, 57, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 57, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 64, 1, 62, 62, 62, 62, 62, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	58, 1, 58, 58, 58, 58, 58, 1, 
+	1, 1, 62, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 63, 1, 
+	1, 1, 61, 61, 61, 61, 61, 61, 
+	61, 61, 61, 61, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 58, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 59, 1, 
-	1, 60, 61, 61, 61, 61, 61, 61, 
-	61, 61, 61, 1, 62, 63, 63, 63, 
-	63, 63, 63, 63, 63, 63, 1, 64, 
-	64, 64, 64, 64, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 64, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 65, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 64, 
+	1, 65, 1, 66, 1, 66, 66, 66, 
+	66, 66, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 66, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 67, 1, 
+	67, 67, 67, 67, 67, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 67, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 68, 
+	69, 69, 69, 69, 69, 69, 69, 69, 
+	69, 1, 70, 70, 70, 70, 70, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 66, 1, 64, 64, 64, 
-	64, 64, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 64, 1, 1, 1, 
+	1, 70, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 71, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	65, 1, 1, 1, 63, 63, 63, 63, 
-	63, 63, 63, 63, 63, 63, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -335,41 +344,49 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 66, 1, 67, 1, 68, 1, 68, 
-	68, 68, 68, 68, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 72, 1, 
+	70, 70, 70, 70, 70, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 68, 1, 
+	1, 1, 1, 1, 1, 1, 1, 70, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 71, 1, 1, 1, 73, 
+	73, 73, 73, 73, 73, 73, 73, 73, 
+	73, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	69, 1, 69, 69, 69, 69, 69, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 69, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 70, 71, 71, 71, 71, 71, 71, 
-	71, 71, 71, 1, 72, 72, 72, 72, 
-	72, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 72, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 73, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 72, 1, 74, 1, 
+	74, 74, 74, 74, 74, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 74, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 75, 1, 75, 75, 75, 75, 75, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 75, 1, 76, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 77, 78, 78, 78, 78, 78, 
+	78, 78, 78, 78, 1, 80, 79, 79, 
+	79, 79, 79, 79, 79, 79, 79, 79, 
+	79, 79, 79, 79, 79, 79, 79, 79, 
+	79, 79, 79, 79, 79, 79, 79, 79, 
+	79, 79, 79, 79, 79, 79, 79, 79, 
+	79, 79, 79, 79, 79, 79, 79, 79, 
+	79, 79, 79, 79, 79, 79, 79, 79, 
+	79, 79, 79, 79, 79, 79, 79, 81, 
+	79, 82, 82, 82, 82, 82, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	74, 1, 72, 72, 72, 72, 72, 1, 
+	82, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 83, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 72, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 73, 1, 1, 
-	1, 75, 75, 75, 75, 75, 75, 75, 
-	75, 75, 75, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -377,33 +394,19 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 74, 1, 
-	76, 1, 76, 76, 76, 76, 76, 1, 
+	1, 1, 1, 1, 1, 84, 1, 79, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 76, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 77, 1, 77, 77, 77, 
-	77, 77, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 77, 1, 78, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 79, 80, 80, 80, 
-	80, 80, 80, 80, 80, 80, 1, 82, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 83, 81, 84, 84, 84, 84, 84, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 79, 1, 85, 85, 85, 85, 85, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 84, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 85, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 85, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 86, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -412,36 +415,43 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 86, 
-	1, 81, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 87, 
+	1, 85, 85, 85, 85, 85, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	85, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 86, 1, 1, 1, 
+	88, 88, 88, 88, 88, 88, 88, 88, 
+	88, 88, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 81, 1, 87, 87, 87, 
-	87, 87, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 87, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	88, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 87, 1, 89, 
+	1, 89, 89, 89, 89, 89, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	89, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 90, 1, 90, 90, 90, 90, 
+	90, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 90, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 91, 92, 92, 92, 92, 
+	92, 92, 92, 92, 92, 1, 85, 85, 
+	85, 85, 85, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 89, 1, 87, 87, 87, 87, 87, 
+	1, 1, 1, 1, 1, 85, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 86, 1, 1, 1, 93, 93, 93, 
+	93, 93, 93, 93, 93, 93, 93, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 87, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 88, 1, 
-	1, 1, 90, 90, 90, 90, 90, 90, 
-	90, 90, 90, 90, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -449,49 +459,39 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 89, 
-	1, 91, 1, 91, 91, 91, 91, 91, 
+	1, 1, 87, 1, 94, 94, 94, 94, 
+	94, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 94, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 91, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 92, 1, 92, 92, 
-	92, 92, 92, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 92, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 93, 94, 94, 
-	94, 94, 94, 94, 94, 94, 94, 1, 
-	87, 87, 87, 87, 87, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 87, 
+	1, 1, 1, 1, 1, 1, 95, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 88, 1, 1, 1, 95, 
-	95, 95, 95, 95, 95, 95, 95, 95, 
-	95, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 96, 1, 
+	95, 95, 95, 95, 95, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 95, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 89, 1, 96, 96, 
-	96, 96, 96, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 96, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 97, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 98, 1, 2, 2, 2, 2, 
-	2, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 96, 1, 23, 23, 23, 23, 
+	23, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 2, 1, 1, 1, 1, 
+	1, 1, 1, 23, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -502,47 +502,47 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 3, 1, 
-	1, 0
+	1, 1, 1, 1, 1, 1, 96, 1, 
+	0
 };
 
 static const char _deserialize_json_trans_targs[] = {
-	1, 0, 2, 3, 3, 4, 5, 19, 
-	25, 38, 44, 52, 6, 13, 7, 8, 
-	9, 10, 12, 10, 12, 11, 3, 56, 
-	11, 56, 14, 15, 16, 17, 18, 17, 
-	18, 11, 3, 56, 20, 21, 22, 23, 
-	24, 11, 3, 56, 24, 26, 32, 27, 
-	28, 29, 30, 31, 30, 31, 11, 3, 
-	56, 33, 34, 35, 36, 37, 36, 37, 
-	11, 3, 56, 39, 40, 41, 42, 43, 
-	11, 3, 56, 43, 45, 46, 47, 50, 
-	51, 47, 48, 49, 11, 3, 56, 11, 
-	3, 56, 51, 53, 54, 50, 55, 55, 
-	56, 57, 58
+	1, 0, 2, 3, 18, 24, 37, 43, 
+	51, 4, 12, 5, 6, 7, 8, 11, 
+	8, 11, 9, 1, 10, 9, 10, 57, 
+	13, 14, 15, 16, 17, 16, 17, 9, 
+	1, 10, 19, 20, 21, 22, 23, 9, 
+	1, 10, 23, 25, 31, 26, 27, 28, 
+	29, 30, 29, 30, 9, 1, 10, 32, 
+	33, 34, 35, 36, 35, 36, 9, 1, 
+	10, 38, 39, 40, 41, 42, 9, 1, 
+	10, 42, 44, 45, 46, 49, 50, 46, 
+	47, 48, 9, 1, 10, 9, 1, 10, 
+	50, 52, 53, 49, 54, 54, 55, 56, 
+	1
 };
 
 static const char _deserialize_json_trans_actions[] = {
-	0, 0, 0, 1, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	2, 2, 2, 0, 0, 3, 3, 4, 
-	0, 5, 0, 0, 2, 2, 2, 0, 
-	0, 6, 6, 7, 0, 0, 0, 2, 
-	2, 8, 8, 9, 0, 0, 0, 0, 
-	0, 2, 2, 2, 0, 0, 10, 10, 
-	11, 0, 0, 2, 2, 2, 0, 0, 
-	12, 12, 13, 0, 0, 0, 2, 2, 
-	14, 14, 15, 0, 0, 0, 2, 16, 
-	16, 0, 17, 0, 18, 18, 19, 20, 
-	20, 21, 17, 0, 0, 22, 22, 23, 
-	0, 0, 0
+	0, 0, 0, 0, 0, 1, 1, 1, 
+	0, 0, 2, 2, 2, 0, 0, 3, 
+	0, 0, 1, 1, 1, 0, 0, 4, 
+	4, 4, 0, 0, 0, 1, 1, 5, 
+	5, 5, 0, 0, 0, 0, 0, 1, 
+	1, 1, 0, 0, 6, 6, 6, 0, 
+	0, 1, 1, 1, 0, 0, 7, 7, 
+	7, 0, 0, 0, 1, 1, 8, 8, 
+	8, 0, 0, 0, 1, 9, 9, 0, 
+	10, 0, 11, 11, 11, 12, 12, 12, 
+	10, 0, 0, 13, 13, 14, 0, 0, 
+	15
 };
 
-static const int deserialize_json_start = 1;
-static const int deserialize_json_first_final = 56;
+static const int deserialize_json_start = 55;
+static const int deserialize_json_first_final = 55;
 static const int deserialize_json_error = 0;
 
-static const int deserialize_json_en_main = 1;
+static const int deserialize_json_en_main = 55;
 
 
 #line 111 "hb-buffer-deserialize-json.rl"
@@ -595,14 +595,14 @@ _resume:
 		goto _again;
 
 	switch ( _deserialize_json_trans_actions[_trans] ) {
-	case 1:
+	case 15:
 #line 38 "hb-buffer-deserialize-json.rl"
 	{
 	hb_memset (&info, 0, sizeof (info));
 	hb_memset (&pos , 0, sizeof (pos ));
 }
 	break;
-	case 5:
+	case 3:
 #line 43 "hb-buffer-deserialize-json.rl"
 	{
 	buffer->add_info (info);
@@ -612,21 +612,21 @@ _resume:
 	*end_ptr = p;
 }
 	break;
-	case 2:
+	case 1:
 #line 51 "hb-buffer-deserialize-json.rl"
 	{
 	tok = p;
 }
 	break;
-	case 17:
+	case 10:
 #line 55 "hb-buffer-deserialize-json.rl"
 	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
 	break;
-	case 23:
+	case 14:
 #line 56 "hb-buffer-deserialize-json.rl"
 	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
 	break;
-	case 18:
+	case 11:
 #line 58 "hb-buffer-deserialize-json.rl"
 	{
 	/* TODO Unescape \" and \\ if found. */
@@ -636,35 +636,35 @@ _resume:
 	  return false;
 }
 	break;
-	case 20:
+	case 12:
 #line 66 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
 	break;
-	case 8:
+	case 5:
 #line 67 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 	break;
-	case 10:
+	case 6:
 #line 68 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
 	break;
-	case 12:
+	case 7:
 #line 69 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 	break;
-	case 3:
+	case 2:
 #line 70 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 	break;
-	case 6:
+	case 4:
 #line 71 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 	break;
-	case 14:
+	case 8:
 #line 72 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
 	break;
-	case 16:
+	case 9:
 #line 51 "hb-buffer-deserialize-json.rl"
 	{
 	tok = p;
@@ -672,7 +672,7 @@ _resume:
 #line 55 "hb-buffer-deserialize-json.rl"
 	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
 	break;
-	case 22:
+	case 13:
 #line 51 "hb-buffer-deserialize-json.rl"
 	{
 	tok = p;
@@ -680,109 +680,7 @@ _resume:
 #line 56 "hb-buffer-deserialize-json.rl"
 	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
 	break;
-	case 19:
-#line 58 "hb-buffer-deserialize-json.rl"
-	{
-	/* TODO Unescape \" and \\ if found. */
-	if (!hb_font_glyph_from_string (font,
-					tok+1, p - tok - 2, /* Skip "" */
-					&info.codepoint))
-	  return false;
-}
-#line 43 "hb-buffer-deserialize-json.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 21:
-#line 66 "hb-buffer-deserialize-json.rl"
-	{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
-#line 43 "hb-buffer-deserialize-json.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 9:
-#line 67 "hb-buffer-deserialize-json.rl"
-	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
-#line 43 "hb-buffer-deserialize-json.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 11:
-#line 68 "hb-buffer-deserialize-json.rl"
-	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
-#line 43 "hb-buffer-deserialize-json.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 13:
-#line 69 "hb-buffer-deserialize-json.rl"
-	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-#line 43 "hb-buffer-deserialize-json.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 4:
-#line 70 "hb-buffer-deserialize-json.rl"
-	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-#line 43 "hb-buffer-deserialize-json.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 7:
-#line 71 "hb-buffer-deserialize-json.rl"
-	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-#line 43 "hb-buffer-deserialize-json.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 15:
-#line 72 "hb-buffer-deserialize-json.rl"
-	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
-#line 43 "hb-buffer-deserialize-json.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-#line 786 "hb-buffer-deserialize-json.hh"
+#line 684 "hb-buffer-deserialize-json.hh"
 	}
 
 _again:
@@ -799,7 +697,7 @@ _again:
 
   *end_ptr = p;
 
-  return p == pe && *(p-1) != ']';
+  return p == pe;
 }
 
 #endif /* HB_BUFFER_DESERIALIZE_JSON_HH */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-json.rl b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-json.rl
index 2f1ad9118c4435a7aee54bc9c07cdecba55b8324..eb092bfe924a7fb5163f7eee72bf44eea512c37e 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-json.rl
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-json.rl
@@ -101,12 +101,12 @@ element = glyph @ensure_glyphs
 	| yadvance
 	| glyphflags;
 item	=
-	( '{' space* element (comma element)* space* '}')
+	( '{' space* element (comma element)* space* '}' space* (','|']') space* )
 	>clear_item
 	@add_item
 	;
 
-main := space* '['? space* item (comma item)* space* (','|']')?;
+main := space* '['? space* item*;
 
 }%%
 
@@ -133,7 +133,7 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
 
   *end_ptr = p;
 
-  return p == pe && *(p-1) != ']';
+  return p == pe;
 }
 
 #endif /* HB_BUFFER_DESERIALIZE_JSON_HH */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text-glyphs.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text-glyphs.hh
index ea81273b31ca3b086b2425df0046ff3b524893fd..fe70b4fc1d5b5aad3818223b88343c5a441e18cd 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text-glyphs.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text-glyphs.hh
@@ -34,285 +34,247 @@
 
 #line 36 "hb-buffer-deserialize-text-glyphs.hh"
 static const unsigned char _deserialize_text_glyphs_trans_keys[] = {
-	0u, 0u, 48u, 57u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 
-	48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 43u, 124u, 9u, 124u, 9u, 124u, 
-	9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 
-	9u, 124u, 9u, 124u, 9u, 124u, 0
+	0u, 0u, 35u, 124u, 48u, 57u, 93u, 124u, 45u, 57u, 48u, 57u, 35u, 124u, 45u, 57u, 
+	48u, 57u, 35u, 124u, 35u, 124u, 35u, 124u, 48u, 57u, 35u, 124u, 45u, 57u, 48u, 57u, 
+	44u, 44u, 45u, 57u, 48u, 57u, 35u, 124u, 35u, 124u, 44u, 57u, 35u, 124u, 43u, 124u, 
+	48u, 124u, 35u, 124u, 35u, 124u, 35u, 124u, 0
 };
 
 static const char _deserialize_text_glyphs_key_spans[] = {
-	0, 10, 13, 10, 13, 10, 10, 13, 
-	10, 1, 13, 10, 14, 82, 116, 116, 
-	116, 116, 116, 116, 116, 116, 116, 116, 
-	116, 116, 116
+	0, 90, 10, 32, 13, 10, 90, 13, 
+	10, 90, 90, 90, 10, 90, 13, 10, 
+	1, 13, 10, 90, 90, 14, 90, 82, 
+	77, 90, 90, 90
 };
 
 static const short _deserialize_text_glyphs_index_offsets[] = {
-	0, 0, 11, 25, 36, 50, 61, 72, 
-	86, 97, 99, 113, 124, 139, 222, 339, 
-	456, 573, 690, 807, 924, 1041, 1158, 1275, 
-	1392, 1509, 1626
+	0, 0, 91, 102, 135, 149, 160, 251, 
+	265, 276, 367, 458, 549, 560, 651, 665, 
+	676, 678, 692, 703, 794, 885, 900, 991, 
+	1074, 1152, 1243, 1334
 };
 
 static const char _deserialize_text_glyphs_indicies[] = {
-	0, 2, 2, 2, 2, 2, 2, 
-	2, 2, 2, 1, 3, 1, 1, 4, 
-	5, 5, 5, 5, 5, 5, 5, 5, 
-	5, 1, 6, 7, 7, 7, 7, 7, 
-	7, 7, 7, 7, 1, 8, 1, 1, 
-	9, 10, 10, 10, 10, 10, 10, 10, 
-	10, 10, 1, 11, 12, 12, 12, 12, 
-	12, 12, 12, 12, 12, 1, 13, 14, 
-	14, 14, 14, 14, 14, 14, 14, 14, 
-	1, 15, 1, 1, 16, 17, 17, 17, 
-	17, 17, 17, 17, 17, 17, 1, 18, 
-	19, 19, 19, 19, 19, 19, 19, 19, 
-	19, 1, 20, 1, 21, 1, 1, 22, 
-	23, 23, 23, 23, 23, 23, 23, 23, 
-	23, 1, 24, 25, 25, 25, 25, 25, 
-	25, 25, 25, 25, 1, 20, 1, 1, 
-	1, 19, 19, 19, 19, 19, 19, 19, 
-	19, 19, 19, 1, 26, 26, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 26, 1, 
-	1, 26, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 26, 26, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 26, 1, 28, 
-	28, 28, 28, 28, 27, 27, 27, 27, 
-	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 27, 27, 27, 27, 27, 28, 27, 
-	27, 29, 27, 27, 27, 27, 27, 27, 
-	27, 30, 1, 27, 27, 27, 27, 27, 
-	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 27, 27, 31, 27, 27, 32, 27, 
-	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 27, 33, 1, 27, 27, 27, 27, 
-	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 27, 27, 27, 27, 27, 27, 27, 
+	1, 0, 0, 0, 0, 0, 0, 
+	0, 2, 3, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 4, 0, 0, 5, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 6, 7, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 7, 0, 8, 9, 9, 9, 
+	9, 9, 9, 9, 9, 9, 3, 10, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 10, 3, 
+	11, 3, 3, 12, 13, 13, 13, 13, 
+	13, 13, 13, 13, 13, 3, 14, 15, 
+	15, 15, 15, 15, 15, 15, 15, 15, 
+	3, 16, 3, 3, 3, 3, 3, 3, 
+	3, 3, 17, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 18, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 18, 3, 19, 3, 3, 20, 
+	21, 21, 21, 21, 21, 21, 21, 21, 
+	21, 3, 22, 23, 23, 23, 23, 23, 
+	23, 23, 23, 23, 3, 24, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 25, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 25, 3, 
+	24, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 23, 23, 23, 
+	23, 23, 23, 23, 23, 23, 23, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 25, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 25, 3, 16, 3, 3, 3, 3, 
+	3, 3, 3, 3, 17, 3, 3, 3, 
+	15, 15, 15, 15, 15, 15, 15, 15, 
+	15, 15, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 18, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 18, 3, 26, 27, 
 	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 27, 28, 27, 34, 34, 34, 34, 
-	34, 26, 26, 26, 26, 26, 26, 26, 
-	26, 26, 26, 26, 26, 26, 26, 26, 
-	26, 26, 26, 34, 26, 26, 35, 26, 
-	26, 26, 26, 26, 26, 26, 36, 1, 
-	26, 26, 26, 26, 26, 26, 26, 26, 
-	26, 26, 26, 26, 26, 26, 26, 26, 
-	37, 26, 26, 38, 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, 39, 
-	1, 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, 40, 
-	26, 41, 41, 41, 41, 41, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	41, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 42, 1, 43, 43, 
-	43, 43, 43, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 43, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 44, 1, 41, 41, 41, 41, 41, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 41, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 45, 45, 45, 45, 45, 45, 
-	45, 45, 45, 45, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 42, 1, 
-	46, 46, 46, 46, 46, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 46, 
-	1, 1, 47, 1, 1, 1, 1, 1, 
-	1, 1, 1, 48, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 49, 1, 50, 50, 50, 
-	50, 50, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 50, 1, 1, 51, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	52, 1, 50, 50, 50, 50, 50, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 50, 1, 1, 51, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 12, 12, 12, 12, 12, 12, 12, 
-	12, 12, 12, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 52, 1, 46, 
-	46, 46, 46, 46, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 46, 1, 
-	1, 47, 1, 1, 1, 1, 1, 1, 
-	1, 1, 48, 1, 1, 1, 7, 7, 
-	7, 7, 7, 7, 7, 7, 7, 7, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 49, 1, 53, 53, 53, 53, 
-	53, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 53, 1, 1, 54, 1, 
-	1, 1, 1, 1, 1, 1, 55, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 56, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 57, 
-	1, 58, 58, 58, 58, 58, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	58, 1, 1, 59, 1, 1, 1, 1, 
-	1, 1, 1, 60, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 61, 1, 58, 58, 
-	58, 58, 58, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 58, 1, 1, 
-	59, 1, 1, 1, 1, 1, 1, 1, 
-	60, 1, 1, 1, 1, 25, 25, 25, 
-	25, 25, 25, 25, 25, 25, 25, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 61, 1, 53, 53, 53, 53, 53, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 53, 1, 1, 54, 1, 1, 
-	1, 1, 1, 1, 1, 55, 1, 1, 
-	1, 1, 62, 62, 62, 62, 62, 62, 
-	62, 62, 62, 62, 1, 1, 1, 1, 
-	1, 1, 56, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 57, 1, 
-	0
+	3, 28, 3, 3, 3, 3, 3, 3, 
+	3, 29, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 30, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 31, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 31, 3, 32, 3, 3, 33, 
+	34, 34, 34, 34, 34, 34, 34, 34, 
+	34, 3, 35, 36, 36, 36, 36, 36, 
+	36, 36, 36, 36, 3, 37, 3, 38, 
+	3, 3, 39, 40, 40, 40, 40, 40, 
+	40, 40, 40, 40, 3, 41, 42, 42, 
+	42, 42, 42, 42, 42, 42, 42, 3, 
+	43, 3, 3, 3, 3, 3, 3, 3, 
+	44, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 45, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 45, 3, 43, 3, 3, 3, 3, 
+	3, 3, 3, 44, 3, 3, 3, 3, 
+	42, 42, 42, 42, 42, 42, 42, 42, 
+	42, 42, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 45, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 45, 3, 37, 3, 
+	3, 3, 36, 36, 36, 36, 36, 36, 
+	36, 36, 36, 36, 3, 28, 3, 3, 
+	3, 3, 3, 3, 3, 29, 3, 3, 
+	3, 3, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 46, 3, 3, 3, 3, 
+	3, 3, 30, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 31, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 31, 3, 
+	0, 0, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 0, 3, 3, 0, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 0, 0, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 0, 3, 47, 47, 47, 47, 47, 
+	47, 47, 47, 47, 47, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	10, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 10, 
+	3, 49, 48, 48, 48, 48, 48, 48, 
+	48, 50, 3, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 51, 48, 48, 52, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 53, 54, 55, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 55, 48, 57, 56, 56, 56, 
+	56, 56, 56, 56, 58, 3, 56, 56, 
+	56, 56, 56, 56, 56, 56, 56, 56, 
+	56, 56, 56, 56, 56, 56, 59, 56, 
+	56, 60, 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, 61, 62, 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, 62, 56, 63, 
+	48, 48, 48, 48, 48, 48, 48, 64, 
+	3, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 65, 48, 48, 66, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	54, 67, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	67, 48, 0
 };
 
 static const char _deserialize_text_glyphs_trans_targs[] = {
-	16, 0, 18, 3, 19, 22, 19, 22, 
-	5, 20, 21, 20, 21, 23, 26, 8, 
-	9, 12, 9, 12, 10, 11, 24, 25, 
-	24, 25, 15, 15, 14, 1, 2, 6, 
-	7, 13, 15, 1, 2, 6, 7, 13, 
-	14, 17, 14, 17, 14, 18, 17, 1, 
-	4, 14, 17, 1, 14, 17, 1, 2, 
-	7, 14, 17, 1, 2, 14, 26
+	1, 2, 4, 0, 12, 14, 23, 26, 
+	3, 24, 26, 5, 6, 11, 6, 11, 
+	2, 7, 26, 8, 9, 10, 9, 10, 
+	2, 26, 13, 22, 2, 4, 14, 26, 
+	15, 16, 21, 16, 21, 17, 18, 19, 
+	20, 19, 20, 2, 4, 26, 22, 24, 
+	1, 2, 4, 12, 14, 27, 23, 26, 
+	1, 2, 4, 12, 14, 23, 26, 2, 
+	4, 12, 14, 26
 };
 
 static const char _deserialize_text_glyphs_trans_actions[] = {
-	1, 0, 1, 1, 1, 1, 0, 0, 
-	1, 1, 1, 0, 0, 1, 1, 1, 
-	1, 1, 0, 0, 2, 1, 1, 1, 
-	0, 0, 0, 4, 3, 5, 5, 5, 
-	5, 4, 6, 7, 7, 7, 7, 0, 
-	6, 8, 8, 0, 0, 0, 9, 10, 
-	10, 9, 11, 12, 11, 13, 14, 14, 
-	14, 13, 15, 16, 16, 15, 0
+	0, 1, 1, 0, 1, 1, 0, 1, 
+	2, 2, 3, 2, 2, 2, 0, 0, 
+	4, 4, 4, 2, 2, 2, 0, 0, 
+	5, 5, 2, 2, 6, 6, 6, 6, 
+	2, 2, 2, 0, 0, 7, 2, 2, 
+	2, 0, 0, 8, 8, 8, 0, 0, 
+	9, 10, 10, 10, 10, 9, 9, 10, 
+	12, 13, 13, 13, 13, 12, 13, 14, 
+	14, 14, 14, 14
 };
 
 static const char _deserialize_text_glyphs_eof_actions[] = {
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 3, 6, 
-	8, 0, 8, 9, 11, 11, 9, 13, 
-	15, 15, 13
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 11, 0
 };
 
-static const int deserialize_text_glyphs_start = 14;
-static const int deserialize_text_glyphs_first_final = 14;
+static const int deserialize_text_glyphs_start = 25;
+static const int deserialize_text_glyphs_first_final = 25;
 static const int deserialize_text_glyphs_error = 0;
 
-static const int deserialize_text_glyphs_en_main = 14;
+static const int deserialize_text_glyphs_en_main = 25;
 
 
-#line 98 "hb-buffer-deserialize-text-glyphs.rl"
+#line 99 "hb-buffer-deserialize-text-glyphs.rl"
 
 
 static hb_bool_t
@@ -322,39 +284,22 @@ _hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer,
 				    const char **end_ptr,
 				    hb_font_t *font)
 {
-  const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
+  const char *p = buf, *pe = buf + buf_len, *eof = pe;
 
   /* Ensure we have positions. */
   (void) hb_buffer_get_glyph_positions (buffer, nullptr);
 
-  while (p < pe && ISSPACE (*p))
-    p++;
-  if (p < pe && *p == (buffer->len ? '|' : '['))
-    *end_ptr = ++p;
-
-  const char *end = strchr ((char *) p, ']');
-  if (end)
-    pe = eof = end;
-  else
-  {
-    end = strrchr ((char *) p, '|');
-    if (end)
-      pe = eof = end;
-    else
-      pe = eof = p;
-  }
-
   const char *tok = nullptr;
   int cs;
   hb_glyph_info_t info = {0};
   hb_glyph_position_t pos = {0};
   
-#line 353 "hb-buffer-deserialize-text-glyphs.hh"
+#line 298 "hb-buffer-deserialize-text-glyphs.hh"
 	{
 	cs = deserialize_text_glyphs_start;
 	}
 
-#line 358 "hb-buffer-deserialize-text-glyphs.hh"
+#line 303 "hb-buffer-deserialize-text-glyphs.hh"
 	{
 	int _slen;
 	int _trans;
@@ -379,13 +324,13 @@ _resume:
 		goto _again;
 
 	switch ( _deserialize_text_glyphs_trans_actions[_trans] ) {
-	case 1:
+	case 2:
 #line 51 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	tok = p;
 }
 	break;
-	case 7:
+	case 1:
 #line 55 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	/* TODO Unescape delimiters. */
@@ -395,27 +340,31 @@ _resume:
 	  return false;
 }
 	break;
-	case 14:
+	case 6:
 #line 63 "hb-buffer-deserialize-text-glyphs.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 	break;
-	case 2:
+	case 7:
 #line 64 "hb-buffer-deserialize-text-glyphs.rl"
 	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
 	break;
-	case 16:
+	case 8:
 #line 65 "hb-buffer-deserialize-text-glyphs.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 	break;
-	case 10:
+	case 4:
 #line 66 "hb-buffer-deserialize-text-glyphs.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 	break;
-	case 12:
+	case 5:
 #line 67 "hb-buffer-deserialize-text-glyphs.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 	break;
-	case 4:
+	case 3:
+#line 68 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
+	break;
+	case 9:
 #line 38 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	hb_memset (&info, 0, sizeof (info));
@@ -426,7 +375,16 @@ _resume:
 	tok = p;
 }
 	break;
-	case 6:
+	case 10:
+#line 38 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	hb_memset (&info, 0, sizeof (info));
+	hb_memset (&pos , 0, sizeof (pos ));
+}
+#line 51 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	tok = p;
+}
 #line 55 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	/* TODO Unescape delimiters. */
@@ -434,67 +392,9 @@ _resume:
 					tok, p - tok,
 					&info.codepoint))
 	  return false;
-}
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 13:
-#line 63 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 15:
-#line 65 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 9:
-#line 66 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 11:
-#line 67 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
 }
 	break;
-	case 8:
-#line 68 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
+	case 12:
 #line 43 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	buffer->add_info (info);
@@ -503,8 +403,6 @@ _resume:
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
-	break;
-	case 5:
 #line 38 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	hb_memset (&info, 0, sizeof (info));
@@ -514,6 +412,8 @@ _resume:
 	{
 	tok = p;
 }
+	break;
+	case 14:
 #line 55 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	/* TODO Unescape delimiters. */
@@ -522,8 +422,6 @@ _resume:
 					&info.codepoint))
 	  return false;
 }
-	break;
-	case 3:
 #line 38 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	hb_memset (&info, 0, sizeof (info));
@@ -532,57 +430,9 @@ _resume:
 #line 51 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	tok = p;
-}
-#line 55 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	/* TODO Unescape delimiters. */
-	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
-					&info.codepoint))
-	  return false;
-}
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-#line 554 "hb-buffer-deserialize-text-glyphs.hh"
-	}
-
-_again:
-	if ( cs == 0 )
-		goto _out;
-	if ( ++p != pe )
-		goto _resume;
-	_test_eof: {}
-	if ( p == eof )
-	{
-	switch ( _deserialize_text_glyphs_eof_actions[cs] ) {
-	case 6:
-#line 55 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	/* TODO Unescape delimiters. */
-	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
-					&info.codepoint))
-	  return false;
-}
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
 }
 	break;
 	case 13:
-#line 63 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 #line 43 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	buffer->add_info (info);
@@ -591,56 +441,6 @@ _again:
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
-	break;
-	case 15:
-#line 65 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 9:
-#line 66 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 11:
-#line 67 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 8:
-#line 68 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 3:
 #line 38 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	hb_memset (&info, 0, sizeof (info));
@@ -658,6 +458,20 @@ _again:
 					&info.codepoint))
 	  return false;
 }
+	break;
+#line 463 "hb-buffer-deserialize-text-glyphs.hh"
+	}
+
+_again:
+	if ( cs == 0 )
+		goto _out;
+	if ( ++p != pe )
+		goto _resume;
+	_test_eof: {}
+	if ( p == eof )
+	{
+	switch ( _deserialize_text_glyphs_eof_actions[cs] ) {
+	case 11:
 #line 43 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	buffer->add_info (info);
@@ -667,22 +481,15 @@ _again:
 	*end_ptr = p;
 }
 	break;
-#line 671 "hb-buffer-deserialize-text-glyphs.hh"
+#line 485 "hb-buffer-deserialize-text-glyphs.hh"
 	}
 	}
 
 	_out: {}
 	}
 
-#line 136 "hb-buffer-deserialize-text-glyphs.rl"
-
+#line 120 "hb-buffer-deserialize-text-glyphs.rl"
 
-  if (pe < orig_pe && *pe == ']')
-  {
-    pe++;
-    if (p == pe)
-      p++;
-  }
 
   *end_ptr = p;
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text-glyphs.rl b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text-glyphs.rl
index 21db14b568bbfd930d6218eb9599e21f5c2c3f60..8efedb8d36862a297686def3aec177b810a5ff88 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text-glyphs.rl
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text-glyphs.rl
@@ -86,14 +86,15 @@ glyph_item	=
 		offsets?
 		advances?
 		glyphflags?
+		( '|' | ']')
 	)
 	>clear_item
 	%add_item
 	;
 
-glyphs = glyph_item (space* '|' space* glyph_item)* space*;
+glyphs = '['? glyph_item* ;
 
-main := space* glyphs;
+main := glyphs;
 
 }%%
 
@@ -104,28 +105,11 @@ _hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer,
 				    const char **end_ptr,
 				    hb_font_t *font)
 {
-  const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
+  const char *p = buf, *pe = buf + buf_len, *eof = pe;
 
   /* Ensure we have positions. */
   (void) hb_buffer_get_glyph_positions (buffer, nullptr);
 
-  while (p < pe && ISSPACE (*p))
-    p++;
-  if (p < pe && *p == (buffer->len ? '|' : '['))
-    *end_ptr = ++p;
-
-  const char *end = strchr ((char *) p, ']');
-  if (end)
-    pe = eof = end;
-  else
-  {
-    end = strrchr ((char *) p, '|');
-    if (end)
-      pe = eof = end;
-    else
-      pe = eof = p;
-  }
-
   const char *tok = nullptr;
   int cs;
   hb_glyph_info_t info = {0};
@@ -135,13 +119,6 @@ _hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer,
     write exec;
   }%%
 
-  if (pe < orig_pe && *pe == ']')
-  {
-    pe++;
-    if (p == pe)
-      p++;
-  }
-
   *end_ptr = p;
 
   return p == pe;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text-unicode.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text-unicode.hh
index a8cdf67e73e22a3a159644cd11e124972a76e0b7..26ec0b42257c91ddb8fa9778bdf32f296b23a301 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text-unicode.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text-unicode.hh
@@ -34,135 +34,106 @@
 
 #line 36 "hb-buffer-deserialize-text-unicode.hh"
 static const unsigned char _deserialize_text_unicode_trans_keys[] = {
-	0u, 0u, 9u, 117u, 43u, 102u, 48u, 102u, 48u, 57u, 9u, 124u, 9u, 124u, 9u, 124u, 
-	9u, 124u, 0
+	0u, 0u, 43u, 102u, 48u, 102u, 48u, 124u, 48u, 57u, 62u, 124u, 48u, 124u, 60u, 117u, 
+	85u, 117u, 85u, 117u, 0
 };
 
 static const char _deserialize_text_unicode_key_spans[] = {
-	0, 109, 60, 55, 10, 116, 116, 116, 
-	116
+	0, 60, 55, 77, 10, 63, 77, 58, 
+	33, 33
 };
 
 static const short _deserialize_text_unicode_index_offsets[] = {
-	0, 0, 110, 171, 227, 238, 355, 472, 
-	589
+	0, 0, 61, 117, 195, 206, 270, 348, 
+	407, 441
 };
 
 static const char _deserialize_text_unicode_indicies[] = {
-	0, 0, 0, 0, 0, 1, 1, 
+	0, 1, 1, 1, 1, 2, 2, 
+	2, 2, 2, 2, 2, 2, 2, 2, 
+	1, 1, 1, 1, 1, 1, 1, 2, 
+	2, 2, 2, 2, 2, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	0, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 2, 
+	2, 2, 2, 2, 2, 1, 2, 2, 
+	2, 2, 2, 2, 2, 2, 2, 2, 
+	1, 1, 1, 1, 1, 1, 1, 2, 
+	2, 2, 2, 2, 2, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 2, 
+	2, 2, 2, 2, 2, 1, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	1, 1, 1, 4, 5, 1, 1, 3, 
+	3, 3, 3, 3, 3, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 3, 
+	3, 3, 3, 3, 3, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 2, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 5, 1, 6, 7, 7, 7, 
+	7, 7, 7, 7, 7, 7, 1, 8, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 2, 1, 3, 
-	1, 1, 1, 1, 4, 4, 4, 4, 
-	4, 4, 4, 4, 4, 4, 1, 1, 
-	1, 1, 1, 1, 1, 4, 4, 4, 
-	4, 4, 4, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 4, 4, 4, 
-	4, 4, 4, 1, 4, 4, 4, 4, 
-	4, 4, 4, 4, 4, 4, 1, 1, 
-	1, 1, 1, 1, 1, 4, 4, 4, 
-	4, 4, 4, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 4, 4, 4, 
-	4, 4, 4, 1, 5, 6, 6, 6, 
-	6, 6, 6, 6, 6, 6, 1, 7, 
-	7, 7, 7, 7, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 7, 1, 
+	1, 1, 1, 1, 1, 8, 1, 9, 
+	9, 9, 9, 9, 9, 9, 9, 9, 
+	9, 1, 1, 1, 1, 8, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 8, 8, 
-	8, 8, 8, 8, 8, 8, 8, 8, 
-	1, 1, 1, 9, 1, 1, 1, 8, 
-	8, 8, 8, 8, 8, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 8, 
-	8, 8, 8, 8, 8, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 10, 1, 11, 11, 11, 11, 
-	11, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 11, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 0, 
-	1, 12, 12, 12, 12, 12, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	12, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 8, 1, 10, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 11, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 13, 1, 12, 12, 
-	12, 12, 12, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 12, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 14, 14, 14, 
-	14, 14, 14, 14, 14, 14, 14, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 11, 1, 
+	11, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	11, 1, 12, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 13, 1, 0
+	1, 1, 12, 1, 0
 };
 
 static const char _deserialize_text_unicode_trans_targs[] = {
-	1, 0, 2, 3, 5, 7, 8, 6, 
-	5, 4, 1, 6, 6, 1, 8
+	2, 0, 3, 3, 4, 9, 5, 6, 
+	9, 6, 8, 1, 1
 };
 
 static const char _deserialize_text_unicode_trans_actions[] = {
-	0, 0, 1, 0, 2, 2, 2, 3, 
-	0, 4, 3, 0, 5, 5, 0
+	0, 0, 1, 0, 2, 2, 1, 1, 
+	3, 0, 0, 4, 6
 };
 
 static const char _deserialize_text_unicode_eof_actions[] = {
-	0, 0, 0, 0, 0, 3, 0, 5, 
-	5
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 5
 };
 
-static const int deserialize_text_unicode_start = 1;
-static const int deserialize_text_unicode_first_final = 5;
+static const int deserialize_text_unicode_start = 7;
+static const int deserialize_text_unicode_first_final = 7;
 static const int deserialize_text_unicode_error = 0;
 
-static const int deserialize_text_unicode_en_main = 1;
+static const int deserialize_text_unicode_en_main = 7;
 
 
-#line 79 "hb-buffer-deserialize-text-unicode.rl"
+#line 80 "hb-buffer-deserialize-text-unicode.rl"
 
 
 static hb_bool_t
@@ -172,37 +143,19 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
 				     const char **end_ptr,
 				     hb_font_t *font)
 {
-  const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
-
-  while (p < pe && ISSPACE (*p))
-    p++;
-  if (p < pe && *p == (buffer->len ? '|' : '<'))
-    *end_ptr = ++p;
-
-  const char *end = strchr ((char *) p, '>');
-  if (end)
-    pe = eof = end;
-  else
-  {
-    end = strrchr ((char *) p, '|');
-    if (end)
-      pe = eof = end;
-    else
-      pe = eof = p;
-  }
-
+  const char *p = buf, *pe = buf + buf_len, *eof = pe;
 
   const char *tok = nullptr;
   int cs;
   hb_glyph_info_t info = {0};
   const hb_glyph_position_t pos = {0};
   
-#line 201 "hb-buffer-deserialize-text-unicode.hh"
+#line 154 "hb-buffer-deserialize-text-unicode.hh"
 	{
 	cs = deserialize_text_unicode_start;
 	}
 
-#line 206 "hb-buffer-deserialize-text-unicode.hh"
+#line 159 "hb-buffer-deserialize-text-unicode.hh"
 	{
 	int _slen;
 	int _trans;
@@ -227,38 +180,27 @@ _resume:
 		goto _again;
 
 	switch ( _deserialize_text_unicode_trans_actions[_trans] ) {
-	case 1:
+	case 4:
 #line 38 "hb-buffer-deserialize-text-unicode.rl"
 	{
 	hb_memset (&info, 0, sizeof (info));
 }
 	break;
-	case 2:
+	case 1:
 #line 51 "hb-buffer-deserialize-text-unicode.rl"
 	{
 	tok = p;
 }
 	break;
-	case 4:
+	case 2:
 #line 55 "hb-buffer-deserialize-text-unicode.rl"
 	{if (!parse_hex (tok, p, &info.codepoint )) return false; }
 	break;
 	case 3:
-#line 55 "hb-buffer-deserialize-text-unicode.rl"
-	{if (!parse_hex (tok, p, &info.codepoint )) return false; }
-#line 42 "hb-buffer-deserialize-text-unicode.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	if (buffer->have_positions)
-	  buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 5:
 #line 57 "hb-buffer-deserialize-text-unicode.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
+	break;
+	case 6:
 #line 42 "hb-buffer-deserialize-text-unicode.rl"
 	{
 	buffer->add_info (info);
@@ -267,9 +209,13 @@ _resume:
 	if (buffer->have_positions)
 	  buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
+}
+#line 38 "hb-buffer-deserialize-text-unicode.rl"
+	{
+	hb_memset (&info, 0, sizeof (info));
 }
 	break;
-#line 273 "hb-buffer-deserialize-text-unicode.hh"
+#line 219 "hb-buffer-deserialize-text-unicode.hh"
 	}
 
 _again:
@@ -281,22 +227,7 @@ _again:
 	if ( p == eof )
 	{
 	switch ( _deserialize_text_unicode_eof_actions[cs] ) {
-	case 3:
-#line 55 "hb-buffer-deserialize-text-unicode.rl"
-	{if (!parse_hex (tok, p, &info.codepoint )) return false; }
-#line 42 "hb-buffer-deserialize-text-unicode.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	if (buffer->have_positions)
-	  buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
 	case 5:
-#line 57 "hb-buffer-deserialize-text-unicode.rl"
-	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 #line 42 "hb-buffer-deserialize-text-unicode.rl"
 	{
 	buffer->add_info (info);
@@ -307,22 +238,15 @@ _again:
 	*end_ptr = p;
 }
 	break;
-#line 311 "hb-buffer-deserialize-text-unicode.hh"
+#line 242 "hb-buffer-deserialize-text-unicode.hh"
 	}
 	}
 
 	_out: {}
 	}
 
-#line 115 "hb-buffer-deserialize-text-unicode.rl"
-
+#line 98 "hb-buffer-deserialize-text-unicode.rl"
 
-  if (pe < orig_pe && *pe == '>')
-  {
-    pe++;
-    if (p == pe)
-      p++;
-  }
 
   *end_ptr = p;
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text-unicode.rl b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text-unicode.rl
index 92873b804f3b18f663fb71df50c6d3c36e925153..1e123c8b216efb81e0c5ca1f33cff28f84c5a738 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text-unicode.rl
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text-unicode.rl
@@ -67,14 +67,15 @@ unicode_item	=
 	(
 		unicode
 		cluster?
+		('|' | '>')
 	)
 	>clear_item
 	%add_item
 	;
 
-unicodes = unicode_item (space* '|' space* unicode_item)* space*;
+unicodes = '<'? unicode_item*;
 
-main := space* unicodes;
+main := unicodes;
 
 }%%
 
@@ -85,25 +86,7 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
 				     const char **end_ptr,
 				     hb_font_t *font)
 {
-  const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
-
-  while (p < pe && ISSPACE (*p))
-    p++;
-  if (p < pe && *p == (buffer->len ? '|' : '<'))
-    *end_ptr = ++p;
-
-  const char *end = strchr ((char *) p, '>');
-  if (end)
-    pe = eof = end;
-  else
-  {
-    end = strrchr ((char *) p, '|');
-    if (end)
-      pe = eof = end;
-    else
-      pe = eof = p;
-  }
-
+  const char *p = buf, *pe = buf + buf_len, *eof = pe;
 
   const char *tok = nullptr;
   int cs;
@@ -114,13 +97,6 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
     write exec;
   }%%
 
-  if (pe < orig_pe && *pe == '>')
-  {
-    pe++;
-    if (p == pe)
-      p++;
-  }
-
   *end_ptr = p;
 
   return p == pe;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-serialize.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-serialize.cc
index 16f189519b199c817ef9afe64aafb222edc28da2..b71aa72199631043cbe92c0340afabe777be409d 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-serialize.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-serialize.cc
@@ -169,11 +169,13 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
     {
       hb_glyph_extents_t extents;
-      hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
-      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
-                                extents.x_bearing, extents.y_bearing));
-      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
-                                extents.width, extents.height));
+      if (hb_font_get_glyph_extents(font, info[i].codepoint, &extents))
+      {
+	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
+				  extents.x_bearing, extents.y_bearing));
+	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
+				  extents.width, extents.height));
+      }
     }
 
     *p++ = '}';
@@ -318,8 +320,8 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
     {
       hb_glyph_extents_t extents;
-      hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
-      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
+      if (hb_font_get_glyph_extents(font, info[i].codepoint, &extents))
+	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
     }
 
     if (i == end-1) {
@@ -737,8 +739,7 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
  * Deserializes glyphs @buffer from textual representation in the format
  * produced by hb_buffer_serialize_glyphs().
  *
- * Return value: `true` if parse was successful, `false` if an error
- * occurred.
+ * Return value: `true` if the full string was parsed, `false` otherwise.
  *
  * Since: 0.9.7
  **/
@@ -810,8 +811,7 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
  * Deserializes Unicode @buffer from textual representation in the format
  * produced by hb_buffer_serialize_unicode().
  *
- * Return value: `true` if parse was successful, `false` if an error
- * occurred.
+ * Return value: `true` if the full string was parsed, `false` otherwise.
  *
  * Since: 2.7.3
  **/
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-verify.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-verify.cc
index 345f08d260f7fb893fe96ff4af39e38300d06a9f..76f821637af1ece3dc2a3985ce9f9ae4a7387a51 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-verify.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-verify.cc
@@ -63,23 +63,24 @@ static bool
 buffer_verify_monotone (hb_buffer_t *buffer,
 			hb_font_t   *font)
 {
-  /* Check that clusters are monotone. */
-  if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES ||
-      buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+  if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
   {
-    bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
+    /* Cannot perform this check without monotone clusters. */
+    return true;
+  }
 
-    unsigned int num_glyphs;
-    hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
+  bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
 
-    for (unsigned int i = 1; i < num_glyphs; i++)
-      if (info[i-1].cluster != info[i].cluster &&
-	  (info[i-1].cluster < info[i].cluster) != is_forward)
-      {
-	buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone.");
-	return false;
-      }
-  }
+  unsigned int num_glyphs;
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
+
+  for (unsigned int i = 1; i < num_glyphs; i++)
+    if (info[i-1].cluster != info[i].cluster &&
+	(info[i-1].cluster < info[i].cluster) != is_forward)
+    {
+      buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone.");
+      return false;
+    }
 
   return true;
 }
@@ -92,8 +93,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t  *buffer,
 			       unsigned int        num_features,
 			       const char * const *shapers)
 {
-  if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
-      buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+  if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
   {
     /* Cannot perform this check without monotone clusters. */
     return true;
@@ -207,8 +207,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t        *buffer,
 				unsigned int        num_features,
 				const char * const *shapers)
 {
-  if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
-      buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+  if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
   {
     /* Cannot perform this check without monotone clusters. */
     return true;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.cc
index d0c40664a66820fde9bad621b761463a0568aa3b..7fb95fe7e190d74e5f98ecb0d0ab81e06aa2e50c 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.cc
@@ -518,7 +518,7 @@ void
 hb_buffer_t::merge_clusters_impl (unsigned int start,
 				  unsigned int end)
 {
-  if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
+  if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))
   {
     unsafe_to_break (start, end);
     return;
@@ -551,7 +551,7 @@ void
 hb_buffer_t::merge_out_clusters (unsigned int start,
 				 unsigned int end)
 {
-  if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
+  if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))
     return;
 
   if (unlikely (end - start < 2))
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.h
index dd0edb9b7d799207ce9c66bbe666b2f6242eca03..705b767b66aa47b9e1acfe21eb954d7db09874f2 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.h
@@ -422,18 +422,34 @@ hb_buffer_get_flags (const hb_buffer_t *buffer);
  * @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: Don't group cluster values.
  * @HB_BUFFER_CLUSTER_LEVEL_DEFAULT: Default cluster level,
  *   equal to @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES.
- * 
+ * @HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES: Only group clusters, but don't enforce monotone order.
+ *
  * Data type for holding HarfBuzz's clustering behavior options. The cluster level
- * dictates one aspect of how HarfBuzz will treat non-base characters 
+ * dictates one aspect of how HarfBuzz will treat non-base characters
  * during shaping.
  *
  * In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES, non-base
  * characters are merged into the cluster of the base character that precedes them.
+ * There is also cluster merging every time the clusters will otherwise become non-monotone.
  *
  * In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS, non-base characters are initially
  * assigned their own cluster values, which are not merged into preceding base
  * clusters. This allows HarfBuzz to perform additional operations like reorder
- * sequences of adjacent marks.
+ * sequences of adjacent marks. The output is still monotone, but the cluster
+ * values are more granular.
+ *
+ * In @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS, non-base characters are assigned their
+ * own cluster values, which are not merged into preceding base clusters. Moreover,
+ * the cluster values are not merged into monotone order. This is the most granular
+ * cluster level, and it is useful for clients that need to know the exact cluster
+ * values of each character, but is harder to use for clients, since clusters
+ * might appear in any order.
+ *
+ * In @HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES, non-base characters are merged into the
+ * cluster of the base character that precedes them. This is similar to the Unicode
+ * Grapheme Cluster algorithm, but it is not exactly the same. The output is
+ * not forced to be monotone. This is useful for clients that want to use HarfBuzz
+ * as a cheap implementation of the Unicode Grapheme Cluster algorithm.
  *
  * @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES is the default, because it maintains
  * backward compatibility with older versions of HarfBuzz. New client programs that
@@ -446,9 +462,52 @@ typedef enum {
   HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES	= 0,
   HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS	= 1,
   HB_BUFFER_CLUSTER_LEVEL_CHARACTERS		= 2,
+  HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES		= 3,
   HB_BUFFER_CLUSTER_LEVEL_DEFAULT = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES
 } hb_buffer_cluster_level_t;
 
+/**
+ * HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE:
+ * @level: #hb_buffer_cluster_level_t to test
+ *
+ * Tests whether a cluster level groups cluster values into monotone order.
+ * Requires that the level be valid.
+ *
+ * Since: 11.0.0
+ */
+#define HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE(level) \
+	((bool) ((1u << (unsigned) (level)) & \
+		 ((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) | \
+		  (1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS))))
+
+/**
+ * HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES:
+ * @level: #hb_buffer_cluster_level_t to test
+ *
+ * Tests whether a cluster level groups cluster values by graphemes. Requires
+ * that the level be valid.
+ *
+ * Since: 11.0.0
+ */
+#define HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES(level) \
+	((bool) ((1u << (unsigned) (level)) & \
+		 ((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) | \
+		  (1u << HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES))))
+
+/**
+ * HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS
+ * @level: #hb_buffer_cluster_level_t to test
+ *
+ * Tests whether a cluster level does not group cluster values by graphemes.
+ * Requires that the level be valid.
+ *
+ * Since: 11.0.0
+ */
+#define HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS(level) \
+	((bool) ((1u << (unsigned) (level)) & \
+		 ((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARCATERS) | \
+		  (1u << HB_BUFFER_CLUSTER_LEVEL_CHARACTERS))))
+
 HB_EXTERN void
 hb_buffer_set_cluster_level (hb_buffer_t               *buffer,
 			     hb_buffer_cluster_level_t  cluster_level);
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-cache.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-cache.hh
index 6d8a54cf102f345834891636a024ea20d5e0aac0..882a71a9daf00f99d592c1f1bb7d0011e4a82bd3 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-cache.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-cache.hh
@@ -52,11 +52,11 @@ struct hb_cache_t
 {
   using item_t = typename std::conditional<thread_safe,
 					   typename std::conditional<key_bits + value_bits - cache_bits <= 16,
-								     hb_atomic_short_t,
-								     hb_atomic_int_t>::type,
+								     hb_atomic_t<unsigned short>,
+								     hb_atomic_t<unsigned int>>::type,
 					   typename std::conditional<key_bits + value_bits - cache_bits <= 16,
-								     short,
-								     int>::type
+								     unsigned short,
+								     unsigned int>::type
 					  >::type;
 
   static_assert ((key_bits >= cache_bits), "");
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-cairo-utils.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-cairo-utils.cc
index ec1499e861e2bd0f9a85f8e360ab0cc60b9e5373..85c62d39a9598f91543a7493389ab81dcbc0f9a3 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-cairo-utils.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-cairo-utils.cc
@@ -726,6 +726,9 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
     float span;
 
     span = angles[n_stops - 1] - angles[0];
+    if (!span)
+      goto done;
+
     k = 0;
     if (angles[0] >= 0)
     {
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-cff2-interp-cs.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-cff2-interp-cs.hh
index 06fbb72c61e16f7aa0bb65f50557eb1cd2525b8b..790aae345abd562f2eb49579ded7273e405f7c5b 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-cff2-interp-cs.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-cff2-interp-cs.hh
@@ -71,7 +71,8 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
   template <typename ACC>
   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)
+    : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs),
+      cached_scalars_vector (&acc.cached_scalars_vector)
   {
     coords = coords_;
     num_coords = num_coords_;
@@ -80,9 +81,39 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
     set_ivs (acc.privateDicts[fd].ivs);
   }
 
-  void fini ()
+  ~cff2_cs_interp_env_t ()
   {
-    SUPER::fini ();
+    release_scalars_vector (scalars);
+  }
+
+  hb_vector_t<float> *acquire_scalars_vector () const
+  {
+    hb_vector_t<float> *scalars = cached_scalars_vector->get_acquire ();
+
+    if (!scalars || !cached_scalars_vector->cmpexch (scalars, nullptr))
+    {
+      scalars = (hb_vector_t<float> *) hb_calloc (1, sizeof (hb_vector_t<float>));
+      if (unlikely (!scalars))
+	return nullptr;
+      scalars->init ();
+    }
+
+    return scalars;
+  }
+
+  void release_scalars_vector (hb_vector_t<float> *scalars) const
+  {
+    if (!scalars)
+      return;
+
+    scalars->clear ();
+
+    if (!cached_scalars_vector->cmpexch (nullptr, scalars))
+    {
+      scalars->fini ();
+      hb_free (scalars);
+    }
+    scalars = nullptr;
   }
 
   op_code_t fetch_op ()
@@ -111,14 +142,20 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
   {
     if (!seen_blend)
     {
-      region_count = varStore->varStore.get_region_index_count (get_ivs ());
-      if (do_blend)
+      scalars = acquire_scalars_vector ();
+      if (unlikely (!scalars))
+	SUPER::set_error ();
+      else
       {
-	if (unlikely (!scalars.resize_exact (region_count)))
-	  SUPER::set_error ();
-	else
-	  varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
-						 &scalars[0], region_count);
+	region_count = varStore->varStore.get_region_index_count (get_ivs ());
+	if (do_blend)
+	{
+	  if (unlikely (!scalars->resize_exact (region_count)))
+	    SUPER::set_error ();
+	  else
+	    varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
+						   &(*scalars)[0], region_count);
+	}
       }
       seen_blend = true;
     }
@@ -149,11 +186,11 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
     double v = 0;
     if (do_blend)
     {
-      if (likely (scalars.length == deltas.length))
+      if (likely (scalars && scalars->length == deltas.length))
       {
-        unsigned count = scalars.length;
+        unsigned count = scalars->length;
 	for (unsigned i = 0; i < count; i++)
-	  v += (double) scalars.arrayZ[i] * deltas.arrayZ[i].to_real ();
+	  v += (double) scalars->arrayZ[i] * deltas.arrayZ[i].to_real ();
       }
     }
     return v;
@@ -167,7 +204,8 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
   const	 CFF2ItemVariationStore *varStore;
   unsigned int  region_count;
   unsigned int  ivs;
-  hb_vector_t<float>  scalars;
+  hb_vector_t<float>  *scalars = nullptr;
+  hb_atomic_t<hb_vector_t<float> *> *cached_scalars_vector = nullptr;
   bool	  do_blend;
   bool	  seen_vsindex_ = false;
   bool	  seen_blend = false;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-common.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-common.cc
index 5d77433b3fec63675c5570059a64e888cbdbc9e0..16fd883d2099ac43613e00b7d814a78c11381fc1 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-common.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-common.cc
@@ -42,7 +42,7 @@
 
 /* hb_options_t */
 
-hb_atomic_int_t _hb_options;
+hb_atomic_t<unsigned> _hb_options;
 
 void
 _hb_options_init ()
@@ -273,7 +273,7 @@ struct hb_language_item_t {
 
 /* Thread-safe lockfree language list */
 
-static hb_atomic_ptr_t <hb_language_item_t> langs;
+static hb_atomic_t<hb_language_item_t *> langs;
 
 static inline void
 free_langs ()
@@ -403,7 +403,7 @@ hb_language_to_string (hb_language_t language)
 hb_language_t
 hb_language_get_default ()
 {
-  static hb_atomic_ptr_t <hb_language_t> default_language;
+  static hb_atomic_t<hb_language_t> default_language;
 
   hb_language_t language = default_language;
   if (unlikely (language == HB_LANGUAGE_INVALID))
@@ -968,6 +968,9 @@ hb_feature_from_string (const char *str, int len,
  * understood by hb_feature_from_string(). The client in responsible for
  * allocating big enough size for @buf, 128 bytes is more than enough.
  *
+ * Note that the feature value will be omitted if it is '1', but the
+ * string won't include any whitespace.
+ *
  * Since: 0.9.5
  **/
 void
@@ -1121,6 +1124,8 @@ get_C_locale ()
  * understood by hb_variation_from_string(). The client in responsible for
  * allocating big enough size for @buf, 128 bytes is more than enough.
  *
+ * Note that the string won't include any whitespace.
+ *
  * Since: 1.4.2
  */
 void
@@ -1212,6 +1217,58 @@ uint8_t
   return hb_color_get_blue (color);
 }
 
+/**
+ * hb_malloc:
+ * @size: The size of the memory to allocate.
+ *
+ * Allocates @size bytes of memory, using the allocator set at
+ * compile-time. Typically just malloc().
+ *
+ * Return value: A pointer to the allocated memory.
+ *
+ * Since: 11.0.0
+ **/
+void* hb_malloc(size_t size) { return hb_malloc_impl (size); }
+
+/**
+ * hb_calloc:
+ * @nmemb: The number of elements to allocate.
+ * @size: The size of each element.
+ *
+ * Allocates @nmemb elements of @size bytes each, initialized to zero,
+ * using the allocator set at compile-time. Typically just calloc().
+ *
+ * Return value: A pointer to the allocated memory.
+ *
+ * Since: 11.0.0
+ **/
+void* hb_calloc(size_t nmemb, size_t size) { return hb_calloc_impl (nmemb, size); }
+
+/**
+ * hb_realloc:
+ * @ptr: The pointer to the memory to reallocate.
+ * @size: The new size of the memory.
+ *
+ * Reallocates the memory pointed to by @ptr to @size bytes, using the
+ * allocator set at compile-time. Typically just realloc().
+ *
+ * Return value: A pointer to the reallocated memory.
+ *
+ * Since: 11.0.0
+ **/
+void* hb_realloc(void *ptr, size_t size) { return hb_realloc_impl (ptr, size); }
+
+/**
+ * hb_free:
+ * @ptr: The pointer to the memory to free.
+ *
+ * Frees the memory pointed to by @ptr, using the allocator set at
+ * compile-time. Typically just free().
+ *
+ * Since: 11.0.0
+ **/
+void  hb_free(void *ptr) { hb_free_impl (ptr); }
+
 
 /* If there is no visibility control, then hb-static.cc will NOT
  * define anything.  Instead, we get it to define one set in here
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-common.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-common.h
index 1108545481652cc5876cbf740cbb870dd8e7e619..1d7b824b6103c6a202e36d84da7733c497f99a59 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-common.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-common.h
@@ -65,6 +65,7 @@ typedef unsigned __int64 uint64_t;
 #else
 #  include <inttypes.h>
 #endif
+#include <stddef.h>
 
 #if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
 #define HB_DEPRECATED __attribute__((__deprecated__))
@@ -948,6 +949,16 @@ typedef struct hb_glyph_extents_t {
  */
 typedef struct hb_font_t hb_font_t;
 
+/* Not of much use to clients. */
+HB_EXTERN void*
+hb_malloc (size_t size);
+HB_EXTERN void*
+hb_calloc (size_t nmemb, size_t size);
+HB_EXTERN void*
+hb_realloc (void *ptr, size_t size);
+HB_EXTERN void
+hb_free (void *ptr);
+
 HB_END_DECLS
 
 #endif /* HB_COMMON_H */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext-font.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext-font.cc
index b9726373d5037fd732964eebe0fd18a100b225cb..76c1fa02d3c1a2ac21147c085f128e2440734c8a 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext-font.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext-font.cc
@@ -28,7 +28,7 @@
 
 #ifdef HAVE_CORETEXT
 
-#include "hb-coretext.h"
+#include "hb-coretext.hh"
 
 #include "hb-draw.hh"
 #include "hb-font.hh"
@@ -42,24 +42,17 @@
 #  define kCTFontOrientationVertical kCTFontVerticalOrientation
 #endif
 
-#define MAX_GLYPHS 64u
-
-static void
-_hb_coretext_font_destroy (void *font_data)
-{
-  CTFontRef ct_font = (CTFontRef) font_data;
-
-  CFRelease (ct_font);
-}
+#define MAX_GLYPHS 256u
 
 static hb_bool_t
-hb_coretext_get_nominal_glyph (hb_font_t *font HB_UNUSED,
-			       void *font_data,
+hb_coretext_get_nominal_glyph (hb_font_t *font,
+			       void *font_data HB_UNUSED,
 			       hb_codepoint_t unicode,
 			       hb_codepoint_t *glyph,
 			       void *user_data HB_UNUSED)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
+
   UniChar ch[2];
   CGGlyph cg_glyph[2];
   unsigned count = 0;
@@ -85,7 +78,7 @@ hb_coretext_get_nominal_glyph (hb_font_t *font HB_UNUSED,
 }
 
 static unsigned int
-hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
+hb_coretext_get_nominal_glyphs (hb_font_t *font,
 				void *font_data,
 				unsigned int count,
 				const hb_codepoint_t *first_unicode,
@@ -94,6 +87,8 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
 				unsigned int glyph_stride,
 				void *user_data HB_UNUSED)
 {
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
+
   // If any non-BMP codepoint is requested, use the slow path.
   bool slow_path = false;
   auto *unicode = first_unicode;
@@ -119,8 +114,6 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
     return count;
   }
 
-  CTFontRef ct_font = (CTFontRef) font_data;
-
   UniChar ch[MAX_GLYPHS];
   CGGlyph cg_glyph[MAX_GLYPHS];
   for (unsigned i = 0; i < count; i += MAX_GLYPHS)
@@ -152,14 +145,14 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
 }
 
 static hb_bool_t
-hb_coretext_get_variation_glyph (hb_font_t *font HB_UNUSED,
-				 void *font_data,
+hb_coretext_get_variation_glyph (hb_font_t *font,
+				 void *font_data HB_UNUSED,
 				 hb_codepoint_t unicode,
 				 hb_codepoint_t variation_selector,
 				 hb_codepoint_t *glyph,
 				 void *user_data HB_UNUSED)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
 
   UniChar ch[4];
   CGGlyph cg_glyph[4];
@@ -194,12 +187,17 @@ hb_coretext_get_variation_glyph (hb_font_t *font HB_UNUSED,
     if (cg_glyph[i])
       return false;
 
+  // Humm. CoreText falls back to the default glyph if the variation selector
+  // is not supported.  We cannot truly detect that case. So, in essence,
+  // we are always returning true here...
+
   *glyph = cg_glyph[0];
   return true;
 }
 
 static void
-hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
+hb_coretext_get_glyph_h_advances (hb_font_t* font,
+				  void* font_data HB_UNUSED,
 				  unsigned count,
 				  const hb_codepoint_t *first_glyph,
 				  unsigned glyph_stride,
@@ -207,7 +205,7 @@ hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
 				  unsigned advance_stride,
 				  void *user_data HB_UNUSED)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
 
   CGFloat ct_font_size = CTFontGetSize (ct_font);
   CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
@@ -233,7 +231,8 @@ hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
 
 #ifndef HB_NO_VERTICAL
 static void
-hb_coretext_get_glyph_v_advances (hb_font_t* font, void* font_data,
+hb_coretext_get_glyph_v_advances (hb_font_t* font,
+				  void* font_data HB_UNUSED,
 				  unsigned count,
 				  const hb_codepoint_t *first_glyph,
 				  unsigned glyph_stride,
@@ -241,7 +240,7 @@ hb_coretext_get_glyph_v_advances (hb_font_t* font, void* font_data,
 				  unsigned advance_stride,
 				  void *user_data HB_UNUSED)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
 
   CGFloat ct_font_size = CTFontGetSize (ct_font);
   CGFloat y_mult = (CGFloat) -font->y_scale / ct_font_size;
@@ -264,18 +263,16 @@ hb_coretext_get_glyph_v_advances (hb_font_t* font, void* font_data,
     }
   }
 }
-#endif
 
-#ifndef HB_NO_VERTICAL
 static hb_bool_t
 hb_coretext_get_glyph_v_origin (hb_font_t *font,
-				void *font_data,
+				void *font_data HB_UNUSED,
 				hb_codepoint_t glyph,
 				hb_position_t *x,
 				hb_position_t *y,
 				void *user_data HB_UNUSED)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
 
   CGFloat ct_font_size = CTFontGetSize (ct_font);
   CGFloat x_mult = (CGFloat) -font->x_scale / ct_font_size;
@@ -294,12 +291,12 @@ hb_coretext_get_glyph_v_origin (hb_font_t *font,
 
 static hb_bool_t
 hb_coretext_get_glyph_extents (hb_font_t *font,
-			       void *font_data,
+			       void *font_data HB_UNUSED,
 			       hb_codepoint_t glyph,
 			       hb_glyph_extents_t *extents,
 			       void *user_data HB_UNUSED)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
 
   CGFloat ct_font_size = CTFontGetSize (ct_font);
   CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
@@ -310,20 +307,21 @@ hb_coretext_get_glyph_extents (hb_font_t *font,
 						    kCTFontOrientationDefault, glyphs, NULL, 1);
 
   extents->x_bearing = round (bounds.origin.x * x_mult);
-  extents->y_bearing = round (bounds.origin.y * y_mult);
+  extents->y_bearing = round ((bounds.origin.y + bounds.size.height) * y_mult);
   extents->width = round (bounds.size.width * x_mult);
-  extents->height = round (bounds.size.height * y_mult);
+  extents->height = round (bounds.origin.y * y_mult) - extents->y_bearing;
 
   return true;
 }
 
 static hb_bool_t
 hb_coretext_get_font_h_extents (hb_font_t *font,
-				void *font_data,
+				void *font_data HB_UNUSED,
 				hb_font_extents_t *metrics,
 				void *user_data HB_UNUSED)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
+
   CGFloat ct_font_size = CTFontGetSize (ct_font);
   CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
 
@@ -371,7 +369,7 @@ hb_coretext_draw_glyph (hb_font_t *font,
 			hb_draw_funcs_t *draw_funcs, void *draw_data,
 			void *user_data)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
 
   CGFloat ct_font_size = CTFontGetSize (ct_font);
   CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
@@ -415,17 +413,20 @@ hb_coretext_get_glyph_name (hb_font_t *font,
 		    (UInt8 *) name, size, &len);
 
   name[len] = '\0';
+
+  CFRelease (cf_name);
+
   return true;
 }
 
 static hb_bool_t
-hb_coretext_get_glyph_from_name (hb_font_t *font HB_UNUSED,
-				 void *font_data,
+hb_coretext_get_glyph_from_name (hb_font_t *font,
+				 void *font_data HB_UNUSED,
 				 const char *name, int len,
 				 hb_codepoint_t *glyph,
 				 void *user_data HB_UNUSED)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
 
   if (len == -1)
     len = strlen (name);
@@ -458,10 +459,8 @@ static struct hb_coretext_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t
 
     hb_font_funcs_set_font_h_extents_func (funcs, hb_coretext_get_font_h_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_h_advances_func (funcs, hb_coretext_get_glyph_h_advances, nullptr, nullptr);
-    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_coretext_get_glyph_h_origin, nullptr, nullptr);
 
 #ifndef HB_NO_VERTICAL
-    //hb_font_funcs_set_font_v_extents_func (funcs, hb_coretext_get_font_v_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_advances_func (funcs, hb_coretext_get_glyph_v_advances, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_coretext_get_glyph_v_origin, nullptr, nullptr);
 #endif
@@ -530,8 +529,7 @@ hb_coretext_font_set_funcs (hb_font_t *font)
 
   hb_font_set_funcs (font,
 		     _hb_coretext_get_font_funcs (),
-		     (void *) CFRetain (ct_font),
-		     _hb_coretext_font_destroy);
+		     nullptr, nullptr);
 }
 
 #undef MAX_GLYPHS
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext-shape.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext-shape.cc
index 0bb235f6d0a16d7b1ff569319ab6a1957ff6a688..c874d49565cc23e7be9aed8395a0d53308b0ce04 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext-shape.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext-shape.cc
@@ -32,279 +32,9 @@
 
 #include "hb-shaper-impl.hh"
 
-#include "hb-coretext.h"
+#include "hb-coretext.hh"
 #include "hb-aat-layout.hh"
 
-
-/**
- * SECTION:hb-coretext
- * @title: hb-coretext
- * @short_description: CoreText integration
- * @include: hb-coretext.h
- *
- * Functions for using HarfBuzz with the CoreText fonts.
- **/
-
-static CTFontRef create_ct_font (CGFontRef cg_font, CGFloat font_size);
-
-static void
-release_table_data (void *user_data)
-{
-  CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
-  CFRelease(cf_data);
-}
-
-static hb_blob_t *
-_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
-{
-  CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
-  CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
-  if (unlikely (!cf_data))
-    return nullptr;
-
-  const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
-  const size_t length = CFDataGetLength (cf_data);
-  if (!data || !length)
-  {
-    CFRelease (cf_data);
-    return nullptr;
-  }
-
-  return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
-			 reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
-			 release_table_data);
-}
-
-static unsigned
-_hb_cg_get_table_tags (const hb_face_t *face HB_UNUSED,
-		       unsigned int start_offset,
-		       unsigned int *table_count,
-		       hb_tag_t *table_tags,
-		       void *user_data)
-{
-  CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
-
-  CTFontRef ct_font = create_ct_font (cg_font, (CGFloat) HB_CORETEXT_DEFAULT_FONT_SIZE);
-
-  auto arr = CTFontCopyAvailableTables (ct_font, kCTFontTableOptionNoOptions);
-
-  unsigned population = (unsigned) CFArrayGetCount (arr);
-  unsigned end_offset;
-
-  if (!table_count)
-    goto done;
-
-  if (unlikely (start_offset >= population))
-  {
-    *table_count = 0;
-    goto done;
-  }
-
-  end_offset = start_offset + *table_count;
-  if (unlikely (end_offset < start_offset))
-  {
-    *table_count = 0;
-    goto done;
-  }
-  end_offset= hb_min (end_offset, (unsigned) population);
-
-  *table_count = end_offset - start_offset;
-  for (unsigned i = start_offset; i < end_offset; i++)
-  {
-    CTFontTableTag tag = (CTFontTableTag)(uintptr_t) CFArrayGetValueAtIndex (arr, i);
-    table_tags[i - start_offset] = tag;
-  }
-
-done:
-  CFRelease (arr);
-  CFRelease (ct_font);
-  return population;
-}
-
-static void
-_hb_cg_font_release (void *data)
-{
-  CGFontRelease ((CGFontRef) data);
-}
-
-
-static CTFontDescriptorRef
-get_last_resort_font_desc ()
-{
-  // TODO Handle allocation failures?
-  CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
-  CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
-					   (const void **) &last_resort,
-					   1,
-					   &kCFTypeArrayCallBacks);
-  CFRelease (last_resort);
-  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
-						   (const void **) &kCTFontCascadeListAttribute,
-						   (const void **) &cascade_list,
-						   1,
-						   &kCFTypeDictionaryKeyCallBacks,
-						   &kCFTypeDictionaryValueCallBacks);
-  CFRelease (cascade_list);
-
-  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
-  CFRelease (attributes);
-  return font_desc;
-}
-
-static void
-release_data (void *info, const void *data, size_t size)
-{
-  assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
-	  hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
-
-  hb_blob_destroy ((hb_blob_t *) info);
-}
-
-static CGFontRef
-create_cg_font (hb_face_t *face)
-{
-  CGFontRef cg_font = nullptr;
-  if (face->destroy == _hb_cg_font_release)
-  {
-    cg_font = CGFontRetain ((CGFontRef) face->user_data);
-  }
-  else
-  {
-    hb_blob_t *blob = hb_face_reference_blob (face);
-    unsigned int blob_length;
-    const char *blob_data = hb_blob_get_data (blob, &blob_length);
-    if (unlikely (!blob_length))
-      DEBUG_MSG (CORETEXT, face, "Face has empty blob");
-
-    CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
-    if (likely (provider))
-    {
-      cg_font = CGFontCreateWithDataProvider (provider);
-      if (unlikely (!cg_font))
-	DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
-      CGDataProviderRelease (provider);
-    }
-  }
-  return cg_font;
-}
-
-static CTFontRef
-create_ct_font (CGFontRef cg_font, CGFloat font_size)
-{
-  CTFontRef ct_font = nullptr;
-
-  /* CoreText does not enable trak table usage / tracking when creating a CTFont
-   * using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
-   * to be through the CTFontCreateUIFontForLanguage call. */
-  CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
-  if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
-      CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
-  {
-#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
-# define kCTFontUIFontSystem kCTFontSystemFontType
-# define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
-#endif
-    CTFontUIFontType font_type = kCTFontUIFontSystem;
-    if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
-      font_type = kCTFontUIFontEmphasizedSystem;
-
-    ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
-    CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
-    if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
-    {
-      CFRelease(ct_font);
-      ct_font = nullptr;
-    }
-    CFRelease (ct_result_name);
-  }
-  CFRelease (cg_postscript_name);
-
-  if (!ct_font)
-    ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
-
-  if (unlikely (!ct_font)) {
-    DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
-    return nullptr;
-  }
-
-  /* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
-   * bug indicate that the cascade list reconfiguration occasionally causes
-   * crashes in CoreText on OS X 10.9, thus let's skip this step on older
-   * operating system versions. Except for the emoji font, where _not_
-   * reconfiguring the cascade list causes CoreText crashes. For details, see
-   * crbug.com/549610 */
-  // 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-  if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
-#pragma GCC diagnostic pop
-    CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
-    bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
-    CFRelease (fontName);
-    if (!isEmojiFont)
-      return ct_font;
-  }
-
-  CFURLRef original_url = nullptr;
-#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
-  ATSFontRef atsFont;
-  FSRef fsref;
-  OSStatus status;
-  atsFont = CTFontGetPlatformFont (ct_font, NULL);
-  status = ATSFontGetFileReference (atsFont, &fsref);
-  if (status == noErr)
-    original_url = CFURLCreateFromFSRef (NULL, &fsref);
-#else
-  original_url = (CFURLRef) CTFontCopyAttribute (ct_font, kCTFontURLAttribute);
-#endif
-
-  /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
-   * font fallback which we don't need anyway. */
-  {
-    CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
-    CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
-    CFRelease (last_resort_font_desc);
-    if (new_ct_font)
-    {
-      /* The CTFontCreateCopyWithAttributes call fails to stay on the same font
-       * when reconfiguring the cascade list and may switch to a different font
-       * when there are fonts that go by the same name, since the descriptor is
-       * just name and size.
-       *
-       * Avoid reconfiguring the cascade lists if the new font is outside the
-       * system locations that we cannot access from the sandboxed renderer
-       * process in Blink. This can be detected by the new file URL location
-       * that the newly found font points to. */
-      CFURLRef new_url = nullptr;
-#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
-      atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
-      status = ATSFontGetFileReference (atsFont, &fsref);
-      if (status == noErr)
-	new_url = CFURLCreateFromFSRef (NULL, &fsref);
-#else
-      new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
-#endif
-      // Keep reconfigured font if URL cannot be retrieved (seems to be the case
-      // on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
-      if (!original_url || !new_url || CFEqual (original_url, new_url)) {
-	CFRelease (ct_font);
-	ct_font = new_ct_font;
-      } else {
-	CFRelease (new_ct_font);
-	DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
-      }
-      if (new_url)
-	CFRelease (new_url);
-    }
-    else
-      DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
-  }
-
-  if (original_url)
-    CFRelease (original_url);
-  return ct_font;
-}
-
 hb_coretext_face_data_t *
 _hb_coretext_shaper_face_data_create (hb_face_t *face)
 {
@@ -325,102 +55,6 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data)
   CFRelease ((CGFontRef) data);
 }
 
-/**
- * hb_coretext_face_create:
- * @cg_font: The CGFontRef to work upon
- *
- * Creates an #hb_face_t face object from the specified
- * CGFontRef.
- *
- * Return value: (transfer full): The new face object
- *
- * Since: 0.9.10
- */
-hb_face_t *
-hb_coretext_face_create (CGFontRef cg_font)
-{
-  hb_face_t *face = hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
-  hb_face_set_get_table_tags_func (face, _hb_cg_get_table_tags, cg_font, nullptr);
-  return face;
-}
-
-/**
- * hb_coretext_face_create_from_file_or_fail:
- * @file_name: A font filename
- * @index: The index of the face within the file
- *
- * Creates an #hb_face_t face object from the specified
- * font file and face index.
- *
- * This is similar in functionality to hb_face_create_from_file_or_fail(),
- * but uses the CoreText library for loading the font file.
- *
- * Return value: (transfer full): The new face object, or `NULL` if
- * no face is found at the specified index or the file cannot be read.
- *
- * Since: 10.1.0
- */
-hb_face_t *
-hb_coretext_face_create_from_file_or_fail (const char   *file_name,
-					   unsigned int  index)
-{
-  auto url = CFURLCreateFromFileSystemRepresentation (nullptr,
-						      (const UInt8 *) file_name,
-						      strlen (file_name),
-						      false);
-  if (unlikely (!url))
-    return nullptr;
-
-  auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromURL (url);
-  if (unlikely (!ct_font_desc_array))
-  {
-    CFRelease (url);
-    return nullptr;
-  }
-  auto ct_font_desc = (CFArrayGetCount (ct_font_desc_array) > index) ?
-		      (CTFontDescriptorRef) CFArrayGetValueAtIndex (ct_font_desc_array, index) : nullptr;
-  if (unlikely (!ct_font_desc))
-  {
-    CFRelease (ct_font_desc_array);
-    CFRelease (url);
-    return nullptr;
-  }
-  CFRelease (url);
-  auto ct_font = ct_font_desc ? CTFontCreateWithFontDescriptor (ct_font_desc, 0, nullptr) : nullptr;
-  CFRelease (ct_font_desc_array);
-  if (unlikely (!ct_font))
-    return nullptr;
-
-  auto cg_font = ct_font ? CTFontCopyGraphicsFont (ct_font, nullptr) : nullptr;
-  CFRelease (ct_font);
-  if (unlikely (!cg_font))
-    return nullptr;
-
-  hb_face_t *face = hb_coretext_face_create (cg_font);
-  CFRelease (cg_font);
-  if (unlikely (hb_face_is_immutable (face)))
-    return nullptr;
-
-  return face;
-}
-
-/**
- * hb_coretext_face_get_cg_font:
- * @face: The #hb_face_t to work upon
- *
- * Fetches the CGFontRef associated with an #hb_face_t
- * face object
- *
- * Return value: the CGFontRef found
- *
- * Since: 0.9.10
- */
-CGFontRef
-hb_coretext_face_get_cg_font (hb_face_t *face)
-{
-  return (CGFontRef) (const void *) face->data.coretext;
-}
-
 
 hb_coretext_font_data_t *
 _hb_coretext_shaper_font_data_create (hb_font_t *font)
@@ -439,7 +73,9 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
     return nullptr;
   }
 
-  if (font->num_coords)
+  unsigned num_axes = hb_ot_var_get_axis_count (face);
+  // https://github.com/harfbuzz/harfbuzz/issues/5163
+  if (num_axes)
   {
     CFMutableDictionaryRef variations =
       CFDictionaryCreateMutable (kCFAllocatorDefault,
@@ -447,14 +83,15 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
 				 &kCFTypeDictionaryKeyCallBacks,
 				 &kCFTypeDictionaryValueCallBacks);
 
-    for (unsigned i = 0; i < font->num_coords; i++)
+    unsigned count = hb_max (num_axes, font->num_coords);
+    for (unsigned i = 0; i < count; i++)
     {
       hb_ot_var_axis_info_t info;
       unsigned int c = 1;
       hb_ot_var_get_axis_infos (font->face, i, &c, &info);
-      if (font->design_coords[i] == info.default_value)
-	continue;
-      float v = hb_clamp (font->design_coords[i], info.min_value, info.max_value);
+      float v = i < font->num_coords ?
+		hb_clamp (font->design_coords[i], info.min_value, info.max_value) :
+		info.default_value;
 
       CFNumberRef tag_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag);
       CFNumberRef value_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &v);
@@ -489,94 +126,6 @@ _hb_coretext_shaper_font_data_destroy (hb_coretext_font_data_t *data)
   CFRelease ((CTFontRef) data);
 }
 
-/**
- * hb_coretext_font_create:
- * @ct_font: The CTFontRef to work upon
- *
- * Creates an #hb_font_t font object from the specified
- * CTFontRef.
- *
- * The created font uses the default font functions implemented
- * natively by HarfBuzz. If you want to use the CoreText font functions
- * instead (rarely needed), you can do so by calling
- * by hb_coretext_font_set_funcs().
- *
- * Return value: (transfer full): The new font object
- *
- * Since: 1.7.2
- **/
-hb_font_t *
-hb_coretext_font_create (CTFontRef ct_font)
-{
-  CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, nullptr);
-  hb_face_t *face = hb_coretext_face_create (cg_font);
-  CFRelease (cg_font);
-  hb_font_t *font = hb_font_create (face);
-  hb_face_destroy (face);
-
-  if (unlikely (hb_object_is_immutable (font)))
-    return font;
-
-  hb_font_set_ptem (font, CTFontGetSize (ct_font));
-
-  /* Copy font variations */
-  CFDictionaryRef variations = CTFontCopyVariation (ct_font);
-  if (variations)
-  {
-    hb_vector_t<hb_variation_t> vars;
-    hb_vector_t<CFTypeRef> keys;
-    hb_vector_t<CFTypeRef> values;
-
-    CFIndex count = CFDictionaryGetCount (variations);
-    if (unlikely (!vars.alloc_exact (count) || !keys.resize_exact (count) || !values.resize_exact (count)))
-      goto done;
-
-    // Fetch them one by one and collect in a vector of our own.
-    CFDictionaryGetKeysAndValues (variations, keys.arrayZ, values.arrayZ);
-    for (CFIndex i = 0; i < count; i++)
-    {
-      int tag;
-      float value;
-      CFNumberGetValue ((CFNumberRef) keys.arrayZ[i], kCFNumberIntType, &tag);
-      CFNumberGetValue ((CFNumberRef) values.arrayZ[i], kCFNumberFloatType, &value);
-
-      hb_variation_t var = {tag, value};
-      vars.push (var);
-    }
-    hb_font_set_variations (font, vars.arrayZ, vars.length);
-
-done:
-    CFRelease (variations);
-  }
-
-  /* Let there be dragons here... */
-  font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
-
-  // https://github.com/harfbuzz/harfbuzz/pull/4895#issuecomment-2408471254
-  //hb_coretext_font_set_funcs (font);
-
-  return font;
-}
-
-/**
- * hb_coretext_font_get_ct_font:
- * @font: #hb_font_t to work upon
- *
- * Fetches the CTFontRef associated with the specified
- * #hb_font_t font object.
- *
- * Return value: the CTFontRef found
- *
- * Since: 0.9.10
- */
-CTFontRef
-hb_coretext_font_get_ct_font (hb_font_t *font)
-{
-  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
-  return ct_font ? (CTFontRef) ct_font : nullptr;
-}
-
-
 /*
  * shaper
  */
@@ -646,7 +195,7 @@ _hb_coretext_shape (hb_shape_plan_t    *shape_plan,
    * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
    * continue pointing to B2 even though B2 was merged into B1's
    * cluster... */
-  if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+  if (HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES (buffer->cluster_level))
   {
     hb_unicode_funcs_t *unicode = buffer->unicode;
     unsigned int count = buffer->len;
@@ -1010,7 +559,7 @@ resize_and_retry:
 
     CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
     unsigned int num_runs = CFArrayGetCount (glyph_runs);
-    DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs);
+    DEBUG_MSG (CORETEXT, nullptr, "Num runs: %u", num_runs);
 
     buffer->len = 0;
     uint32_t status_or = 0;
@@ -1292,7 +841,7 @@ resize_and_retry:
      * or the native OT backend, only that the cluster indices will be
      * monotonic in the output buffer. */
     if (count > 1 && (status_or & kCTRunStatusNonMonotonic) &&
-	buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
+	HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
     {
       hb_glyph_info_t *info = buffer->info;
       if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6c0525b3a07dd951b707c034ef587797b2107f24
--- /dev/null
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.cc
@@ -0,0 +1,572 @@
+/*
+ * Copyright © 2012,2013  Mozilla Foundation.
+ * Copyright © 2012,2013  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Mozilla Author(s): Jonathan Kew
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb.hh"
+
+#ifdef HAVE_CORETEXT
+
+#include "hb-shaper-impl.hh"
+
+#include "hb-coretext.hh"
+
+
+/**
+ * SECTION:hb-coretext
+ * @title: hb-coretext
+ * @short_description: CoreText integration
+ * @include: hb-coretext.h
+ *
+ * Functions for using HarfBuzz with the CoreText fonts.
+ **/
+
+static void
+release_table_data (void *user_data)
+{
+  CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
+  CFRelease(cf_data);
+}
+
+static hb_blob_t *
+_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+{
+  CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
+  CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
+  if (unlikely (!cf_data))
+    return nullptr;
+
+  const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
+  const size_t length = CFDataGetLength (cf_data);
+  if (!data || !length)
+  {
+    CFRelease (cf_data);
+    return nullptr;
+  }
+
+  return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
+			 reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
+			 release_table_data);
+}
+
+static unsigned
+_hb_cg_get_table_tags (const hb_face_t *face HB_UNUSED,
+		       unsigned int start_offset,
+		       unsigned int *table_count,
+		       hb_tag_t *table_tags,
+		       void *user_data)
+{
+  CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
+
+  CTFontRef ct_font = create_ct_font (cg_font, (CGFloat) HB_CORETEXT_DEFAULT_FONT_SIZE);
+
+  auto arr = CTFontCopyAvailableTables (ct_font, kCTFontTableOptionNoOptions);
+
+  unsigned population = (unsigned) CFArrayGetCount (arr);
+  unsigned end_offset;
+
+  if (!table_count)
+    goto done;
+
+  if (unlikely (start_offset >= population))
+  {
+    *table_count = 0;
+    goto done;
+  }
+
+  end_offset = start_offset + *table_count;
+  if (unlikely (end_offset < start_offset))
+  {
+    *table_count = 0;
+    goto done;
+  }
+  end_offset= hb_min (end_offset, (unsigned) population);
+
+  *table_count = end_offset - start_offset;
+  for (unsigned i = start_offset; i < end_offset; i++)
+  {
+    CTFontTableTag tag = (CTFontTableTag)(uintptr_t) CFArrayGetValueAtIndex (arr, i);
+    table_tags[i - start_offset] = tag;
+  }
+
+done:
+  CFRelease (arr);
+  CFRelease (ct_font);
+  return population;
+}
+
+static void
+_hb_cg_font_release (void *data)
+{
+  CGFontRelease ((CGFontRef) data);
+}
+
+
+static CTFontDescriptorRef
+get_last_resort_font_desc ()
+{
+  // TODO Handle allocation failures?
+  CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
+  CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
+					   (const void **) &last_resort,
+					   1,
+					   &kCFTypeArrayCallBacks);
+  CFRelease (last_resort);
+  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
+						   (const void **) &kCTFontCascadeListAttribute,
+						   (const void **) &cascade_list,
+						   1,
+						   &kCFTypeDictionaryKeyCallBacks,
+						   &kCFTypeDictionaryValueCallBacks);
+  CFRelease (cascade_list);
+
+  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
+  CFRelease (attributes);
+  return font_desc;
+}
+
+static void
+release_data (void *info, const void *data, size_t size)
+{
+  assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
+	  hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
+
+  hb_blob_destroy ((hb_blob_t *) info);
+}
+
+CGFontRef
+create_cg_font (CFArrayRef ct_font_desc_array, unsigned int named_instance_index)
+{
+  if (named_instance_index == 0)
+  {
+    // Default instance. We don't know which one is it. Return the first one.
+    // We will set the correct variations on it later.
+  }
+  else
+    named_instance_index--;
+  auto ct_font_desc = (CFArrayGetCount (ct_font_desc_array) > named_instance_index) ?
+		      (CTFontDescriptorRef) CFArrayGetValueAtIndex (ct_font_desc_array, named_instance_index) : nullptr;
+  if (unlikely (!ct_font_desc))
+  {
+    CFRelease (ct_font_desc_array);
+    return nullptr;
+  }
+  auto ct_font = ct_font_desc ? CTFontCreateWithFontDescriptor (ct_font_desc, 0, nullptr) : nullptr;
+  CFRelease (ct_font_desc_array);
+  if (unlikely (!ct_font))
+    return nullptr;
+
+  auto cg_font = ct_font ? CTFontCopyGraphicsFont (ct_font, nullptr) : nullptr;
+  CFRelease (ct_font);
+
+  return cg_font;
+}
+
+CGFontRef
+create_cg_font (hb_blob_t *blob, unsigned int index)
+{
+  hb_blob_make_immutable (blob);
+  unsigned int blob_length;
+  const char *blob_data = hb_blob_get_data (blob, &blob_length);
+  if (unlikely (!blob_length))
+    DEBUG_MSG (CORETEXT, blob, "Empty blob");
+
+  unsigned ttc_index = index & 0xFFFF;
+  unsigned named_instance_index = index >> 16;
+
+  if (ttc_index != 0)
+  {
+    DEBUG_MSG (CORETEXT, blob, "TTC index %d not supported", ttc_index);
+    return nullptr; // CoreText does not support TTCs
+  }
+
+  if (unlikely (named_instance_index != 0))
+  {
+    auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromData (CFDataCreate (kCFAllocatorDefault, (const UInt8 *) blob_data, blob_length));
+    if (unlikely (!ct_font_desc_array))
+      return nullptr;
+    return create_cg_font (ct_font_desc_array, named_instance_index);
+  }
+
+  hb_blob_reference (blob);
+  CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
+  CGFontRef cg_font = nullptr;
+  if (likely (provider))
+  {
+    cg_font = CGFontCreateWithDataProvider (provider);
+    if (unlikely (!cg_font))
+      DEBUG_MSG (CORETEXT, blob, "CGFontCreateWithDataProvider() failed");
+    CGDataProviderRelease (provider);
+  }
+  return cg_font;
+}
+
+CGFontRef
+create_cg_font (hb_face_t *face)
+{
+  CGFontRef cg_font = nullptr;
+  if (face->destroy == _hb_cg_font_release)
+    cg_font = CGFontRetain ((CGFontRef) face->user_data);
+  else
+  {
+    hb_blob_t *blob = hb_face_reference_blob (face);
+    cg_font = create_cg_font (blob, face->index);
+    hb_blob_destroy (blob);
+  }
+  return cg_font;
+}
+
+CTFontRef
+create_ct_font (CGFontRef cg_font, CGFloat font_size)
+{
+  CTFontRef ct_font = nullptr;
+
+  /* CoreText does not enable trak table usage / tracking when creating a CTFont
+   * using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
+   * to be through the CTFontCreateUIFontForLanguage call. */
+  CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
+  if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
+      CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
+  {
+#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
+# define kCTFontUIFontSystem kCTFontSystemFontType
+# define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
+#endif
+    CTFontUIFontType font_type = kCTFontUIFontSystem;
+    if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
+      font_type = kCTFontUIFontEmphasizedSystem;
+
+    ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
+    CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
+    if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
+    {
+      CFRelease(ct_font);
+      ct_font = nullptr;
+    }
+    CFRelease (ct_result_name);
+  }
+  CFRelease (cg_postscript_name);
+
+  if (!ct_font)
+    ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
+
+  if (unlikely (!ct_font)) {
+    DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
+    return nullptr;
+  }
+
+  /* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
+   * bug indicate that the cascade list reconfiguration occasionally causes
+   * crashes in CoreText on OS X 10.9, thus let's skip this step on older
+   * operating system versions. Except for the emoji font, where _not_
+   * reconfiguring the cascade list causes CoreText crashes. For details, see
+   * crbug.com/549610 */
+  // 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+  if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
+#pragma GCC diagnostic pop
+    CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
+    bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
+    CFRelease (fontName);
+    if (!isEmojiFont)
+      return ct_font;
+  }
+
+  CFURLRef original_url = nullptr;
+#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+  ATSFontRef atsFont;
+  FSRef fsref;
+  OSStatus status;
+  atsFont = CTFontGetPlatformFont (ct_font, NULL);
+  status = ATSFontGetFileReference (atsFont, &fsref);
+  if (status == noErr)
+    original_url = CFURLCreateFromFSRef (NULL, &fsref);
+#else
+  original_url = (CFURLRef) CTFontCopyAttribute (ct_font, kCTFontURLAttribute);
+#endif
+
+  /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
+   * font fallback which we don't need anyway. */
+  {
+    CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
+    CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
+    CFRelease (last_resort_font_desc);
+    if (new_ct_font)
+    {
+      /* The CTFontCreateCopyWithAttributes call fails to stay on the same font
+       * when reconfiguring the cascade list and may switch to a different font
+       * when there are fonts that go by the same name, since the descriptor is
+       * just name and size.
+       *
+       * Avoid reconfiguring the cascade lists if the new font is outside the
+       * system locations that we cannot access from the sandboxed renderer
+       * process in Blink. This can be detected by the new file URL location
+       * that the newly found font points to. */
+      CFURLRef new_url = nullptr;
+#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+      atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
+      status = ATSFontGetFileReference (atsFont, &fsref);
+      if (status == noErr)
+	new_url = CFURLCreateFromFSRef (NULL, &fsref);
+#else
+      new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
+#endif
+      // Keep reconfigured font if URL cannot be retrieved (seems to be the case
+      // on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
+      if (!original_url || !new_url || CFEqual (original_url, new_url)) {
+	CFRelease (ct_font);
+	ct_font = new_ct_font;
+      } else {
+	CFRelease (new_ct_font);
+	DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
+      }
+      if (new_url)
+	CFRelease (new_url);
+    }
+    else
+      DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
+  }
+
+  if (original_url)
+    CFRelease (original_url);
+  return ct_font;
+}
+
+/**
+ * hb_coretext_face_create:
+ * @cg_font: The CGFontRef to work upon
+ *
+ * Creates an #hb_face_t face object from the specified
+ * CGFontRef.
+ *
+ * Return value: (transfer full): The new face object
+ *
+ * Since: 0.9.10
+ */
+hb_face_t *
+hb_coretext_face_create (CGFontRef cg_font)
+{
+  hb_face_t *face = hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
+  hb_face_set_get_table_tags_func (face, _hb_cg_get_table_tags, cg_font, nullptr);
+  return face;
+}
+
+/**
+ * hb_coretext_face_create_from_file_or_fail:
+ * @file_name: A font filename
+ * @index: The index of the face within the file
+ *
+ * Creates an #hb_face_t face object from the specified
+ * font file and face index.
+ *
+ * This is similar in functionality to hb_face_create_from_file_or_fail(),
+ * but uses the CoreText library for loading the font file.
+ *
+ * Return value: (transfer full): The new face object, or `NULL` if
+ * no face is found at the specified index or the file cannot be read.
+ *
+ * Since: 10.1.0
+ */
+hb_face_t *
+hb_coretext_face_create_from_file_or_fail (const char   *file_name,
+					   unsigned int  index)
+{
+  auto url = CFURLCreateFromFileSystemRepresentation (nullptr,
+						      (const UInt8 *) file_name,
+						      strlen (file_name),
+						      false);
+  if (unlikely (!url))
+    return nullptr;
+
+  auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromURL (url);
+  if (unlikely (!ct_font_desc_array))
+  {
+    CFRelease (url);
+    return nullptr;
+  }
+
+  unsigned ttc_index = index & 0xFFFF;
+  unsigned named_instance_index = index >> 16;
+
+  if (ttc_index != 0)
+  {
+    DEBUG_MSG (CORETEXT, nullptr, "TTC index %d not supported", ttc_index);
+    return nullptr; // CoreText does not support TTCs
+  }
+
+  auto cg_font = create_cg_font (ct_font_desc_array, named_instance_index);
+  CFRelease (url);
+
+  hb_face_t *face = hb_coretext_face_create (cg_font);
+  CFRelease (cg_font);
+  if (unlikely (hb_face_is_immutable (face)))
+    return nullptr;
+
+  hb_face_set_index (face, index);
+
+  return face;
+}
+
+/**
+ * hb_coretext_face_create_from_blob_or_fail:
+ * @blob: A blob containing the font data
+ * @index: The index of the face within the blob
+ *
+ * Creates an #hb_face_t face object from the specified
+ * blob and face index.
+ *
+ * This is similar in functionality to hb_face_create_from_blob_or_fail(),
+ * but uses the CoreText library for loading the font data.
+ *
+ * Return value: (transfer full): The new face object, or `NULL` if
+ * no face is found at the specified index or the blob cannot be read.
+ *
+ * Since: 11.0.0
+ */
+hb_face_t *
+hb_coretext_face_create_from_blob_or_fail (hb_blob_t    *blob,
+					   unsigned int  index)
+{
+  auto cg_font = create_cg_font (blob, index);
+  if (unlikely (!cg_font))
+    return nullptr;
+
+  hb_face_t *face = hb_coretext_face_create (cg_font);
+  CFRelease (cg_font);
+  if (unlikely (hb_face_is_immutable (face)))
+    return nullptr;
+
+  hb_face_set_index (face, index);
+
+  return face;
+}
+
+/**
+ * hb_coretext_face_get_cg_font:
+ * @face: The #hb_face_t to work upon
+ *
+ * Fetches the CGFontRef associated with an #hb_face_t
+ * face object
+ *
+ * Return value: the CGFontRef found
+ *
+ * Since: 0.9.10
+ */
+CGFontRef
+hb_coretext_face_get_cg_font (hb_face_t *face)
+{
+  return (CGFontRef) (const void *) face->data.coretext;
+}
+
+/**
+ * hb_coretext_font_create:
+ * @ct_font: The CTFontRef to work upon
+ *
+ * Creates an #hb_font_t font object from the specified
+ * CTFontRef.
+ *
+ * The created font uses the default font functions implemented
+ * natively by HarfBuzz. If you want to use the CoreText font functions
+ * instead (rarely needed), you can do so by calling
+ * by hb_coretext_font_set_funcs().
+ *
+ * Return value: (transfer full): The new font object
+ *
+ * Since: 1.7.2
+ **/
+hb_font_t *
+hb_coretext_font_create (CTFontRef ct_font)
+{
+  CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, nullptr);
+  hb_face_t *face = hb_coretext_face_create (cg_font);
+  CFRelease (cg_font);
+  hb_font_t *font = hb_font_create (face);
+  hb_face_destroy (face);
+
+  if (unlikely (hb_object_is_immutable (font)))
+    return font;
+
+  hb_font_set_ptem (font, CTFontGetSize (ct_font));
+
+  /* Copy font variations */
+  CFDictionaryRef variations = CTFontCopyVariation (ct_font);
+  if (variations)
+  {
+    hb_vector_t<hb_variation_t> vars;
+    hb_vector_t<CFTypeRef> keys;
+    hb_vector_t<CFTypeRef> values;
+
+    CFIndex count = CFDictionaryGetCount (variations);
+    if (unlikely (!vars.alloc_exact (count) || !keys.resize_exact (count) || !values.resize_exact (count)))
+      goto done;
+
+    // Fetch them one by one and collect in a vector of our own.
+    CFDictionaryGetKeysAndValues (variations, keys.arrayZ, values.arrayZ);
+    for (CFIndex i = 0; i < count; i++)
+    {
+      int tag;
+      float value;
+      CFNumberGetValue ((CFNumberRef) keys.arrayZ[i], kCFNumberIntType, &tag);
+      CFNumberGetValue ((CFNumberRef) values.arrayZ[i], kCFNumberFloatType, &value);
+
+      hb_variation_t var = {tag, value};
+      vars.push (var);
+    }
+    hb_font_set_variations (font, vars.arrayZ, vars.length);
+
+done:
+    CFRelease (variations);
+  }
+
+  /* Let there be dragons here... */
+  font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
+
+  // https://github.com/harfbuzz/harfbuzz/pull/4895#issuecomment-2408471254
+  //hb_coretext_font_set_funcs (font);
+
+  return font;
+}
+
+/**
+ * hb_coretext_font_get_ct_font:
+ * @font: #hb_font_t to work upon
+ *
+ * Fetches the CTFontRef associated with the specified
+ * #hb_font_t font object.
+ *
+ * Return value: the CTFontRef found
+ *
+ * Since: 0.9.10
+ */
+CTFontRef
+hb_coretext_font_get_ct_font (hb_font_t *font)
+{
+  return (CTFontRef) (const void *) font->data.coretext;
+}
+
+
+#endif
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.h
index 3626f1c12f2499e137deec8eb7fe423ec3cd2241..a7c7fee76740ea6be8a54bc9cb117a4603d6afe7 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.h
@@ -84,6 +84,10 @@ HB_EXTERN hb_face_t *
 hb_coretext_face_create_from_file_or_fail (const char   *file_name,
 					   unsigned int  index);
 
+HB_EXTERN hb_face_t *
+hb_coretext_face_create_from_blob_or_fail (hb_blob_t    *blob,
+					   unsigned int  index);
+
 HB_EXTERN hb_font_t *
 hb_coretext_font_create (CTFontRef ct_font);
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.hh
new file mode 100644
index 0000000000000000000000000000000000000000..5f58d2abffd39a198efdcf6b716732c23c1c3328
--- /dev/null
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.hh
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2012,2013  Mozilla Foundation.
+ * Copyright © 2012,2013  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Mozilla Author(s): Jonathan Kew
+ * Google Author(s): Behdad Esfahbod
+ */
+
+
+#ifndef HB_CORETEXT_HH
+#define HB_CORETEXT_HH
+
+#include "hb.hh"
+
+#include "hb-coretext.h"
+
+#include "hb-aat-layout.hh"
+
+
+HB_INTERNAL CGFontRef
+create_cg_font (CFArrayRef ct_font_desc_array, unsigned int index);
+
+HB_INTERNAL CGFontRef
+create_cg_font (hb_blob_t *blob, unsigned int index);
+
+HB_INTERNAL CGFontRef
+create_cg_font (hb_face_t *face);
+
+HB_INTERNAL CTFontRef
+create_ct_font (CGFontRef cg_font, CGFloat font_size);
+
+
+#endif /* HB_CORETEXT_HH */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-debug.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-debug.hh
index 559db4067e240b4cfb9959d68e29d351994e886c..f79b42bc4b3282590a63053ed090fb368d233112 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-debug.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-debug.hh
@@ -49,15 +49,15 @@ struct hb_options_t
 };
 
 union hb_options_union_t {
-  int i;
+  unsigned i;
   hb_options_t opts;
 };
-static_assert ((sizeof (hb_atomic_int_t) >= sizeof (hb_options_union_t)), "");
+static_assert ((sizeof (hb_atomic_t<unsigned>) >= sizeof (hb_options_union_t)), "");
 
 HB_INTERNAL void
 _hb_options_init ();
 
-extern HB_INTERNAL hb_atomic_int_t _hb_options;
+extern HB_INTERNAL hb_atomic_t<unsigned> _hb_options;
 
 static inline hb_options_t
 hb_options ()
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite-font.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite-font.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9752110e474d98b1d3cdc887ecde449e7cea830a
--- /dev/null
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite-font.cc
@@ -0,0 +1,388 @@
+/*
+ * Copyright © 2025  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Author(s): Behdad Esfahbod
+ */
+
+#include "hb.hh"
+
+#ifdef HAVE_DIRECTWRITE
+
+#include "hb-directwrite.h"
+
+#include <d2d1.h>
+
+#include "hb-draw.hh"
+#include "hb-font.hh"
+#include "hb-machinery.hh"
+
+#define MAX_GLYPHS 256u
+
+static unsigned int
+hb_directwrite_get_nominal_glyphs (hb_font_t *font,
+				   void *font_data HB_UNUSED,
+				   unsigned int count,
+				   const hb_codepoint_t *first_unicode,
+				   unsigned int unicode_stride,
+				   hb_codepoint_t *first_glyph,
+				   unsigned int glyph_stride,
+				   void *user_data HB_UNUSED)
+{
+  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
+
+  for (unsigned i = 0; i < count;)
+  {
+    UINT32 unicodes[MAX_GLYPHS];
+    UINT16 gids[MAX_GLYPHS];
+
+    unsigned n = hb_min (MAX_GLYPHS, count - i);
+
+    for (unsigned j = 0; j < n; j++)
+    {
+      unicodes[j] = *first_unicode;
+      first_unicode = &StructAtOffset<const hb_codepoint_t> (first_unicode, unicode_stride);
+    }
+
+    if (!SUCCEEDED (dw_face->GetGlyphIndices (unicodes, n, gids)))
+      return i;
+
+    for (unsigned j = 0; j < n; j++)
+    {
+      if (!gids[j])
+        return i + j;
+      *first_glyph = gids[j];
+      first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
+    }
+
+    i += n;
+  }
+
+  return count;
+}
+
+static hb_bool_t
+hb_directwrite_get_font_h_extents (hb_font_t *font,
+				   void *font_data HB_UNUSED,
+				   hb_font_extents_t *metrics,
+				   void *user_data HB_UNUSED)
+{
+  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
+
+  DWRITE_FONT_METRICS dw_metrics;
+  dw_face->GetMetrics (&dw_metrics);
+
+  metrics->ascender = font->em_scale_y (dw_metrics.ascent);
+  metrics->descender = -font->em_scale_y (dw_metrics.descent);
+  metrics->line_gap = font->em_scale_y (dw_metrics.lineGap);
+
+  return true;
+}
+
+static void
+hb_directwrite_get_glyph_h_advances (hb_font_t* font,
+				     void* font_data HB_UNUSED,
+				     unsigned count,
+				     const hb_codepoint_t *first_glyph,
+				     unsigned glyph_stride,
+				     hb_position_t *first_advance,
+				     unsigned advance_stride,
+				     void *user_data HB_UNUSED)
+{
+  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
+
+  IDWriteFontFace1 *dw_face1 = nullptr;
+  dw_face->QueryInterface (__uuidof(IDWriteFontFace1), (void**)&dw_face1);
+  assert (dw_face1);
+
+  for (unsigned i = 0; i < count;)
+  {
+    UINT16 gids[MAX_GLYPHS];
+    INT32 advances[MAX_GLYPHS];
+
+    unsigned n = hb_min (MAX_GLYPHS, count - i);
+
+    for (unsigned j = 0; j < n; j++)
+    {
+      gids[j] = *first_glyph;
+      advances[j] = 0;
+      first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
+    }
+    dw_face1->GetDesignGlyphAdvances (n, gids, advances, false);
+    for (unsigned j = 0; j < n; j++)
+    {
+      *first_advance = font->em_scale_x (advances[j]);
+      first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
+    }
+
+    i += n;
+  }
+}
+
+#ifndef HB_NO_VERTICAL
+
+static void
+hb_directwrite_get_glyph_v_advances (hb_font_t* font,
+				     void* font_data HB_UNUSED,
+				     unsigned count,
+				     const hb_codepoint_t *first_glyph,
+				     unsigned glyph_stride,
+				     hb_position_t *first_advance,
+				     unsigned advance_stride,
+				     void *user_data HB_UNUSED)
+{
+  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
+
+  IDWriteFontFace1 *dw_face1 = nullptr;
+  dw_face->QueryInterface (__uuidof(IDWriteFontFace1), (void**)&dw_face1);
+  assert (dw_face1);
+
+  for (unsigned i = 0; i < count;)
+  {
+    UINT16 gids[MAX_GLYPHS];
+    INT32 advances[MAX_GLYPHS];
+
+    unsigned n = hb_min (MAX_GLYPHS, count - i);
+
+    for (unsigned j = 0; j < n; j++)
+    {
+      gids[j] = *first_glyph;
+      advances[j] = 0;
+      first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
+    }
+    dw_face1->GetDesignGlyphAdvances (n, gids, advances, true);
+    for (unsigned j = 0; j < n; j++)
+    {
+      *first_advance = -font->em_scale_y (advances[j]);
+      first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
+    }
+
+    i += n;
+  }
+}
+
+static hb_bool_t
+hb_directwrite_get_glyph_v_origin (hb_font_t *font,
+				   void *font_data HB_UNUSED,
+				   hb_codepoint_t glyph,
+				   hb_position_t *x,
+				   hb_position_t *y,
+				   void *user_data HB_UNUSED)
+{
+  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
+
+  UINT16 gid = glyph;
+  DWRITE_GLYPH_METRICS metrics;
+
+  if (FAILED (dw_face->GetDesignGlyphMetrics (&gid, 1, &metrics)))
+    return false;
+
+  *x = font->em_scale_x (metrics.advanceWidth / 2);
+  *y = font->em_scale_y (metrics.verticalOriginY); // Untested
+
+  return true;
+}
+#endif
+
+static hb_bool_t
+hb_directwrite_get_glyph_extents (hb_font_t *font,
+				  void *font_data HB_UNUSED,
+				  hb_codepoint_t glyph,
+				  hb_glyph_extents_t *extents,
+				  void *user_data HB_UNUSED)
+{
+  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
+
+  UINT16 gid = glyph;
+  DWRITE_GLYPH_METRICS metrics;
+
+  if (FAILED (dw_face->GetDesignGlyphMetrics (&gid, 1, &metrics)))
+    return false;
+
+  extents->x_bearing = font->em_scale_x (metrics.leftSideBearing);
+  extents->y_bearing = font->em_scale_y (metrics.verticalOriginY - metrics.topSideBearing);
+  extents->width = font->em_scale_x (metrics.advanceWidth - metrics.rightSideBearing) - extents->x_bearing;
+  extents->height = font->em_scale_y (metrics.verticalOriginY - metrics.advanceHeight + metrics.bottomSideBearing) - extents->y_bearing; // Magic
+
+  return true;
+}
+
+
+#ifndef HB_NO_DRAW
+
+class GeometrySink : public IDWriteGeometrySink
+{
+  hb_font_t *font;
+  hb_draw_session_t drawing;
+
+public:
+  GeometrySink(hb_font_t *font,
+	       hb_draw_funcs_t *draw_funcs,
+	       void *draw_data)
+    : font (font), drawing ({draw_funcs, draw_data, font->slant}) {}
+
+  virtual ~GeometrySink() {}
+
+  HRESULT STDMETHODCALLTYPE Close() override { return S_OK; }
+  void STDMETHODCALLTYPE SetFillMode(D2D1_FILL_MODE) override {}
+  void STDMETHODCALLTYPE SetSegmentFlags(D2D1_PATH_SEGMENT) override {}
+
+  IFACEMETHOD(QueryInterface)(REFIID, void **) override { return E_NOINTERFACE; }
+  IFACEMETHOD_(ULONG, AddRef)() override { return 1; }
+  IFACEMETHOD_(ULONG, Release)() override { return 1; }
+
+  void STDMETHODCALLTYPE BeginFigure(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN) override
+  {
+    drawing.move_to (font->em_scalef_x (startPoint.x), -font->em_scalef_y (startPoint.y));
+  }
+
+  void STDMETHODCALLTYPE AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, UINT beziersCount) override
+  {
+    for (unsigned i = 0; i < beziersCount; ++i)
+      drawing.cubic_to (font->em_scalef_x (beziers[i].point1.x), -font->em_scalef_y (beziers[i].point1.y),
+			font->em_scalef_x (beziers[i].point2.x), -font->em_scalef_y (beziers[i].point2.y),
+			font->em_scalef_x (beziers[i].point3.x), -font->em_scalef_y (beziers[i].point3.y));
+  }
+
+  void STDMETHODCALLTYPE AddLines(const D2D1_POINT_2F *points, UINT pointsCount) override
+  {
+    for (unsigned i = 0; i < pointsCount; ++i)
+      drawing.line_to (font->em_scalef_x (points[i].x), -font->em_scalef_y (points[i].y));
+  }
+
+  void STDMETHODCALLTYPE EndFigure(D2D1_FIGURE_END) override
+  {
+    drawing.close_path ();
+  }
+};
+
+static void
+hb_directwrite_draw_glyph (hb_font_t *font,
+			   void *font_data HB_UNUSED,
+			   hb_codepoint_t glyph,
+			   hb_draw_funcs_t *draw_funcs, void *draw_data,
+			   void *user_data)
+{
+  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
+
+  GeometrySink sink (font, draw_funcs, draw_data);
+  UINT16 gid = static_cast<UINT16>(glyph);
+  unsigned upem = font->face->get_upem();
+
+  (void) dw_face->GetGlyphRunOutline (upem,
+				      &gid, nullptr, nullptr,
+				      1,
+				      false, false,
+				      &sink);
+}
+
+#endif
+
+static inline void free_static_directwrite_funcs ();
+
+static struct hb_directwrite_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_directwrite_font_funcs_lazy_loader_t>
+{
+  static hb_font_funcs_t *create ()
+  {
+    hb_font_funcs_t *funcs = hb_font_funcs_create ();
+
+    hb_font_funcs_set_nominal_glyphs_func (funcs, hb_directwrite_get_nominal_glyphs, nullptr, nullptr);
+    //hb_font_funcs_set_variation_glyph_func (funcs, hb_directwrite_get_variation_glyph, nullptr, nullptr);
+
+    hb_font_funcs_set_font_h_extents_func (funcs, hb_directwrite_get_font_h_extents, nullptr, nullptr);
+    hb_font_funcs_set_glyph_h_advances_func (funcs, hb_directwrite_get_glyph_h_advances, nullptr, nullptr);
+
+#ifndef HB_NO_VERTICAL
+    hb_font_funcs_set_glyph_v_advances_func (funcs, hb_directwrite_get_glyph_v_advances, nullptr, nullptr);
+    hb_font_funcs_set_glyph_v_origin_func (funcs, hb_directwrite_get_glyph_v_origin, nullptr, nullptr);
+#endif
+
+#ifndef HB_NO_DRAW
+    hb_font_funcs_set_draw_glyph_func (funcs, hb_directwrite_draw_glyph, nullptr, nullptr);
+#endif
+
+    hb_font_funcs_set_glyph_extents_func (funcs, hb_directwrite_get_glyph_extents, nullptr, nullptr);
+
+#ifndef HB_NO_OT_FONT_GLYPH_NAMES
+    //hb_font_funcs_set_glyph_name_func (funcs, hb_directwrite_get_glyph_name, nullptr, nullptr);
+    //hb_font_funcs_set_glyph_from_name_func (funcs, hb_directwrite_get_glyph_from_name, nullptr, nullptr);
+#endif
+
+    hb_font_funcs_make_immutable (funcs);
+
+    hb_atexit (free_static_directwrite_funcs);
+
+    return funcs;
+  }
+} static_directwrite_funcs;
+
+static inline
+void free_static_directwrite_funcs ()
+{
+  static_directwrite_funcs.free_instance ();
+}
+
+static hb_font_funcs_t *
+_hb_directwrite_get_font_funcs ()
+{
+  return static_directwrite_funcs.get_unconst ();
+}
+
+/**
+ * hb_directwrite_font_set_funcs:
+ * @font: #hb_font_t to work upon
+ *
+ * Configures the font-functions structure of the specified
+ * #hb_font_t font object to use DirectWrite font functions.
+ *
+ * In particular, you can use this function to configure an
+ * existing #hb_face_t face object for use with DirectWrite font
+ * functions even if that #hb_face_t face object was initially
+ * created with hb_face_create(), and therefore was not
+ * initially configured to use DirectWrite font functions.
+ *
+ * <note>Note: Internally, this function creates a DirectWrite font.
+ * </note>
+ *
+ * Since: 11.0.0
+ **/
+void
+hb_directwrite_font_set_funcs (hb_font_t *font)
+{
+  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
+  if (unlikely (!dw_face))
+  {
+    hb_font_set_funcs (font,
+		       hb_font_funcs_get_empty (),
+		       nullptr, nullptr);
+    return;
+  }
+
+  dw_face->AddRef ();
+  hb_font_set_funcs (font,
+		     _hb_directwrite_get_font_funcs (),
+		     nullptr, nullptr);
+}
+
+#undef MAX_GLYPHS
+
+#endif
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite-shape.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite-shape.cc
new file mode 100644
index 0000000000000000000000000000000000000000..485075e64644f96b8721b65bfcec0a8567399b83
--- /dev/null
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite-shape.cc
@@ -0,0 +1,656 @@
+/*
+ *  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
+ */
+
+#include "hb.hh"
+
+#ifdef HAVE_DIRECTWRITE
+
+#include "hb-shaper-impl.hh"
+
+#include "hb-directwrite.hh"
+
+#include "hb-ms-feature-ranges.hh"
+
+
+/*
+* shaper face data
+*/
+
+hb_directwrite_face_data_t *
+_hb_directwrite_shaper_face_data_create (hb_face_t *face)
+{
+  hb_blob_t *blob = hb_face_reference_blob (face);
+
+  hb_directwrite_face_data_t *data = (hb_directwrite_face_data_t *) dw_face_create (blob, face->index);
+
+  hb_blob_destroy (blob);
+
+  return data;
+}
+
+void
+_hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
+{
+  ((IDWriteFontFace *) data)->Release ();
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_directwrite_font_data_t {};
+
+hb_directwrite_font_data_t *
+_hb_directwrite_shaper_font_data_create (hb_font_t *font)
+{
+  IDWriteFontFace *fontFace = (IDWriteFontFace *) (const void *) font->face->data.directwrite;
+
+  /*
+   * Set up variations.
+   */
+  IDWriteFontFace5 *fontFaceVariations = nullptr;
+  {
+    IDWriteFontFace5 *fontFace5;
+    if (SUCCEEDED (fontFace->QueryInterface (__uuidof (IDWriteFontFace5), (void **) &fontFace5)))
+    {
+      IDWriteFontResource *fontResource;
+      if (SUCCEEDED (fontFace5->GetFontResource (&fontResource)))
+      {
+	hb_vector_t<DWRITE_FONT_AXIS_VALUE> axis_values;
+	if (likely (axis_values.resize_exact (font->num_coords)))
+	{
+	  for (unsigned int i = 0; i < font->num_coords; i++)
+	  {
+	    hb_ot_var_axis_info_t info;
+	    unsigned int c = 1;
+	    hb_ot_var_get_axis_infos (font->face, i, &c, &info);
+	    axis_values[i].axisTag = (DWRITE_FONT_AXIS_TAG) hb_uint32_swap (info.tag);
+	    axis_values[i].value = i < font->num_coords ?
+				   hb_clamp (font->design_coords[i], info.min_value, info.max_value) :
+				   info.default_value;
+	  }
+
+	  fontResource->CreateFontFace (DWRITE_FONT_SIMULATIONS::DWRITE_FONT_SIMULATIONS_NONE,
+					axis_values.arrayZ, axis_values.length, &fontFaceVariations);
+	}
+	fontResource->Release ();
+      }
+      fontFace5->Release ();
+    }
+  }
+
+  return (hb_directwrite_font_data_t *) fontFaceVariations;
+}
+
+void
+_hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data)
+{
+  ((IDWriteFontFace *) data)->Release ();
+}
+
+
+// Most of TextAnalysis is originally written by Bas Schouten for Mozilla project
+// but now is relicensed to MIT for HarfBuzz use
+class TextAnalysis : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
+{
+private:
+  hb_reference_count_t mRefCount;
+public:
+  IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
+  { return S_OK; }
+  IFACEMETHOD_ (ULONG, AddRef) ()
+  {
+    return mRefCount.inc () + 1;
+  }
+  IFACEMETHOD_ (ULONG, Release) ()
+  {
+    signed refCount = mRefCount.dec () - 1;
+    assert (refCount >= 0);
+    if (refCount)
+      return refCount;
+    delete this;
+    return 0;
+  }
+
+  // A single contiguous run of characters containing the same analysis
+  // results.
+  struct Run
+  {
+    uint32_t mTextStart;   // starting text position of this run
+    uint32_t mTextLength;  // number of contiguous code units covered
+    uint32_t mGlyphStart;  // starting glyph in the glyphs array
+    uint32_t mGlyphCount;  // number of glyphs associated with this run
+    // text
+    DWRITE_SCRIPT_ANALYSIS mScript;
+    uint8_t mBidiLevel;
+    bool mIsSideways;
+
+    bool ContainsTextPosition (uint32_t aTextPosition) const
+    {
+      return aTextPosition >= mTextStart &&
+	     aTextPosition <  mTextStart + mTextLength;
+    }
+
+    Run *nextRun;
+  };
+
+public:
+  TextAnalysis (const wchar_t* text, uint32_t textLength,
+		const wchar_t* localeName, DWRITE_READING_DIRECTION readingDirection)
+	       : mTextLength (textLength), mText (text), mLocaleName (localeName),
+		 mReadingDirection (readingDirection), mCurrentRun (nullptr)
+  {
+    mRefCount.init ();
+  }
+  virtual ~TextAnalysis ()
+  {
+    // delete runs, except mRunHead which is part of the TextAnalysis object
+    for (Run *run = mRunHead.nextRun; run;)
+    {
+      Run *origRun = run;
+      run = run->nextRun;
+      delete origRun;
+    }
+  }
+
+  STDMETHODIMP
+  GenerateResults (IDWriteTextAnalyzer* textAnalyzer, Run **runHead)
+  {
+    // Analyzes the text using the script analyzer and returns
+    // the result as a series of runs.
+
+    HRESULT hr = S_OK;
+
+    // Initially start out with one result that covers the entire range.
+    // This result will be subdivided by the analysis processes.
+    mRunHead.mTextStart = 0;
+    mRunHead.mTextLength = mTextLength;
+    mRunHead.mBidiLevel =
+      (mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
+    mRunHead.nextRun = nullptr;
+    mCurrentRun = &mRunHead;
+
+    // Call each of the analyzers in sequence, recording their results.
+    if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this)))
+      *runHead = &mRunHead;
+
+    return hr;
+  }
+
+  // IDWriteTextAnalysisSource implementation
+
+  IFACEMETHODIMP
+  GetTextAtPosition (uint32_t textPosition,
+		     OUT wchar_t const** textString,
+		     OUT uint32_t* textLength)
+  {
+    if (textPosition >= mTextLength)
+    {
+      // No text at this position, valid query though.
+      *textString = nullptr;
+      *textLength = 0;
+    }
+    else
+    {
+      *textString = mText + textPosition;
+      *textLength = mTextLength - textPosition;
+    }
+    return S_OK;
+  }
+
+  IFACEMETHODIMP
+  GetTextBeforePosition (uint32_t textPosition,
+			 OUT wchar_t const** textString,
+			 OUT uint32_t* textLength)
+  {
+    if (textPosition == 0 || textPosition > mTextLength)
+    {
+      // Either there is no text before here (== 0), or this
+      // is an invalid position. The query is considered valid though.
+      *textString = nullptr;
+      *textLength = 0;
+    }
+    else
+    {
+      *textString = mText;
+      *textLength = textPosition;
+    }
+    return S_OK;
+  }
+
+  IFACEMETHODIMP_ (DWRITE_READING_DIRECTION)
+  GetParagraphReadingDirection () { return mReadingDirection; }
+
+  IFACEMETHODIMP GetLocaleName (uint32_t textPosition, uint32_t* textLength,
+				wchar_t const** localeName)
+  { return S_OK; }
+
+  IFACEMETHODIMP
+  GetNumberSubstitution (uint32_t textPosition,
+			 OUT uint32_t* textLength,
+			 OUT IDWriteNumberSubstitution** numberSubstitution)
+  {
+    // We do not support number substitution.
+    *numberSubstitution = nullptr;
+    *textLength = mTextLength - textPosition;
+
+    return S_OK;
+  }
+
+  // IDWriteTextAnalysisSink implementation
+
+  IFACEMETHODIMP
+  SetScriptAnalysis (uint32_t textPosition, uint32_t textLength,
+		     DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
+  {
+    SetCurrentRun (textPosition);
+    SplitCurrentRun (textPosition);
+    while (textLength > 0)
+    {
+      Run *run = FetchNextRun (&textLength);
+      run->mScript = *scriptAnalysis;
+    }
+
+    return S_OK;
+  }
+
+  IFACEMETHODIMP
+  SetLineBreakpoints (uint32_t textPosition,
+		      uint32_t textLength,
+		      const DWRITE_LINE_BREAKPOINT* lineBreakpoints)
+  { return S_OK; }
+
+  IFACEMETHODIMP SetBidiLevel (uint32_t textPosition, uint32_t textLength,
+			       uint8_t explicitLevel, uint8_t resolvedLevel)
+  { return S_OK; }
+
+  IFACEMETHODIMP
+  SetNumberSubstitution (uint32_t textPosition, uint32_t textLength,
+			 IDWriteNumberSubstitution* numberSubstitution)
+  { return S_OK; }
+
+protected:
+  Run *FetchNextRun (IN OUT uint32_t* textLength)
+  {
+    // Used by the sink setters, this returns a reference to the next run.
+    // Position and length are adjusted to now point after the current run
+    // being returned.
+
+    Run *origRun = mCurrentRun;
+    // Split the tail if needed (the length remaining is less than the
+    // current run's size).
+    if (*textLength < mCurrentRun->mTextLength)
+      SplitCurrentRun (mCurrentRun->mTextStart + *textLength);
+    else
+      // Just advance the current run.
+      mCurrentRun = mCurrentRun->nextRun;
+    *textLength -= origRun->mTextLength;
+
+    // Return a reference to the run that was just current.
+    return origRun;
+  }
+
+  void SetCurrentRun (uint32_t textPosition)
+  {
+    // Move the current run to the given position.
+    // Since the analyzers generally return results in a forward manner,
+    // this will usually just return early. If not, find the
+    // corresponding run for the text position.
+
+    if (mCurrentRun && mCurrentRun->ContainsTextPosition (textPosition))
+      return;
+
+    for (Run *run = &mRunHead; run; run = run->nextRun)
+      if (run->ContainsTextPosition (textPosition))
+      {
+	mCurrentRun = run;
+	return;
+      }
+    assert (0); // We should always be able to find the text position in one of our runs
+  }
+
+  void SplitCurrentRun (uint32_t splitPosition)
+  {
+    if (!mCurrentRun)
+    {
+      assert (0); // SplitCurrentRun called without current run
+      // Shouldn't be calling this when no current run is set!
+      return;
+    }
+    // Split the current run.
+    if (splitPosition <= mCurrentRun->mTextStart)
+    {
+      // No need to split, already the start of a run
+      // or before it. Usually the first.
+      return;
+    }
+    Run *newRun = new Run;
+
+    *newRun = *mCurrentRun;
+
+    // Insert the new run in our linked list.
+    newRun->nextRun = mCurrentRun->nextRun;
+    mCurrentRun->nextRun = newRun;
+
+    // Adjust runs' text positions and lengths.
+    uint32_t splitPoint = splitPosition - mCurrentRun->mTextStart;
+    newRun->mTextStart += splitPoint;
+    newRun->mTextLength -= splitPoint;
+    mCurrentRun->mTextLength = splitPoint;
+    mCurrentRun = newRun;
+  }
+
+protected:
+  // Input
+  // (weak references are fine here, since this class is a transient
+  //  stack-based helper that doesn't need to copy data)
+  uint32_t mTextLength;
+  const wchar_t* mText;
+  const wchar_t* mLocaleName;
+  DWRITE_READING_DIRECTION mReadingDirection;
+
+  // Current processing state.
+  Run *mCurrentRun;
+
+  // Output is a list of runs starting here
+  Run  mRunHead;
+};
+
+/*
+ * shaper
+ */
+
+hb_bool_t
+_hb_directwrite_shape (hb_shape_plan_t    *shape_plan,
+		       hb_font_t          *font,
+		       hb_buffer_t        *buffer,
+		       const hb_feature_t *features,
+		       unsigned int        num_features)
+{
+  IDWriteFontFace *fontFace = (IDWriteFontFace *) (const void *) font->data.directwrite;
+  auto *global = get_directwrite_global ();
+  if (unlikely (!global))
+    return false;
+  IDWriteFactory *dwriteFactory = global->dwriteFactory;
+
+  IDWriteTextAnalyzer* analyzer;
+  dwriteFactory->CreateTextAnalyzer (&analyzer);
+
+  unsigned int scratch_size;
+  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
+#define ALLOCATE_ARRAY(Type, name, len) \
+  Type *name = (Type *) scratch; \
+  do { \
+    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
+    assert (_consumed <= scratch_size); \
+    scratch += _consumed; \
+    scratch_size -= _consumed; \
+  } while (0)
+
+#define utf16_index() var1.u32
+
+  ALLOCATE_ARRAY (wchar_t, textString, buffer->len * 2);
+
+  unsigned int chars_len = 0;
+  for (unsigned int i = 0; i < buffer->len; i++)
+  {
+    hb_codepoint_t c = buffer->info[i].codepoint;
+    buffer->info[i].utf16_index () = chars_len;
+    if (likely (c <= 0xFFFFu))
+      textString[chars_len++] = c;
+    else if (unlikely (c > 0x10FFFFu))
+      textString[chars_len++] = 0xFFFDu;
+    else
+    {
+      textString[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
+      textString[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
+    }
+  }
+
+  ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
+  /* Need log_clusters to assign features. */
+  chars_len = 0;
+  for (unsigned int i = 0; i < buffer->len; i++)
+  {
+    hb_codepoint_t c = buffer->info[i].codepoint;
+    unsigned int cluster = buffer->info[i].cluster;
+    log_clusters[chars_len++] = cluster;
+    if (hb_in_range (c, 0x10000u, 0x10FFFFu))
+      log_clusters[chars_len++] = cluster; /* Surrogates. */
+  }
+
+  DWRITE_READING_DIRECTION readingDirection;
+  readingDirection = buffer->props.direction ?
+		     DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
+		     DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
+
+  /*
+  * There's an internal 16-bit limit on some things inside the analyzer,
+  * but we never attempt to shape a word longer than 64K characters
+  * in a single gfxShapedWord, so we cannot exceed that limit.
+  */
+  uint32_t textLength = chars_len;
+
+  TextAnalysis analysis (textString, textLength, nullptr, readingDirection);
+  TextAnalysis::Run *runHead;
+  HRESULT hr;
+  hr = analysis.GenerateResults (analyzer, &runHead);
+
+#define FAIL(...) \
+  HB_STMT_START { \
+    DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
+    return false; \
+  } HB_STMT_END
+
+  if (FAILED (hr))
+    FAIL ("Analyzer failed to generate results.");
+
+  uint32_t maxGlyphCount = 3 * textLength / 2 + 16;
+  uint32_t glyphCount;
+  bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
+
+  const wchar_t localeName[20] = {0};
+  if (buffer->props.language)
+    mbstowcs ((wchar_t*) localeName,
+	      hb_language_to_string (buffer->props.language), 20);
+
+  /*
+   * Set up features.
+   */
+  static_assert ((sizeof (DWRITE_TYPOGRAPHIC_FEATURES) == sizeof (hb_ms_features_t)), "");
+  static_assert ((sizeof (DWRITE_FONT_FEATURE) == sizeof (hb_ms_feature_t)), "");
+  hb_vector_t<hb_ms_features_t *> range_features;
+  hb_vector_t<uint32_t> range_char_counts;
+
+  // https://github.com/harfbuzz/harfbuzz/pull/5114
+  // The data allocated by these two vectors are used by the above two, so they
+  // should remain alive as long as the above two are.
+  hb_vector_t<hb_ms_feature_t> feature_records;
+  hb_vector_t<hb_ms_range_record_t> range_records;
+  if (num_features)
+  {
+    if (hb_ms_setup_features (features, num_features, feature_records, range_records))
+    {
+      hb_ms_make_feature_ranges (feature_records,
+				 range_records,
+				 0,
+				 chars_len,
+				 log_clusters,
+				 range_features,
+				 range_char_counts);
+    }
+  }
+
+  uint16_t* clusterMap;
+  clusterMap = new uint16_t[textLength];
+  DWRITE_SHAPING_TEXT_PROPERTIES* textProperties;
+  textProperties = new DWRITE_SHAPING_TEXT_PROPERTIES[textLength];
+
+retry_getglyphs:
+  uint16_t* glyphIndices = new uint16_t[maxGlyphCount];
+  DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties;
+  glyphProperties = new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount];
+
+  hr = analyzer->GetGlyphs (textString,
+			    chars_len,
+			    fontFace,
+			    false,
+			    isRightToLeft,
+			    &runHead->mScript,
+			    localeName,
+			    nullptr,
+			    (const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
+			    range_char_counts.arrayZ,
+			    range_features.length,
+			    maxGlyphCount,
+			    clusterMap,
+			    textProperties,
+			    glyphIndices,
+			    glyphProperties,
+			    &glyphCount);
+
+  if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
+  {
+    delete [] glyphIndices;
+    delete [] glyphProperties;
+
+    maxGlyphCount *= 2;
+
+    goto retry_getglyphs;
+  }
+  if (FAILED (hr))
+    FAIL ("Analyzer failed to get glyphs.");
+
+  float* glyphAdvances = new float[maxGlyphCount];
+  DWRITE_GLYPH_OFFSET* glyphOffsets = new DWRITE_GLYPH_OFFSET[maxGlyphCount];
+
+  /* The -2 in the following is to compensate for possible
+   * alignment needed after the WORD array.  sizeof (WORD) == 2. */
+  unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
+			     / (sizeof (WORD) +
+				sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) +
+				sizeof (int) +
+				sizeof (DWRITE_GLYPH_OFFSET) +
+				sizeof (uint32_t));
+  ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
+
+#undef ALLOCATE_ARRAY
+
+  unsigned fontEmSize = font->face->get_upem ();
+
+  float x_mult = font->x_multf;
+  float y_mult = font->y_multf;
+
+  hr = analyzer->GetGlyphPlacements (textString,
+				     clusterMap,
+				     textProperties,
+				     chars_len,
+				     glyphIndices,
+				     glyphProperties,
+				     glyphCount,
+				     fontFace,
+				     fontEmSize,
+				     false,
+				     isRightToLeft,
+				     &runHead->mScript,
+				     localeName,
+				     (const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
+				     range_char_counts.arrayZ,
+				     range_features.length,
+				     glyphAdvances,
+				     glyphOffsets);
+
+  if (FAILED (hr))
+    FAIL ("Analyzer failed to get glyph placements.");
+
+  /* Ok, we've got everything we need, now compose output buffer,
+   * very, *very*, carefully! */
+
+  /* Calculate visual-clusters.  That's what we ship. */
+  for (unsigned int i = 0; i < glyphCount; i++)
+    vis_clusters[i] = (uint32_t) -1;
+  for (unsigned int i = 0; i < buffer->len; i++)
+  {
+    uint32_t *p =
+      &vis_clusters[log_clusters[buffer->info[i].utf16_index ()]];
+    *p = hb_min (*p, buffer->info[i].cluster);
+  }
+  for (unsigned int i = 1; i < glyphCount; i++)
+    if (vis_clusters[i] == (uint32_t) -1)
+      vis_clusters[i] = vis_clusters[i - 1];
+
+#undef utf16_index
+
+  if (unlikely (!buffer->ensure (glyphCount)))
+    FAIL ("Buffer in error");
+
+#undef FAIL
+
+  /* Set glyph infos */
+  buffer->len = 0;
+  for (unsigned int i = 0; i < glyphCount; i++)
+  {
+    hb_glyph_info_t *info = &buffer->info[buffer->len++];
+
+    info->codepoint = glyphIndices[i];
+    info->cluster = vis_clusters[i];
+
+    /* The rest is crap.  Let's store position info there for now. */
+    info->mask = glyphAdvances[i];
+    info->var1.i32 = glyphOffsets[i].advanceOffset;
+    info->var2.i32 = glyphOffsets[i].ascenderOffset;
+  }
+
+  /* Set glyph positions */
+  buffer->clear_positions ();
+  for (unsigned int i = 0; i < glyphCount; i++)
+  {
+    hb_glyph_info_t *info = &buffer->info[i];
+    hb_glyph_position_t *pos = &buffer->pos[i];
+
+    /* TODO vertical */
+    pos->x_advance = round (x_mult * (int32_t) info->mask);
+    pos->x_offset = round (x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32));
+    pos->y_offset = round (y_mult * info->var2.i32);
+  }
+
+  if (isRightToLeft) hb_buffer_reverse (buffer);
+
+  buffer->clear_glyph_flags ();
+  buffer->unsafe_to_break ();
+
+  delete [] clusterMap;
+  delete [] glyphIndices;
+  delete [] textProperties;
+  delete [] glyphProperties;
+  delete [] glyphAdvances;
+  delete [] glyphOffsets;
+
+  /* Wow, done! */
+  return true;
+}
+
+
+#endif
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.cc
index 5b191262a2382ab39133406bc2eec9e4d9ef393f..9c4bab95df59420de45193661a0a5cbc8acbfb90 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.cc
@@ -26,14 +26,10 @@
 
 #ifdef HAVE_DIRECTWRITE
 
-#include "hb-shaper-impl.hh"
+#include "hb-directwrite.hh"
 
-#include <dwrite_1.h>
-#include <dwrite_3.h>
+#include "hb-font.hh"
 
-#include "hb-directwrite.h"
-
-#include "hb-ms-feature-ranges.hh"
 
 /**
  * SECTION:hb-directwrite
@@ -44,173 +40,89 @@
  * Functions for using HarfBuzz with DirectWrite fonts.
  **/
 
-/* Declare object creator for dynamic support of DWRITE */
-typedef HRESULT (WINAPI *t_DWriteCreateFactory)(
-  DWRITE_FACTORY_TYPE factoryType,
-  REFIID              iid,
-  IUnknown            **factory
-);
-
-
-/*
- * DirectWrite font stream helpers
- */
+static inline void free_static_directwrite_global ();
 
-// This is a font loader which provides only one font (unlike its original design).
-// For a better implementation which was also source of this
-// and DWriteFontFileStream, have a look at to NativeFontResourceDWrite.cpp in Mozilla
-class DWriteFontFileLoader : public IDWriteFontFileLoader
+static struct hb_directwrite_global_lazy_loader_t : hb_lazy_loader_t<hb_directwrite_global_t,
+								     hb_directwrite_global_lazy_loader_t>
 {
-private:
-  IDWriteFontFileStream *mFontFileStream;
-public:
-  DWriteFontFileLoader (IDWriteFontFileStream *fontFileStream)
-  { mFontFileStream = fontFileStream; }
-
-  // IUnknown interface
-  IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
-  { return S_OK; }
-  IFACEMETHOD_ (ULONG, AddRef) ()  { return 1; }
-  IFACEMETHOD_ (ULONG, Release) () { return 1; }
-
-  // IDWriteFontFileLoader methods
-  virtual HRESULT STDMETHODCALLTYPE
-  CreateStreamFromKey (void const* fontFileReferenceKey,
-		       uint32_t fontFileReferenceKeySize,
-		       OUT IDWriteFontFileStream** fontFileStream)
+  static hb_directwrite_global_t * create ()
   {
-    *fontFileStream = mFontFileStream;
-    return S_OK;
-  }
+    hb_directwrite_global_t *global = new hb_directwrite_global_t;
 
-  virtual ~DWriteFontFileLoader() {}
-};
+    if (unlikely (!global))
+      return nullptr;
+    if (unlikely (!global->success))
+    {
+      delete global;
+      return nullptr;
+    }
 
-class DWriteFontFileStream : public IDWriteFontFileStream
-{
-private:
-  uint8_t *mData;
-  uint32_t mSize;
-public:
-  DWriteFontFileStream (uint8_t *aData, uint32_t aSize)
-  {
-    mData = aData;
-    mSize = aSize;
-  }
+    hb_atexit (free_static_directwrite_global);
 
-  // IUnknown interface
-  IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
-  { return S_OK; }
-  IFACEMETHOD_ (ULONG, AddRef) ()  { return 1; }
-  IFACEMETHOD_ (ULONG, Release) () { return 1; }
-
-  // IDWriteFontFileStream methods
-  virtual HRESULT STDMETHODCALLTYPE
-  ReadFileFragment (void const** fragmentStart,
-		    UINT64 fileOffset,
-		    UINT64 fragmentSize,
-		    OUT void** fragmentContext)
+    return global;
+  }
+  static void destroy (hb_directwrite_global_t *l)
   {
-    // We are required to do bounds checking.
-    if (fileOffset + fragmentSize > mSize) return E_FAIL;
-
-    // truncate the 64 bit fileOffset to size_t sized index into mData
-    size_t index = static_cast<size_t> (fileOffset);
-
-    // We should be alive for the duration of this.
-    *fragmentStart = &mData[index];
-    *fragmentContext = nullptr;
-    return S_OK;
+    delete l;
   }
-
-  virtual void STDMETHODCALLTYPE
-  ReleaseFileFragment (void* fragmentContext) {}
-
-  virtual HRESULT STDMETHODCALLTYPE
-  GetFileSize (OUT UINT64* fileSize)
+  static hb_directwrite_global_t * get_null ()
   {
-    *fileSize = mSize;
-    return S_OK;
+    return nullptr;
   }
+} static_directwrite_global;
 
-  virtual HRESULT STDMETHODCALLTYPE
-  GetLastWriteTime (OUT UINT64* lastWriteTime) { return E_NOTIMPL; }
-
-  virtual ~DWriteFontFileStream() {}
-};
 
+static inline
+void free_static_directwrite_global ()
+{
+  static_directwrite_global.free_instance ();
+}
 
-/*
-* shaper face data
-*/
+hb_directwrite_global_t *
+get_directwrite_global ()
+{
+  return static_directwrite_global.get_unconst ();
+}
 
-struct hb_directwrite_face_data_t
+DWriteFontFileStream::DWriteFontFileStream (hb_blob_t *blob)
 {
-  HMODULE dwrite_dll;
-  IDWriteFactory *dwriteFactory;
-  IDWriteFontFile *fontFile;
-  DWriteFontFileStream *fontFileStream;
-  DWriteFontFileLoader *fontFileLoader;
-  IDWriteFontFace *fontFace;
-  hb_blob_t *faceBlob;
-};
+  auto *global = get_directwrite_global ();
+  mLoader = global->fontFileLoader;
+  mRefCount.init ();
+  mLoader->AddRef ();
+  hb_blob_make_immutable (blob);
+  mBlob = hb_blob_reference (blob);
+  mData = (uint8_t *) hb_blob_get_data (blob, &mSize);
+  fontFileKey = mLoader->RegisterFontFileStream (this);
+}
 
-hb_directwrite_face_data_t *
-_hb_directwrite_shaper_face_data_create (hb_face_t *face)
+DWriteFontFileStream::~DWriteFontFileStream()
 {
-  hb_directwrite_face_data_t *data = new hb_directwrite_face_data_t;
-  if (unlikely (!data))
-    return nullptr;
+  mLoader->UnregisterFontFileStream (fontFileKey);
+  mLoader->Release ();
+  hb_blob_destroy (mBlob);
+}
 
+IDWriteFontFace *
+dw_face_create (hb_blob_t *blob, unsigned index)
+{
 #define FAIL(...) \
   HB_STMT_START { \
     DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
     return nullptr; \
   } HB_STMT_END
 
-  data->dwrite_dll = LoadLibrary (TEXT ("DWRITE"));
-  if (unlikely (!data->dwrite_dll))
-    FAIL ("Cannot find DWrite.DLL");
-
-  t_DWriteCreateFactory p_DWriteCreateFactory;
-
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-function-type"
-#endif
-
-  p_DWriteCreateFactory = (t_DWriteCreateFactory)
-			  GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
-
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
+  auto *global = get_directwrite_global ();
+  if (unlikely (!global))
+    FAIL ("Couldn't load DirectWrite!");
 
-  if (unlikely (!p_DWriteCreateFactory))
-    FAIL ("Cannot find DWriteCreateFactory().");
-
-  HRESULT hr;
-
-  // TODO: factory and fontFileLoader should be cached separately
-  IDWriteFactory* dwriteFactory;
-  hr = p_DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
-			      (IUnknown**) &dwriteFactory);
-
-  if (unlikely (hr != S_OK))
-    FAIL ("Failed to run DWriteCreateFactory().");
-
-  hb_blob_t *blob = hb_face_reference_blob (face);
-  DWriteFontFileStream *fontFileStream;
-  fontFileStream = new DWriteFontFileStream ((uint8_t *) hb_blob_get_data (blob, nullptr),
-					     hb_blob_get_length (blob));
-
-  DWriteFontFileLoader *fontFileLoader = new DWriteFontFileLoader (fontFileStream);
-  dwriteFactory->RegisterFontFileLoader (fontFileLoader);
+  DWriteFontFileStream *fontFileStream = new DWriteFontFileStream (blob);
 
   IDWriteFontFile *fontFile;
-  uint64_t fontFileKey = 0;
-  hr = dwriteFactory->CreateCustomFontFileReference (&fontFileKey, sizeof (fontFileKey),
-						     fontFileLoader, &fontFile);
+  auto hr = global->dwriteFactory->CreateCustomFontFileReference (&fontFileStream->fontFileKey, sizeof (fontFileStream->fontFileKey),
+								  global->fontFileLoader, &fontFile);
+
+  fontFileStream->Release ();
 
   if (FAILED (hr))
     FAIL ("Failed to load font file from data!");
@@ -221,585 +133,19 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
   uint32_t numberOfFaces;
   hr = fontFile->Analyze (&isSupported, &fileType, &faceType, &numberOfFaces);
   if (FAILED (hr) || !isSupported)
-    FAIL ("Font file is not supported.");
-
-#undef FAIL
-
-  IDWriteFontFace *fontFace;
-  dwriteFactory->CreateFontFace (faceType, 1, &fontFile, 0,
-				 DWRITE_FONT_SIMULATIONS_NONE, &fontFace);
-
-  data->dwriteFactory = dwriteFactory;
-  data->fontFile = fontFile;
-  data->fontFileStream = fontFileStream;
-  data->fontFileLoader = fontFileLoader;
-  data->fontFace = fontFace;
-  data->faceBlob = blob;
-
-  return data;
-}
-
-void
-_hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
-{
-  if (data->fontFace)
-    data->fontFace->Release ();
-  if (data->fontFile)
-    data->fontFile->Release ();
-  if (data->dwriteFactory)
-  {
-    if (data->fontFileLoader)
-      data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader);
-    data->dwriteFactory->Release ();
-  }
-  delete data->fontFileLoader;
-  delete data->fontFileStream;
-  hb_blob_destroy (data->faceBlob);
-  if (data->dwrite_dll)
-    FreeLibrary (data->dwrite_dll);
-  delete data;
-}
-
-
-/*
- * shaper font data
- */
-
-struct hb_directwrite_font_data_t {};
-
-hb_directwrite_font_data_t *
-_hb_directwrite_shaper_font_data_create (hb_font_t *font)
-{
-  return (hb_directwrite_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
-}
-
-void
-_hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data)
-{
-  if (data != HB_SHAPER_DATA_SUCCEEDED)
-    ((IDWriteFont *) (const void *) data)->Release();
-}
-
-
-// Most of TextAnalysis is originally written by Bas Schouten for Mozilla project
-// but now is relicensed to MIT for HarfBuzz use
-class TextAnalysis : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
-{
-public:
-
-  IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
-  { return S_OK; }
-  IFACEMETHOD_ (ULONG, AddRef) () { return 1; }
-  IFACEMETHOD_ (ULONG, Release) () { return 1; }
-
-  // A single contiguous run of characters containing the same analysis
-  // results.
-  struct Run
-  {
-    uint32_t mTextStart;   // starting text position of this run
-    uint32_t mTextLength;  // number of contiguous code units covered
-    uint32_t mGlyphStart;  // starting glyph in the glyphs array
-    uint32_t mGlyphCount;  // number of glyphs associated with this run
-    // text
-    DWRITE_SCRIPT_ANALYSIS mScript;
-    uint8_t mBidiLevel;
-    bool mIsSideways;
-
-    bool ContainsTextPosition (uint32_t aTextPosition) const
-    {
-      return aTextPosition >= mTextStart &&
-	     aTextPosition <  mTextStart + mTextLength;
-    }
-
-    Run *nextRun;
-  };
-
-public:
-  TextAnalysis (const wchar_t* text, uint32_t textLength,
-		const wchar_t* localeName, DWRITE_READING_DIRECTION readingDirection)
-	       : mTextLength (textLength), mText (text), mLocaleName (localeName),
-		 mReadingDirection (readingDirection), mCurrentRun (nullptr) {}
-  ~TextAnalysis ()
-  {
-    // delete runs, except mRunHead which is part of the TextAnalysis object
-    for (Run *run = mRunHead.nextRun; run;)
-    {
-      Run *origRun = run;
-      run = run->nextRun;
-      delete origRun;
-    }
-  }
-
-  STDMETHODIMP
-  GenerateResults (IDWriteTextAnalyzer* textAnalyzer, Run **runHead)
-  {
-    // Analyzes the text using the script analyzer and returns
-    // the result as a series of runs.
-
-    HRESULT hr = S_OK;
-
-    // Initially start out with one result that covers the entire range.
-    // This result will be subdivided by the analysis processes.
-    mRunHead.mTextStart = 0;
-    mRunHead.mTextLength = mTextLength;
-    mRunHead.mBidiLevel =
-      (mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
-    mRunHead.nextRun = nullptr;
-    mCurrentRun = &mRunHead;
-
-    // Call each of the analyzers in sequence, recording their results.
-    if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this)))
-      *runHead = &mRunHead;
-
-    return hr;
-  }
-
-  // IDWriteTextAnalysisSource implementation
-
-  IFACEMETHODIMP
-  GetTextAtPosition (uint32_t textPosition,
-		     OUT wchar_t const** textString,
-		     OUT uint32_t* textLength)
-  {
-    if (textPosition >= mTextLength)
-    {
-      // No text at this position, valid query though.
-      *textString = nullptr;
-      *textLength = 0;
-    }
-    else
-    {
-      *textString = mText + textPosition;
-      *textLength = mTextLength - textPosition;
-    }
-    return S_OK;
-  }
-
-  IFACEMETHODIMP
-  GetTextBeforePosition (uint32_t textPosition,
-			 OUT wchar_t const** textString,
-			 OUT uint32_t* textLength)
-  {
-    if (textPosition == 0 || textPosition > mTextLength)
-    {
-      // Either there is no text before here (== 0), or this
-      // is an invalid position. The query is considered valid though.
-      *textString = nullptr;
-      *textLength = 0;
-    }
-    else
-    {
-      *textString = mText;
-      *textLength = textPosition;
-    }
-    return S_OK;
-  }
-
-  IFACEMETHODIMP_ (DWRITE_READING_DIRECTION)
-  GetParagraphReadingDirection () { return mReadingDirection; }
-
-  IFACEMETHODIMP GetLocaleName (uint32_t textPosition, uint32_t* textLength,
-				wchar_t const** localeName)
-  { return S_OK; }
-
-  IFACEMETHODIMP
-  GetNumberSubstitution (uint32_t textPosition,
-			 OUT uint32_t* textLength,
-			 OUT IDWriteNumberSubstitution** numberSubstitution)
-  {
-    // We do not support number substitution.
-    *numberSubstitution = nullptr;
-    *textLength = mTextLength - textPosition;
-
-    return S_OK;
-  }
-
-  // IDWriteTextAnalysisSink implementation
-
-  IFACEMETHODIMP
-  SetScriptAnalysis (uint32_t textPosition, uint32_t textLength,
-		     DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
-  {
-    SetCurrentRun (textPosition);
-    SplitCurrentRun (textPosition);
-    while (textLength > 0)
-    {
-      Run *run = FetchNextRun (&textLength);
-      run->mScript = *scriptAnalysis;
-    }
-
-    return S_OK;
-  }
-
-  IFACEMETHODIMP
-  SetLineBreakpoints (uint32_t textPosition,
-		      uint32_t textLength,
-		      const DWRITE_LINE_BREAKPOINT* lineBreakpoints)
-  { return S_OK; }
-
-  IFACEMETHODIMP SetBidiLevel (uint32_t textPosition, uint32_t textLength,
-			       uint8_t explicitLevel, uint8_t resolvedLevel)
-  { return S_OK; }
-
-  IFACEMETHODIMP
-  SetNumberSubstitution (uint32_t textPosition, uint32_t textLength,
-			 IDWriteNumberSubstitution* numberSubstitution)
-  { return S_OK; }
-
-protected:
-  Run *FetchNextRun (IN OUT uint32_t* textLength)
   {
-    // Used by the sink setters, this returns a reference to the next run.
-    // Position and length are adjusted to now point after the current run
-    // being returned.
-
-    Run *origRun = mCurrentRun;
-    // Split the tail if needed (the length remaining is less than the
-    // current run's size).
-    if (*textLength < mCurrentRun->mTextLength)
-      SplitCurrentRun (mCurrentRun->mTextStart + *textLength);
-    else
-      // Just advance the current run.
-      mCurrentRun = mCurrentRun->nextRun;
-    *textLength -= origRun->mTextLength;
-
-    // Return a reference to the run that was just current.
-    return origRun;
-  }
-
-  void SetCurrentRun (uint32_t textPosition)
-  {
-    // Move the current run to the given position.
-    // Since the analyzers generally return results in a forward manner,
-    // this will usually just return early. If not, find the
-    // corresponding run for the text position.
-
-    if (mCurrentRun && mCurrentRun->ContainsTextPosition (textPosition))
-      return;
-
-    for (Run *run = &mRunHead; run; run = run->nextRun)
-      if (run->ContainsTextPosition (textPosition))
-      {
-	mCurrentRun = run;
-	return;
-      }
-    assert (0); // We should always be able to find the text position in one of our runs
-  }
-
-  void SplitCurrentRun (uint32_t splitPosition)
-  {
-    if (!mCurrentRun)
-    {
-      assert (0); // SplitCurrentRun called without current run
-      // Shouldn't be calling this when no current run is set!
-      return;
-    }
-    // Split the current run.
-    if (splitPosition <= mCurrentRun->mTextStart)
-    {
-      // No need to split, already the start of a run
-      // or before it. Usually the first.
-      return;
-    }
-    Run *newRun = new Run;
-
-    *newRun = *mCurrentRun;
-
-    // Insert the new run in our linked list.
-    newRun->nextRun = mCurrentRun->nextRun;
-    mCurrentRun->nextRun = newRun;
-
-    // Adjust runs' text positions and lengths.
-    uint32_t splitPoint = splitPosition - mCurrentRun->mTextStart;
-    newRun->mTextStart += splitPoint;
-    newRun->mTextLength -= splitPoint;
-    mCurrentRun->mTextLength = splitPoint;
-    mCurrentRun = newRun;
-  }
-
-protected:
-  // Input
-  // (weak references are fine here, since this class is a transient
-  //  stack-based helper that doesn't need to copy data)
-  uint32_t mTextLength;
-  const wchar_t* mText;
-  const wchar_t* mLocaleName;
-  DWRITE_READING_DIRECTION mReadingDirection;
-
-  // Current processing state.
-  Run *mCurrentRun;
-
-  // Output is a list of runs starting here
-  Run  mRunHead;
-};
-
-/*
- * shaper
- */
-
-hb_bool_t
-_hb_directwrite_shape (hb_shape_plan_t    *shape_plan,
-		       hb_font_t          *font,
-		       hb_buffer_t        *buffer,
-		       const hb_feature_t *features,
-		       unsigned int        num_features)
-{
-  hb_face_t *face = font->face;
-  const hb_directwrite_face_data_t *face_data = face->data.directwrite;
-  IDWriteFactory *dwriteFactory = face_data->dwriteFactory;
-  IDWriteFontFace *fontFace = face_data->fontFace;
-
-  IDWriteTextAnalyzer* analyzer;
-  dwriteFactory->CreateTextAnalyzer (&analyzer);
-
-  unsigned int scratch_size;
-  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
-#define ALLOCATE_ARRAY(Type, name, len) \
-  Type *name = (Type *) scratch; \
-  do { \
-    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
-    assert (_consumed <= scratch_size); \
-    scratch += _consumed; \
-    scratch_size -= _consumed; \
-  } while (0)
-
-#define utf16_index() var1.u32
-
-  ALLOCATE_ARRAY (wchar_t, textString, buffer->len * 2);
-
-  unsigned int chars_len = 0;
-  for (unsigned int i = 0; i < buffer->len; i++)
-  {
-    hb_codepoint_t c = buffer->info[i].codepoint;
-    buffer->info[i].utf16_index () = chars_len;
-    if (likely (c <= 0xFFFFu))
-      textString[chars_len++] = c;
-    else if (unlikely (c > 0x10FFFFu))
-      textString[chars_len++] = 0xFFFDu;
-    else
-    {
-      textString[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
-      textString[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
-    }
-  }
-
-  ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
-  /* Need log_clusters to assign features. */
-  chars_len = 0;
-  for (unsigned int i = 0; i < buffer->len; i++)
-  {
-    hb_codepoint_t c = buffer->info[i].codepoint;
-    unsigned int cluster = buffer->info[i].cluster;
-    log_clusters[chars_len++] = cluster;
-    if (hb_in_range (c, 0x10000u, 0x10FFFFu))
-      log_clusters[chars_len++] = cluster; /* Surrogates. */
-  }
-
-  DWRITE_READING_DIRECTION readingDirection;
-  readingDirection = buffer->props.direction ?
-		     DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
-		     DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
-
-  /*
-  * There's an internal 16-bit limit on some things inside the analyzer,
-  * but we never attempt to shape a word longer than 64K characters
-  * in a single gfxShapedWord, so we cannot exceed that limit.
-  */
-  uint32_t textLength = chars_len;
-
-  TextAnalysis analysis (textString, textLength, nullptr, readingDirection);
-  TextAnalysis::Run *runHead;
-  HRESULT hr;
-  hr = analysis.GenerateResults (analyzer, &runHead);
-
-#define FAIL(...) \
-  HB_STMT_START { \
-    DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
-    return false; \
-  } HB_STMT_END
-
-  if (FAILED (hr))
-    FAIL ("Analyzer failed to generate results.");
-
-  uint32_t maxGlyphCount = 3 * textLength / 2 + 16;
-  uint32_t glyphCount;
-  bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
-
-  const wchar_t localeName[20] = {0};
-  if (buffer->props.language)
-    mbstowcs ((wchar_t*) localeName,
-	      hb_language_to_string (buffer->props.language), 20);
-
-  /*
-   * Set up features.
-   */
-  static_assert ((sizeof (DWRITE_TYPOGRAPHIC_FEATURES) == sizeof (hb_ms_features_t)), "");
-  static_assert ((sizeof (DWRITE_FONT_FEATURE) == sizeof (hb_ms_feature_t)), "");
-  hb_vector_t<hb_ms_features_t *> range_features;
-  hb_vector_t<uint32_t> range_char_counts;
-  if (num_features)
-  {
-    hb_vector_t<hb_ms_feature_t> feature_records;
-    hb_vector_t<hb_ms_range_record_t> range_records;
-    if (hb_ms_setup_features (features, num_features, feature_records, range_records))
-      hb_ms_make_feature_ranges (feature_records,
-				 range_records,
-				 0,
-				 chars_len,
-				 log_clusters,
-				 range_features,
-				 range_char_counts);
-  }
-
-  uint16_t* clusterMap;
-  clusterMap = new uint16_t[textLength];
-  DWRITE_SHAPING_TEXT_PROPERTIES* textProperties;
-  textProperties = new DWRITE_SHAPING_TEXT_PROPERTIES[textLength];
-
-retry_getglyphs:
-  uint16_t* glyphIndices = new uint16_t[maxGlyphCount];
-  DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties;
-  glyphProperties = new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount];
-
-  hr = analyzer->GetGlyphs (textString,
-			    chars_len,
-			    fontFace,
-			    false,
-			    isRightToLeft,
-			    &runHead->mScript,
-			    localeName,
-			    nullptr,
-			    (const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
-			    range_char_counts.arrayZ,
-			    range_features.length,
-			    maxGlyphCount,
-			    clusterMap,
-			    textProperties,
-			    glyphIndices,
-			    glyphProperties,
-			    &glyphCount);
-
-  if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
-  {
-    delete [] glyphIndices;
-    delete [] glyphProperties;
-
-    maxGlyphCount *= 2;
-
-    goto retry_getglyphs;
-  }
-  if (FAILED (hr))
-    FAIL ("Analyzer failed to get glyphs.");
-
-  float* glyphAdvances = new float[maxGlyphCount];
-  DWRITE_GLYPH_OFFSET* glyphOffsets = new DWRITE_GLYPH_OFFSET[maxGlyphCount];
-
-  /* The -2 in the following is to compensate for possible
-   * alignment needed after the WORD array.  sizeof (WORD) == 2. */
-  unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
-			     / (sizeof (WORD) +
-				sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) +
-				sizeof (int) +
-				sizeof (DWRITE_GLYPH_OFFSET) +
-				sizeof (uint32_t));
-  ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
-
-#undef ALLOCATE_ARRAY
-
-  int fontEmSize = font->face->get_upem ();
-  if (fontEmSize < 0) fontEmSize = -fontEmSize;
-
-  if (fontEmSize < 0) fontEmSize = -fontEmSize;
-  double x_mult = (double) font->x_scale / fontEmSize;
-  double y_mult = (double) font->y_scale / fontEmSize;
-
-  hr = analyzer->GetGlyphPlacements (textString,
-				     clusterMap,
-				     textProperties,
-				     chars_len,
-				     glyphIndices,
-				     glyphProperties,
-				     glyphCount,
-				     fontFace,
-				     fontEmSize,
-				     false,
-				     isRightToLeft,
-				     &runHead->mScript,
-				     localeName,
-				     (const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
-				     range_char_counts.arrayZ,
-				     range_features.length,
-				     glyphAdvances,
-				     glyphOffsets);
-
-  if (FAILED (hr))
-    FAIL ("Analyzer failed to get glyph placements.");
-
-  /* Ok, we've got everything we need, now compose output buffer,
-   * very, *very*, carefully! */
-
-  /* Calculate visual-clusters.  That's what we ship. */
-  for (unsigned int i = 0; i < glyphCount; i++)
-    vis_clusters[i] = (uint32_t) -1;
-  for (unsigned int i = 0; i < buffer->len; i++)
-  {
-    uint32_t *p =
-      &vis_clusters[log_clusters[buffer->info[i].utf16_index ()]];
-    *p = hb_min (*p, buffer->info[i].cluster);
+    fontFile->Release ();
+    FAIL ("Font file is not supported.");
   }
-  for (unsigned int i = 1; i < glyphCount; i++)
-    if (vis_clusters[i] == (uint32_t) -1)
-      vis_clusters[i] = vis_clusters[i - 1];
-
-#undef utf16_index
-
-  if (unlikely (!buffer->ensure (glyphCount)))
-    FAIL ("Buffer in error");
 
 #undef FAIL
 
-  /* Set glyph infos */
-  buffer->len = 0;
-  for (unsigned int i = 0; i < glyphCount; i++)
-  {
-    hb_glyph_info_t *info = &buffer->info[buffer->len++];
-
-    info->codepoint = glyphIndices[i];
-    info->cluster = vis_clusters[i];
-
-    /* The rest is crap.  Let's store position info there for now. */
-    info->mask = glyphAdvances[i];
-    info->var1.i32 = glyphOffsets[i].advanceOffset;
-    info->var2.i32 = glyphOffsets[i].ascenderOffset;
-  }
-
-  /* Set glyph positions */
-  buffer->clear_positions ();
-  for (unsigned int i = 0; i < glyphCount; i++)
-  {
-    hb_glyph_info_t *info = &buffer->info[i];
-    hb_glyph_position_t *pos = &buffer->pos[i];
-
-    /* TODO vertical */
-    pos->x_advance = x_mult * (int32_t) info->mask;
-    pos->x_offset = x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32);
-    pos->y_offset = y_mult * info->var2.i32;
-  }
+  IDWriteFontFace *fontFace = nullptr;
+  global->dwriteFactory->CreateFontFace (faceType, 1, &fontFile, index,
+					 DWRITE_FONT_SIMULATIONS_NONE, &fontFace);
+  fontFile->Release ();
 
-  if (isRightToLeft) hb_buffer_reverse (buffer);
-
-  buffer->clear_glyph_flags ();
-  buffer->unsafe_to_break ();
-
-  delete [] clusterMap;
-  delete [] glyphIndices;
-  delete [] textProperties;
-  delete [] glyphProperties;
-  delete [] glyphAdvances;
-  delete [] glyphOffsets;
-
-  /* Wow, done! */
-  return true;
+  return fontFace;
 }
 
 struct _hb_directwrite_font_table_context {
@@ -823,8 +169,8 @@ _hb_directwrite_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *
   uint32_t length;
   void *table_context;
   BOOL exists;
-  if (!dw_face || FAILED (dw_face->TryGetFontTable (hb_uint32_swap (tag), &data,
-						    &length, &table_context, &exists)))
+  if (FAILED (dw_face->TryGetFontTable (hb_uint32_swap (tag), &data,
+					&length, &table_context, &exists)))
     return nullptr;
 
   if (!data || !exists || !length)
@@ -834,6 +180,11 @@ _hb_directwrite_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *
   }
 
   _hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) hb_malloc (sizeof (_hb_directwrite_font_table_context));
+  if (unlikely (!context))
+  {
+    dw_face->ReleaseFontTable (table_context);
+    return nullptr;
+  }
   context->face = dw_face;
   context->table_context = table_context;
 
@@ -844,8 +195,7 @@ _hb_directwrite_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *
 static void
 _hb_directwrite_face_release (void *data)
 {
-  if (data)
-    ((IDWriteFontFace *) data)->Release ();
+  ((IDWriteFontFace *) data)->Release ();
 }
 
 /**
@@ -861,10 +211,82 @@ _hb_directwrite_face_release (void *data)
 hb_face_t *
 hb_directwrite_face_create (IDWriteFontFace *dw_face)
 {
-  if (dw_face)
-    dw_face->AddRef ();
-  return hb_face_create_for_tables (_hb_directwrite_reference_table, dw_face,
-				    _hb_directwrite_face_release);
+  if (!dw_face)
+    return hb_face_get_empty ();
+
+  dw_face->AddRef ();
+  hb_face_t *face = hb_face_create_for_tables (_hb_directwrite_reference_table,
+					       dw_face,
+					       _hb_directwrite_face_release);
+
+  hb_face_set_index (face, dw_face->GetIndex ());
+  hb_face_set_glyph_count (face, dw_face->GetGlyphCount ());
+
+  return face;
+}
+
+/**
+ * hb_directwrite_face_create_from_file_or_fail:
+ * @file_name: A font filename
+ * @index: The index of the face within the file
+ *
+ * Creates an #hb_face_t face object from the specified
+ * font file and face index.
+ *
+ * This is similar in functionality to hb_face_create_from_file_or_fail(),
+ * but uses the DirectWrite library for loading the font file.
+ *
+ * Return value: (transfer full): The new face object, or `NULL` if
+ * no face is found at the specified index or the file cannot be read.
+ *
+ * Since: 11.0.0
+ */
+hb_face_t *
+hb_directwrite_face_create_from_file_or_fail (const char   *file_name,
+					      unsigned int  index)
+{
+  auto *blob = hb_blob_create_from_file_or_fail (file_name);
+  if (unlikely (!blob))
+    return nullptr;
+
+  return hb_directwrite_face_create_from_blob_or_fail (blob, index);
+}
+
+/**
+ * hb_directwrite_face_create_from_blob_or_fail:
+ * @blob: A blob containing the font data
+ * @index: The index of the face within the blob
+ *
+ * Creates an #hb_face_t face object from the specified
+ * blob and face index.
+ *
+ * This is similar in functionality to hb_face_create_from_blob_or_fail(),
+ * but uses the DirectWrite library for loading the font data.
+ *
+ * Return value: (transfer full): The new face object, or `NULL` if
+ * no face is found at the specified index or the blob cannot be read.
+ *
+ * Since: 11.0.0
+ */
+HB_EXTERN hb_face_t *
+hb_directwrite_face_create_from_blob_or_fail (hb_blob_t    *blob,
+					      unsigned int  index)
+{
+  IDWriteFontFace *dw_face = dw_face_create (blob, index);
+  if (unlikely (!dw_face))
+    return nullptr;
+
+  hb_face_t *face = hb_directwrite_face_create (dw_face);
+  if (unlikely (hb_object_is_immutable (face)))
+  {
+    dw_face->Release ();
+    return face;
+  }
+
+  /* Let there be dragons here... */
+  face->data.directwrite.cmpexch (nullptr, (hb_directwrite_face_data_t *) dw_face);
+
+  return face;
 }
 
 /**
@@ -880,7 +302,7 @@ hb_directwrite_face_create (IDWriteFontFace *dw_face)
 IDWriteFontFace *
 hb_directwrite_face_get_dw_font_face (hb_face_t *face)
 {
-  return face->data.directwrite->fontFace;
+  return (IDWriteFontFace *) (const void *) face->data.directwrite;
 }
 
 #ifndef HB_DISABLE_DEPRECATED
@@ -906,29 +328,25 @@ hb_directwrite_face_get_font_face (hb_face_t *face)
 
 /**
  * hb_directwrite_font_create:
- * @dw_font: a DirectWrite IDWriteFont object.
+ * @dw_face: a DirectWrite IDWriteFontFace object.
  *
- * Constructs a new font object from the specified DirectWrite IDWriteFont.
+ * Constructs a new font object from the specified DirectWrite IDWriteFontFace.
  *
  * Return value: #hb_font_t object corresponding to the given input
  *
- * Since: 10.3.0
+ * Since: 11.0.0
  **/
 hb_font_t *
-hb_directwrite_font_create (IDWriteFont *dw_font)
+hb_directwrite_font_create (IDWriteFontFace *dw_face)
 {
-  IDWriteFontFace *dw_face = nullptr;
   IDWriteFontFace5 *dw_face5 = nullptr;
 
-  if (FAILED (dw_font->CreateFontFace (&dw_face)))
-    return hb_font_get_empty ();
-
   hb_face_t *face = hb_directwrite_face_create (dw_face);
   hb_font_t *font = hb_font_create (face);
   hb_face_destroy (face);
 
   if (unlikely (hb_object_is_immutable (font)))
-    goto done;
+    return font;
 
   /* Copy font variations */
   if (SUCCEEDED (dw_face->QueryInterface (__uuidof (IDWriteFontFace5), (void**) &dw_face5)))
@@ -945,7 +363,7 @@ hb_directwrite_font_create (IDWriteFont *dw_font)
 	{
 	  for (uint32_t i = 0; i < count; ++i)
 	  {
-	    hb_tag_t tag = values[i].axisTag;
+	    hb_tag_t tag = hb_uint32_swap (values[i].axisTag);
 	    float value = values[i].value;
 	    vars[i] = {tag, value};
 	  }
@@ -956,28 +374,45 @@ hb_directwrite_font_create (IDWriteFont *dw_font)
     dw_face5->Release ();
   }
 
-  dw_font->AddRef ();
-  font->data.directwrite.cmpexch (nullptr, (hb_directwrite_font_data_t *) dw_font);
+  /* Let there be dragons here... */
+  dw_face->AddRef ();
+  font->data.directwrite.cmpexch (nullptr, (hb_directwrite_font_data_t *) dw_face);
 
-done:
-  dw_face->Release ();
   return font;
 }
 
+/**
+* hb_directwrite_font_get_dw_font_face:
+* @font: a #hb_font_t object
+*
+* Gets the DirectWrite IDWriteFontFace associated with @font.
+*
+* Return value: DirectWrite IDWriteFontFace object corresponding to the given input
+*
+* Since: 11.0.0
+**/
+IDWriteFontFace *
+hb_directwrite_font_get_dw_font_face (hb_font_t *font)
+{
+  return (IDWriteFontFace *) (const void *) font->data.directwrite;
+}
+
+
 /**
 * hb_directwrite_font_get_dw_font:
 * @font: a #hb_font_t object
 *
-* Gets the DirectWrite IDWriteFont associated with @font.
+* Deprecated.
 *
-* Return value: DirectWrite IDWriteFont object corresponding to the given input
+* Return value: Returns `NULL`.
 *
 * Since: 10.3.0
+* Deprecated: 11.0.0:
 **/
 IDWriteFont *
 hb_directwrite_font_get_dw_font (hb_font_t *font)
 {
-  return (IDWriteFont *) (const void *) font->data.directwrite;
+  return nullptr;
 }
 
 #endif
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.h
index 121569c15362c9a4a053424514275f07e6bc5bcf..a05b1a40ebb8c9fe7ee6289a027d09d65bd75281 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.h
@@ -27,19 +27,32 @@
 
 #include "hb.h"
 
+#include <dwrite_3.h>
+
 HB_BEGIN_DECLS
 
 HB_EXTERN hb_face_t *
 hb_directwrite_face_create (IDWriteFontFace *dw_face);
 
+HB_EXTERN hb_face_t *
+hb_directwrite_face_create_from_file_or_fail (const char   *file_name,
+					      unsigned int  index);
+
+HB_EXTERN hb_face_t *
+hb_directwrite_face_create_from_blob_or_fail (hb_blob_t    *blob,
+					      unsigned int  index);
+
 HB_EXTERN IDWriteFontFace *
 hb_directwrite_face_get_dw_font_face (hb_face_t *face);
 
 HB_EXTERN hb_font_t *
-hb_directwrite_font_create (IDWriteFont *dw_font);
+hb_directwrite_font_create (IDWriteFontFace *dw_face);
 
-HB_EXTERN IDWriteFont *
-hb_directwrite_font_get_dw_font (hb_font_t *font);
+HB_EXTERN IDWriteFontFace *
+hb_directwrite_font_get_dw_font_face (hb_font_t *font);
+
+HB_EXTERN void
+hb_directwrite_font_set_funcs (hb_font_t *font);
 
 #ifndef HB_DISABLE_DEPRECATED
 
@@ -47,6 +60,10 @@ HB_DEPRECATED_FOR (hb_directwrite_face_get_dw_font_face)
 HB_EXTERN IDWriteFontFace *
 hb_directwrite_face_get_font_face (hb_face_t *face);
 
+HB_DEPRECATED
+HB_EXTERN IDWriteFont *
+hb_directwrite_font_get_dw_font (hb_font_t *font);
+
 #endif
 
 HB_END_DECLS
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.hh
new file mode 100644
index 0000000000000000000000000000000000000000..f51ab059abd93db38876564939eb12b819017621
--- /dev/null
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.hh
@@ -0,0 +1,243 @@
+/*
+ *  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_DIRECTWRITE_HH
+#define HB_DIRECTWRITE_HH
+
+#include "hb.hh"
+
+#include "hb-directwrite.h"
+
+#include "hb-mutex.hh"
+#include "hb-map.hh"
+
+/*
+ * DirectWrite font stream helpers
+ */
+
+// Have a look at to NativeFontResourceDWrite.cpp in Mozilla
+
+
+/* Declare object creator for dynamic support of DWRITE */
+typedef HRESULT (WINAPI *t_DWriteCreateFactory)(
+  DWRITE_FACTORY_TYPE factoryType,
+  REFIID              iid,
+  IUnknown            **factory
+);
+
+class DWriteFontFileLoader : public IDWriteFontFileLoader
+{
+private:
+  hb_reference_count_t mRefCount;
+  hb_mutex_t mutex;
+  hb_hashmap_t<uint64_t, IDWriteFontFileStream *> mFontStreams;
+  uint64_t mNextFontFileKey = 0;
+public:
+  DWriteFontFileLoader ()
+  {
+    mRefCount.init ();
+  }
+
+  uint64_t RegisterFontFileStream (IDWriteFontFileStream *fontFileStream)
+  {
+    fontFileStream->AddRef ();
+    auto lock = hb_lock_t (mutex);
+    mFontStreams.set (mNextFontFileKey, fontFileStream);
+    return mNextFontFileKey++;
+  }
+  void UnregisterFontFileStream (uint64_t fontFileKey)
+  {
+    auto lock = hb_lock_t (mutex);
+    IDWriteFontFileStream *stream = mFontStreams.get (fontFileKey);
+    if (stream)
+    {
+      mFontStreams.del (fontFileKey);
+      stream->Release ();
+    }
+  }
+
+  // IUnknown interface
+  IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
+  { return S_OK; }
+  IFACEMETHOD_ (ULONG, AddRef) ()
+  {
+    return mRefCount.inc () + 1;
+  }
+  IFACEMETHOD_ (ULONG, Release) ()
+  {
+    signed refCount = mRefCount.dec () - 1;
+    assert (refCount >= 0);
+    if (refCount)
+      return refCount;
+    delete this;
+    return 0;
+  }
+
+  // IDWriteFontFileLoader methods
+  virtual HRESULT STDMETHODCALLTYPE
+  CreateStreamFromKey (void const* fontFileReferenceKey,
+		       uint32_t fontFileReferenceKeySize,
+		       OUT IDWriteFontFileStream** fontFileStream)
+  {
+    if (fontFileReferenceKeySize != sizeof (uint64_t))
+      return E_INVALIDARG;
+    uint64_t fontFileKey = * (uint64_t *) fontFileReferenceKey;
+    IDWriteFontFileStream *stream = mFontStreams.get (fontFileKey);
+    if (!stream)
+      return E_FAIL;
+    stream->AddRef ();
+    *fontFileStream = stream;
+    return S_OK;
+  }
+
+  virtual ~DWriteFontFileLoader()
+  {
+    for (auto v : mFontStreams.values ())
+      v->Release ();
+  }
+};
+
+class DWriteFontFileStream : public IDWriteFontFileStream
+{
+private:
+  hb_reference_count_t mRefCount;
+  hb_blob_t *mBlob;
+  uint8_t *mData;
+  unsigned mSize;
+  DWriteFontFileLoader *mLoader;
+public:
+  uint64_t fontFileKey;
+public:
+  DWriteFontFileStream (hb_blob_t *blob);
+
+  // IUnknown interface
+  IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
+  { return S_OK; }
+  IFACEMETHOD_ (ULONG, AddRef) ()
+  {
+    return mRefCount.inc () + 1;
+  }
+  IFACEMETHOD_ (ULONG, Release) ()
+  {
+    signed refCount = mRefCount.dec () - 1;
+    assert (refCount >= 0);
+    if (refCount)
+      return refCount;
+    delete this;
+    return 0;
+  }
+
+  // IDWriteFontFileStream methods
+  virtual HRESULT STDMETHODCALLTYPE
+  ReadFileFragment (void const** fragmentStart,
+		    UINT64 fileOffset,
+		    UINT64 fragmentSize,
+		    OUT void** fragmentContext)
+  {
+    // We are required to do bounds checking.
+    if (fileOffset + fragmentSize > mSize) return E_FAIL;
+
+    // truncate the 64 bit fileOffset to size_t sized index into mData
+    size_t index = static_cast<size_t> (fileOffset);
+
+    // We should be alive for the duration of this.
+    *fragmentStart = &mData[index];
+    *fragmentContext = nullptr;
+    return S_OK;
+  }
+
+  virtual void STDMETHODCALLTYPE
+  ReleaseFileFragment (void* fragmentContext) {}
+
+  virtual HRESULT STDMETHODCALLTYPE
+  GetFileSize (OUT UINT64* fileSize)
+  {
+    *fileSize = mSize;
+    return S_OK;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE
+  GetLastWriteTime (OUT UINT64* lastWriteTime) { return E_NOTIMPL; }
+
+  virtual ~DWriteFontFileStream();
+};
+
+struct hb_directwrite_global_t
+{
+  hb_directwrite_global_t ()
+  {
+    dwrite_dll = LoadLibraryW (L"DWrite.dll");
+
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+
+    t_DWriteCreateFactory p_DWriteCreateFactory = (t_DWriteCreateFactory)
+			    GetProcAddress (dwrite_dll, "DWriteCreateFactory");
+
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+    if (unlikely (!p_DWriteCreateFactory))
+      return;
+
+    HRESULT hr = p_DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
+					(IUnknown**) &dwriteFactory);
+
+    if (unlikely (hr != S_OK))
+      return;
+
+    fontFileLoader = new DWriteFontFileLoader ();
+    dwriteFactory->RegisterFontFileLoader (fontFileLoader);
+
+    success = true;
+  }
+  ~hb_directwrite_global_t ()
+  {
+    if (fontFileLoader)
+      fontFileLoader->Release ();
+    if (dwriteFactory)
+      dwriteFactory->Release ();
+    if (dwrite_dll)
+      FreeLibrary (dwrite_dll);
+  }
+
+  bool success = false;
+  HMODULE dwrite_dll;
+  IDWriteFactory *dwriteFactory;
+  DWriteFontFileLoader *fontFileLoader;
+};
+
+
+HB_INTERNAL hb_directwrite_global_t *
+get_directwrite_global ();
+
+HB_INTERNAL IDWriteFontFace *
+dw_face_create (hb_blob_t *blob, unsigned index);
+
+
+#endif /* HB_DIRECTWRITE_HH */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-draw.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-draw.h
index 6306b69c09b56948188377fccf4d693ccb013ce4..de36901e2a70af7aa16fa6bbd755944c79215964 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-draw.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-draw.h
@@ -41,9 +41,16 @@ HB_BEGIN_DECLS
  * @path_start_y: Y component of the start of current path
  * @current_x: X component of current point
  * @current_y: Y component of current point
+ * @slant_xy: (Since: 11.0.0): Slanting factor for synthetic oblique
  *
  * Current drawing state.
  *
+ * The @slant_xy is a slanting factor for synthetic oblique. If the font's
+ * oblique angle is not 0, this factor is used to slant the drawing. For
+ * fonts with uniform x and y scales, this factor is calculated as
+ * tan(oblique_angle). For fonts with non-uniform scales, this factor is
+ * calculated as tan(oblique_angle) * x_scale / y_scale, or 0 if y_scale is 0.
+ *
  * Since: 4.0.0
  **/
 typedef struct hb_draw_state_t {
@@ -55,6 +62,8 @@ typedef struct hb_draw_state_t {
   float current_x;
   float current_y;
 
+  float slant_xy;
+
   /*< private >*/
   hb_var_num_t   reserved1;
   hb_var_num_t   reserved2;
@@ -62,7 +71,6 @@ typedef struct hb_draw_state_t {
   hb_var_num_t   reserved4;
   hb_var_num_t   reserved5;
   hb_var_num_t   reserved6;
-  hb_var_num_t   reserved7;
 } hb_draw_state_t;
 
 /**
@@ -70,7 +78,7 @@ typedef struct hb_draw_state_t {
  *
  * The default #hb_draw_state_t at the start of glyph drawing.
  */
-#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}}
+#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}}
 
 
 /**
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-draw.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-draw.hh
index 87d03a4882244449ed8aa66bee8d68ba1c25a9b0..15978cdf0a37bcd32eee299f6b447c5f114fb514 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-draw.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-draw.hh
@@ -99,6 +99,10 @@ struct hb_draw_funcs_t
 	   float to_x, float to_y)
   {
     if (unlikely (st.path_open)) close_path (draw_data, st);
+
+    if (st.slant_xy)
+      to_x += to_y * st.slant_xy;
+
     st.current_x = to_x;
     st.current_y = to_y;
   }
@@ -109,7 +113,12 @@ struct hb_draw_funcs_t
 	   float to_x, float to_y)
   {
     if (unlikely (!st.path_open)) start_path (draw_data, st);
+
+    if (st.slant_xy)
+      to_x += to_y * st.slant_xy;
+
     emit_line_to (draw_data, st, to_x, to_y);
+
     st.current_x = to_x;
     st.current_y = to_y;
   }
@@ -121,7 +130,15 @@ struct hb_draw_funcs_t
 		float to_x, float to_y)
   {
     if (unlikely (!st.path_open)) start_path (draw_data, st);
+
+    if (st.slant_xy)
+    {
+      control_x += control_y * st.slant_xy;
+      to_x += to_y * st.slant_xy;
+    }
+
     emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y);
+
     st.current_x = to_x;
     st.current_y = to_y;
   }
@@ -134,7 +151,16 @@ struct hb_draw_funcs_t
 	    float to_x, float to_y)
   {
     if (unlikely (!st.path_open)) start_path (draw_data, st);
+
+    if (st.slant_xy)
+    {
+      control1_x += control1_y * st.slant_xy;
+      control2_x += control2_y * st.slant_xy;
+      to_x += to_y * st.slant_xy;
+    }
+
     emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
+
     st.current_x = to_x;
     st.current_y = to_y;
   }
@@ -168,46 +194,32 @@ DECLARE_NULL_INSTANCE (hb_draw_funcs_t);
 
 struct hb_draw_session_t
 {
-  hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_ = 0.f)
-    : slant {slant_}, not_slanted {slant == 0.f},
-      funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT
-  {}
+  hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_xy = 0.f)
+    : funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT
+  { st.slant_xy = slant_xy; }
 
   ~hb_draw_session_t () { close_path (); }
 
   HB_ALWAYS_INLINE
   void move_to (float to_x, float to_y)
   {
-    if (likely (not_slanted))
-      funcs->move_to (draw_data, st,
-		      to_x, to_y);
-    else
-      funcs->move_to (draw_data, st,
-		      to_x + to_y * slant, to_y);
+    funcs->move_to (draw_data, st,
+		    to_x, to_y);
   }
   HB_ALWAYS_INLINE
   void line_to (float to_x, float to_y)
   {
-    if (likely (not_slanted))
-      funcs->line_to (draw_data, st,
-		      to_x, to_y);
-    else
-      funcs->line_to (draw_data, st,
-		      to_x + to_y * slant, to_y);
+    funcs->line_to (draw_data, st,
+		    to_x, to_y);
   }
   void
   HB_ALWAYS_INLINE
   quadratic_to (float control_x, float control_y,
 		float to_x, float to_y)
   {
-    if (likely (not_slanted))
-      funcs->quadratic_to (draw_data, st,
-			   control_x, control_y,
-			   to_x, to_y);
-    else
-      funcs->quadratic_to (draw_data, st,
-			   control_x + control_y * slant, control_y,
-			   to_x + to_y * slant, to_y);
+    funcs->quadratic_to (draw_data, st,
+			 control_x, control_y,
+			 to_x, to_y);
   }
   void
   HB_ALWAYS_INLINE
@@ -215,16 +227,10 @@ struct hb_draw_session_t
 	    float control2_x, float control2_y,
 	    float to_x, float to_y)
   {
-    if (likely (not_slanted))
-      funcs->cubic_to (draw_data, st,
-		       control1_x, control1_y,
-		       control2_x, control2_y,
-		       to_x, to_y);
-    else
-      funcs->cubic_to (draw_data, st,
-		       control1_x + control1_y * slant, control1_y,
-		       control2_x + control2_y * slant, control2_y,
-		       to_x + to_y * slant, to_y);
+    funcs->cubic_to (draw_data, st,
+		     control1_x, control1_y,
+		     control2_x, control2_y,
+		     to_x, to_y);
   }
   HB_ALWAYS_INLINE
   void close_path ()
@@ -233,8 +239,6 @@ struct hb_draw_session_t
   }
 
   public:
-  float slant;
-  bool not_slanted;
   hb_draw_funcs_t *funcs;
   void *draw_data;
   hb_draw_state_t st;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-face.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-face.cc
index 002bb37d4c7b2ed772f8b7d878b4de3d4d895868..9051247bc95ffec966fac016cc26c9afa4fc4706 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-face.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-face.cc
@@ -34,6 +34,16 @@
 #include "hb-ot-face.hh"
 #include "hb-ot-cmap-table.hh"
 
+#ifdef HAVE_FREETYPE
+#include "hb-ft.h"
+#endif
+#ifdef HAVE_CORETEXT
+#include "hb-coretext.h"
+#endif
+#ifdef HAVE_DIRECTWRITE
+#include "hb-directwrite.h"
+#endif
+
 
 /**
  * SECTION:hb-face
@@ -72,14 +82,14 @@ hb_face_count (hb_blob_t *blob)
   if (unlikely (!blob))
     return 0;
 
-  /* TODO We shouldn't be sanitizing blob.  Port to run sanitizer and return if not sane. */
-  /* Make API signature const after. */
-  hb_blob_t *sanitized = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
-  const OT::OpenTypeFontFile& ot = *sanitized->as<OT::OpenTypeFontFile> ();
-  unsigned int ret = ot.get_face_count ();
-  hb_blob_destroy (sanitized);
+  hb_sanitize_context_t c (blob);
+
+  const char *start = hb_blob_get_data (blob, nullptr);
+  auto *ot = reinterpret_cast<OT::OpenTypeFontFile *> (const_cast<char *> (start));
+  if (unlikely (!ot->sanitize (&c)))
+    return 0;
 
-  return ret;
+  return ot->get_face_count ();
 }
 
 /*
@@ -318,7 +328,209 @@ hb_face_create_from_file_or_fail (const char   *file_name,
 
   return face;
 }
+
+static 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);
+} supported_face_loaders[] =
+{
+  {"ot",
+#ifndef HB_NO_OPEN
+   hb_face_create_from_file_or_fail,
+#else
+   nullptr,
+#endif
+   hb_face_create_or_fail
+  },
+#ifdef HAVE_FREETYPE
+  {"ft",
+   hb_ft_face_create_from_file_or_fail,
+   hb_ft_face_create_from_blob_or_fail
+  },
+#endif
+#ifdef HAVE_CORETEXT
+  {"coretext",
+   hb_coretext_face_create_from_file_or_fail,
+   hb_coretext_face_create_from_blob_or_fail
+  },
 #endif
+#ifdef HAVE_DIRECTWRITE
+  {"directwrite",
+   hb_directwrite_face_create_from_file_or_fail,
+   hb_directwrite_face_create_from_blob_or_fail
+  },
+#endif
+};
+
+static const char *get_default_loader_name ()
+{
+  static hb_atomic_t<const char *> static_loader_name;
+  const char *loader_name = static_loader_name.get_acquire ();
+  if (!loader_name)
+  {
+    loader_name = getenv ("HB_FACE_LOADER");
+    if (!loader_name)
+      loader_name = "";
+    if (!static_loader_name.cmpexch (nullptr, loader_name))
+      loader_name = static_loader_name.get_acquire ();
+  }
+  return loader_name;
+}
+
+/**
+ * hb_face_create_from_file_or_fail_using:
+ * @file_name: A font filename
+ * @index: The index of the face within the file
+ * @loader_name: (nullable): The name of the loader to use, or `NULL`
+ *
+ * A thin wrapper around the face loader functions registered with HarfBuzz.
+ * If @loader_name is `NULL` or the empty string, the first available loader
+ * is used.
+ *
+ * For example, the FreeType ("ft") loader might be able to load
+ * WOFF and WOFF2 files if FreeType is built with those features,
+ * whereas the OpenType ("ot") loader will not.
+ *
+ * Return value: (transfer full): The new face object, or `NULL` if
+ * the file cannot be read or the loader fails to load the face.
+ *
+ * Since: 11.0.0
+ **/
+hb_face_t *
+hb_face_create_from_file_or_fail_using (const char   *file_name,
+					unsigned int  index,
+					const char   *loader_name)
+{
+  // Duplicated in hb_face_create_or_fail_using
+  bool retry = false;
+  if (!loader_name || !*loader_name)
+  {
+    loader_name = get_default_loader_name ();
+    retry = true;
+  }
+  if (loader_name && !*loader_name) loader_name = nullptr;
+
+retry:
+  for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
+  {
+    if (!loader_name || (supported_face_loaders[i].from_file && !strcmp (supported_face_loaders[i].name, loader_name)))
+      return supported_face_loaders[i].from_file (file_name, index);
+  }
+
+  if (retry)
+  {
+    retry = false;
+    loader_name = nullptr;
+    goto retry;
+  }
+
+  return nullptr;
+}
+
+/**
+ * hb_face_create_or_fail_using:
+ * @blob: #hb_blob_t to work upon
+ * @index: The index of the face within @blob
+ * @loader_name: (nullable): The name of the loader to use, or `NULL`
+ *
+ * A thin wrapper around the face loader functions registered with HarfBuzz.
+ * If @loader_name is `NULL` or the empty string, the first available loader
+ * is used.
+ *
+ * For example, the FreeType ("ft") loader might be able to load
+ * WOFF and WOFF2 files if FreeType is built with those features,
+ * whereas the OpenType ("ot") loader will not.
+ *
+ * Return value: (transfer full): The new face object, or `NULL` if
+ * the loader fails to load the face.
+ *
+ * Since: 11.0.0
+ **/
+hb_face_t *
+hb_face_create_or_fail_using (hb_blob_t    *blob,
+			      unsigned int  index,
+			      const char   *loader_name)
+{
+  // Duplicated in hb_face_create_from_file_or_fail_using
+  bool retry = false;
+  if (!loader_name || !*loader_name)
+  {
+    loader_name = get_default_loader_name ();
+    retry = true;
+  }
+  if (loader_name && !*loader_name) loader_name = nullptr;
+
+retry:
+  for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
+  {
+    if (!loader_name || (supported_face_loaders[i].from_blob && !strcmp (supported_face_loaders[i].name, loader_name)))
+      return supported_face_loaders[i].from_blob (blob, index);
+  }
+
+  if (retry)
+  {
+    retry = false;
+    loader_name = nullptr;
+    goto retry;
+  }
+
+  return nullptr;
+}
+
+static inline void free_static_face_loader_list ();
+
+static const char * const nil_face_loader_list[] = {nullptr};
+
+static struct hb_face_loader_list_lazy_loader_t : hb_lazy_loader_t<const char *,
+								  hb_face_loader_list_lazy_loader_t>
+{
+  static const char ** create ()
+  {
+    const char **face_loader_list = (const char **) hb_calloc (1 + ARRAY_LENGTH (supported_face_loaders), sizeof (const char *));
+    if (unlikely (!face_loader_list))
+      return nullptr;
+
+    unsigned i;
+    for (i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
+      face_loader_list[i] = supported_face_loaders[i].name;
+    face_loader_list[i] = nullptr;
+
+    hb_atexit (free_static_face_loader_list);
+
+    return face_loader_list;
+  }
+  static void destroy (const char **l)
+  { hb_free (l); }
+  static const char * const * get_null ()
+  { return nil_face_loader_list; }
+} static_face_loader_list;
+
+static inline
+void free_static_face_loader_list ()
+{
+  static_face_loader_list.free_instance ();
+}
+
+/**
+ * hb_face_list_loaders:
+ *
+ * Retrieves the list of face loaders supported by HarfBuzz.
+ *
+ * Return value: (transfer none) (array zero-terminated=1): a
+ *    `NULL`-terminated array of supported face loaders
+ *    constant strings. The returned array is owned by HarfBuzz
+ *    and should not be modified or freed.
+ *
+ * Since: 11.0.0
+ **/
+const char **
+hb_face_list_loaders ()
+{
+  return static_face_loader_list.get_unconst ();
+}
+#endif
+
 
 /**
  * hb_face_get_empty:
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-face.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-face.h
index afc198547734a53ceaeac463b199b9a7850f1c1b..5d39a48cc63e9dc5fa9272f1bf0f376e2c625940 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-face.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-face.h
@@ -63,10 +63,24 @@ HB_EXTERN hb_face_t *
 hb_face_create_or_fail (hb_blob_t    *blob,
 			unsigned int  index);
 
+HB_EXTERN hb_face_t *
+hb_face_create_or_fail_using (hb_blob_t    *blob,
+			      unsigned int  index,
+			      const char   *loader_name);
+
 HB_EXTERN hb_face_t *
 hb_face_create_from_file_or_fail (const char   *file_name,
 				  unsigned int  index);
 
+HB_EXTERN hb_face_t *
+hb_face_create_from_file_or_fail_using (const char   *file_name,
+					unsigned int  index,
+					const char   *loader_name);
+
+HB_EXTERN const char **
+hb_face_list_loaders (void);
+
+
 /**
  * hb_reference_table_func_t:
  * @face: an #hb_face_t to reference table for
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-face.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-face.hh
index 6401568326b2f3ba3d6460f8c974ea061400937c..77c2437213cab62ca35d230ca0d734a0c069f463 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-face.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-face.hh
@@ -49,8 +49,8 @@ struct hb_face_t
   hb_object_header_t header;
 
   unsigned int index;			/* Face index in a collection, zero-based. */
-  mutable hb_atomic_int_t upem;		/* Units-per-EM. */
-  mutable hb_atomic_int_t num_glyphs;	/* Number of glyphs. */
+  mutable hb_atomic_t<unsigned> upem;	/* Units-per-EM. */
+  mutable hb_atomic_t<unsigned> num_glyphs;/* Number of glyphs. */
 
   hb_reference_table_func_t  reference_table_func;
   void                      *user_data;
@@ -70,7 +70,7 @@ struct hb_face_t
     plan_node_t *next;
   };
 #ifndef HB_NO_SHAPER
-  hb_atomic_ptr_t<plan_node_t> shape_plans;
+  hb_atomic_t<plan_node_t *> shape_plans;
 #endif
 
   hb_blob_t *reference_table (hb_tag_t tag) const
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-font.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-font.cc
index 96b79ecca752d052226650be0463a26a641cd424..b73a87048812d9438a77900940f23c53376dab8f 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-font.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-font.cc
@@ -38,6 +38,22 @@
 #include "hb-ot-var-avar-table.hh"
 #include "hb-ot-var-fvar-table.hh"
 
+#ifndef HB_NO_OT_FONT
+#include "hb-ot.h"
+#endif
+#ifdef HAVE_FREETYPE
+#include "hb-ft.h"
+#endif
+#ifdef HAVE_FONTATIONS
+#include "hb-fontations.h"
+#endif
+#ifdef HAVE_CORETEXT
+#include "hb-coretext.h"
+#endif
+#ifdef HAVE_DIRECTWRITE
+#include "hb-directwrite.h"
+#endif
+
 
 /**
  * SECTION:hb-font
@@ -1854,10 +1870,7 @@ hb_font_create (hb_face_t *face)
 {
   hb_font_t *font = _hb_font_create (face);
 
-#ifndef HB_NO_OT_FONT
-  /* Install our in-house, very lightweight, funcs. */
-  hb_ot_font_set_funcs (font);
-#endif
+  hb_font_set_funcs_using (font, nullptr);
 
 #ifndef HB_NO_VAR
   if (face && face->index >> 16)
@@ -1880,7 +1893,7 @@ _hb_font_adopt_var_coords (hb_font_t *font,
   font->design_coords = design_coords;
   font->num_coords = coords_length;
 
-  font->mults_changed (); // Easiest to call this to drop cached data
+  font->changed ();
 }
 
 /**
@@ -1935,7 +1948,8 @@ hb_font_create_sub_font (hb_font_t *parent)
     }
   }
 
-  font->mults_changed ();
+  font->changed ();
+  font->serial_coords = font->serial;
 
   return font;
 }
@@ -2023,7 +2037,7 @@ hb_font_set_user_data (hb_font_t          *font,
 		       hb_bool_t           replace)
 {
   if (!hb_object_is_immutable (font))
-    font->serial++;
+    font->changed ();
 
   return hb_object_set_user_data (font, key, data, destroy, replace);
 }
@@ -2098,7 +2112,7 @@ hb_font_is_immutable (hb_font_t *font)
 unsigned int
 hb_font_get_serial (hb_font_t *font)
 {
-  return font->serial;
+  return font->serial.get_acquire ();
 }
 
 /**
@@ -2117,9 +2131,7 @@ hb_font_changed (hb_font_t *font)
   if (hb_object_is_immutable (font))
     return;
 
-  font->serial++;
-
-  font->mults_changed ();
+  font->changed ();
 }
 
 /**
@@ -2141,8 +2153,6 @@ hb_font_set_parent (hb_font_t *font,
   if (parent == font->parent)
     return;
 
-  font->serial++;
-
   if (!parent)
     parent = hb_font_get_empty ();
 
@@ -2151,6 +2161,8 @@ hb_font_set_parent (hb_font_t *font,
   font->parent = hb_font_reference (parent);
 
   hb_font_destroy (old);
+
+  font->changed ();
 }
 
 /**
@@ -2188,8 +2200,6 @@ hb_font_set_face (hb_font_t *font,
   if (face == font->face)
     return;
 
-  font->serial++;
-
   if (unlikely (!face))
     face = hb_face_get_empty ();
 
@@ -2197,9 +2207,11 @@ hb_font_set_face (hb_font_t *font,
 
   hb_face_make_immutable (face);
   font->face = hb_face_reference (face);
-  font->mults_changed ();
+  font->changed ();
 
   hb_face_destroy (old);
+
+  font->changed ();
 }
 
 /**
@@ -2244,8 +2256,6 @@ hb_font_set_funcs (hb_font_t         *font,
     return;
   }
 
-  font->serial++;
-
   if (font->destroy)
     font->destroy (font->user_data);
 
@@ -2257,6 +2267,8 @@ hb_font_set_funcs (hb_font_t         *font,
   font->klass = klass;
   font->user_data = font_data;
   font->destroy = destroy;
+
+  font->changed ();
 }
 
 /**
@@ -2283,15 +2295,151 @@ hb_font_set_funcs_data (hb_font_t         *font,
     return;
   }
 
-  font->serial++;
-
   if (font->destroy)
     font->destroy (font->user_data);
 
   font->user_data = font_data;
   font->destroy = destroy;
+
+  font->changed ();
 }
 
+static struct supported_font_funcs_t {
+	char name[16];
+	void (*func) (hb_font_t *);
+} supported_font_funcs[] =
+{
+#ifndef HB_NO_OT_FONT
+  {"ot",	hb_ot_font_set_funcs},
+#endif
+#ifdef HAVE_FREETYPE
+  {"ft",	hb_ft_font_set_funcs},
+#endif
+#ifdef HAVE_FONTATIONS
+  {"fontations",hb_fontations_font_set_funcs},
+#endif
+#ifdef HAVE_CORETEXT
+  {"coretext",	hb_coretext_font_set_funcs},
+#endif
+#ifdef HAVE_DIRECTWRITE
+  {"directwrite",hb_directwrite_font_set_funcs},
+#endif
+};
+
+static const char *get_default_funcs_name ()
+{
+  static hb_atomic_t<const char *> static_funcs_name;
+  const char *name = static_funcs_name.get_acquire ();
+  if (!name)
+  {
+    name = getenv ("HB_FONT_FUNCS");
+    if (!name)
+      name = "";
+    if (!static_funcs_name.cmpexch (nullptr, name))
+      name = static_funcs_name.get_acquire ();
+  }
+  return name;
+}
+
+/**
+ * hb_font_set_funcs_using:
+ * @font: #hb_font_t to work upon
+ * @name: The name of the font-functions structure to use, or `NULL`
+ *
+ * Sets the font-functions structure to use for a font, based on the
+ * specified name.
+ *
+ * If @name is `NULL` or the empty string, the default (first) functioning font-functions
+ * are used.  This default can be changed by setting the `HB_FONT_FUNCS` environment
+ * variable to the name of the desired font-functions.
+ *
+ * Return value: `true` if the font-functions was found and set, `false` otherwise
+ *
+ * Since: 11.0.0
+ **/
+hb_bool_t
+hb_font_set_funcs_using (hb_font_t  *font,
+			 const char *name)
+{
+  bool retry = false;
+
+  if (!name || !*name)
+  {
+    name = get_default_funcs_name ();
+    retry = true;
+  }
+  if (name && !*name) name = nullptr;
+
+retry:
+  for (unsigned i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++)
+    if (!name || strcmp (supported_font_funcs[i].name, name) == 0)
+    {
+      supported_font_funcs[i].func (font);
+      if (name || font->klass != hb_font_funcs_get_empty ())
+	return true;
+    }
+
+  if (retry)
+  {
+    retry = false;
+    name = nullptr;
+    goto retry;
+  }
+
+  return false;
+}
+
+static inline void free_static_font_funcs_list ();
+
+static const char * const nil_font_funcs_list[] = {nullptr};
+
+static struct hb_font_funcs_list_lazy_loader_t : hb_lazy_loader_t<const char *,
+								  hb_font_funcs_list_lazy_loader_t>
+{
+  static const char ** create ()
+  {
+    const char **font_funcs_list = (const char **) hb_calloc (1 + ARRAY_LENGTH (supported_font_funcs), sizeof (const char *));
+    if (unlikely (!font_funcs_list))
+      return nullptr;
+
+    unsigned i;
+    for (i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++)
+      font_funcs_list[i] = supported_font_funcs[i].name;
+    font_funcs_list[i] = nullptr;
+
+    hb_atexit (free_static_font_funcs_list);
+
+    return font_funcs_list;
+  }
+  static void destroy (const char **l)
+  { hb_free (l); }
+  static const char * const * get_null ()
+  { return nil_font_funcs_list; }
+} static_font_funcs_list;
+
+static inline
+void free_static_font_funcs_list ()
+{
+  static_font_funcs_list.free_instance ();
+}
+
+/**
+ * hb_font_list_funcs:
+ *
+ * Retrieves the list of font functions supported by HarfBuzz.
+ *
+ * Return value: (transfer none) (array zero-terminated=1): a
+ *    `NULL`-terminated array of supported font functions
+ *    constant strings. The returned array is owned by HarfBuzz
+ *    and should not be modified or freed.
+ *
+ * Since: 11.0.0
+ **/
+const char **
+hb_font_list_funcs ()
+{
+  return static_font_funcs_list.get_unconst ();
+}
 
 /**
  * hb_font_set_scale:
@@ -2339,11 +2487,10 @@ hb_font_set_scale (hb_font_t *font,
   if (font->x_scale == x_scale && font->y_scale == y_scale)
     return;
 
-  font->serial++;
-
   font->x_scale = x_scale;
   font->y_scale = y_scale;
-  font->mults_changed ();
+
+  font->changed ();
 }
 
 /**
@@ -2390,10 +2537,10 @@ hb_font_set_ppem (hb_font_t    *font,
   if (font->x_ppem == x_ppem && font->y_ppem == y_ppem)
     return;
 
-  font->serial++;
-
   font->x_ppem = x_ppem;
   font->y_ppem = y_ppem;
+
+  font->changed ();
 }
 
 /**
@@ -2437,9 +2584,9 @@ hb_font_set_ptem (hb_font_t *font,
   if (font->ptem == ptem)
     return;
 
-  font->serial++;
-
   font->ptem = ptem;
+
+  font->changed ();
 }
 
 /**
@@ -2499,12 +2646,11 @@ hb_font_set_synthetic_bold (hb_font_t *font,
       font->embolden_in_place == (bool) in_place)
     return;
 
-  font->serial++;
-
   font->x_embolden = x_embolden;
   font->y_embolden = y_embolden;
   font->embolden_in_place = in_place;
-  font->mults_changed ();
+
+  font->changed ();
 }
 
 /**
@@ -2558,10 +2704,9 @@ hb_font_set_synthetic_slant (hb_font_t *font, float slant)
   if (font->slant == slant)
     return;
 
-  font->serial++;
-
   font->slant = slant;
-  font->mults_changed ();
+
+  font->changed ();
 }
 
 /**
@@ -2607,8 +2752,6 @@ hb_font_set_variations (hb_font_t            *font,
   if (hb_object_is_immutable (font))
     return;
 
-  font->serial_coords = ++font->serial;
-
   if (!variations_length && font->instance_index == HB_FONT_NO_VAR_NAMED_INSTANCE)
   {
     hb_font_set_var_coords_normalized (font, nullptr, 0);
@@ -2677,8 +2820,6 @@ hb_font_set_variation (hb_font_t *font,
   if (hb_object_is_immutable (font))
     return;
 
-  font->serial_coords = ++font->serial;
-
   // TODO Share some of this code with set_variations()
 
   const OT::fvar &fvar = *font->face->table.fvar;
@@ -2749,8 +2890,6 @@ hb_font_set_var_coords_design (hb_font_t    *font,
   if (hb_object_is_immutable (font))
     return;
 
-  font->serial_coords = ++font->serial;
-
   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;
 
@@ -2787,8 +2926,6 @@ hb_font_set_var_named_instance (hb_font_t *font,
   if (font->instance_index == instance_index)
     return;
 
-  font->serial_coords = ++font->serial;
-
   font->instance_index = instance_index;
   hb_font_set_variations (font, nullptr, 0);
 }
@@ -2834,8 +2971,6 @@ hb_font_set_var_coords_normalized (hb_font_t    *font,
   if (hb_object_is_immutable (font))
     return;
 
-  font->serial_coords = ++font->serial;
-
   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;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-font.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-font.h
index 3c2355af2d7254936bd71b0b7504372fa5169a50..478c808e128eb43fc0eb498a8cebc58f65ab9568 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-font.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-font.h
@@ -1052,6 +1052,12 @@ hb_font_set_funcs_data (hb_font_t         *font,
 			void              *font_data,
 			hb_destroy_func_t  destroy);
 
+HB_EXTERN hb_bool_t
+hb_font_set_funcs_using (hb_font_t  *font,
+			 const char *name);
+
+HB_EXTERN const char **
+hb_font_list_funcs (void);
 
 HB_EXTERN void
 hb_font_set_scale (hb_font_t *font,
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-font.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-font.hh
index 4c8190b0dd17d297acbbf9ca0bb44a510d2100e5..5945ec1c2fe3d774e8364fe21f7edb49c7713310 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-font.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-font.hh
@@ -32,6 +32,7 @@
 #include "hb.hh"
 
 #include "hb-face.hh"
+#include "hb-atomic.hh"
 #include "hb-shaper.hh"
 
 
@@ -105,8 +106,8 @@ DECLARE_NULL_INSTANCE (hb_font_funcs_t);
 struct hb_font_t
 {
   hb_object_header_t header;
-  unsigned int serial;
-  unsigned int serial_coords;
+  hb_atomic_t<unsigned> serial;
+  hb_atomic_t<unsigned> serial_coords;
 
   hb_font_t *parent;
   hb_face_t *face;
@@ -191,22 +192,33 @@ struct hb_font_t
 
   void scale_glyph_extents (hb_glyph_extents_t *extents)
   {
-    float x1 = em_fscale_x (extents->x_bearing);
-    float y1 = em_fscale_y (extents->y_bearing);
-    float x2 = em_fscale_x (extents->x_bearing + extents->width);
-    float y2 = em_fscale_y (extents->y_bearing + extents->height);
-
-    /* Apply slant. */
-    if (slant_xy)
-    {
-      x1 += hb_min (y1 * slant_xy, y2 * slant_xy);
-      x2 += hb_max (y1 * slant_xy, y2 * slant_xy);
-    }
+    float x1 = em_scale_x (extents->x_bearing);
+    float y1 = em_scale_y (extents->y_bearing);
+    float x2 = em_scale_x (extents->x_bearing + extents->width);
+    float y2 = em_scale_y (extents->y_bearing + extents->height);
 
     extents->x_bearing = floorf (x1);
     extents->y_bearing = floorf (y1);
     extents->width = ceilf (x2) - extents->x_bearing;
     extents->height = ceilf (y2) - extents->y_bearing;
+  }
+
+  void synthetic_glyph_extents (hb_glyph_extents_t *extents)
+  {
+    /* Apply slant. */
+    if (slant_xy)
+    {
+      hb_position_t x1 = extents->x_bearing;
+      hb_position_t y1 = extents->y_bearing;
+      hb_position_t x2 = extents->x_bearing + extents->width;
+      hb_position_t y2 = extents->y_bearing + extents->height;
+
+      x1 += floorf (hb_min (y1 * slant_xy, y2 * slant_xy));
+      x2 += ceilf (hb_max (y1 * slant_xy, y2 * slant_xy));
+
+      extents->x_bearing = x1;
+      extents->width = x2 - extents->x_bearing;
+    }
 
     if (x_strength || y_strength)
     {
@@ -389,10 +401,14 @@ struct hb_font_t
 			       hb_glyph_extents_t *extents)
   {
     hb_memset (extents, 0, sizeof (*extents));
-    return klass->get.f.glyph_extents (this, user_data,
-				       glyph,
-				       extents,
-				       !klass->user_data ? nullptr : klass->user_data->glyph_extents);
+    bool ret = klass->get.f.glyph_extents (this, user_data,
+					   glyph,
+					   extents,
+					   !klass->user_data ? nullptr : klass->user_data->glyph_extents);
+    if (ret)
+      synthetic_glyph_extents (extents);
+
+    return ret;
   }
 
   hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
@@ -686,7 +702,7 @@ struct hb_font_t
     return false;
   }
 
-  void mults_changed ()
+  void changed ()
   {
     float upem = face->get_upem ();
 
@@ -703,6 +719,8 @@ struct hb_font_t
     slant_xy = y_scale ? slant * x_scale / y_scale : 0.f;
 
     data.fini ();
+
+    serial++;
   }
 
   hb_position_t em_mult (int16_t v, int64_t mult)
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-fontations.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-fontations.h
new file mode 100644
index 0000000000000000000000000000000000000000..6a3fce0b577eaffff447bec351f1e8b77747a3b7
--- /dev/null
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-fontations.h
@@ -0,0 +1,56 @@
+/*
+ *  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_FONTATIONS_H
+#define HB_FONTATIONS_H
+
+#include "hb.h"
+
+/**
+ * SECTION: hb-fontations
+ * @title: hb-fontations
+ * @short_description: Fontations integration
+ * @include: hb-fontations.h
+ *
+ * Functions for using HarfBuzz with
+ * [Fontations](https://github.com/googlefonts/fontations/) fonts.
+ **/
+
+HB_BEGIN_DECLS
+
+/**
+ * hb_fontations_font_set_funcs:
+ * @font: #hb_font_t to work upon
+ *
+ * Configures the font-functions structure of the specified #hb_font_t font
+ * object to use Fontations font functions.
+ *
+ * Since: 11.0.0
+ **/
+HB_EXTERN void
+hb_fontations_font_set_funcs (hb_font_t *font);
+
+HB_END_DECLS
+
+#endif /* HB_FONTATIONS_H */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ft-colr.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ft-colr.hh
index c96698369d13f1521547cef65a94599b7309a629..b41d5555374876b5a31a5af64f42a27827788c46 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ft-colr.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ft-colr.hh
@@ -83,7 +83,7 @@ struct hb_ft_paint_context_t
   hb_ft_paint_context_t (const hb_ft_font_t *ft_font,
 			 hb_font_t *font,
 			 hb_paint_funcs_t *paint_funcs, void *paint_data,
-			 FT_Color *palette,
+			 hb_array_t<const FT_Color> palette,
 			 unsigned palette_index,
 			 hb_color_t foreground) :
     ft_font (ft_font), font(font),
@@ -103,7 +103,7 @@ struct hb_ft_paint_context_t
   hb_font_t *font;
   hb_paint_funcs_t *funcs;
   void *data;
-  FT_Color *palette;
+  hb_array_t<const FT_Color> palette;
   unsigned palette_index;
   hb_color_t foreground;
   hb_decycler_t glyphs_decycler;
@@ -167,7 +167,7 @@ _hb_ft_color_line_get_color_stops (hb_color_line_t *color_line,
 					 hb_color_get_red (color),
 					 (hb_color_get_alpha (color) * stop.color.alpha) >> 14);
 	}
-	else
+	else if (c->palette)
 	{
 	  FT_Color ft_color = c->palette[stop.color.palette_index];
 	  color_stops->color = HB_COLOR (ft_color.blue,
@@ -175,6 +175,8 @@ _hb_ft_color_line_get_color_stops (hb_color_line_t *color_line,
 					 ft_color.red,
 					 (ft_color.alpha * stop.color.alpha) >> 14);
 	}
+	else
+	  color_stops->color = HB_COLOR (0, 0, 0, 0);
       }
 
       color_stops++;
@@ -229,9 +231,7 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
 	if (unlikely (!node.visit ((uintptr_t) other_paint.p)))
 	  continue;
 
-	c->funcs->push_group (c->data);
 	c->recurse (other_paint);
-	c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
       }
     }
     break;
@@ -316,11 +316,11 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
     break;
     case FT_COLR_PAINTFORMAT_GLYPH:
     {
-      c->funcs->push_inverse_root_transform (c->data, c->font);
+      c->funcs->push_inverse_font_transform (c->data, c->font);
       c->ft_font->lock.unlock ();
       c->funcs->push_clip_glyph (c->data, paint.u.glyph.glyphID, c->font);
       c->ft_font->lock.lock ();
-      c->funcs->push_root_transform (c->data, c->font);
+      c->funcs->push_font_transform (c->data, c->font);
       c->recurse (paint.u.glyph.paint);
       c->funcs->pop_transform (c->data);
       c->funcs->pop_clip (c->data);
@@ -335,7 +335,7 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
       if (unlikely (!node.visit (gid)))
 	return;
 
-      c->funcs->push_inverse_root_transform (c->data, c->font);
+      c->funcs->push_inverse_font_transform (c->data, c->font);
       c->ft_font->lock.unlock ();
       if (c->funcs->color_glyph (c->data, gid, c->font))
       {
@@ -451,10 +451,12 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
     break;
     case FT_COLR_PAINTFORMAT_COMPOSITE:
     {
+      c->funcs->push_group (c->data);
       c->recurse (paint.u.composite.backdrop_paint);
       c->funcs->push_group (c->data);
       c->recurse (paint.u.composite.source_paint);
       c->funcs->pop_group (c->data, _hb_ft_paint_composite_mode (paint.u.composite.composite_mode));
+      c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
     }
     break;
 
@@ -479,17 +481,24 @@ hb_ft_paint_glyph_colr (hb_font_t *font,
 
   /* Face is locked. */
 
-  FT_Error error;
-  FT_Color*         palette;
+  FT_Palette_Data   palette_data = {};
+  FT_Color*         palette = NULL;
   FT_LayerIterator  iterator;
 
   FT_Bool  have_layers;
   FT_UInt  layer_glyph_index;
   FT_UInt  layer_color_index;
 
-  error = FT_Palette_Select(ft_face, palette_index, &palette);
-  if (error)
-    palette = NULL;
+  (void) FT_Palette_Data_Get(ft_face, &palette_data);
+  (void) FT_Palette_Select(ft_face, palette_index, &palette);
+  if (!palette)
+  {
+    // https://github.com/harfbuzz/harfbuzz/issues/5116
+    (void) FT_Palette_Select(ft_face, 0, &palette);
+  }
+
+  auto palette_array = hb_array ((const FT_Color *) palette,
+				 palette ? palette_data.num_palette_entries : 0);
 
   /* COLRv1 */
   FT_OpaquePaint paint = {0};
@@ -499,7 +508,7 @@ hb_ft_paint_glyph_colr (hb_font_t *font,
   {
     hb_ft_paint_context_t c (ft_font, font,
 			     paint_funcs, paint_data,
-			     palette, palette_index, foreground);
+			     palette_array, palette_index, foreground);
     hb_decycler_node_t node (c.glyphs_decycler);
     node.visit (gid);
 
@@ -524,10 +533,10 @@ hb_ft_paint_glyph_colr (hb_font_t *font,
       hb_paint_extents_context_t extents_data;
       hb_ft_paint_context_t ce (ft_font, font,
 			        extents_funcs, &extents_data,
-			        palette, palette_index, foreground);
+			        palette_array, palette_index, foreground);
       hb_decycler_node_t node2 (ce.glyphs_decycler);
       node2.visit (gid);
-      ce.funcs->push_root_transform (ce.data, font);
+      ce.funcs->push_font_transform (ce.data, font);
       ce.recurse (paint);
       ce.funcs->pop_transform (ce.data);
       hb_extents_t extents = extents_data.get_extents ();
@@ -540,7 +549,7 @@ hb_ft_paint_glyph_colr (hb_font_t *font,
 				    extents.ymax);
     }
 
-    c.funcs->push_root_transform (c.data, font);
+    c.funcs->push_font_transform (c.data, font);
 
     if (is_bounded)
      {
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ft.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ft.cc
index efb4b7d2435dd711228e3719fe583c39a7a82777..756ba8a54bb73b52f3b8e0e4cbb962c5b38aa2e5 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ft.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ft.cc
@@ -101,7 +101,7 @@ struct hb_ft_font_t
 
   mutable hb_mutex_t lock; /* Protects members below. */
   FT_Face ft_face;
-  mutable unsigned cached_serial;
+  mutable hb_atomic_t<unsigned> cached_serial;
   mutable hb_ft_advance_cache_t advance_cache;
 };
 
@@ -118,7 +118,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
 
   ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
 
-  ft_font->cached_serial = (unsigned) -1;
+  ft_font->cached_serial = UINT_MAX;
   new (&ft_font->advance_cache) hb_ft_advance_cache_t;
 
   return ft_font;
@@ -213,9 +213,10 @@ _hb_ft_hb_font_check_changed (hb_font_t *font,
 {
   if (font->serial != ft_font->cached_serial)
   {
+    hb_lock_t lock (ft_font->lock);
     _hb_ft_hb_font_changed (font, ft_font->ft_face);
     ft_font->advance_cache.clear ();
-    ft_font->cached_serial = font->serial;
+    ft_font->cached_serial.set_release (font->serial.get_acquire ());
     return true;
   }
   return false;
@@ -478,6 +479,8 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
 			    void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_position_t *orig_first_advance = first_advance;
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
@@ -561,6 +564,8 @@ hb_ft_get_glyph_v_advance (hb_font_t *font,
 			   void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Fixed v;
   float y_mult;
@@ -614,6 +619,8 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
 			  void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
   float x_mult, y_mult;
@@ -658,6 +665,8 @@ hb_ft_get_glyph_h_kerning (hb_font_t *font,
 			   void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Vector kerningv;
 
@@ -677,10 +686,12 @@ hb_ft_get_glyph_extents (hb_font_t *font,
 			 void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
   float x_mult, y_mult;
-  float slant_xy = font->slant_xy;
+
 #ifdef HAVE_FT_GET_TRANSFORM
   if (ft_font->transform)
   {
@@ -708,34 +719,11 @@ hb_ft_get_glyph_extents (hb_font_t *font,
   float x2 = x1 + x_mult *  ft_face->glyph->metrics.width;
   float y2 = y1 + y_mult * -ft_face->glyph->metrics.height;
 
-  /* Apply slant. */
-  if (slant_xy)
-  {
-    x1 += hb_min (y1 * slant_xy, y2 * slant_xy);
-    x2 += hb_max (y1 * slant_xy, y2 * slant_xy);
-  }
-
   extents->x_bearing = floorf (x1);
   extents->y_bearing = floorf (y1);
   extents->width = ceilf (x2) - extents->x_bearing;
   extents->height = ceilf (y2) - extents->y_bearing;
 
-  if (font->x_strength || font->y_strength)
-  {
-    /* Y */
-    int y_shift = font->y_strength;
-    if (font->y_scale < 0) y_shift = -y_shift;
-    extents->y_bearing += y_shift;
-    extents->height -= y_shift;
-
-    /* X */
-    int x_shift = font->x_strength;
-    if (font->x_scale < 0) x_shift = -x_shift;
-    if (font->embolden_in_place)
-      extents->x_bearing -= x_shift / 2;
-    extents->width += x_shift;
-  }
-
   return true;
 }
 
@@ -749,6 +737,8 @@ hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
 			       void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
 
@@ -826,6 +816,8 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
 			  void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
   float y_mult;
@@ -916,6 +908,8 @@ hb_ft_draw_glyph (hb_font_t *font,
 		  void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
 
@@ -990,6 +984,8 @@ hb_ft_paint_glyph (hb_font_t *font,
                    void *user_data)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
 
@@ -1079,10 +1075,8 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
 
     hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr);
-    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
 
 #ifndef HB_NO_VERTICAL
-    //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
 #endif
@@ -1090,7 +1084,6 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
 #ifndef HB_NO_OT_SHAPE_FALLBACK
     hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
 #endif
-    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
     hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
     hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
@@ -1456,6 +1449,10 @@ hb_ft_font_changed (hb_font_t *font)
  * variation-axis settings on the @font.
  * This call is fast if nothing has changed on @font.
  *
+ * Note that as of version 11.0.0, calling this function is not necessary,
+ * as HarfBuzz will automatically detect changes to the font and update
+ * the underlying FT_Face as needed.
+ *
  * Return value: true if changed, false otherwise
  *
  * Since: 4.4.0
@@ -1587,7 +1584,8 @@ destroy_ft_library (void *arg)
  * font file and face index.
  *
  * This is similar in functionality to hb_face_create_from_file_or_fail(),
- * but uses the FreeType library for loading the font file.
+ * but uses the FreeType library for loading the font file. This can
+ * be useful, for example, to load WOFF and WOFF2 font data.
  *
  * Return value: (transfer full): The new face object, or `NULL` if
  * no face is found at the specified index or the file cannot be read.
@@ -1624,6 +1622,75 @@ hb_ft_face_create_from_file_or_fail (const char   *file_name,
   return face;
 }
 
+static hb_user_data_key_t ft_blob_key = {0};
+
+static void
+_destroy_blob (void *p)
+{
+  hb_blob_destroy ((hb_blob_t *) p);
+}
+
+/**
+ * hb_ft_face_create_from_blob_or_fail:
+ * @blob: A blob
+ * @index: The index of the face within the blob
+ *
+ * Creates an #hb_face_t face object from the specified
+ * font blob and face index.
+ *
+ * This is similar in functionality to hb_face_create_from_blob_or_fail(),
+ * but uses the FreeType library for loading the font blob. This can
+ * be useful, for example, to load WOFF and WOFF2 font data.
+ *
+ * Return value: (transfer full): The new face object, or `NULL` if
+ * loading fails (eg. blob does not contain valid font data).
+ *
+ * Since: 11.0.0
+ */
+hb_face_t *
+hb_ft_face_create_from_blob_or_fail (hb_blob_t    *blob,
+				     unsigned int  index)
+{
+  FT_Library ft_library = reference_ft_library ();
+  if (unlikely (!ft_library))
+  {
+    DEBUG_MSG (FT, ft_library, "reference_ft_library failed");
+    return nullptr;
+  }
+
+  hb_blob_make_immutable (blob);
+  unsigned blob_size;
+  const char *blob_data = hb_blob_get_data (blob, &blob_size);
+
+  FT_Face ft_face;
+  if (unlikely (FT_New_Memory_Face (ft_library,
+				    (const FT_Byte *) blob_data,
+				    blob_size,
+				    index,
+				    &ft_face)))
+    return nullptr;
+
+  hb_face_t *face = hb_ft_face_create_referenced (ft_face);
+  FT_Done_Face (ft_face);
+
+  ft_face->generic.data = ft_library;
+  ft_face->generic.finalizer = finalize_ft_library;
+
+  if (hb_face_is_immutable (face))
+    return nullptr;
+
+  // Hook the blob to the hb_face_t, since FT_Face still needs it.
+  hb_blob_reference (blob);
+  if (!hb_face_set_user_data (face, &ft_blob_key, blob, _destroy_blob, true))
+  {
+    hb_blob_destroy (blob);
+    hb_face_destroy (face);
+    return nullptr;
+  }
+
+  return face;
+}
+
 static void
 _release_blob (void *arg)
 {
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ft.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-ft.h
index 42bfb4f46744d5c064c492f7d7d66365002ff646..227b4f221bf2b2c01c016a1e82bfea4626c576f6 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ft.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ft.h
@@ -88,6 +88,10 @@ HB_EXTERN hb_face_t *
 hb_ft_face_create_from_file_or_fail (const char   *file_name,
 				     unsigned int  index);
 
+HB_EXTERN hb_face_t *
+hb_ft_face_create_from_blob_or_fail (hb_blob_t    *blob,
+				     unsigned int  index);
+
 /*
  * hb-font from ft-face.
  */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-geometry.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-geometry.hh
index 2f7fcb32857bb586d15abdcd8ca402677b64d7bc..c22a26a404a65f2a5dca6754b3f6c1a456835051 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-geometry.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-geometry.hh
@@ -30,6 +30,11 @@
 struct hb_extents_t
 {
   hb_extents_t () {}
+  hb_extents_t (const hb_glyph_extents_t &extents) :
+		xmin (hb_min (extents.x_bearing, extents.x_bearing + extents.width)),
+		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) :
     xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {}
 
@@ -38,6 +43,12 @@ struct hb_extents_t
 
   void union_ (const hb_extents_t &o)
   {
+    if (o.is_empty ()) return;
+    if (is_empty ())
+    {
+      *this = o;
+      return;
+    }
     xmin = hb_min (xmin, o.xmin);
     ymin = hb_min (ymin, o.ymin);
     xmax = hb_max (xmax, o.xmax);
@@ -46,6 +57,11 @@ struct hb_extents_t
 
   void intersect (const hb_extents_t &o)
   {
+    if (o.is_empty () || is_empty ())
+    {
+      *this = hb_extents_t {};
+      return;
+    }
     xmin = hb_max (xmin, o.xmin);
     ymin = hb_max (ymin, o.ymin);
     xmax = hb_min (xmax, o.xmax);
@@ -69,6 +85,18 @@ struct hb_extents_t
     }
   }
 
+  hb_glyph_extents_t to_glyph_extents (bool xneg = false, bool yneg = false) const
+  {
+    hb_position_t x0 = (hb_position_t) roundf (xmin);
+    hb_position_t y0 = (hb_position_t) roundf (ymin);
+    hb_position_t x1 = (hb_position_t) roundf (xmax);
+    hb_position_t y1 = (hb_position_t) roundf (ymax);
+    return hb_glyph_extents_t {xneg ? x1 : x0,
+			       yneg ? y0 : y1,
+			       xneg ? x0 - x1 : x1 - x0,
+			       yneg ? y1 - y0 : y0 - y1};
+  }
+
   float xmin = 0.f;
   float ymin = 0.f;
   float xmax = -1.f;
@@ -218,7 +246,7 @@ struct hb_bounds_t
     EMPTY,
   };
 
-  hb_bounds_t (status_t status) : status (status) {}
+  hb_bounds_t (status_t status = UNBOUNDED) : status (status) {}
   hb_bounds_t (const hb_extents_t &extents) :
     status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {}
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-graphite2.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-graphite2.cc
index 7ea0386223871c134ed20b9f50737e2eaf17c299..c547134d5f3f3be21b0ab33e80c18ba20bc0f34c 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-graphite2.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-graphite2.cc
@@ -68,7 +68,7 @@ struct hb_graphite2_face_data_t
 {
   hb_face_t *face;
   gr_face   *grface;
-  hb_atomic_ptr_t<hb_graphite2_tablelist_t> tlist;
+  hb_atomic_t<hb_graphite2_tablelist_t *> tlist;
 };
 
 static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len)
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-machinery.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-machinery.hh
index ecff94f1b642e35778f887220e393ad795775923..6127c4d0ce53b7b8c314f120a89eb09801a94c5f 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-machinery.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-machinery.hh
@@ -273,7 +273,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
 
   private:
   /* Must only have one pointer. */
-  hb_atomic_ptr_t<Stored *> instance;
+  hb_atomic_t<Stored *> instance;
 };
 
 /* Specializations. */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-object.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-object.hh
index 5cffe1666b984b656d8607b373182b9369fb37b8..7b34d671fbfeb5796b2ce51a7e0ab480b60c5974 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-object.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-object.hh
@@ -142,7 +142,7 @@ struct hb_lockable_set_t
 
 struct hb_reference_count_t
 {
-  mutable hb_atomic_int_t ref_count;
+  mutable hb_atomic_t<int> ref_count;
 
   void init (int v = 1) { ref_count = v; }
   int get_relaxed () const { return ref_count; }
@@ -213,8 +213,8 @@ struct hb_user_data_array_t
 struct hb_object_header_t
 {
   hb_reference_count_t ref_count;
-  mutable hb_atomic_int_t writable = 0;
-  hb_atomic_ptr_t<hb_user_data_array_t> user_data;
+  mutable hb_atomic_t<bool> writable = false;
+  hb_atomic_t<hb_user_data_array_t *> user_data;
 
   bool is_inert () const { return !ref_count.get_relaxed (); }
 };
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-open-type.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-open-type.hh
index 7437fddfa3822bda34c1fe7d60ac0549ca8817f4..f2040ea5c9c0698088c4762300dfc67c781f6169 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-open-type.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-open-type.hh
@@ -1888,7 +1888,7 @@ struct TupleValues
 
     bool ensure_run ()
     {
-      if (likely (run_count > 0)) return true;
+      if (run_count > 0) return true;
 
       if (unlikely (p >= end))
       {
@@ -1943,6 +1943,11 @@ struct TupleValues
 	unsigned count = hb_min (n - i, (unsigned) run_count);
 	switch (width)
 	{
+	  case 0:
+	  {
+	    arrayZ += count;
+	    break;
+	  }
 	  case 1:
 	  {
 	    const auto *pp = (const HBINT8 *) p;
@@ -1958,6 +1963,8 @@ struct TupleValues
 #endif
 	    for (; j < count; j++)
 	      *arrayZ++ += scaled ? *pp++ * scale : *pp++;
+
+	    p = (const unsigned char *) pp;
 	  }
 	  break;
 	  case 2:
@@ -1975,6 +1982,8 @@ struct TupleValues
 #endif
 	    for (; j < count; j++)
 	      *arrayZ++ += scaled ? *pp++ * scale : *pp++;
+
+	    p = (const unsigned char *) pp;
 	  }
 	  break;
 	  case 4:
@@ -1982,10 +1991,11 @@ struct TupleValues
 	    const auto *pp = (const HBINT32 *) p;
 	    for (unsigned j = 0; j < count; j++)
 	      *arrayZ++ += scaled ? *pp++ * scale : *pp++;
+
+	    p = (const unsigned char *) pp;
 	  }
 	  break;
 	}
-	p += count * width;
 	run_count -= count;
 	i += count;
       }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cff1-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cff1-table.hh
index 666efeb925c8c26a8458091ac0b6b99b8b351954..9d3f4b2495372b156aefe1e820efb3ba33d52fd1 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cff1-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cff1-table.hh
@@ -1176,7 +1176,8 @@ struct cff1
 	  if (unlikely (!font_interp.interpret (*font)))   goto fail;
 	  PRIVDICTVAL *priv = &privateDicts[i];
 	  const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
-	  if (unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail;
+	  if (unlikely (font->privateDictInfo.size &&
+			privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail;
 	  num_interp_env_t env2 (privDictStr);
 	  dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env2);
 	  priv->init ();
@@ -1191,7 +1192,8 @@ struct cff1
 	PRIVDICTVAL *priv = &privateDicts[0];
 
 	const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
-	if (unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail;
+	if (font->privateDictInfo.size &&
+	    unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail;
 	num_interp_env_t env (privDictStr);
 	dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env);
 	priv->init ();
@@ -1483,7 +1485,7 @@ struct cff1
       int cmp (const gname_t &a) const { return cmp (&a, this); }
     };
 
-    mutable hb_atomic_ptr_t<hb_sorted_vector_t<gname_t>> glyph_names;
+    mutable hb_atomic_t<hb_sorted_vector_t<gname_t> *> glyph_names;
 
     typedef accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> SUPER;
   };
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cff2-table.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cff2-table.cc
index 57023cb912cc416235fa580ca12c890a8e0b76b0..4157bd3b56936db93ef1898cd8190d5a4f3c8d9b 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cff2-table.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cff2-table.cc
@@ -102,6 +102,14 @@ struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_e
 bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
 					   hb_codepoint_t glyph,
 					   hb_glyph_extents_t *extents) const
+{
+  return get_extents_at (font, glyph, extents, hb_array (font->coords, font->num_coords));
+}
+
+bool OT::cff2::accelerator_t::get_extents_at (hb_font_t *font,
+					      hb_codepoint_t glyph,
+					      hb_glyph_extents_t *extents,
+					      hb_array_t<const int> coords) const
 {
 #ifdef HB_NO_OT_FONT_CFF
   /* XXX Remove check when this code moves to .hh file. */
@@ -112,7 +120,7 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
 
   unsigned int fd = fdSelect->get_fd (glyph);
   const hb_ubytes_t str = (*charStrings)[glyph];
-  cff2_cs_interp_env_t<number_t> env (str, *this, fd, font->coords, font->num_coords);
+  cff2_cs_interp_env_t<number_t> env (str, *this, fd, coords.arrayZ, coords.length);
   cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t, number_t> interp (env);
   cff2_extents_param_t  param;
   if (unlikely (!interp.interpret (param))) return false;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cff2-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cff2-table.hh
index 0074d5bd85a90ac87f604c32d3e92dba93cc8a0d..536c918f0e3cf9c4ae4e19ffffb9a5492f56391b 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cff2-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cff2-table.hh
@@ -458,7 +458,8 @@ struct cff2
 	if (unlikely (!font_interp.interpret (*font))) goto fail;
 
 	const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
-	if (unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail;
+	if (unlikely (font->privateDictInfo.size &&
+		      privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail;
 	cff2_priv_dict_interp_env_t env2 (privDictStr);
 	dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2);
 	privateDicts[i].init ();
@@ -481,6 +482,13 @@ struct cff2
       privateDicts.fini ();
       hb_blob_destroy (blob);
       blob = nullptr;
+
+      auto *scalars = cached_scalars_vector.get_acquire ();
+      if (scalars && cached_scalars_vector.cmpexch (scalars, nullptr))
+      {
+	scalars->fini ();
+	hb_free (scalars);
+      }
     }
 
     hb_vector_t<uint16_t> *create_glyph_to_sid_map () const
@@ -508,6 +516,8 @@ struct cff2
     hb_vector_t<cff2_font_dict_values_t>     fontDicts;
     hb_vector_t<PRIVDICTVAL>  privateDicts;
 
+    mutable hb_atomic_t<hb_vector_t<float> *> cached_scalars_vector;
+
     unsigned int	      num_glyphs = 0;
   };
 
@@ -518,6 +528,10 @@ struct cff2
     HB_INTERNAL bool get_extents (hb_font_t *font,
 				  hb_codepoint_t glyph,
 				  hb_glyph_extents_t *extents) const;
+    HB_INTERNAL bool get_extents_at (hb_font_t *font,
+				     hb_codepoint_t glyph,
+				     hb_glyph_extents_t *extents,
+				     hb_array_t<const int> coords) const;
     HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
     HB_INTERNAL bool get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t<const int> coords) const;
   };
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color.cc
index 37d42e08d94e6f75437574438c203aa6e27d3b66..1436fe563f4342bc479ba3cc73f7a5cb4873045a 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color.cc
@@ -204,7 +204,7 @@ hb_ot_color_palette_get_colors (hb_face_t     *face,
 hb_bool_t
 hb_ot_color_has_layers (hb_face_t *face)
 {
-  return face->table.COLR->has_v0_data ();
+  return face->table.COLR->colr->has_v0_data ();
 }
 
 /**
@@ -221,7 +221,7 @@ hb_ot_color_has_layers (hb_face_t *face)
 hb_bool_t
 hb_ot_color_has_paint (hb_face_t *face)
 {
-  return face->table.COLR->has_v1_data ();
+  return face->table.COLR->colr->has_v1_data ();
 }
 
 /**
@@ -240,7 +240,7 @@ hb_bool_t
 hb_ot_color_glyph_has_paint (hb_face_t      *face,
                              hb_codepoint_t  glyph)
 {
-  return face->table.COLR->has_paint_for_glyph (glyph);
+  return face->table.COLR->colr->has_paint_for_glyph (glyph);
 }
 
 /**
@@ -266,7 +266,7 @@ hb_ot_color_glyph_get_layers (hb_face_t           *face,
 			      unsigned int        *layer_count, /* IN/OUT.  May be NULL. */
 			      hb_ot_color_layer_t *layers /* OUT.     May be NULL. */)
 {
-  return face->table.COLR->get_glyph_layers (glyph, start_offset, layer_count, layers);
+  return face->table.COLR->colr->get_glyph_layers (glyph, start_offset, layer_count, layers);
 }
 
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-face-table-list.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-face-table-list.hh
index 97825f4d19c75acd665250d66b98936abff9d76a..afc8aa476e290274117b02042ffc3ed8d9fa2306 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-face-table-list.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-face-table-list.hh
@@ -136,7 +136,7 @@ HB_OT_TABLE (AAT, feat)
 
 /* OpenType color fonts. */
 #ifndef HB_NO_COLOR
-HB_OT_CORE_TABLE (OT, COLR)
+HB_OT_ACCELERATOR (OT, COLR)
 HB_OT_CORE_TABLE (OT, CPAL)
 HB_OT_ACCELERATOR (OT, CBDT)
 HB_OT_ACCELERATOR (OT, sbix)
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-face.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-face.cc
index 1cf14f3ebc62a9f8d53bbd036d7b3fde90d6f072..d17f088073c309995ff712d9ca777da9f672fd84 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-face.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-face.cc
@@ -36,6 +36,7 @@
 #include "hb-ot-name-table.hh"
 #include "hb-ot-post-table.hh"
 #include "OT/Color/CBDT/CBDT.hh"
+#include "OT/Color/COLR/COLR.hh"
 #include "OT/Color/sbix/sbix.hh"
 #include "OT/Color/svg/svg.hh"
 #include "hb-ot-layout-gdef-table.hh"
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-font.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-font.cc
index edfece170b8f308d03fc2a775c3c01ba5b4cba5d..9bd0db4b8acbc6cc10ca1ab2f466bd0daacce693 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-font.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-font.cc
@@ -85,8 +85,8 @@ struct hb_ot_font_t
 #endif
 
   /* h_advance caching */
-  mutable hb_atomic_int_t cached_coords_serial;
-  mutable hb_atomic_ptr_t<hb_ot_font_advance_cache_t> advance_cache;
+  mutable hb_atomic_t<int> cached_coords_serial;
+  mutable hb_atomic_t<hb_ot_font_advance_cache_t *> advance_cache;
 };
 
 static hb_ot_font_t *
@@ -471,6 +471,9 @@ hb_ot_get_glyph_extents (hb_font_t *font,
   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;
 
+#ifndef HB_NO_VAR_COMPOSITES
+  if (ot_face->VARC->get_extents (font, glyph, extents)) return true;
+#endif
 #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
   if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
   if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-kern-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-kern-table.hh
index d11a913c7128b6e66d841027be7c0cfa5ae695eb..33865450125f3f860d6b8eed53919b62cfa6a391 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-kern-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-kern-table.hh
@@ -27,6 +27,7 @@
 #ifndef HB_OT_KERN_TABLE_HH
 #define HB_OT_KERN_TABLE_HH
 
+#include "hb-aat-layout-common.hh"
 #include "hb-aat-layout-kerx-table.hh"
 
 
@@ -400,6 +401,7 @@ struct kern
 
     hb_blob_ptr_t<kern> table;
     AAT::kern_accelerator_data_t accel_data;
+    AAT::hb_aat_scratch_t scratch;
   };
 
   protected:
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-common.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-common.hh
index f9a5c1b9cfb4bf5c91ab68ff98faa72f4f78da0a..ad54a1d79c5ae06ef18030d7b0a1ff65c93f04b7 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-common.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-common.hh
@@ -2565,7 +2565,7 @@ struct VarRegionList
     if (cache)
     {
       cached_value = &(cache[region_index]);
-      if (likely (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID))
+      if (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID)
 	return *cached_value;
     }
 
@@ -2743,7 +2743,7 @@ struct SparseVarRegionList
     if (cache)
     {
       cached_value = &(cache[region_index]);
-      if (likely (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID))
+      if (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID)
 	return *cached_value;
     }
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsubgpos.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsubgpos.hh
index 183e08ccc3ea9d6514c370ced23bb82f125d2874..7d49710d11e3a582e7fc713bbd8db38920718767 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsubgpos.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsubgpos.hh
@@ -4900,7 +4900,7 @@ struct GSUBGPOS
 
       this->lookup_count = table->get_lookup_count ();
 
-      this->accels = (hb_atomic_ptr_t<hb_ot_layout_lookup_accelerator_t> *) hb_calloc (this->lookup_count, sizeof (*accels));
+      this->accels = (hb_atomic_t<hb_ot_layout_lookup_accelerator_t *> *) hb_calloc (this->lookup_count, sizeof (*accels));
       if (unlikely (!this->accels))
       {
 	this->lookup_count = 0;
@@ -4948,7 +4948,7 @@ struct GSUBGPOS
 
     hb_blob_ptr_t<T> table;
     unsigned int lookup_count;
-    hb_atomic_ptr_t<hb_ot_layout_lookup_accelerator_t> *accels;
+    hb_atomic_t<hb_ot_layout_lookup_accelerator_t *> *accels;
   };
 
   protected:
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc
index f7ad72fd4e9754fb385f8d3f582923f41f5e025c..3aca40eb7a9d57e99edbf9ade28cc6b1e026b150 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc
@@ -131,13 +131,15 @@ hb_ot_layout_kern (const hb_ot_shape_plan_t *plan,
 		   hb_font_t *font,
 		   hb_buffer_t  *buffer)
 {
-  hb_blob_t *blob = font->face->table.kern.get_blob ();
-  const auto& kern = *font->face->table.kern;
+  auto &accel = *font->face->table.kern;
+  hb_blob_t *blob = accel.get_blob ();
 
   AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
 
   if (!buffer->message (font, "start table kern")) return;
-  kern.apply (&c);
+  c.buffer_glyph_set = accel.scratch.create_buffer_glyph_set ();
+  accel.apply (&c);
+  accel.scratch.destroy_buffer_glyph_set (c.buffer_glyph_set);
   (void) buffer->message (font, "end table kern");
 }
 #endif
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.hh
index 52dafbba4ea903d0818b5a21df6926dcac76bb92..ddec57e068f41dac662579070147229490d6b3cf 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.hh
@@ -202,7 +202,8 @@ enum hb_unicode_props_flags_t {
   /* If GEN_CAT=FORMAT, top byte masks: */
   UPROPS_MASK_Cf_ZWJ	= 0x0100u,
   UPROPS_MASK_Cf_ZWNJ	= 0x0200u,
-  UPROPS_MASK_Cf_VS	= 0x0400u
+  UPROPS_MASK_Cf_VS	= 0x0400u,
+  UPROPS_MASK_Cf_AAT_DELETED	= 0x0800u
 };
 HB_MARK_AS_FLAG_T (hb_unicode_props_flags_t);
 
@@ -386,6 +387,8 @@ _hb_grapheme_group_func (const hb_glyph_info_t& a HB_UNUSED,
 static inline void
 _hb_ot_layout_reverse_graphemes (hb_buffer_t *buffer)
 {
+  // MONOTONE_GRAPHEMES was already applied and is taken care of by _hb_grapheme_group_func.
+  // So we just check for MONOTONE_CHARACTERS here.
   buffer->reverse_groups (_hb_grapheme_group_func,
 			  buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
 }
@@ -418,6 +421,17 @@ _hb_glyph_info_flip_joiners (hb_glyph_info_t *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);
+}
+static inline void
+_hb_glyph_info_set_aat_deleted (hb_glyph_info_t *info)
+{
+  _hb_glyph_info_set_general_category (info, HB_UNICODE_GENERAL_CATEGORY_FORMAT);
+  info->unicode_props() |= UPROPS_MASK_Cf_AAT_DELETED;
+}
 
 /* lig_props: aka lig_id / lig_comp
  *
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-post-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-post-table.hh
index 18ecea182564711b5542bf32badefcffa7307aa1..c8a58bdf85ea3118f45193a30379f429e914660e 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-post-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-post-table.hh
@@ -290,7 +290,7 @@ struct post
     const Array16Of<HBUINT16> *glyphNameIndex = nullptr;
     hb_vector_t<uint32_t> index_to_offset;
     const uint8_t *pool = nullptr;
-    hb_atomic_ptr_t<uint16_t *> gids_sorted_by_name;
+    hb_atomic_t<uint16_t *> gids_sorted_by_name;
   };
 
   bool has_data () const { return version.to_int (); }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.cc
index c9defc49a20e092680ef67212d2c95f29d1aba04..dfc6be0fbd6ea7c86d48b4ed2dac9ad5f589cf8b 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.cc
@@ -84,6 +84,7 @@ hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t                     *fac
 						props (props),
 						map (face, props)
 #ifndef HB_NO_AAT_SHAPE
+						, aat_map (face, props)
 						, apply_morx (_hb_apply_morx (face, props))
 #endif
 {
@@ -106,6 +107,10 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t           &plan,
   plan.props = props;
   plan.shaper = shaper;
   map.compile (plan.map, key);
+#ifndef HB_NO_AAT_SHAPE
+  if (apply_morx)
+    aat_map.compile (plan.aat_map);
+#endif
 
 #ifndef HB_NO_OT_SHAPE_FRACTIONS
   plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
@@ -551,7 +556,7 @@ hb_form_clusters (hb_buffer_t *buffer)
   if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
     return;
 
-  if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+  if (HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES (buffer->cluster_level))
     foreach_grapheme (buffer, start, end)
       buffer->merge_clusters (start, end);
   else
@@ -609,7 +614,7 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
    * Ogham fonts are supposed to be implemented BTT or not.  Need to research that
    * first. */
   if ((HB_DIRECTION_IS_HORIZONTAL (direction) &&
-       direction != horiz_dir && horiz_dir != HB_DIRECTION_INVALID) ||
+       direction != horiz_dir && HB_DIRECTION_IS_VALID (horiz_dir)) ||
       (HB_DIRECTION_IS_VERTICAL   (direction) &&
        direction != HB_DIRECTION_TTB))
   {
@@ -1109,10 +1114,6 @@ hb_ot_position_plan (const hb_ot_shape_context_t *c)
   /* Finish off.  Has to follow a certain order. */
   hb_ot_layout_position_finish_advances (c->font, c->buffer);
   hb_ot_zero_width_default_ignorables (c->buffer);
-#ifndef HB_NO_AAT_SHAPE
-  if (c->plan->apply_morx)
-    hb_aat_layout_zero_width_deleted_glyphs (c->buffer);
-#endif
   hb_ot_layout_position_finish_offsets (c->font, c->buffer);
 
   /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.hh
index 791bc6896bb12ce477373070deb00f604c651ee3..49398818539b9891d9cb0e8a064456885cd6f12a 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.hh
@@ -66,6 +66,7 @@ struct hb_ot_shape_plan_t
   hb_segment_properties_t props;
   const struct hb_ot_shaper_t *shaper;
   hb_ot_map_t map;
+  hb_aat_map_t aat_map;
   const void *data;
 #ifndef HB_NO_OT_SHAPE_FRACTIONS
   hb_mask_t frac_mask, numr_mask, dnom_mask;
@@ -141,6 +142,7 @@ struct hb_ot_shape_planner_t
   hb_segment_properties_t props;
   hb_ot_map_builder_t map;
 #ifndef HB_NO_AAT_SHAPE
+  hb_aat_map_builder_t aat_map;
   bool apply_morx : 1;
 #else
   static constexpr bool apply_morx = false;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-arabic.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-arabic.cc
index 4e3b512b482f752a8d8f8008648ea278b42d0d81..44b670fcc02f2fb2e302e650b910e60ffe7fa40a 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-arabic.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-arabic.cc
@@ -260,7 +260,7 @@ struct arabic_shape_plan_t
    * mask_array[NONE] == 0. */
   hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1];
 
-  hb_atomic_ptr_t<arabic_fallback_plan_t> fallback_plan;
+  hb_atomic_t<arabic_fallback_plan_t *> fallback_plan;
 
   unsigned int do_fallback : 1;
   unsigned int has_stch : 1;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-hangul.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-hangul.cc
index c90476bc468b1b5f287c4236cef67a8373f4e4a1..50ea5327295f5f5cef5ced3bead83f15201fc3ca 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-hangul.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-hangul.cc
@@ -298,8 +298,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
 	  end = start + 2;
 	if (unlikely (!buffer->successful))
 	  break;
-	if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
-	  buffer->merge_out_clusters (start, end);
+	buffer->merge_out_clusters (start, end);
 	continue;
       }
     }
@@ -372,8 +371,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
 	  if (i < end)
 	    info[i++].hangul_shaping_feature() = TJMO;
 
-	  if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
-	    buffer->merge_out_clusters (start, end);
+	  buffer->merge_out_clusters (start, end);
 	  continue;
 	}
 	else if ((!tindex && buffer->idx + 1 < count && isT (buffer->cur(+1).codepoint)))
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-indic.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-indic.cc
index f8c970fc3eb5e3c26f69a834181cffc37b8935aa..5f57a672ee7122d04dfc69d84326cbe533725ed1 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-indic.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-indic.cc
@@ -301,7 +301,7 @@ struct indic_shape_plan_t
 #else
   static constexpr bool uniscribe_bug_compatible = false;
 #endif
-  mutable hb_atomic_int_t virama_glyph;
+  mutable hb_atomic_t<hb_codepoint_t> virama_glyph;
 
   hb_indic_would_substitute_feature_t rphf;
   hb_indic_would_substitute_feature_t pref;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-thai.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-thai.cc
index 6cd67cde35e65d94aed8ee88dc0b26acf466b057..6124a2114f8f84ed04a134a2d5de8e2edd778809 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-thai.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-thai.cc
@@ -360,7 +360,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
     {
       /* Since we decomposed, and NIKHAHIT is combining, merge clusters with the
        * previous cluster. */
-      if (start && buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+      if (start)
 	buffer->merge_out_clusters (start - 1, end);
     }
   }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-tag.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-tag.cc
index 0c63756b14d4cc31ebe4d08adb76999620f38e2d..b70db154c58ad3cc584dafb9115a1e7d6de2113e 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-tag.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-tag.cc
@@ -326,7 +326,7 @@ hb_ot_tags_from_language (const char   *lang_str,
 
     hb_tag_t lang_tag = hb_tag_from_string (lang_str, first_len);
 
-    static hb_atomic_int_t last_tag_idx; /* Poor man's cache. */
+    static hb_atomic_t<unsigned> last_tag_idx = 0; /* Poor man's cache. */
     unsigned tag_idx = last_tag_idx;
 
     if (likely (tag_idx < ot_languages_len && ot_languages[tag_idx].language == lang_tag) ||
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-gvar-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-gvar-table.hh
index b388c7143c7c120333417bd6f1900fa4717c1237..b32720be7ca45828f951bc08dc6140b62cd3076a 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-gvar-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-gvar-table.hh
@@ -53,10 +53,6 @@ struct hb_glyf_scratch_t
   contour_point_vector_t deltas;
   hb_vector_t<unsigned int> shared_indices;
   hb_vector_t<unsigned int> private_indices;
-
-  // VARC
-  hb_vector_t<unsigned> axisIndices;
-  hb_vector_t<float> axisValues;
 };
 
 namespace OT {
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-paint-extents.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-paint-extents.hh
index 2d4491e07172987b392751ff6fcc162333f38413..708af4a860222226e262728b8feebc3be6305369 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-paint-extents.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-paint-extents.hh
@@ -35,13 +35,22 @@ typedef struct  hb_paint_extents_context_t hb_paint_extents_context_t;
 
 struct hb_paint_extents_context_t
 {
-  hb_paint_extents_context_t ()
+  void clear ()
   {
+    transforms.clear ();
+    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});
   }
 
+  hb_paint_extents_context_t ()
+  {
+    clear ();
+  }
+
   hb_extents_t get_extents ()
   {
     return groups.tail().extents;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-paint.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-paint.cc
index 8eb24eb28b2ea66afc31f47bddba52671b1d52aa..755b181696e8bca6b41980a96e10ed94c614b42d 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-paint.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-paint.cc
@@ -464,6 +464,42 @@ hb_paint_push_transform (hb_paint_funcs_t *funcs, void *paint_data,
   funcs->push_transform (paint_data, xx, yx, xy, yy, dx, dy);
 }
 
+/**
+ * hb_paint_push_font_transform:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ * @font: a font
+ *
+ * Push the transform reflecting the font's scale and slant
+ * settings onto the paint functions.
+ *
+ * Since: 11.0.0
+ */
+void
+hb_paint_push_font_transform (hb_paint_funcs_t *funcs, void *paint_data,
+                              const hb_font_t *font)
+{
+  funcs->push_font_transform (paint_data, font);
+}
+
+/**
+ * hb_paint_push_inverse_font_transform:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ * @font: a font
+ *
+ * Push the inverse of the transform reflecting the font's
+ * scale and slant settings onto the paint functions.
+ *
+ * Since: 11.0.0
+ */
+void
+hb_paint_push_inverse_font_transform (hb_paint_funcs_t *funcs, void *paint_data,
+                                      const hb_font_t *font)
+{
+  funcs->push_inverse_font_transform (paint_data, font);
+}
+
 /**
  * hb_paint_pop_transform:
  * @funcs: paint functions
@@ -646,7 +682,7 @@ hb_paint_radial_gradient (hb_paint_funcs_t *funcs, void *paint_data,
                           float x0, float y0, float r0,
                           float x1, float y1, float r1)
 {
-  funcs->radial_gradient (paint_data, color_line, x0, y0, r0, y1, x1, r1);
+  funcs->radial_gradient (paint_data, color_line, x0, y0, r0, x1, y1, r1);
 }
 
 /**
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-paint.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-paint.h
index d8896a5230a295c6f82029175963fffd64fbc42c..309213e2d7a82eeda0e1d22d076355616132fb6d 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-paint.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-paint.h
@@ -956,6 +956,14 @@ hb_paint_push_transform (hb_paint_funcs_t *funcs, void *paint_data,
                          float xy, float yy,
                          float dx, float dy);
 
+HB_EXTERN void
+hb_paint_push_font_transform (hb_paint_funcs_t *funcs, void *paint_data,
+                              const hb_font_t *font);
+
+HB_EXTERN void
+hb_paint_push_inverse_font_transform (hb_paint_funcs_t *funcs, void *paint_data,
+                                      const hb_font_t *font);
+
 HB_EXTERN void
 hb_paint_pop_transform (hb_paint_funcs_t *funcs, void *paint_data);
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-paint.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-paint.hh
index 56b790dbee9886a0b17ce9452c52f158fdd511c5..5a7b903a072e9c67917240d205fffa9695ae99b0 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-paint.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-paint.hh
@@ -157,7 +157,7 @@ struct hb_paint_funcs_t
 
   /* Internal specializations. */
 
-  void push_root_transform (void *paint_data,
+  void push_font_transform (void *paint_data,
                             const hb_font_t *font)
   {
     float upem = font->face->get_upem ();
@@ -168,8 +168,8 @@ struct hb_paint_funcs_t
 		    xscale/upem, 0, slant * yscale/upem, yscale/upem, 0, 0);
   }
 
-  void push_inverse_root_transform (void *paint_data,
-                                    hb_font_t *font)
+  void push_inverse_font_transform (void *paint_data,
+                                    const hb_font_t *font)
   {
     float upem = font->face->get_upem ();
     int xscale = font->x_scale ? font->x_scale : upem;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-set.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-set.hh
index f098bd4c1db539e14f7e1afc1c40b90cceece801..5cd983c0081c8264bfe8a7a87abd3657d39a48d3 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-set.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-set.hh
@@ -30,6 +30,7 @@
 
 #include "hb.hh"
 #include "hb-bit-set-invertible.hh"
+#include "hb-bit-vector.hh" // Just to include
 
 
 template <typename impl_t>
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-shape.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-shape.cc
index 844f7b9e806a5445e8c130241d474c5b7f2d3d26..c62f8c6bcdd8b7a61346d9f2e20a8f0854a00dbd 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-shape.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-shape.cc
@@ -91,8 +91,10 @@ void free_static_shaper_list ()
  *
  * Retrieves the list of shapers supported by HarfBuzz.
  *
- * Return value: (transfer none) (array zero-terminated=1): an array of
- *    constant strings
+ * Return value: (transfer none) (array zero-terminated=1): a
+ *    `NULL`-terminated array of supported shapers constant string.
+ *    The returned array is owned by HarfBuzz and should not be
+ *    modified or freed.
  *
  * Since: 0.9.2
  **/
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-static.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-static.cc
index c9bd0a61bf81299ad7f6255c0f804a1d173a71e2..e328bc48a49ef3023f056bc674be3dd5f0110436 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-static.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-static.cc
@@ -41,6 +41,7 @@
 #include "hb-ot-maxp-table.hh"
 
 #ifndef HB_NO_VISIBILITY
+
 #include "hb-ot-name-language-static.hh"
 
 uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-cff-common.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-cff-common.hh
index c3f7b40c8136bc79b9df26f7ec426bddf91f322c..c6532ad5eccdd5faa14d762a4cd67c83d9ae5c9e 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-cff-common.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-cff-common.hh
@@ -570,7 +570,7 @@ struct cff_subset_accelerator_t
   parsed_cs_str_vec_t parsed_charstrings;
   parsed_cs_str_vec_t parsed_global_subrs;
   hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs;
-  mutable hb_atomic_ptr_t<glyph_to_sid_map_t> glyph_to_sid_map;
+  mutable hb_atomic_t<glyph_to_sid_map_t *> glyph_to_sid_map;
 
  private:
   hb_blob_t* original_blob;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-vector.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-vector.hh
index 0e01d010f37c08a65ed99be73c21bfc7dcbd0f2c..2c1344c03a35411d4ff3bb3eda9f4369eed33d33 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-vector.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-vector.hh
@@ -90,7 +90,13 @@ struct hb_vector_t
   {
     auto iter = hb_iter (o);
     if (iter.is_random_access_iterator || iter.has_fast_len)
-      alloc (hb_len (iter), true);
+    {
+      if (unlikely (!alloc (hb_len (iter), true)))
+	return;
+      unsigned count = hb_len (iter);
+      for (unsigned i = 0; i < count; i++)
+	push_has_room (*iter++);
+    }
     while (iter)
     {
       if (unlikely (!alloc (length + 1)))
@@ -436,7 +442,6 @@ struct hb_vector_t
 	new_allocated += (new_allocated >> 1) + 8;
     }
 
-
     /* Reallocate */
 
     bool overflows =
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-wasm-shape.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-wasm-shape.cc
index a8b91879a43e48ccc18d665787b8cbb483ee7014..f83329e1c1bef0c3f92c53e5212f7c4feeb55c84 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-wasm-shape.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-wasm-shape.cc
@@ -113,7 +113,7 @@ struct hb_wasm_shape_plan_t {
 struct hb_wasm_face_data_t {
   hb_blob_t *wasm_blob;
   wasm_module_t wasm_module;
-  mutable hb_atomic_ptr_t<hb_wasm_shape_plan_t> plan;
+  mutable hb_atomic_t<hb_wasm_shape_plan_t *> plan;
 };
 
 static bool
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb.hh
index 7c265483ff2c51aa9914925b7be364bcc17316c4..ffbfef099fbf8848ee12b2574b13df1a9e3ae67a 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb.hh
@@ -230,33 +230,6 @@
 #define HB_PASTE(a,b) HB_PASTE1(a,b)
 
 
-/* Compile-time custom allocator support. */
-
-#if !defined(HB_CUSTOM_MALLOC) \
-  && defined(hb_malloc_impl) \
-  && defined(hb_calloc_impl) \
-  && defined(hb_realloc_impl) \
-  && defined(hb_free_impl)
-#define HB_CUSTOM_MALLOC
-#endif
-
-#ifdef HB_CUSTOM_MALLOC
-extern "C" void* hb_malloc_impl(size_t size);
-extern "C" void* hb_calloc_impl(size_t nmemb, size_t size);
-extern "C" void* hb_realloc_impl(void *ptr, size_t size);
-extern "C" void  hb_free_impl(void *ptr);
-#define hb_malloc hb_malloc_impl
-#define hb_calloc hb_calloc_impl
-#define hb_realloc hb_realloc_impl
-#define hb_free hb_free_impl
-#else
-#define hb_malloc malloc
-#define hb_calloc calloc
-#define hb_realloc realloc
-#define hb_free free
-#endif
-
-
 /*
  * Compiler attributes
  */
@@ -282,7 +255,7 @@ extern "C" void  hb_free_impl(void *ptr);
 #define __attribute__(x)
 #endif
 
-#if defined(__MINGW32__) && (__GNUC__ >= 3)
+#if defined(__MINGW32__) && (__GNUC__ >= 3) && !defined(__clang__)
 #define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (gnu_printf, format_idx, arg_idx)))
 #elif defined(__GNUC__) && (__GNUC__ >= 3)
 #define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
@@ -539,6 +512,29 @@ static_assert ((sizeof (hb_var_int_t) == 4), "");
 #define HB_PI 3.14159265358979f
 #define HB_2_PI (2.f * HB_PI)
 
+/* Compile-time custom allocator support. */
+
+#if !defined(HB_CUSTOM_MALLOC) \
+  && defined(hb_malloc_impl) \
+  && defined(hb_calloc_impl) \
+  && defined(hb_realloc_impl) \
+  && defined(hb_free_impl)
+#define HB_CUSTOM_MALLOC
+#endif
+
+#ifdef HB_CUSTOM_MALLOC
+extern "C" void* hb_malloc_impl(size_t size);
+extern "C" void* hb_calloc_impl(size_t nmemb, size_t size);
+extern "C" void* hb_realloc_impl(void *ptr, size_t size);
+extern "C" void  hb_free_impl(void *ptr);
+#else
+#define hb_malloc_impl malloc
+#define hb_calloc_impl calloc
+#define hb_realloc_impl realloc
+#define hb_free_impl free
+#endif
+
+
 
 /* Headers we include for everyone.  Keep topologically sorted by dependency.
  * They express dependency amongst themselves, but no other file should include
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/justify.py b/source/libs/harfbuzz/harfbuzz-src/src/justify.py
index db2fb70104afa6fe02f30dcb745505e98e8dbbf8..8458d2ec681f639c5037469042f4f6e6100d72d0 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/justify.py
+++ b/source/libs/harfbuzz/harfbuzz-src/src/justify.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+
 import gi
 
 gi.require_version("Gtk", "3.0")
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/meson.build b/source/libs/harfbuzz/harfbuzz-src/src/meson.build
index 8e40e049893f1a9445290064063ef4dd7f1778ae..2ef82092ec782c4ad14d01b1d971bf00f63c6a66 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/meson.build
+++ b/source/libs/harfbuzz/harfbuzz-src/src/meson.build
@@ -28,6 +28,9 @@ hb_base_sources = files(
   'hb-atomic.hh',
   'hb-bimap.hh',
   'hb-bit-page.hh',
+  'hb-bit-set.hh',
+  'hb-bit-set-invertible.hh',
+  'hb-bit-vector.hh',
   'hb-blob.cc',
   'hb-blob.hh',
   'hb-buffer-serialize.cc',
@@ -199,6 +202,7 @@ hb_base_sources = files(
   'hb-ot-os2-unicode-ranges.hh',
   'hb-ot-post-macroman.hh',
   'hb-ot-post-table.hh',
+  'hb-ot-post-table-v2subset.hh',
   'hb-ot-shaper-arabic-fallback.hh',
   'hb-ot-shaper-arabic-joining-list.hh',
   'hb-ot-shaper-arabic-pua.hh',
@@ -241,7 +245,9 @@ hb_base_sources = files(
   'hb-ot-var-varc-table.hh',
   'hb-ot-var.cc',
   'hb-ot-vorg-table.hh',
+  'hb-priority-queue.hh',
   'hb-pool.hh',
+  'hb-repacker.hh',
   'hb-sanitize.hh',
   'hb-serialize.hh',
   'hb-set-digest.hh',
@@ -326,6 +332,9 @@ hb_base_headers += hb_version_h
 hb_ft_sources = files('hb-ft.cc', 'hb-ft-colr.hh')
 hb_ft_headers = files('hb-ft.h')
 
+hb_fontations_sources = files()
+hb_fontations_headers = files('hb-fontations.h')
+
 hb_glib_sources = files('hb-glib.cc')
 hb_glib_headers = files('hb-glib.h')
 
@@ -340,6 +349,7 @@ hb_wasm_sources = files(
   'hb-wasm-api-common.hh',
   'hb-wasm-api-face.hh',
   'hb-wasm-api-font.hh',
+  'hb-wasm-api-list.hh',
   'hb-wasm-api-shape.hh',
   'hb-wasm-shape.cc',
 )
@@ -347,10 +357,10 @@ hb_wasm_headers = files()
 
 # System-dependent sources and headers
 
-hb_coretext_sources = files('hb-coretext-shape.cc', 'hb-coretext-font.cc')
+hb_coretext_sources = files('hb-coretext.cc', 'hb-coretext.hh', 'hb-coretext-font.cc', 'hb-coretext-shape.cc')
 hb_coretext_headers = files('hb-coretext.h')
 
-hb_directwrite_sources = files('hb-directwrite.cc')
+hb_directwrite_sources = files('hb-directwrite.cc', 'hb-directwrite.hh', 'hb-directwrite-font.cc', 'hb-directwrite-shape.cc')
 hb_directwrite_headers = files('hb-directwrite.h')
 
 hb_gdi_sources = files('hb-gdi.cc')
@@ -513,6 +523,15 @@ if conf.get('HAVE_CORETEXT', 0) == 1
   harfbuzz_deps += coretext_deps
 endif
 
+if conf.get('HAVE_FONTATIONS', 0) == 1
+
+  subdir('fontations')
+
+  hb_sources += hb_fontations_sources
+  hb_headers += hb_fontations_headers
+  harfbuzz_deps += [harfbuzz_fontations_dep]
+endif
+
 have_icu = conf.get('HAVE_ICU', 0) == 1
 have_icu_builtin = conf.get('HAVE_ICU_BUILTIN', 0) == 1
 if have_icu and have_icu_builtin
@@ -650,6 +669,7 @@ if conf.get('HAVE_CAIRO', 0) == 1
   hb_cairo_sources = [
     'hb-cairo.cc',
     'hb-cairo-utils.cc',
+    'hb-cairo-utils.hh',
     'hb-static.cc'
   ]
 
@@ -663,7 +683,7 @@ if conf.get('HAVE_CAIRO', 0) == 1
     include_directories: incconfig,
     dependencies: [m_dep, cairo_dep],
     link_with: [libharfbuzz],
-     cpp_args: cpp_args + extra_hb_cpp_args,
+    cpp_args: cpp_args + extra_hb_cpp_args,
     soversion: hb_so_version,
     version: version,
     install: true,
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/test-buffer-serialize.cc b/source/libs/harfbuzz/harfbuzz-src/src/test-buffer-serialize.cc
index aced1c8d1b4beb2b4791d05e4fac396aee70e14f..421e5da6847d8a61dab98b3d3e49365b03a2e28b 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/test-buffer-serialize.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/test-buffer-serialize.cc
@@ -43,6 +43,23 @@ main (int argc, char **argv)
 
 #ifndef HB_NO_BUFFER_SERIALIZE
 
+  hb_buffer_serialize_format_t format = HB_BUFFER_SERIALIZE_FORMAT_TEXT;
+  if (argc > 1)
+  {
+    if (!strcmp (argv[1], "--json"))
+    {
+      format = HB_BUFFER_SERIALIZE_FORMAT_JSON;
+      argc--;
+      argv++;
+    }
+    else if (!strcmp (argv[1], "--text"))
+    {
+      format = HB_BUFFER_SERIALIZE_FORMAT_TEXT;
+      argc--;
+      argv++;
+    }
+  }
+
   if (argc < 2)
     argv[1] = (char *) "/dev/null";
 
@@ -68,10 +85,13 @@ main (int argc, char **argv)
     while (true)
     {
       const char *p = line;
+      const char *end = p + strlen (p);
+      if (p < end && *(end - 1) == '\n')
+	  end--;
       if (!hb_buffer_deserialize_glyphs (buf,
-					 p, -1, &p,
+					 p, end - p, &p,
 					 font,
-					 HB_BUFFER_SERIALIZE_FORMAT_TEXT))
+					 format))
       {
         ret = false;
         break;
@@ -97,7 +117,8 @@ main (int argc, char **argv)
       unsigned len;
       offset += hb_buffer_serialize_glyphs (buf, offset, count,
 					    out, sizeof (out), &len,
-					    font, HB_BUFFER_SERIALIZE_FORMAT_TEXT,
+					    font,
+					    format,
 					    HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS);
       fwrite (out, 1, len, stdout);
     }
diff --git a/source/libs/harfbuzz/include/Makefile.am b/source/libs/harfbuzz/include/Makefile.am
index c208f1627891579113df7a8e468da7f42ab5322d..21d8da54f62f7810dd674a2b421473af43abccb2 100644
--- a/source/libs/harfbuzz/include/Makefile.am
+++ b/source/libs/harfbuzz/include/Makefile.am
@@ -1,4 +1,4 @@
-## $Id: Makefile.am 73427 2025-01-11 23:22:13Z kakuto $
+## $Id: Makefile.am 74729 2025-03-24 00:38:36Z kakuto $
 ## Proxy Makefile.am to install harfbuzz headers for TeX Live.
 ##
 ##   Copyright 2015-2016 Karl Berry <tex-live@tug.org>
@@ -23,6 +23,7 @@ hdr_links = \
 	$(HARFBUZZ_SRC)/hb-draw.h \
 	$(HARFBUZZ_SRC)/hb-face.h \
 	$(HARFBUZZ_SRC)/hb-font.h \
+	$(HARFBUZZ_SRC)/hb-fontations.h \
 	$(HARFBUZZ_SRC)/hb-map.h \
 	$(HARFBUZZ_SRC)/hb-ot-deprecated.h \
 	$(HARFBUZZ_SRC)/hb-paint.h \
diff --git a/source/libs/harfbuzz/include/Makefile.in b/source/libs/harfbuzz/include/Makefile.in
index e6cf30dfe7a0cc645f300afcc0cbb96c3b4cb160..03b7908e86f12fd899aa9b5a9e5f0281c8015e06 100644
--- a/source/libs/harfbuzz/include/Makefile.in
+++ b/source/libs/harfbuzz/include/Makefile.in
@@ -255,10 +255,10 @@ hdr_links = $(HARFBUZZ_SRC)/hb.h $(HARFBUZZ_SRC)/hb-aat-layout.h \
 	$(HARFBUZZ_SRC)/hb-buffer.h $(HARFBUZZ_SRC)/hb-common.h \
 	$(HARFBUZZ_SRC)/hb-deprecated.h $(HARFBUZZ_SRC)/hb-draw.h \
 	$(HARFBUZZ_SRC)/hb-face.h $(HARFBUZZ_SRC)/hb-font.h \
-	$(HARFBUZZ_SRC)/hb-map.h $(HARFBUZZ_SRC)/hb-ot-deprecated.h \
-	$(HARFBUZZ_SRC)/hb-paint.h $(HARFBUZZ_SRC)/hb-set.h \
-	$(HARFBUZZ_SRC)/hb-shape.h $(HARFBUZZ_SRC)/hb-shape-plan.h \
-	$(HARFBUZZ_SRC)/hb-style.h \
+	$(HARFBUZZ_SRC)/hb-fontations.h $(HARFBUZZ_SRC)/hb-map.h \
+	$(HARFBUZZ_SRC)/hb-ot-deprecated.h $(HARFBUZZ_SRC)/hb-paint.h \
+	$(HARFBUZZ_SRC)/hb-set.h $(HARFBUZZ_SRC)/hb-shape.h \
+	$(HARFBUZZ_SRC)/hb-shape-plan.h $(HARFBUZZ_SRC)/hb-style.h \
 	$(HARFBUZZ_SRC)/hb-subset-serialize.h \
 	$(HARFBUZZ_SRC)/hb-unicode.h $(HARFBUZZ_BLD)/hb-version.h \
 	$(HARFBUZZ_SRC)/hb-ot.h $(HARFBUZZ_SRC)/hb-ot-color.h \
diff --git a/source/libs/harfbuzz/version.ac b/source/libs/harfbuzz/version.ac
index c52799ab6d209b6aa16064da0c7e0b1e46f5808e..e71c57a1bccd4d8168f1bfe4b1ab8c0bc68cc788 100644
--- a/source/libs/harfbuzz/version.ac
+++ b/source/libs/harfbuzz/version.ac
@@ -8,4 +8,4 @@ dnl
 dnl --------------------------------------------------------
 dnl
 dnl  m4-include this file to define the current harfbuzz version
-m4_define([harfbuzz_version], [10.4.0])
+m4_define([harfbuzz_version], [11.0.0])
diff --git a/source/texk/texlive/windows_wrapper/runscript.tlu b/source/texk/texlive/windows_wrapper/runscript.tlu
index d6f5ef23c953d736942f489f1559f8bf1127cf4e..ca790556f4ff250b59523f32f890501727c570c6 100644
--- a/source/texk/texlive/windows_wrapper/runscript.tlu
+++ b/source/texk/texlive/windows_wrapper/runscript.tlu
@@ -1,7 +1,7 @@
 
 
-local svnrevision = string.match("$Revision: 71447 $", "%d+") or "0"
-local svndate     = string.match("$Date: 2024-06-06 09:46:11 +0200 (Thu, 06 Jun 2024) $", "[-%d]+") or "2009-12-04"
+local svnrevision = string.match("$Revision: 74666 $", "%d+") or "0"
+local svndate     = string.match("$Date: 2025-03-17 04:44:40 +0100 (Mon, 17 Mar 2025) $", "[-%d]+") or "2009-12-04"
 local bannerstr   = "runscript wrapper utility (rev. " ..
                     svnrevision .. ", " .. svndate .. ")\n" .. 
                     "usage:   runscript script-name [arguments]\n" ..
@@ -843,11 +843,22 @@ elseif progname == 'latexdef' then
   progname = 'texdef'
   argline = ' --tex latex ' .. argline
 elseif progname == 'cllualatex' then
+-- Originally argline was changed to add '--engine=...'.
+-- However cllualatex and clxelatex did not work due to Engine
+-- not specified error. This is because changed argline is not
+-- used by dofile() for a lua script.
+-- Here we rewrite arguments directly. (2025/03/17)
   progname = 'cluttex'
-  argline = ' --engine=lualatex ' .. argline
+  for k = #arg, 1, -1 do
+    arg[k+1] = arg[k]
+  end
+  arg[1] = '--engine=lualatex'
 elseif progname == 'clxelatex' then
   progname = 'cluttex'
-  argline = ' --engine=xelatex ' .. argline
+  for k = #arg, 1, -1 do
+    arg[k+1] = arg[k]
+  end
+  arg[1] = '--engine=xelatex'
 end
 
 -- general case
diff --git a/source/texk/web2c/ChangeLog b/source/texk/web2c/ChangeLog
index 992baa5086fa091ea2b90ed8cb2a47656f6ca10b..61ffcd29496b84d45085e0a181286b8cb3424e09 100644
--- a/source/texk/web2c/ChangeLog
+++ b/source/texk/web2c/ChangeLog
@@ -1,14 +1,33 @@
+2025-03-12  Andreas Scherer  <https://ascherer.github.io>
+
+	* weave.ch: Prevent get_line() when parsing module name.
+	Report and patch from Benjamin Gray
+	(https://tug.org/pipermail/tex-k/2025-March/004166.html).
+
+2025-03-12  Andreas Scherer  <https://ascherer.github.io>
+
+	* weave.ch: Parse and reject verbatim in TeX part.
+	Report and patch from Benjamin Gray
+	(https://tug.org/pipermail/tex-k/2025-March/004169.html).
+
+2025-03-11  Andreas Scherer  <https://ascherer.github.io>
+
+	* tangle.ch,
+	* tangleboot.pin: Prevent integer overflow in scan_numeric().
+	Report and initial patch from Benjamin Gray
+	(https://tug.org/pipermail/tex-k/2025-March/004165.html).
+
 2025-03-10  Andreas Scherer  <https://ascherer.github.io>
 
-	* texk/web2c/tangle.ch,
-	* texk/web2c/tangleboot.pin: Reject strings as macro names.
+	* tangle.ch,
+	* tangleboot.pin: Reject strings as macro names.
 	Report and initial patch from Benjamin Gray
 	(https://tug.org/pipermail/tex-k/2025-March/004163.html).
 
 2025-03-10  Andreas Scherer  <https://ascherer.github.io>
 
-	* texk/web2c/tangle.ch,
-	* texk/web2c/tangleboot.pin: Change case for letters only.
+	* tangle.ch,
+	* tangleboot.pin: Change case for letters only.
 	Report and initial patch from Benjamin Gray
 	(https://tug.org/pipermail/tex-k/2025-March/004161.html).
 
diff --git a/source/texk/web2c/DIFF b/source/texk/web2c/DIFF
new file mode 100644
index 0000000000000000000000000000000000000000..1b8ae50c3803ca3edbddd344696c4e5af84ab732
--- /dev/null
+++ b/source/texk/web2c/DIFF
@@ -0,0 +1,11 @@
+Files luatexdir/ChangeLog and /home/luigisvn/projects/texlive/trunk/Build/source/texk/web2c/luatexdir/ChangeLog differ
+Files luatexdir/lua/ltexlib.c and /home/luigisvn/projects/texlive/trunk/Build/source/texk/web2c/luatexdir/lua/ltexlib.c differ
+Only in luatexdir/luaffi: ffi.c.orig
+Files luatexdir/luatex.c and /home/luigisvn/projects/texlive/trunk/Build/source/texk/web2c/luatexdir/luatex.c differ
+Files luatexdir/luatex_svnversion.h and /home/luigisvn/projects/texlive/trunk/Build/source/texk/web2c/luatexdir/luatex_svnversion.h differ
+Files luatexdir/tex/commands.c and /home/luigisvn/projects/texlive/trunk/Build/source/texk/web2c/luatexdir/tex/commands.c differ
+Files luatexdir/tex/equivalents.h and /home/luigisvn/projects/texlive/trunk/Build/source/texk/web2c/luatexdir/tex/equivalents.h differ
+Files luatexdir/tex/maincontrol.c and /home/luigisvn/projects/texlive/trunk/Build/source/texk/web2c/luatexdir/tex/maincontrol.c differ
+Files luatexdir/tex/mlist.c and /home/luigisvn/projects/texlive/trunk/Build/source/texk/web2c/luatexdir/tex/mlist.c differ
+Files luatexdir/tex/mlist.h and /home/luigisvn/projects/texlive/trunk/Build/source/texk/web2c/luatexdir/tex/mlist.h differ
+Files luatexdir/tex/texmath.c and /home/luigisvn/projects/texlive/trunk/Build/source/texk/web2c/luatexdir/tex/texmath.c differ
diff --git a/source/texk/web2c/cwebdir/ChangeLog b/source/texk/web2c/cwebdir/ChangeLog
index 1ed6c99a679ba221605520a45e06b7fb0555aa52..b650e2b94d97047abf513b4a0bf74b00cfa29a59 100644
--- a/source/texk/web2c/cwebdir/ChangeLog
+++ b/source/texk/web2c/cwebdir/ChangeLog
@@ -1,3 +1,12 @@
+2025-03-12  Andreas Scherer  <https://ascherer.github.io>
+
+	* ctwill-w2c.ch,
+	* cweav-w2c.ch,
+	* cweave.w,
+	* po/cweb.pot,
+	* po/de/cweb.po,
+	* po/it/cweb.po: Handle verbatim strings in TeX part.
+
 2025-02-26  Andreas Scherer  <https://ascherer.github.io>
 
 	* tests/ham-sorted.tex,
diff --git a/source/texk/web2c/cwebdir/cweav-w2c.ch b/source/texk/web2c/cwebdir/cweav-w2c.ch
index 5838e0045d93f3e776f28d2cd9e4dcef8e847477..105e48ee139dd6c9d79ed012091b465b0f98034a 100644
--- a/source/texk/web2c/cwebdir/cweav-w2c.ch
+++ b/source/texk/web2c/cwebdir/cweav-w2c.ch
@@ -471,24 +471,30 @@ if (show_progress) printf("%s",_("\nWriting the output file..."));
 @z
 
 @x [12.232] l.4268
-        err_print("! TeX string should be in C text only"); break;
+        err_print("! TeX string should be in C text only");
 @y
-        err_print(_("! TeX string should be in C text only")); break;
+        err_print(_("! TeX string should be in C text only"));
 @z
 
-@x [12.232] l.4274
+@x [12.232] l.4271
+        err_print("! Verbatim string should be in C text only"); break;
+@y
+        err_print(_("! Verbatim string should be in C text only")); break;
+@z
+
+@x [12.232] l.4277
         err_print("! You can't do that in TeX text"); break;
 @y
         err_print(_("! You can't do that in TeX text")); break;
 @z
 
-@x [12.236] l.4346
+@x [12.236] l.4349
     err_print("! Improper macro definition");
 @y
     err_print(_("! Improper macro definition"));
 @z
 
-@x [12.236] l.4359
+@x [12.236] l.4362
         } @=/* otherwise fall through */@>@;
       default: err_print("! Improper macro definition"); break;
 @y
@@ -496,62 +502,62 @@ if (show_progress) printf("%s",_("\nWriting the output file..."));
       default: err_print(_("! Improper macro definition")); break;
 @z
 
-@x [12.237] l.4386
+@x [12.237] l.4389
   if (scrap_ptr!=scrap_info+2) err_print("! Improper format definition");
 @y
   if (scrap_ptr!=scrap_info+2) err_print(_("! Improper format definition"));
 @z
 
-@x [12.240] l.4421
+@x [12.240] l.4424
   err_print("! You need an = sign after the section name");
 @y
   err_print(_("! You need an = sign after the section name"));
 @z
 
-@x [12.241] l.4443
+@x [12.241] l.4446
   err_print("! You can't do that in C text");
 @y
   err_print(_("! You can't do that in C text"));
 @z
 
-@x [13.247] l.4534
+@x [13.247] l.4537
   if (show_progress) printf("%s","\nWriting the index...");
 @y
   if (show_progress) printf("%s",_("\nWriting the index..."));
 @z
 
-@x [13.247] l.4545
+@x [13.247] l.4548
     fatal("! Cannot open index file ",idx_file_name);
 @y
     fatal(_("! Cannot open index file "),idx_file_name);
 @z
 
-@x [13.247] l.4557
+@x [13.247] l.4560
     fatal("! Cannot open section file ",scn_file_name);
 @y
     fatal(_("! Cannot open section file "),scn_file_name);
 @z
 
-@x [13.247] l.4569
+@x [13.247] l.4572
 fclose(active_file);
 @y
 fclose(active_file); active_file=tex_file=NULL;
 if (check_for_change) @<Update the result when it has changed@>@;
 @z
 
-@x [13.247] l.4572
+@x [13.247] l.4575
   printf("%s","Done.");
 @y
   printf("%s",_("Done."));
 @z
 
-@x [13.257] l.4724
+@x [13.257] l.4727
     if (sort_ptr>=scrap_info_end) overflow("sorting");
 @y
     if (sort_ptr>=scrap_info_end) overflow(_("sorting"));
 @z
 
-@x [13.269] l.4861
+@x [13.269] l.4864
   puts("\nMemory usage statistics:");
 @.Memory usage statistics:@>
   printf("%td names (out of %ld)\n",@^system dependencies@>
@@ -595,7 +601,7 @@ if (check_for_change) @<Update the result when it has changed@>@;
             (ptrdiff_t)(max_sort_ptr-scrap_info),(long)max_scraps);
 @z
 
-@x [14.270] l.4883
+@x [14.270] l.4886
 @** Index.
 @y
 @** Extensions to {\tentex CWEB}.  The following sections introduce new or
diff --git a/source/texk/web2c/cwebdir/cweave.w b/source/texk/web2c/cwebdir/cweave.w
index 39de8a432be9298ab1e0fd359479b29de973e7ec..87095b1e00fe4efdc90fa8ccb62fee47c4ea0cc4 100644
--- a/source/texk/web2c/cwebdir/cweave.w
+++ b/source/texk/web2c/cwebdir/cweave.w
@@ -4261,12 +4261,15 @@ index entries are not copied and \CEE/ text within \pb\ is translated.
   switch (next_control=copy_TeX()) {
     case '|': init_stack(); output_C(); break;
     case '@@': out('@@'); break;
-    case TeX_string: case noop:
+    case TeX_string: case verbatim: case noop:
     case xref_roman: case xref_wildcard: case xref_typewriter:
     case section_name: loc-=2; next_control=get_next(); /* skip to \.{@@>} */
       if (next_control==TeX_string)
-        err_print("! TeX string should be in C text only"); break;
+        err_print("! TeX string should be in C text only");
 @.TeX string should be...@>
+      if (next_control==verbatim)
+        err_print("! Verbatim string should be in C text only"); break;
+@.Verbatim string should be...@>
     case thin_space: case math_break: case ord:
     case line_break: case big_line_break: case no_line_break: case join:
     case pseudo_semi: case macro_arg_open: case macro_arg_close:
diff --git a/source/texk/web2c/luatexdir/luatex_svnversion.h b/source/texk/web2c/luatexdir/luatex_svnversion.h
index 147375209acbc19f24e922523a1b101c4cc8ef6e..89ac42960e9887430b559a9c6d21a9553491336d 100644
--- a/source/texk/web2c/luatexdir/luatex_svnversion.h
+++ b/source/texk/web2c/luatexdir/luatex_svnversion.h
@@ -1,4 +1,4 @@
 #ifndef luatex_svn_revision_h
 #define luatex_svn_revision_h
-#define luatex_svn_revision 7676
+#define luatex_svn_revision 7677
 #endif
diff --git a/source/texk/web2c/tangle.ch b/source/texk/web2c/tangle.ch
index 8ce847bb3fbea7b6e2e11934fe33607e188fc458..1343ded43255cd7ccd61c8c222e79d9c3e87ead9 100644
--- a/source/texk/web2c/tangle.ch
+++ b/source/texk/web2c/tangle.ch
@@ -497,15 +497,10 @@ identifier: begin k:=0; j:=byte_start[cur_val]; w:=cur_val mod ww;
   end;
 @z
 
-@x [11.119] l.2199 - Stretch limits of constants to match what we set for expressions.
-  if n>=@'2000000000 then err_print('! Constant too big')
+@x [11.119] l.2185 - Calculate with decimal limit value INT_MAX/10.
+  if n>=@'1463146314 then err_print('! Constant too big')
 @y
-  if n>=@'10000000000 then err_print('! Constant too big')
-@z
-@x [11.119] l.2208
-  if n>=@"8000000 then err_print('! Constant too big')
-@y
-  if n>=@"40000000 then err_print('! Constant too big')
+  if n>=214748364 then err_print('! Constant too big')
 @z
 
 @x [14.157] l.2862 - Larger numerics.
@@ -526,6 +521,31 @@ equiv[p]:=accumulator+@'10000000000; {name |p| now is defined to equal |accumula
     add_in(equiv[q]-@'10000000000);
 @z
 
+@x [14.160] l.2915 - Avoid numeric overflow; see also section 119.
+repeat val:=10*val+next_control-"0"; next_control:=get_next;
+@y
+repeat if val>=214748364 then err_print('! Constant too big')
+@.Constant too big@>
+  else val:=10*val+next_control-"0";
+  next_control:=get_next;
+@z
+@x [14.161] l.2920 - Avoid numeric overflow; see also section 119.
+repeat val:=8*val+next_control-"0"; next_control:=get_next;
+@y
+repeat if val>=@'2000000000 then err_print('! Constant too big')
+@.Constant too big@>
+  else val:=8*val+next_control-"0";
+  next_control:=get_next;
+@z
+@x [14.162] l.2926 - Avoid numeric overflow; see also section 119.
+val:=16*val+next_control-"0"; next_control:=get_next;
+@y
+  if val>=@"8000000 then err_print('! Constant too big')
+@.Constant too big@>
+  else val:=16*val+next_control-"0";
+  next_control:=get_next;
+@z
+
 @x [15.165] l.2964 - Add parametric2 macros (macros that use [] to delimit arguments).
   "(": incr(bal);
   ")": if bal=0 then err_print('! Extra )')
diff --git a/source/texk/web2c/tangleboot.pin b/source/texk/web2c/tangleboot.pin
index a829f257d5f4df78d7c81dc1e60e66d343bb9b32..fac3b1b8e9c7c79206cde199fcf9e36c0e0073b2 100644
--- a/source/texk/web2c/tangleboot.pin
+++ b/source/texk/web2c/tangleboot.pin
@@ -479,12 +479,12 @@ write(stdout,'! Constant too big');error;end else n:=10*n+curchar;
 curchar:=getoutput;until(curchar>57)or(curchar<48);sendval(n);k:=0;
 if curchar=101 then curchar:=69;if curchar=69 then goto 2 else goto 21;
 end;125:sendval(poolchecksum);12:begin n:=0;curchar:=48;
-repeat curchar:=curchar-48;if n>=1073741824 then begin writeln(stdout);
+repeat curchar:=curchar-48;if n>=268435456 then begin writeln(stdout);
 write(stdout,'! Constant too big');error;end else n:=8*n+curchar;
 curchar:=getoutput;until(curchar>55)or(curchar<48);sendval(n);goto 21;
 end;13:begin n:=0;curchar:=48;
 repeat if curchar>=65 then curchar:=curchar-55 else curchar:=curchar-48;
-if n>=1073741824 then begin writeln(stdout);
+if n>=134217728 then begin writeln(stdout);
 write(stdout,'! Constant too big');error;end else n:=16*n+curchar;
 curchar:=getoutput;
 until(curchar>70)or(curchar<48)or((curchar>57)and(curchar<65));
@@ -699,16 +699,22 @@ var accumulator:integer;nextsign:-1..+1;q:namepointer;val:integer;
 begin{158:}accumulator:=0;nextsign:=+1;
 while true do begin nextcontrol:=getnext;
 21:case nextcontrol of 48,49,50,51,52,53,54,55,56,57:begin{160:}val:=0;
-repeat val:=10*val+nextcontrol-48;nextcontrol:=getnext;
+repeat if val>=214748364 then begin writeln(stdout);
+write(stdout,'! Constant too big');error;
+end else val:=10*val+nextcontrol-48;nextcontrol:=getnext;
 until(nextcontrol>57)or(nextcontrol<48){:160};
 begin accumulator:=accumulator+nextsign*(val);nextsign:=+1;end;goto 21;
 end;12:begin{161:}val:=0;nextcontrol:=48;
-repeat val:=8*val+nextcontrol-48;nextcontrol:=getnext;
+repeat if val>=268435456 then begin writeln(stdout);
+write(stdout,'! Constant too big');error;
+end else val:=8*val+nextcontrol-48;nextcontrol:=getnext;
 until(nextcontrol>55)or(nextcontrol<48){:161};
 begin accumulator:=accumulator+nextsign*(val);nextsign:=+1;end;goto 21;
 end;13:begin{162:}val:=0;nextcontrol:=48;
 repeat if nextcontrol>=65 then nextcontrol:=nextcontrol-7;
-val:=16*val+nextcontrol-48;nextcontrol:=getnext;
+if val>=134217728 then begin writeln(stdout);
+write(stdout,'! Constant too big');error;
+end else val:=16*val+nextcontrol-48;nextcontrol:=getnext;
 until(nextcontrol>70)or(nextcontrol<48)or((nextcontrol>57)and(
 nextcontrol<65)){:162};begin accumulator:=accumulator+nextsign*(val);
 nextsign:=+1;end;goto 21;end;130:begin q:=idlookup(0);