summaryrefslogtreecommitdiff
path: root/macros
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2020-09-03 03:01:14 +0000
committerNorbert Preining <norbert@preining.info>2020-09-03 03:01:14 +0000
commitfc732340b62b41cedbe82bcb3675a86c65343a21 (patch)
treec490d1d57d300b1024517118f6e494d68eae5bcd /macros
parent66aedee32b96d68acc7b854602552c75ef261973 (diff)
CTAN sync 202009030301
Diffstat (limited to 'macros')
-rw-r--r--macros/latex/contrib/caption/README2
-rw-r--r--macros/latex/contrib/caption/caption.dtx51
-rw-r--r--macros/latex/contrib/changelog/changelog.pdfbin46126 -> 46523 bytes
-rw-r--r--macros/latex/contrib/changelog/changelog.sty13
-rw-r--r--macros/latex/contrib/changelog/changelog.tex13
-rw-r--r--macros/latex/contrib/changelog/example.pdfbin16775 -> 16679 bytes
-rw-r--r--macros/latex/contrib/l3backend/CHANGELOG.md11
-rw-r--r--macros/latex/contrib/l3backend/README.md2
-rw-r--r--macros/latex/contrib/l3backend/l3backend-basics.dtx165
-rw-r--r--macros/latex/contrib/l3backend/l3backend-box.dtx14
-rw-r--r--macros/latex/contrib/l3backend/l3backend-color.dtx325
-rw-r--r--macros/latex/contrib/l3backend/l3backend-draw.dtx46
-rw-r--r--macros/latex/contrib/l3backend/l3backend-graphics.dtx24
-rw-r--r--macros/latex/contrib/l3backend/l3backend-header.dtx12
-rw-r--r--macros/latex/contrib/l3backend/l3backend-pdf.dtx419
-rw-r--r--macros/latex/contrib/l3backend/l3backend.ins40
-rw-r--r--macros/latex/contrib/l3experimental/CHANGELOG.md16
-rw-r--r--macros/latex/contrib/l3experimental/README.md2
-rw-r--r--macros/latex/contrib/l3experimental/l3benchmark.dtx4
-rw-r--r--macros/latex/contrib/l3experimental/l3benchmark.pdfbin314321 -> 314255 bytes
-rw-r--r--macros/latex/contrib/l3experimental/l3color.dtx246
-rw-r--r--macros/latex/contrib/l3experimental/l3color.pdfbin367377 -> 367535 bytes
-rw-r--r--macros/latex/contrib/l3experimental/l3draw-boxes.dtx2
-rw-r--r--macros/latex/contrib/l3experimental/l3draw-code.pdfbin606221 -> 606612 bytes
-rw-r--r--macros/latex/contrib/l3experimental/l3draw-layers.dtx2
-rw-r--r--macros/latex/contrib/l3experimental/l3draw-paths.dtx2
-rw-r--r--macros/latex/contrib/l3experimental/l3draw-points.dtx2
-rw-r--r--macros/latex/contrib/l3experimental/l3draw-scopes.dtx2
-rw-r--r--macros/latex/contrib/l3experimental/l3draw-softpath.dtx2
-rw-r--r--macros/latex/contrib/l3experimental/l3draw-state.dtx2
-rw-r--r--macros/latex/contrib/l3experimental/l3draw-transforms.dtx6
-rw-r--r--macros/latex/contrib/l3experimental/l3draw.dtx4
-rw-r--r--macros/latex/contrib/l3experimental/l3draw.pdfbin489876 -> 489817 bytes
-rw-r--r--macros/latex/contrib/l3experimental/l3galley.dtx4
-rw-r--r--macros/latex/contrib/l3experimental/l3galley.pdfbin385812 -> 385764 bytes
-rw-r--r--macros/latex/contrib/l3experimental/l3graphics.dtx4
-rw-r--r--macros/latex/contrib/l3experimental/l3graphics.pdfbin363180 -> 363123 bytes
-rw-r--r--macros/latex/contrib/l3experimental/l3pdf-code.pdfbin276917 -> 276730 bytes
-rw-r--r--macros/latex/contrib/l3experimental/l3pdf.dtx4
-rw-r--r--macros/latex/contrib/l3experimental/l3pdf.pdfbin350863 -> 350795 bytes
-rw-r--r--macros/latex/contrib/l3experimental/l3str-format.dtx4
-rw-r--r--macros/latex/contrib/l3experimental/l3str-format.pdfbin344948 -> 344898 bytes
-rw-r--r--macros/latex/contrib/l3experimental/l3sys-shell.dtx4
-rw-r--r--macros/latex/contrib/l3experimental/l3sys-shell.pdfbin311773 -> 311734 bytes
-rw-r--r--macros/latex/contrib/l3experimental/xcoffins.dtx4
-rw-r--r--macros/latex/contrib/l3experimental/xcoffins.pdfbin372941 -> 372890 bytes
-rw-r--r--macros/latex/contrib/l3experimental/xgalley.dtx4
-rw-r--r--macros/latex/contrib/l3experimental/xgalley.pdfbin285732 -> 285681 bytes
-rw-r--r--macros/latex/contrib/l3kernel/CHANGELOG.md24
-rw-r--r--macros/latex/contrib/l3kernel/README.md2
-rw-r--r--macros/latex/contrib/l3kernel/expl3.dtx121
-rw-r--r--macros/latex/contrib/l3kernel/expl3.pdfbin585053 -> 585131 bytes
-rw-r--r--macros/latex/contrib/l3kernel/interface3.pdfbin1555681 -> 1556010 bytes
-rw-r--r--macros/latex/contrib/l3kernel/interface3.tex2
-rw-r--r--macros/latex/contrib/l3kernel/l3basics.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3bootstrap.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3box.dtx14
-rw-r--r--macros/latex/contrib/l3kernel/l3candidates.dtx4
-rw-r--r--macros/latex/contrib/l3kernel/l3cctab.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3clist.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3coffins.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3color-base.dtx3
-rw-r--r--macros/latex/contrib/l3kernel/l3debug.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3deprecation.dtx18
-rw-r--r--macros/latex/contrib/l3kernel/l3doc.dtx13
-rw-r--r--macros/latex/contrib/l3kernel/l3docstrip.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3docstrip.pdfbin263337 -> 263273 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3expan.dtx13
-rw-r--r--macros/latex/contrib/l3kernel/l3file.dtx139
-rw-r--r--macros/latex/contrib/l3kernel/l3flag.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-assign.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-aux.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-basics.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-convert.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-expo.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-extended.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-logic.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-parse.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-random.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-round.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-traps.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-trig.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fparray.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3int.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3intarray.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3kernel-functions.dtx20
-rw-r--r--macros/latex/contrib/l3kernel/l3keys.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3legacy.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3luatex.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3msg.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3names.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3news.pdfbin379235 -> 379235 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news01.pdfbin113527 -> 113527 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news02.pdfbin140776 -> 140776 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news03.pdfbin144785 -> 144785 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news04.pdfbin107115 -> 107115 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news05.pdfbin105090 -> 105090 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news06.pdfbin140795 -> 140795 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news07.pdfbin119094 -> 119094 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news08.pdfbin152413 -> 152413 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news09.pdfbin235322 -> 235322 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news10.pdfbin147097 -> 147097 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news11.pdfbin165946 -> 165946 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news12.pdfbin199139 -> 199139 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3prefixes.pdfbin75889 -> 75889 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3prg.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3prop.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3quark.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3regex.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3seq.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3skip.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3sort.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3str-convert.dtx318
-rw-r--r--macros/latex/contrib/l3kernel/l3str.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3styleguide.pdfbin280064 -> 279972 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3styleguide.tex2
-rw-r--r--macros/latex/contrib/l3kernel/l3syntax-changes.pdfbin228354 -> 228265 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3syntax-changes.tex2
-rw-r--r--macros/latex/contrib/l3kernel/l3sys.dtx115
-rw-r--r--macros/latex/contrib/l3kernel/l3term-glossary.pdfbin217736 -> 217636 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3term-glossary.tex2
-rw-r--r--macros/latex/contrib/l3kernel/l3text-case.dtx4
-rw-r--r--macros/latex/contrib/l3kernel/l3text-purify.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3text.dtx4
-rw-r--r--macros/latex/contrib/l3kernel/l3tl-analysis.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3tl.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3token.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3unicode.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/source3.pdfbin5844782 -> 5862842 bytes
-rw-r--r--macros/latex/contrib/l3kernel/source3.tex2
-rw-r--r--macros/latex/contrib/metastr/README.txt2
-rw-r--r--macros/latex/contrib/metastr/metastr.dtx51
-rw-r--r--macros/latex/contrib/metastr/metastr.pdfbin340489 -> 340901 bytes
-rw-r--r--macros/latex/contrib/newverbs/README4
-rw-r--r--macros/latex/contrib/newverbs/newverbs.dtx10
-rw-r--r--macros/latex/contrib/newverbs/newverbs.pdfbin220993 -> 221177 bytes
-rw-r--r--macros/luatex/generic/lualibs/NEWS3
-rw-r--r--macros/luatex/generic/lualibs/README.md6
-rw-r--r--macros/luatex/generic/lualibs/lualibs-basic-merged.lua49
-rw-r--r--macros/luatex/generic/lualibs/lualibs-extended-merged.lua90
-rw-r--r--macros/luatex/generic/lualibs/lualibs-lpeg.lua8
-rw-r--r--macros/luatex/generic/lualibs/lualibs-lua.lua6
-rw-r--r--macros/luatex/generic/lualibs/lualibs-os.lua12
-rw-r--r--macros/luatex/generic/lualibs/lualibs-package.lua25
-rw-r--r--macros/luatex/generic/lualibs/lualibs-trac-inf.lua41
-rw-r--r--macros/luatex/generic/lualibs/lualibs-unicode.lua1
-rw-r--r--macros/luatex/generic/lualibs/lualibs-util-prs.lua38
-rw-r--r--macros/luatex/generic/lualibs/lualibs-util-str.lua86
-rw-r--r--macros/luatex/generic/lualibs/lualibs-util-tab.lua9
-rw-r--r--macros/luatex/generic/lualibs/lualibs.dtx18
-rw-r--r--macros/luatex/generic/lualibs/lualibs.pdfbin80861 -> 81574 bytes
-rw-r--r--macros/luatex/generic/luaotfload/NEWS19
-rw-r--r--macros/luatex/generic/luaotfload/README.md4
-rw-r--r--macros/luatex/generic/luaotfload/filegraph.pdfbin39877 -> 40015 bytes
-rw-r--r--macros/luatex/generic/luaotfload/filegraph.tex4
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-2020-08-31.lua (renamed from macros/luatex/generic/luaotfload/fontloader-2020-05-06.lua)988
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-basics-gen.lua6
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-basics-nod.lua7
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-cff.lua51
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-con.lua91
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-def.lua5
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-dsp.lua3
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-imp-effects.lua68
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-imp-italics.lua46
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-map.lua2
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-ocl.lua118
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-one.lua1
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-onr.lua1
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-ota.lua116
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-otj.lua1
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-otr.lua117
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-ots.lua48
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-ott.lua38
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-shp.lua395
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-ttf.lua1
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-vfc.lua2
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-l-lpeg.lua8
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-l-lua.lua6
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-l-unicode.lua1
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-reference-load-order.lua32
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-reference.lua10110
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-util-fil.lua1
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-util-str.lua86
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-colors.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-conf.pdfbin77393 -> 77426 bytes
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-configuration.lua58
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-database.lua177
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-diagnostics.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-dvi.lua131
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-embolden.lua6
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-fallback.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-features.lua167
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-filelist.lua14
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-harf-define.lua6
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua97
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-init.lua180
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-latex.pdfbin446181 -> 486239 bytes
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-letterspace.lua6
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-loaders.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-log.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-main.lua27
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-main.tex71
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-multiscript.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-notdef.lua16
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-parsers.lua29
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-resolvers.lua8
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-scripts.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-status.lua180
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-suppress.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-szss.lua6
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-tool.12
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-tool.lua37
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-tool.pdfbin76865 -> 76886 bytes
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-tool.rst4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-tounicode.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-unicode.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload.conf.52
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload.conf.rst4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload.sty9
-rw-r--r--macros/luatex/generic/luaotfload/scripts-demo.pdfbin21523 -> 21504 bytes
-rw-r--r--macros/luatex/generic/luaotfload/shaper-demo-graphite.pdfbin8487 -> 8468 bytes
-rw-r--r--macros/luatex/generic/luaotfload/shaper-demo.pdfbin8411 -> 8392 bytes
225 files changed, 9542 insertions, 6941 deletions
diff --git a/macros/latex/contrib/caption/README b/macros/latex/contrib/caption/README
index 76c478b98f..ca3df1b169 100644
--- a/macros/latex/contrib/caption/README
+++ b/macros/latex/contrib/caption/README
@@ -1,7 +1,7 @@
==========================================================================
The `caption' package bundle
-Release 2020-08-30
+Release 2020-09-02
Copyright (C) 1994-2020 Axel Sommerfeldt (axel.sommerfeldt@f-m.fm)
License: LPPL = LaTeX Project Public Licence
diff --git a/macros/latex/contrib/caption/caption.dtx b/macros/latex/contrib/caption/caption.dtx
index 0a029f8d38..1068796a87 100644
--- a/macros/latex/contrib/caption/caption.dtx
+++ b/macros/latex/contrib/caption/caption.dtx
@@ -32,7 +32,7 @@
% caption-deu.tex, caption-eng.tex, caption-rus.tex.
%
% \fi
-% \CheckSum{2715}
+% \CheckSum{2690}
%
% \iffalse
%<*driver>
@@ -217,13 +217,13 @@
%
% \begin{macrocode}
\NeedsTeXFormat{LaTeX2e}[1994/12/01]
-\ProvidesPackage{caption}[2020/08/30 v3.5 Customizing captions (AR)]
+\ProvidesPackage{caption}[2020/09/02 v3.5a Customizing captions (AR)]
% \end{macrocode}
%
% \section{Loading the kernel}
%
% \begin{macrocode}
-\RequirePackage{caption3}[2020/08/23] % needs v2.0 or newer
+\RequirePackage{caption3}[2020/08/30] % needs v2.0 or newer
% \end{macrocode}
%
% \section{Check against unknown document classes}
@@ -355,6 +355,7 @@
% \changes{v3.1}{2007/07/21}{Option `compatibility' added}
% \changes{v3.1}{2007/09/01}{caption v1.x compatibility options revised}
% \changes{v3.1d}{2007/10/24}{Bugfix 07-10-24 in caption v1.x$ compatibility options}
+% \changes{v3.5a}{2020/09/02}{caption v1.x compatibility options fixed}
%
% Currently we support |v1| and |v3| as values for the |compatibility=| option.
% But since this used to be a boolean option is the past we still support any boolean value
@@ -405,20 +406,15 @@
%
% \begin{macrocode}
\DeclareCaptionOptionNoValue*{normal}{%
- \caption@setformat{plain}%
- \caption@setjustification{justified}}
+ \caption@setup{format=plain,justification=justified}}
\DeclareCaptionOptionNoValue*{isu}{%
- \caption@setformat{hang}%
- \caption@setjustification{justified}}
+ \caption@setup{format=hang,justification=justified}}
\DeclareCaptionOptionNoValue*{hang}{%
- \caption@setformat{hang}%
- \caption@setjustification{justified}}
+ \caption@setup{format=hang,justification=justified}}
\DeclareCaptionOptionNoValue*{center}{%
- \caption@setformat{plain}%
- \caption@setjustification{centering}}
+ \caption@setup{format=plain,justification=centering}}
\DeclareCaptionOptionNoValue*{centerlast}{%
- \caption@setformat{plain}%
- \caption@setjustification{centerlast}}
+ \caption@setup{format=plain,justification=centerlast}}
% \end{macrocode}
%
% \begin{macrocode}
@@ -431,19 +427,19 @@
% \end{macrocode}
%
% \begin{macrocode}
-\DeclareCaptionOptionNoValue*{up}{\l@addto@macro\captionlabelfont\upshape}
-\DeclareCaptionOptionNoValue*{it}{\l@addto@macro\captionlabelfont\itshape}
-\DeclareCaptionOptionNoValue*{sl}{\l@addto@macro\captionlabelfont\slshape}
-\DeclareCaptionOptionNoValue*{sc}{\l@addto@macro\captionlabelfont\scshape}
-\DeclareCaptionOptionNoValue*{md}{\l@addto@macro\captionlabelfont\mdseries}
-\DeclareCaptionOptionNoValue*{bf}{\l@addto@macro\captionlabelfont\bfseries}
-\DeclareCaptionOptionNoValue*{rm}{\l@addto@macro\captionlabelfont\rmfamily}
-\DeclareCaptionOptionNoValue*{sf}{\l@addto@macro\captionlabelfont\sffamily}
-\DeclareCaptionOptionNoValue*{tt}{\l@addto@macro\captionlabelfont\ttfamily}
+\DeclareCaptionOptionNoValue*{up}{\caption@setup{labelfont+=up}}
+\DeclareCaptionOptionNoValue*{it}{\caption@setup{labelfont+=it}}
+\DeclareCaptionOptionNoValue*{sl}{\caption@setup{labelfont+=sl}}
+\DeclareCaptionOptionNoValue*{sc}{\caption@setup{labelfont+=sc}}
+\DeclareCaptionOptionNoValue*{md}{\caption@setup{labelfont+=md}}
+\DeclareCaptionOptionNoValue*{bf}{\caption@setup{labelfont+=bf}}
+\DeclareCaptionOptionNoValue*{rm}{\caption@setup{labelfont+=rm}}
+\DeclareCaptionOptionNoValue*{sf}{\caption@setup{labelfont+=sf}}
+\DeclareCaptionOptionNoValue*{tt}{\caption@setup{labelfont+=tt}}
% \end{macrocode}
%
% \begin{macrocode}
-\DeclareCaptionOptionNoValue*{nooneline}{\caption@setbool{slc}{0}}
+\DeclareCaptionOptionNoValue*{nooneline}{\caption@setup{slc=0}}
% \end{macrocode}
%
% \begin{macrocode}
@@ -455,17 +451,16 @@
% \changes{v3.0h}{2005/07/08}{caption2 \version{2.x} compatibility options added}
% \changes{v3.1}{2007/09/01}{caption2 v2.x compatibility options revised}
% \changes{v3.1d}{2007/10/24}{Bugfix 07-10-24 in caption v2.x$ compatibility options}
+% \changes{v3.5a}{2020/09/02}{caption v2.x compatibility options fixed}
%
% \begin{macrocode}
\DeclareCaptionOptionNoValue*{flushleft}{%
- \caption@setformat{plain}%
- \caption@setjustification{raggedright}}
+ \caption@setup{format=plain,justification=raggedright}}
\DeclareCaptionOptionNoValue*{flushright}{%
- \caption@setformat{plain}%
- \caption@setjustification{raggedleft}}
+ \caption@setup{format=plain,justification=raggedleft}}
% \end{macrocode}
% \begin{macrocode}
-\DeclareCaptionOptionNoValue*{oneline}{\caption@setbool{slc}{1}}
+\DeclareCaptionOptionNoValue*{oneline}{\caption@setup{slc=1}}
% \end{macrocode}
% \begin{macrocode}
\DeclareCaptionOptionNoValue*{ignoreLTcapwidth}{%
diff --git a/macros/latex/contrib/changelog/changelog.pdf b/macros/latex/contrib/changelog/changelog.pdf
index d74e29c378..800b2ac365 100644
--- a/macros/latex/contrib/changelog/changelog.pdf
+++ b/macros/latex/contrib/changelog/changelog.pdf
Binary files differ
diff --git a/macros/latex/contrib/changelog/changelog.sty b/macros/latex/contrib/changelog/changelog.sty
index b217acb048..6c329e9a18 100644
--- a/macros/latex/contrib/changelog/changelog.sty
+++ b/macros/latex/contrib/changelog/changelog.sty
@@ -1,4 +1,4 @@
-\ProvidesPackage{changelog}[2020/08/26 2.3.0 Typesetting changelogs]
+\ProvidesPackage{changelog}[2020/08/26 2.4.0 Typesetting changelogs]
% Description: Provides the changelog environment for typesetting changelogs
% License: LPPL 1.3c
% Homepage: https://github.com/9999years/latex-changelog
@@ -83,6 +83,17 @@
\DeclareTranslation{French}{changelog-Miscellaneous}{Divers}
\DeclareTranslation{French}{changelog-Unreleased}{Non publié}
\DeclareTranslation{French}{changelog-Yanked}{Annulé}
+% Japanese translations by cmplstofB <github.com/cmplstofB>
+\DeclareTranslation{Japanese}{changelog}{変更履歴}
+\DeclareTranslation{Japanese}{changelog-Added}{追加}
+\DeclareTranslation{Japanese}{changelog-Changed}{変更}
+\DeclareTranslation{Japanese}{changelog-Deprecated}{非推奨}
+\DeclareTranslation{Japanese}{changelog-Removed}{削除}
+\DeclareTranslation{Japanese}{changelog-Fixed}{修正}
+\DeclareTranslation{Japanese}{changelog-Security}{安全性}
+\DeclareTranslation{Japanese}{changelog-Miscellaneous}{雑題}
+\DeclareTranslation{Japanese}{changelog-Unreleased}{未公開}
+\DeclareTranslation{Japanese}{changelog-Yanked}{緊急変更}
\newif\ifchangelog@versionfirst
\newcommand{\changelog@item}[1]{%
diff --git a/macros/latex/contrib/changelog/changelog.tex b/macros/latex/contrib/changelog/changelog.tex
index 32a699eee6..3e5611dd5d 100644
--- a/macros/latex/contrib/changelog/changelog.tex
+++ b/macros/latex/contrib/changelog/changelog.tex
@@ -37,7 +37,7 @@
\author{Rebecca Turner\thanks{Brandeis University; \email{rbt@sent.as}}}
\title{The \cl\ Package}
-\date{2020/08/26 2.3.0}
+\date{2020/08/26 2.4.0}
\begin{document}
\maketitle
@@ -260,8 +260,8 @@ Prints the ``revoked release'' notice:
\section{Translations}
Want to use \cl\ in a non-English document? Great! \cl\ comes with
-translations for English, German, Spanish, and French, as well as support
-for adding new translations (see section~\ref{s:contrib} below for
+translations for English, German, Spanish, French, and Japanese, as well as
+support for adding new translations (see section~\ref{s:contrib} below for
translation credits). To use built-in translations, simply load \ctan{babel}
with the desired language:
\begin{otherlanguage}{german}
@@ -319,6 +319,7 @@ an email} and I'll incorporate the translation into \cl's next release!
Support for translating the changelog's section title and Spanish
translations.
\item[Damien Calesse <\https{github.com/kranack}>] French translations.
+ \item[cmplstofB <\https{github.com/cmplstofB}>] Japanese translations.
\end{description}
\section{Changelog}
@@ -326,6 +327,12 @@ an email} and I'll incorporate the translation into \cl's next release!
This is this package's actual changelog --- not an example!
\begin{changelog}[author=Rebecca Turner <\email{rbt@sent.as}>, section=false]
+\begin{version}[v=2.4.0, date=2020-09-02,
+ author={cmplstofB <\https{github.com/cmplstofB}>}]
+\added
+ \item Japanese translations.
+\end{version}
+
\begin{version}[v=2.3.0, date=2020-08-26,
author={Damien Calesse <\https{github.com/kranack}>}]
\added
diff --git a/macros/latex/contrib/changelog/example.pdf b/macros/latex/contrib/changelog/example.pdf
index 138b097680..6cb7383b02 100644
--- a/macros/latex/contrib/changelog/example.pdf
+++ b/macros/latex/contrib/changelog/example.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3backend/CHANGELOG.md b/macros/latex/contrib/l3backend/CHANGELOG.md
index 6d9dbaab14..5937d8be02 100644
--- a/macros/latex/contrib/l3backend/CHANGELOG.md
+++ b/macros/latex/contrib/l3backend/CHANGELOG.md
@@ -6,6 +6,14 @@ this project uses date-based 'snapshot' version identifiers.
## [Unreleased]
+## [2020-09-01]
+
+### Changed
+- Improved support for Separation colors
+- Updated approach to `dvipdfmx`/XeTeX color support
+- Split `pdfmode` driver into pdfTeX- and LuaTeX-specific files
+- Renamed `xdvipdfmx` backend files to `xetex`
+
## [2020-08-07]
### Changed
@@ -102,7 +110,8 @@ this project uses date-based 'snapshot' version identifiers.
- Include `l3backend` in file names
- Moved backend code to internal for each 'parent' module
-[Unreleased]: https://github.com/latex3/latex3/compare/2020-08-07...HEAD
+[Unreleased]: https://github.com/latex3/latex3/compare/2020-09-01...HEAD
+[2020-09-01]: https://github.com/latex3/latex3/compare/2020-08-07...2020-09-01
[2020-08-07]: https://github.com/latex3/latex3/compare/2020-06-29...2020-08-07
[2020-06-29]: https://github.com/latex3/latex3/compare/2020-06-23...2020-06-29
[2020-06-23]: https://github.com/latex3/latex3/compare/2020-06-18...2020-06-23
diff --git a/macros/latex/contrib/l3backend/README.md b/macros/latex/contrib/l3backend/README.md
index a0ebb98003..86d0912e2c 100644
--- a/macros/latex/contrib/l3backend/README.md
+++ b/macros/latex/contrib/l3backend/README.md
@@ -1,7 +1,7 @@
LaTeX3 Backend Drivers
======================
-Release 2020-08-07
+Release 2020-09-01
This package forms parts of `expl3`, and contains the code used to interface
with backends (drivers) across the `expl3` codebase. The functions here are
diff --git a/macros/latex/contrib/l3backend/l3backend-basics.dtx b/macros/latex/contrib/l3backend/l3backend-basics.dtx
index 209b2a648f..a90cd6bb05 100644
--- a/macros/latex/contrib/l3backend/l3backend-basics.dtx
+++ b/macros/latex/contrib/l3backend/l3backend-basics.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -68,29 +68,59 @@
% All the file identifiers are up-front so that they come out in the right
% place in the files.
% \begin{macrocode}
-%<*package>
\ProvidesExplFile
%<*dvipdfmx>
- {l3backend-dvipdfmx.def}{2020-08-07}{}
+ {l3backend-dvipdfmx.def}{2020-09-01}{}
{L3 backend support: dvipdfmx}
%</dvipdfmx>
%<*dvips>
- {l3backend-dvips.def}{2020-08-07}{}
+ {l3backend-dvips.def}{2020-09-01}{}
{L3 backend support: dvips}
%</dvips>
%<*dvisvgm>
- {l3backend-dvisvgm.def}{2020-08-07}{}
+ {l3backend-dvisvgm.def}{2020-09-01}{}
{L3 backend support: dvisvgm}
%</dvisvgm>
-%<*pdfmode>
- {l3backend-pdfmode.def}{2020-08-07}{}
- {L3 backend support: PDF mode}
-%</pdfmode>
-%<*xdvipdfmx>
- {l3backend-xdvipdfmx.def}{2020-08-07}{}
- {L3 backend support: xdvipdfmx}
-%</xdvipdfmx>
-%</package>
+%<*luatex>
+ {l3backend-luatex.def}{2020-09-01}{}
+ {L3 backend support: PDF output (LuaTeX)}
+%</luatex>
+%<*pdftex>
+ {l3backend-pdftex.def}{2020-09-01}{}
+ {L3 backend support: PDF output (pdfTeX)}
+%</pdftex>
+%<*xetex>
+ {l3backend-xetex.def}{2020-09-01}{}
+ {L3 backend support: XeTeX}
+%</xetex>
+% \end{macrocode}
+%
+% Check if the loaded kernel is at least enough to load this file.
+% The kernel date has to be at least equal to \cs{ExplBackendFileDate}
+% or later. If \cs{__kernel_dependency_version_check:Nn} doesn't
+% exist we're loading in an older kernel, so it's an error anyway.
+% With time, this test should vanish and only the dependency check
+% should remain.
+% \begin{macrocode}
+\cs_if_exist:NTF \__kernel_dependency_version_check:nn
+ {
+ \__kernel_dependency_version_check:nn {2020-09-01}
+%<dvipdfmx> {l3backend-dvipdfmx.def}
+%<dvips> {l3backend-dvips.def}
+%<dvisvgm> {l3backend-dvisvgm.def}
+%<luatex> {l3backend-luatex.def}
+%<pdftex> {l3backend-pdftex.def}
+%<xetex> {l3backend-xetex.def}
+ }
+ {
+ \cs_if_exist_use:cF { @latex@error } { \errmessage }
+ {
+ Mismatched~LaTeX~support~files~detected. \MessageBreak
+ Loading~aborted!
+ }
+ { \use:c { @ehd } }
+ \tex_endinput:D
+ }
% \end{macrocode}
%
% The order of the backend code here is such that we get somewhat logical
@@ -98,10 +128,10 @@
% mix all of the code by concept is almost unmanageable.) The key parts which
% are shared are
% \begin{itemize}
-% \item Color support is either \texttt{dvips}-like or \texttt{pdfmode}-like.
-% \item \texttt{pdfmode} and \texttt{(x)dvipdfmx} share drawing routines.
-% \item \texttt{xdvipdfmx} is largely the same as \texttt{dvipdfmx} so
-% takes most of the same code.
+% \item Color support is either \texttt{dvips}-like or \LuaTeX{}/pdfTeX{}-like.
+% \item \LuaTeX{}/pdfTeX{} and \texttt{dvipdfmx}/\XeTeX{} share drawing routines.
+% \item \XeTeX{} is the same as \texttt{dvipdfmx} other than image size
+% extraction so takes most of the same code.
% \end{itemize}
%
% \begin{macro}
@@ -155,15 +185,13 @@
% This is held until the start of shipout such that a document with no
% actual output does not write anything.
% \begin{macrocode}
-\cs_if_exist:NTF \AtBeginDvi
- { \AtBeginDvi }
- { \use:n }
- {
- \bool_lazy_and:nnT
- { \cs_if_exist_p:N \g__kernel_backend_header_bool }
- { \g__kernel_backend_header_bool }
+\bool_if:NT \g__kernel_backend_header_bool
+ {
+ \cs_if_exist:NTF \AtBeginDvi
+ { \AtBeginDvi }
+ { \use:n }
{ \__kernel_backend_literal:n { header = l3backend-dvips.pro } }
- }
+ }
% \end{macrocode}
%
% \begin{macro}
@@ -211,17 +239,16 @@
%</dvips>
% \end{macrocode}
%
-% \subsection{\texttt{pdfmode} backend}
+% \subsection{\LuaTeX{} and \pdfTeX{} backends}
%
% \begin{macrocode}
-%<*pdfmode>
+%<*luatex|pdftex>
% \end{macrocode}
%
-% The direct PDF backend covers both \pdfTeX{} and \LuaTeX{}. The latter
-% renames and restructures the backend primitives but this can be handled
-% at one level of abstraction. As such, we avoid using two separate backends
-% for this material at the cost of some \texttt{x}-type definitions to get
-% everything expanded up-front.
+% Both \LuaTeX{} and \pdfTeX{} write PDFs directly rather than via an
+% intermediate file. Although there are similarities, the move of \LuaTeX{}
+% to have more code in Lua means we create two independent files using
+% shared DocStrip code.
%
% \begin{macro}{\__kernel_backend_literal_pdf:n, \__kernel_backend_literal_pdf:x}
% This is equivalent to \verb|\special{pdf:}| but the engine can
@@ -230,12 +257,15 @@
% Note that this is still inside the text (\texttt{BT} \dots \texttt{ET}
% block).
% \begin{macrocode}
-\cs_new_protected:Npx \__kernel_backend_literal_pdf:n #1
+\cs_new_protected:Npn \__kernel_backend_literal_pdf:n #1
{
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D literal }
- { \tex_pdfliteral:D }
- { \exp_not:N \exp_not:n {#1} }
+%<*luatex>
+ \tex_pdfextension:D literal
+%</luatex>
+%<*pdftex>
+ \tex_pdfliteral:D
+%</pdftex>
+ { \exp_not:n {#1} }
}
\cs_generate_variant:Nn \__kernel_backend_literal_pdf:n { x }
% \end{macrocode}
@@ -245,13 +275,15 @@
% Page literals are pretty simple. To avoid an expansion, we write out
% by hand.
% \begin{macrocode}
-\cs_new_protected:Npx \__kernel_backend_literal_page:n #1
+\cs_new_protected:Npn \__kernel_backend_literal_page:n #1
{
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D literal ~ }
- { \tex_pdfliteral:D }
- page
- { \exp_not:N \exp_not:n {#1} }
+%<*luatex>
+ \tex_pdfextension:D literal ~
+%</luatex>
+%<*pdftex>
+ \tex_pdfliteral:D
+%</pdftex>
+ page { \exp_not:n {#1} }
}
% \end{macrocode}
% \end{macro}
@@ -259,17 +291,23 @@
% \begin{macro}{\__kernel_backend_scope_begin:, \__kernel_backend_scope_end:}
% Higher-level interfaces for saving and restoring the graphic state.
% \begin{macrocode}
-\cs_new_protected:Npx \__kernel_backend_scope_begin:
+\cs_new_protected:Npn \__kernel_backend_scope_begin:
{
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D save \scan_stop: }
- { \tex_pdfsave:D }
+%<*luatex>
+ \tex_pdfextension:D save \scan_stop:
+%</luatex>
+%<*pdftex>
+ \tex_pdfsave:D
+%</pdftex>
}
-\cs_new_protected:Npx \__kernel_backend_scope_end:
+\cs_new_protected:Npn \__kernel_backend_scope_end:
{
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D restore \scan_stop: }
- { \tex_pdfrestore:D }
+%<*luatex>
+ \tex_pdfextension:D restore \scan_stop:
+%</luatex>
+%<*pdftex>
+ \tex_pdfrestore:D
+%</pdftex>
}
% \end{macrocode}
% \end{macro}
@@ -279,31 +317,34 @@
% into the PDF. With \pdfTeX{} and \LuaTeX{} in direct PDF output mode there
% is a primitive for this, which only needs the rotation/scaling/skew part.
% \begin{macrocode}
-\cs_new_protected:Npx \__kernel_backend_matrix:n #1
+\cs_new_protected:Npn \__kernel_backend_matrix:n #1
{
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D setmatrix }
- { \tex_pdfsetmatrix:D }
- { \exp_not:N \exp_not:n {#1} }
+%<*luatex>
+ \tex_pdfextension:D setmatrix
+%</luatex>
+%<*pdftex>
+ \tex_pdfsetmatrix:D
+%</pdftex>
+ { \exp_not:n {#1} }
}
\cs_generate_variant:Nn \__kernel_backend_matrix:n { x }
% \end{macrocode}
% \end{macro}
%
% \begin{macrocode}
-%</pdfmode>
+%</luatex|pdftex>
% \end{macrocode}
%
% \subsection{\texttt{dvipdfmx} backend}
%
% \begin{macrocode}
-%<*dvipdfmx|xdvipdfmx>
+%<*dvipdfmx|xetex>
% \end{macrocode}
%
% The \texttt{dvipdfmx} shares code with the PDF mode one (using the common
-% section to this file) but also with \texttt{xdvipdfmx}. The latter is close
+% section to this file) but also with \XeTeX{}. The latter is close
% to identical to \texttt{dvipdfmx} and so all of the code here is extracted
-% for both backends, with some \texttt{clean up} for \texttt{xdvipdfmx} as
+% for both backends, with some \texttt{clean up} for \XeTeX{} as
% required.
%
% \begin{macro}{\__kernel_backend_literal_pdf:n, \__kernel_backend_literal_pdf:x}
@@ -336,7 +377,7 @@
% \end{macro}
%
% \begin{macrocode}
-%</dvipdfmx|xdvipdfmx>
+%</dvipdfmx|xetex>
% \end{macrocode}
%
% \subsection{\texttt{dvisvgm} backend}
diff --git a/macros/latex/contrib/l3backend/l3backend-box.dtx b/macros/latex/contrib/l3backend/l3backend-box.dtx
index c5ef445658..78cf2d9ebb 100644
--- a/macros/latex/contrib/l3backend/l3backend-box.dtx
+++ b/macros/latex/contrib/l3backend/l3backend-box.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -151,10 +151,10 @@
%</dvips>
% \end{macrocode}
%
-% \subsection{\texttt{pdfmode} backend}
+% \subsection{\LuaTeX{} and \pdfTeX{} backends}
%
% \begin{macrocode}
-%<*pdfmode>
+%<*luatex|pdftex>
% \end{macrocode}
%
% \begin{macro}{\@@_backend_clip:N}
@@ -247,17 +247,17 @@
% \end{macro}
%
% \begin{macrocode}
-%</pdfmode>
+%</luatex|pdftex>
% \end{macrocode}
%
% \subsection{\texttt{dvipdfmx} backend}
%
% \begin{macrocode}
-%<*dvipdfmx|xdvipdfmx>
+%<*dvipdfmx|xetex>
% \end{macrocode}
%
% \begin{macro}{\@@_backend_clip:N}
-% The code here is identical to that for \texttt{pdfmode}: unlike rotation and
+% The code here is identical to that for \LuaTeX{}/\pdfTeX{}: unlike rotation and
% scaling, there is no higher-level support in the backend for clipping.
% \begin{macrocode}
\cs_new_protected:Npn \@@_backend_clip:N #1
@@ -327,7 +327,7 @@
% \end{macro}
%
% \begin{macrocode}
-%</dvipdfmx|xdvipdfmx>
+%</dvipdfmx|xetex>
% \end{macrocode}
%
% \subsection{\texttt{dvisvgm} backend}
diff --git a/macros/latex/contrib/l3backend/l3backend-color.dtx b/macros/latex/contrib/l3backend/l3backend-color.dtx
index 6defac4817..165313c04b 100644
--- a/macros/latex/contrib/l3backend/l3backend-color.dtx
+++ b/macros/latex/contrib/l3backend/l3backend-color.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -60,18 +60,62 @@
%<@@=color>
% \end{macrocode}
%
-% Color support is split into two parts: a \enquote{general} concept and
-% one directly linked to drawings (or rather the split between filling
-% and stroking). General color is relatively easy to handle: we have a color
-% stack available with all modern drivers, and can use that.
-% Whilst \texttt{(x)dvipdfmx} does have its own approach to color specials,
-% it is easier to use \texttt{dvips}-like ones for all cases except direct
-% PDF output.
+% Color support is split into parts: general color, separations, and color for
+% drawings. We have different approaches in each backend, and have some choices
+% to make about \texttt{dvipdfmx}/\XeTeX{} in particular. Whilst it is in some ways
+% convenient to use the same approach in multiple backends, the fact that
+% \texttt{dvipdfmx}/\XeTeX{} is PDF-based means it (largely) sticks closer to
+% direct PDF output.
+%
+% \subsection{\texttt{dvipmdfx}/\XeTeX{}}
+%
+% \begin{macrocode}
+%<*dvipdfmx|xetex>
+% \end{macrocode}
+%
+% These backends have the most possible approaches: it recognises both
+% \texttt{dvips}-based color specials and it's own format, plus one can
+% include PDF statements directly. The latter are not subject to the stack,
+% so are not suitable for general use. Of the two stack methods, the dedicated
+% one has been extended to cover color spaces, so it is used in preference to
+% the \texttt{dvips} one.
+%
+% The \LaTeXe{} backend code uses \texttt{dvips}-based code with
+% \texttt{dvipmdfx}/\XeTeX{}, and so we leave getting color from \LaTeXe{} to
+% a shared code path below.
+%
+% \begin{macro}
+% {
+% \@@_backend_select_cmyk:n ,
+% \@@_backend_select_gray:n ,
+% \@@_backend_select_rgb:n
+% }
+% \begin{macro}{\@@_backend_reset:}
+% \begin{macro}{color.sc, color.fc}
+% Push the data to the stack.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_backend_select_cmyk:n #1
+ {
+ \__kernel_backend_literal:n { pdf: bc ~ [#1] }
+ \group_insert_after:N \@@_backend_reset:
+ }
+\cs_new_eq:NN \@@_backend_select_gray:n \@@_backend_select_cmyk:n
+\cs_new_eq:NN \@@_backend_select_rgb:n \@@_backend_select_cmyk:n
+\cs_new_protected:Npn \@@_backend_reset:
+ { \__kernel_backend_literal:n { pdf: ec } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%</dvipdfmx|xetex>
+% \end{macrocode}
%
% \subsection{\texttt{dvips}-style}
%
% \begin{macrocode}
-%<*dvisvgm|dvipdfmx|dvips|xdvipdfmx>
+%<*dvisvgm|dvipdfmx|dvips|xetex>
% \end{macrocode}
%
% \begin{macro}{\@@_backend_pickup:N}
@@ -106,6 +150,14 @@
% \end{macro}
% \end{macro}
%
+% \begin{macrocode}
+%</dvisvgm|dvipdfmx|dvips|xetex>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*dvisvgm|dvips>
+% \end{macrocode}
+%
% \begin{macro}
% {
% \@@_backend_select_cmyk:n ,
@@ -140,21 +192,14 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}{\@@_backend_select_separation:nn}
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_backend_select_separation:nn #1#2
- { \@@_backend_select:n {#1} }
-% \end{macrocode}
-% \end{macro}
-%
% \begin{macrocode}
-%</dvisvgm|dvipdfmx|dvips|xdvipdfmx>
+%</dvisvgm|dvips>
% \end{macrocode}
%
-% \subsection{\texttt{pdfmode}}
+% \subsection{\LuaTeX{} and \pdfTeX{}}
%
% \begin{macrocode}
-%<*pdfmode>
+%<*luatex|pdftex>
% \end{macrocode}
%
% \begin{macro}{\@@_backend_pickup:N}
@@ -225,44 +270,252 @@
{ \@@_backend_select:n { #1 ~ g ~ #1 ~ G } }
\cs_new_protected:Npn \@@_backend_select_rgb:n #1
{ \@@_backend_select:n { #1 ~ rg ~ #1 ~ RG } }
-\cs_new_protected:Npx \@@_backend_select:n #1
+\cs_new_protected:Npn \@@_backend_select:n #1
+ {
+%<*luatex>
+ \tex_pdfextension:D colorstack
+%</luatex>
+%<*pdftex>
+ \tex_pdfcolorstack:D
+%</pdftex>
+ \l__kernel_color_stack_int push {#1}
+ \group_insert_after:N \@@_backend_reset:
+ }
+\cs_new_protected:Npn \@@_backend_reset:
+ {
+%<*luatex>
+ \tex_pdfextension:D colorstack
+%</luatex>
+%<*pdftex>
+ \tex_pdfcolorstack:D
+%</pdftex>
+ \l__kernel_color_stack_int pop \scan_stop:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%</luatex|pdftex>
+% \end{macrocode}
+%
+% \subsection{Separations}
+%
+% Here, life gets interesting and we need essentially one approach per
+% backend.
+%
+% \begin{macrocode}
+%<*dvips>
+% \end{macrocode}
+%
+% \begin{macro}{\@@_backend_select_separation:nn}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_backend_select_separation:nn #1#2
+ { \@@_backend_select:n { setspotcolor ~ #1 ~ #2 } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_backend_separation_init:nnnnn}
+% \begin{macro}{\@@_backend_separation_init:nnn}
+% \begin{macro}[EXP]{\@@_backend_separation_init:n}
+% \begin{macro}[EXP]{\@@_backend_separation_init:w}
+% \begin{macro}{\@@_backend_separation_init_cielab:nnnnn}
+% \begin{macro}{\@@_backend_separation_init_cielab:n}
+% Initialising here means creating a small header set up plus massaging
+% some data. This comes about as we have to deal with PDF-focussed data,
+% which makes most sense \enquote{higher-up}. The approach is based on
+% ideas from \url{https://tex.stackexchange.com/q/560093}.
+% \begin{macrocode}
+\cs_new_protected:Npx \@@_backend_separation_init:nnnnn #1#2#3#4#5
{
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D colorstack }
- { \tex_pdfcolorstack:D }
- \exp_not:N \l__kernel_color_stack_int push {#1}
- \group_insert_after:N \exp_not:N \@@_backend_reset:
+ \bool_if:NT \g__kernel_backend_header_bool
+ {
+ \cs_if_exist:NTF \AtBeginDvi
+ { \AtBeginDvi }
+ { \use:n }
+ {
+ \exp_not:N \@@_backend_separation_init:nnn
+ {#1} {#2} {#5}
+ }
+ }
}
-\cs_new_protected:Npx \@@_backend_reset:
+\cs_new_protected:Npn \@@_backend_separation_init:nnn #1#2#3
{
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D colorstack }
- { \tex_pdfcolorstack:D }
- \exp_not:N \l__kernel_color_stack_int pop \scan_stop:
+ \__kernel_backend_literal:e
+ {
+ !
+ TeXDict ~ begin ~
+ /color \int_use:N \g_@@_separation_int \c_space_tl
+ [#3] ~ aload ~ pop ~ ( \str_convert_pdfname:n {#1} ) ~
+ find \@@_backend_separation_init:n {#2} customcolor ~ def ~
+ end
+ }
+ }
+\cs_new:Npn \@@_backend_separation_init:n #1
+ {
+ \@@_backend_separation_init:w #1 /Device #1 /Device \s_@@_stop
}
+\cs_new:Npn \@@_backend_separation_init:w #1 /Device #2 /Device #3 \s_@@_stop
+ { \str_lowercase:n {#2} }
% \end{macrocode}
+% Currently no CIELAB support.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_backend_separation_init_cielab:nnnnn #1#2#3#4#5 { }
+\cs_new_protected:Npn \@@_backend_separation_init_cielab:n #1 { }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
% \end{macro}
% \end{macro}
%
+% \begin{macrocode}
+%</dvips>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*dvisvgm>
+% \end{macrocode}
+%
% \begin{macro}{\@@_backend_select_separation:nn}
+% No support at present.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_backend_select_separation:nn #1#2 { }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {\@@_backend_separation_init:nnnnn, \@@_backend_separation_init_cielab:nnnnn}
+% \begin{macro}{\@@_backend_separation_init_cielab:n}
+% No support at present.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_backend_separation_init:nnnnn #1#2#3#4#5 { }
+\cs_new_protected:Npn \@@_backend_separation_init_cielab:nnnnn #1#2#3#4#5 { }
+\cs_new_protected:Npn \@@_backend_separation_init_cielab:n #1 { }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%</dvisvgm>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*dvipdfmx|luatex|pdftex|xetex>
+% \end{macrocode}
+%
+% \begin{macro}{\@@_backend_select_separation:nn}
+% Different syntaxes here as the stacks are accessed very differently.
% \begin{macrocode}
\cs_new_protected:Npn \@@_backend_select_separation:nn #1#2
+%<*dvipdfmx|xetex>
+ { \@@_backend_select:n { @#1 ~ [#2] } }
+%</dvipdfmx|xetex>
+%<*luatex|pdftex>
{ \@@_backend_select:n { /#1 ~ cs ~ /#1 ~ CS ~ #2 ~ scn ~ #2 ~ SCN } }
+%</luatex|pdftex>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_backend_separation_init:nnnnn}
+% \begin{macro}{\@@_backend_separation_init:n}
+% \begin{macro}{\@@_backend_separation_init_cielab:nnnnn}
+% \begin{macro}{\@@_backend_separation_init_cielab:n}
+% Initialising the PDF structures needs two parts: creating an object
+% containing the \enquote{real} name of the Separation, then adding a reference
+% to that to each page. The latter uses the internal name of the \texttt{cs}.
+% For \texttt{dvipdfmx}/\XeTeX{}, the backend does most of the work so we need a
+% simplified version.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_backend_separation_init:nnnnn #1#2#3#4#5
+ {
+ \@@_backend_separation_init:n
+ {
+ /Separation
+ / \str_convert_pdfname:n {#1} ~ #2 ~
+ <<
+ /FunctionType ~ 2
+ /Domain ~ [0 ~ 1]
+ \tl_if_blank:nF {#3} { /Range ~ [#3] }
+ /C0 ~ [#4] ~
+ /C1 ~ [#5] /N ~ 1
+ >>
+ }
+%<*luatex|pdftex>
+ \use:x
+ {
+ \pdfcoredict_gput:nnn
+ { Page / Resources / ColorSpace }
+ { color \int_use:N \g_@@_separation_int }
+ { \pdf_object_last: }
+ }
+%</luatex|pdftex>
+ }
+\cs_if_exist:NF \pdf_object_now:nn
+ { \cs_gset_protected:Npn \@@_backend_separation_init:nnnnn #1#2#3#4#5 { } }
+\cs_new_protected:Npn \@@_backend_separation_init:n #1
+ {
+%<*dvipdfmx|xetex>
+ \__kernel_backend_literal:x
+ {
+ pdf:obj ~ @ color \int_use:N \g_@@_separation_int \c_space_tl
+ [#1]
+ }
+%</dvipdfmx|xetex>
+%<*luatex|pdftex>
+ \pdf_object_now:nx { array } {#1}
+%</luatex|pdftex>
+ }
+% \end{macrocode}
+% For CIELAB colors, we need one object per document for the illuminant,
+% plus initialisation of the color space referencing that object.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_backend_separation_init_cielab:nnnnn #1#2#3#4#5
+ {
+ \@@_backend_separation_init:nnnnn
+ {#2}
+ { \pdf_object_ref:n { @@_illuminant_cielab_ #1 } }
+ { \c_@@_model_range_lab_tl }
+ { 100 ~ 0 ~ 0 }
+ { #3 ~ #4 ~ #5 }
+ }
+\cs_if_exist:NF \pdf_object_now:nn
+ { \cs_gset_protected:Npn \@@_backend_separation_init_cielab:nnnnn #1#2#3#4#5 { } }
+\cs_new_protected:Npn \@@_backend_separation_init_cielab:n #1
+ {
+ \pdf_object_new:nn { @@_illuminant_cielab_ #1 } { array }
+ \pdf_object_write:nx { @@_illuminant_cielab_ #1 }
+ {
+ /Lab ~
+ <<
+ /WhitePoint ~
+ [ \tl_use:c { c_@@_model_whitepoint_cielab_ #1 _tl } ]
+ /Range ~ [ \c_@@_model_range_lab_tl ]
+ >>
+ }
+ }
+\cs_if_exist:NF \pdf_object_new:nn
+ { \cs_gset_protected:Npn \@@_backend_separation_init_cielab:n #1 { } }
% \end{macrocode}
% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
%
% \begin{macrocode}
-%</pdfmode>
+%</dvipdfmx|luatex|pdftex|xetex>
% \end{macrocode}
%
% \subsection{Fill and stroke color}
%
-% Here, \texttt{(x)dvipdfmx} follows \texttt{pdfmode}, while for \texttt{dvips}
+% Here, \texttt{dvipdfmx}/\XeTeX{} follows \LuaTeX{} and \pdfTeX{},
+% while for \texttt{dvips}
% we have to manage fill and stroke color ourselves. We also handle
% \texttt{dvisvgm} independently, as there we can create SVG directly.
%
% \begin{macrocode}
-%<*dvipdfmx|pdfmode|xdvipdfmx>
+%<*dvipdfmx|luatex|pdftex|xetex>
% \end{macrocode}
%
% \begin{macro}
@@ -274,8 +527,8 @@
% \@@_backend_stroke_gray:n ,
% \@@_backend_stroke_rgb:n
% }
-% Drawing (fill/stroke) color is handled in \texttt{(x)dvipdfmx} in the
-% same way as \texttt{pdfmode}. We use the same approach as earlier, except the
+% Drawing (fill/stroke) color is handled in \texttt{dvipdfmx}/\XeTeX{} in the
+% same way as \LuaTeX{}/\pdfTeX{}. We use the same approach as earlier, except the
% color stack is not involved so the generic direct PDF operation is used.
% There is no worry about the nature of strokes: everything is handled
% automatically.
@@ -309,7 +562,7 @@
% \end{macro}
%
% \begin{macrocode}
-%</dvipdfmx|pdfmode|xdvipdfmx>
+%</dvipdfmx|luatex|pdftex|xetex>
% \end{macrocode}
%
% \begin{macrocode}
diff --git a/macros/latex/contrib/l3backend/l3backend-draw.dtx b/macros/latex/contrib/l3backend/l3backend-draw.dtx
index 7f0f4cfb4a..00e9144e4a 100644
--- a/macros/latex/contrib/l3backend/l3backend-draw.dtx
+++ b/macros/latex/contrib/l3backend/l3backend-draw.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -339,7 +339,7 @@
% In \texttt{dvips}, keeping the transformations in line with the engine
% is unfortunately not possible for scaling and rotations: even if we
% decompose the matrix into those operations, there is still no backend
-% tracking (\emph{cf.}~\texttt{(x)dvipdfmx}). Thus we take the shortest
+% tracking (\emph{cf.}~\texttt{dvipdfmx}/\XeTeX{}). Thus we take the shortest
% path available and simply dump the matrix as given.
% \begin{macrocode}
\cs_new_protected:Npn \@@_backend_cm:nnnn #1#2#3#4
@@ -393,13 +393,13 @@
%</dvips>
% \end{macrocode}
%
-% \subsection{\texttt{pdfmode} and \texttt{(x)dvipdfmx}}
+% \subsection{\LuaTeX{}, \pdfTeX{}, \texttt{dvipdfmx} and \XeTeX{}}
%
-% Both \texttt{pdfmode} and \texttt{(x)dvipdfmx} directly produce PDF output
+% \LuaTeX{}, \pdfTeX{}, \texttt{dvipdfmx} and \XeTeX{} directly produce PDF output
% and understand a shared set of specials for drawing commands.
%
% \begin{macrocode}
-%<*dvipdfmx|pdfmode|xdvipdfmx>
+%<*dvipdfmx|luatex|pdftex|xetex>
% \end{macrocode}
%
% \subsubsection{Drawing}
@@ -575,25 +575,25 @@
%
% \begin{macro}{\@@_backend_cm:nnnn}
% \begin{macro}{\@@_backend_cm_aux:nnnn}
-% Another split here between \texttt{pdfmode} and \texttt{(x)dvipdfmx}.
+% Another split here between \LuaTeX{}/pdfTeX{} and \texttt{dvipdfmx}/\XeTeX{}.
% In the former, we have a direct method to maintain alignment: the backend
-% can use a matrix itself. For \texttt{(x)dvipdfmx}, we can to decompose the
+% can use a matrix itself. For \texttt{dvipdfmx}/\XeTeX{}, we can to decompose the
% matrix into rotations and a scaling, then use those operations as they
% are handled by the backend. (There is backend support for matrix operations in
-% \texttt{(x)dvipdfmx}, but as a matched pair so not suitable for the
+% \texttt{dvipdfmx}/\XeTeX{}, but as a matched pair so not suitable for the
% \enquote{stand alone} transformation set up here.)
% \begin{macrocode}
\cs_new_protected:Npn \@@_backend_cm:nnnn #1#2#3#4
{
-%<*pdfmode>
+%<*luatex|pdftex>
\__kernel_backend_matrix:n { #1 ~ #2 ~ #3 ~ #4 }
-%</pdfmode>
-%<*dvipdfmx|xdvipdfmx>
+%</luatex|pdftex>
+%<*dvipdfmx|xetex>
\@@_backend_cm_decompose:nnnnN {#1} {#2} {#3} {#4}
\@@_backend_cm_aux:nnnn
-%</dvipdfmx|xdvipdfmx>
+%</dvipdfmx|xetex>
}
-%<*dvipdfmx|xdvipdfmx>
+%<*dvipdfmx|xetex>
\cs_new_protected:Npn \@@_backend_cm_aux:nnnn #1#2#3#4
{
\__kernel_backend_literal:x
@@ -617,7 +617,7 @@
{ \fp_eval:n { round ( -#4 , 5 ) } }
}
}
-%</dvipdfmx|xdvipdfmx>
+%</dvipdfmx|xetex>
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -677,7 +677,7 @@
% way of specifying a transformation matrix exchanges where one would
% normally expect $B$ and $C$ to be.
% \begin{macrocode}
-%<*dvipdfmx|xdvipdfmx>
+%<*dvipdfmx|xetex>
\cs_new_protected:Npn \@@_backend_cm_decompose:nnnnN #1#2#3#4#5
{
\use:x
@@ -720,7 +720,7 @@
{ #5 {#1} {#2} {#3} {#4} }
{ #5 {#1} {#3} {#2} {#4} }
}
-%</dvipdfmx|xdvipdfmx>
+%</dvipdfmx|xetex>
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -736,24 +736,24 @@
\cs_new_protected:Npn \@@_backend_box_use:Nnnnn #1#2#3#4#5
{
\__kernel_backend_scope_begin:
-%<*pdfmode>
+%<*luatex|pdftex>
\@@_backend_cm:nnnn {#2} {#3} {#4} {#5}
-%</pdfmode>
-%<*dvipdfmx|xdvipdfmx>
+%</luatex|pdftex>
+%<*dvipdfmx|xetex>
\__kernel_backend_literal:n
{ pdf:btrans~matrix~ #2 ~ #3 ~ #4 ~ #5 ~ 0 ~ 0 }
-%</dvipdfmx|xdvipdfmx>
+%</dvipdfmx|xetex>
\hbox_overlap_right:n { \box_use:N #1 }
-%<*dvipdfmx|xdvipdfmx>
+%<*dvipdfmx|xetex>
\__kernel_backend_literal:n { pdf:etrans }
-%</dvipdfmx|xdvipdfmx>
+%</dvipdfmx|xetex>
\__kernel_backend_scope_end:
}
% \end{macrocode}
% \end{macro}
%
% \begin{macrocode}
-%</dvipdfmx|pdfmode|xdvipdfmx>
+%</dvipdfmx|luatex|pdftex|xetex>
% \end{macrocode}
%
% \subsection{\texttt{dvisvgm} backend}
diff --git a/macros/latex/contrib/l3backend/l3backend-graphics.dtx b/macros/latex/contrib/l3backend/l3backend-graphics.dtx
index ba3b2ed5e9..f4eeebbfcb 100644
--- a/macros/latex/contrib/l3backend/l3backend-graphics.dtx
+++ b/macros/latex/contrib/l3backend/l3backend-graphics.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -95,10 +95,10 @@
%</dvips>
% \end{macrocode}
%
-% \subsection{\texttt{pdfmode} backend}
+% \subsection{\LuaTeX{} and \pdfTeX{} backends}
%
% \begin{macrocode}
-%<*pdfmode>
+%<*luatex|pdftex>
% \end{macrocode}
%
% \begin{variable}{\l_@@_graphics_attr_tl}
@@ -223,7 +223,7 @@
% \begin{macro}{\@@_backend_include_eps:n}
% \begin{variable}
% {\l_@@_backend_dir_str, \l_@@_backend_name_str, \l_@@_backend_ext_str}
-% EPS graphics may be included in \texttt{pdfmode} by conversion to
+% EPS graphics may be included in \LuaTeX{}/pdfTeX{} by conversion to
% PDF: this requires restricted shell escape. Modelled on the \pkg{epstopdf}
% \LaTeXe{} package, but simplified, conversion takes place here if we have
% shell access.
@@ -274,13 +274,13 @@
% \end{macro}
%
% \begin{macrocode}
-%</pdfmode>
+%</luatex|pdftex>
% \end{macrocode}
%
% \subsection{\texttt{dvipdfmx} backend}
%
% \begin{macrocode}
-%<*dvipdfmx|xdvipdfmx>
+%<*dvipdfmx|xetex>
% \end{macrocode}
%
% \begin{macro}
@@ -326,7 +326,7 @@
% \begin{macro}{\@@_backend_include_auxii:nnn, \@@_backend_include_auxii:xnn}
% \begin{macro}{\@@_backend_include_auxiii:nnn}
% The special syntax depends on the file type. There is a difference in
-% how PDF graphics are best handled between |dvipdfmx| and |xdvipdfmx|: for
+% how PDF graphics are best handled between |dvipdfmx| and \XeTeX{}: for
% the latter it is better to use the primitive route. The relevant code for
% that is included later in this file.
% \begin{macrocode}
@@ -425,13 +425,13 @@
% \end{macro}
%
% \begin{macrocode}
-%</dvipdfmx|xdvipdfmx>
+%</dvipdfmx|xetex>
% \end{macrocode}
%
-% \subsection{\texttt{xdvipdfmx} backend}
+% \subsection{\XeTeX{} backend}
%
% \begin{macrocode}
-%<*xdvipdfmx>
+%<*xetex>
% \end{macrocode}
%
% \subsubsection{Images}
@@ -448,7 +448,7 @@
% \begin{macro}{\@@_backend_getbb_auxiv:nnNnn, \@@_backend_getbb_auxiv:VnNnn}
% \begin{macro}{\@@_backend_getbb_auxv:nNnn, \@@_backend_getbb_auxv:nNnn}
% \begin{macro}[EXP]{\@@_backend_getbb_pagebox:w}
-% For \texttt{xdvipdfmx}, there are two primitives that allow us to obtain
+% For \XeTeX{}, there are two primitives that allow us to obtain
% the bounding box without needing \texttt{extractbb}. The only complexity
% is passing the various minor variations to a common core process. The
% \XeTeX{} primitive omits the text |box| from the page box specification,
@@ -536,7 +536,7 @@
% \end{macro}
%
% \begin{macrocode}
-%</xdvipdfmx>
+%</xetex>
% \end{macrocode}
%
% \subsection{\texttt{dvisvgm} backend}
diff --git a/macros/latex/contrib/l3backend/l3backend-header.dtx b/macros/latex/contrib/l3backend/l3backend-header.dtx
index 24e7ee2cfa..c2d0f87452 100644
--- a/macros/latex/contrib/l3backend/l3backend-header.dtx
+++ b/macros/latex/contrib/l3backend/l3backend-header.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -67,6 +67,16 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{TeXcolorsetspotcolor, setspotcolor}
+% Support for separation/spot colors: this strange naming is so
+% things work with the color stack.
+% \begin{macrocode}
+TeXDict begin
+/TeXcolorsetspotcolor { setcustomcolor } def
+end
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{pdf.globaldict}
% A small global dictionary for backend use.
% \begin{macrocode}
diff --git a/macros/latex/contrib/l3backend/l3backend-pdf.dtx b/macros/latex/contrib/l3backend/l3backend-pdf.dtx
index fb569f2c24..f0f20e1b9a 100644
--- a/macros/latex/contrib/l3backend/l3backend-pdf.dtx
+++ b/macros/latex/contrib/l3backend/l3backend-pdf.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -744,10 +744,10 @@
%</dvips>
% \end{macrocode}
%
-% \subsection{\texttt{pdfmode} backend}
+% \subsection{\LuaTeX{} and \pdfTeX{} backend}
%
% \begin{macrocode}
-%<*pdfmode>
+%<*luatex|pdftex>
% \end{macrocode}
%
% \subsubsection{Annotations}
@@ -755,28 +755,35 @@
% \begin{macro}{\@@_backend_annotation:nnnn}
% Simply pass the raw data through, just dealing with evaluation of dimensions.
% \begin{macrocode}
-\cs_new_protected:Npx \@@_backend_annotation:nnnn #1#2#3#4
+\cs_new_protected:Npn \@@_backend_annotation:nnnn #1#2#3#4
{
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D annot ~ }
- { \tex_pdfannot:D }
- width ~ \exp_not:N \dim_eval:n {#1} ~
- height ~ \exp_not:N \dim_eval:n {#2} ~
- depth ~ \exp_not:N \dim_eval:n {#3} ~
+%<*luatex>
+ \tex_pdfextension:D annot ~
+%</luatex>
+%<*pdftex>
+ \tex_pdfannot:D
+%</pdftex>
+ width ~ \dim_eval:n {#1} ~
+ height ~ \dim_eval:n {#2} ~
+ depth ~ \dim_eval:n {#3} ~
{#4}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]{\@@_backend_annotation_last:}
-% A tiny amount of extra data gets added here.
+% A tiny amount of extra data gets added here; we use \texttt{x}-type
+% expansion to get the space in the right place and form.
% \begin{macrocode}
\cs_new:Npx \@@_backend_annotation_last:
{
\exp_not:N \int_value:w
- \cs_if_exist:NTF \tex_pdffeedback:D
- { \exp_not:N \tex_pdffeedback:D lastannot ~ }
- { \exp_not:N \tex_pdflastannot:D }
+%<*luatex>
+ \exp_not:N \tex_pdffeedback:D lastannot
+%</luatex>
+%<*pdftex>
+ \exp_not:N \tex_pdfannot:D
+%</pdftex>
\c_space_tl 0 ~ R
}
% \end{macrocode}
@@ -792,19 +799,25 @@
{ \@@_backend_link_begin:nnnw {#1} { goto~name } {#2} }
\cs_new_protected:Npn \@@_backend_link_begin_user:nnw #1#2
{ \@@_backend_link_begin:nnnw {#1} { user } {#2} }
-\cs_new_protected:Npx \@@_backend_link_begin:nnnw #1#2#3
+\cs_new_protected:Npn \@@_backend_link_begin:nnnw #1#2#3
{
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D startlink ~ }
- { \tex_pdfstartlink:D }
- attr {#1}
- #2 {#3}
+%<*luatex>
+ \tex_pdfextension:D startlink ~
+%</luatex>
+%<*pdftex>
+ \tex_pdfstartlink:D
+%</pdftex>
+ attr {#1}
+ #2 {#3}
}
-\cs_new_protected:Npx \@@_backend_link_end:
+\cs_new_protected:Npn \@@_backend_link_end:
{
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D endlink \scan_stop: }
- { \tex_pdfendlink:D }
+%<*luatex>
+ \tex_pdfextension:D endlink \scan_stop:
+%</luatex>
+%<*pdftex>
+ \tex_pdfendlink:D
+%</pdftex>
}
% \end{macrocode}
% \end{macro}
@@ -817,9 +830,12 @@
\cs_new:Npx \@@_backend_link_last:
{
\exp_not:N \int_value:w
- \cs_if_exist:NTF \tex_pdffeedback:D
- { \exp_not:N \tex_pdffeedback:D lastlink ~ }
- { \exp_not:N \tex_pdflastlink:D }
+%<*luatex>
+ \exp_not:N \tex_pdffeedback:D lastlink
+%</luatex>
+%<*pdftex>
+ \exp_not:N \tex_pdflastlink:D
+%</pdftex>
\c_space_tl 0 ~ R
}
% \end{macrocode}
@@ -828,12 +844,15 @@
% \begin{macro}{\@@_backend_link_margin:n}
% A simple task: pass the data to the primitive.
% \begin{macrocode}
-\cs_new_protected:Npx \@@_backend_link_margin:n #1
+\cs_new_protected:Npn \@@_backend_link_margin:n #1
{
- \cs_if_exist:NTF \tex_pdfvariable:D
- { \exp_not:N \tex_pdfvariable:D linkmargin }
- { \exp_not:N \tex_pdflinkmargin:D }
- \exp_not:N \dim_eval:n {#1} \scan_stop:
+%<*luatex>
+ \tex_pdfvariable:D linkmargin
+%</luatex>
+%<*pdftex>
+ \tex_pdflinkmargin:D
+%</pdftex>
+ \dim_eval:n {#1} \scan_stop:
}
% \end{macrocode}
% \end{macro}
@@ -844,13 +863,16 @@
% percentage, but we need to pass it as \emph{per mille}. The rectangle
% version is also easy as everything is build in.
% \begin{macrocode}
-\cs_new_protected:Npx \@@_backend_destination:nn #1#2
+\cs_new_protected:Npn \@@_backend_destination:nn #1#2
{
- \cs_if_exist:NTF \tex_pdfextension:D
- { \exp_not:N \tex_pdfextension:D dest ~ }
- { \exp_not:N \tex_pdfdest:D }
+%<*luatex>
+ \tex_pdfextension:D dest ~
+%</luatex>
+%<*pdftex>
+ \tex_pdfdest:D
+%</pdftex>
name {#1}
- \exp_not:N \str_case:nnF {#2}
+ \str_case:nnF {#2}
{
{ xyz } { xyz }
{ fit } { fit }
@@ -860,21 +882,24 @@
{ fith } { fith }
{ fitv } { fitv }
}
- { xyz ~ zoom \exp_not:N \fp_eval:n { #2 * 10 } }
+ { xyz ~ zoom \fp_eval:n { #2 * 10 } }
\scan_stop:
}
-\cs_new_protected:Npx \@@_backend_destination_box:nn #1#2
+\cs_new_protected:Npn \@@_backend_destination_box:nn #1#2
{
\group_begin:
\hbox_set:Nn \l_@@_internal_box {#2}
- \cs_if_exist:NTF \tex_pdfextension:D
- { \exp_not:N \tex_pdfextension:D dest ~ }
- { \exp_not:N \tex_pdfdest:D }
+%<*luatex>
+ \tex_pdfextension:D dest ~
+%</luatex>
+%<*pdftex>
+ \tex_pdfdest:D
+%</pdftex>
name {#1}
fitr ~
- width \exp_not:N \box_wd:N \l_@@_internal_box
- height \exp_not:N \box_ht:N \l_@@_internal_box
- depth \exp_not:N \box_dp:N \l_@@_internal_box
+ width \box_wd:N \l_@@_internal_box
+ height \box_ht:N \l_@@_internal_box
+ depth \box_dp:N \l_@@_internal_box
\box_use:N \l_@@_internal_box
\group_end:
}
@@ -885,19 +910,25 @@
%
% \begin{macro}{\@@_backend_catalog_gput:nn, \@@_backend_info_gput:nn}
% \begin{macrocode}
-\cs_new_protected:Npx \@@_backend_catalog_gput:nn #1#2
+\cs_new_protected:Npn \@@_backend_catalog_gput:nn #1#2
{
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D catalog }
- { \tex_pdfcatalog:D }
- { / #1 ~ #2 }
+%<*luatex>
+ \tex_pdfextension:D catalog
+%</luatex>
+%<*pdftex>
+ \tex_pdfcatalog:D
+%</pdftex>
+ { / #1 ~ #2 }
}
-\cs_new_protected:Npx \@@_backend_info_gput:nn #1#2
+\cs_new_protected:Npn \@@_backend_info_gput:nn #1#2
{
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D info }
- { \tex_pdfinfo:D }
- { / #1 ~ #2 }
+%<*luatex>
+ \tex_pdfextension:D info
+%</luatex>
+%<*pdftex>
+ \tex_pdfinfo:D
+%</pdftex>
+ { / #1 ~ #2 }
}
% \end{macrocode}
% \end{macro}
@@ -916,26 +947,25 @@
% Declaring objects means reserving at the PDF level plus starting
% tracking.
% \begin{macrocode}
-\group_begin:
- \cs_set_protected:Npn \@@_tmp:w #1#2
- {
- \cs_new_protected:Npx \@@_backend_object_new:nn ##1##2
- {
- #1 reserveobjnum ~
- \int_const:cn
- { c_@@_backend_object_ \exp_not:N \tl_to_str:n {##1} _int }
- {#2}
- \prop_gput:Nnn \exp_not:N \g_@@_backend_object_prop {##1} {##2}
- }
- }
- \cs_if_exist:NTF \tex_pdfextension:D
- {
- \@@_tmp:w
- { \tex_pdfextension:D obj ~ }
- { \exp_not:N \tex_pdffeedback:D lastobj }
- }
- { \@@_tmp:w { \tex_pdfobj:D } { \tex_pdflastobj:D } }
-\group_end:
+\cs_new_protected:Npn \@@_backend_object_new:nn #1#2
+ {
+%<*luatex>
+ \tex_pdfextension:D obj ~
+%</luatex>
+%<*pdftex>
+ \tex_pdfobj:D
+%</pdftex>
+ reserveobjnum ~
+ \int_const:cn
+ { c_@@_backend_object_ \tl_to_str:n {#1} _int }
+%<*luatex>
+ { \tex_pdffeedback:D lastobj }
+%</luatex>
+%<*pdftex>
+ { \tex_pdflastobj:D }
+%</pdftex>
+ \prop_gput:Nnn \exp_not:N \g_@@_backend_object_prop {#1} {#2}
+ }
\cs_new:Npn \@@_backend_object_ref:n #1
{ \int_use:c { c_@@_backend_object_ \tl_to_str:n {#1} _int } ~ 0 ~ R }
% \end{macrocode}
@@ -947,36 +977,34 @@
% Writing the data needs a little information about the structure of the
% object.
% \begin{macrocode}
-\group_begin:
- \cs_set_protected:Npn \@@_tmp:w #1
- {
- \cs_new_protected:Npn \@@_backend_object_write:nn ##1##2
+\cs_new_protected:Npn \@@_backend_object_write:nn #1#2
+ {
+%<*luatex>
+ \tex_immediate:D \tex_pdfextension:D obj ~
+%</luatex>
+%<*pdftex>
+ \tex_immediate:D \tex_pdfobj:D
+%</pdftex>
+ useobjnum ~
+ \int_use:c
+ { c_@@_backend_object_ \tl_to_str:n {#1} _int }
+ \str_case_e:nn
+ { \prop_item:Nn \g_@@_backend_object_prop {#1} }
{
- \tex_immediate:D #1 useobjnum ~
- \int_use:c
- { c_@@_backend_object_ \tl_to_str:n {##1} _int }
- \str_case_e:nn
- { \prop_item:Nn \g_@@_backend_object_prop {##1} }
- {
- { array } { { [ ~ \exp_not:n {##2} ~ ] } }
- { dict } { { << ~ \exp_not:n {##2} ~ >> } }
- { fstream }
- {
- stream ~ attr ~ { \@@_exp_not_i:nn ##2 } ~
- file ~ { \@@_exp_not_ii:nn ##2 }
- }
- { stream }
- {
- stream ~ attr ~ { \@@_exp_not_i:nn ##2 } ~
- { \@@_exp_not_ii:nn ##2 }
- }
- }
+ { array } { { [ ~ \exp_not:n {#2} ~ ] } }
+ { dict } { { << ~ \exp_not:n {#2} ~ >> } }
+ { fstream }
+ {
+ stream ~ attr ~ { \@@_exp_not_i:nn #2 } ~
+ file ~ { \@@_exp_not_ii:nn #2 }
+ }
+ { stream }
+ {
+ stream ~ attr ~ { \@@_exp_not_i:nn #2 } ~
+ { \@@_exp_not_ii:nn #2 }
+ }
}
- }
- \cs_if_exist:NTF \tex_pdfextension:D
- { \@@_tmp:w { \tex_pdfextension:D obj ~ } }
- { \@@_tmp:w { \tex_pdfobj:D } }
-\group_end:
+ }
\cs_generate_variant:Nn \@@_backend_object_write:nn { nx }
\cs_new:Npn \@@_exp_not_i:nn #1#2 { \exp_not:n {#1} }
\cs_new:Npn \@@_exp_not_ii:nn #1#2 { \exp_not:n {#2} }
@@ -987,34 +1015,31 @@
% \begin{macro}{\@@_backend_object_now:nn, \@@_backend_object_now:nx}
% Much like writing, but direct creation.
% \begin{macrocode}
-\group_begin:
- \cs_set_protected:Npn \@@_tmp:w #1
- {
- \cs_new_protected:Npn \@@_backend_object_now:nn ##1##2
+\cs_new_protected:Npn \@@_backend_object_now:nn #1#2
+ {
+%<*luatex>
+ \tex_immediate:D \tex_pdfextension:D obj ~
+%</luatex>
+%<*pdftex>
+ \tex_immediate:D \tex_pdfobj:D
+%</pdftex>
+ \str_case:nn
+ {#1}
{
- \tex_immediate:D #1
- \str_case:nn
- {##1}
- {
- { array } { { [ ~ \exp_not:n {##2} ~ ] } }
- { dict } { { << ~ \exp_not:n {##2} ~ >> } }
- { fstream }
- {
- stream ~ attr ~ { \@@_exp_not_i:nn ##2 } ~
- file ~ { \@@_exp_not_ii:nn ##2 }
- }
- { stream }
- {
- stream ~ attr ~ { \@@_exp_not_i:nn ##2 } ~
- { \@@_exp_not_ii:nn ##2 }
- }
- }
+ { array } { { [ ~ \exp_not:n {#2} ~ ] } }
+ { dict } { { << ~ \exp_not:n {#2} ~ >> } }
+ { fstream }
+ {
+ stream ~ attr ~ { \@@_exp_not_i:nn #2 } ~
+ file ~ { \@@_exp_not_ii:nn #2 }
+ }
+ { stream }
+ {
+ stream ~ attr ~ { \@@_exp_not_i:nn #2 } ~
+ { \@@_exp_not_ii:nn #2 }
+ }
}
- }
- \cs_if_exist:NTF \tex_pdfextension:D
- { \@@_tmp:w { \tex_pdfextension:D obj ~ } }
- { \@@_tmp:w { \tex_pdfobj:D } }
-\group_end:
+ }
\cs_generate_variant:Nn \@@_backend_object_now:nn { nx }
% \end{macrocode}
% \end{macro}
@@ -1025,23 +1050,29 @@
\cs_new:Npx \@@_backend_object_last:
{
\exp_not:N \int_value:w
- \cs_if_exist:NTF \tex_pdffeedback:D
- { \exp_not:N \tex_pdffeedback:D lastobj ~ }
- { \exp_not:N \tex_pdflastobj:D }
+%<*luatex>
+ \exp_not:N \tex_pdffeedback:D lastobj ~
+%</luatex>
+%<*pdftex>
+ \exp_not:N \tex_pdflastobj:D
+%</pdftex>
\c_space_tl 0 ~ R
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]{\@@_backend_pageobject_ref:n}
-% The usual wrapper situation.
+% The usual wrapper situation; the three spaces here are essential.
% \begin{macrocode}
\cs_new:Npx \@@_backend_pageobject_ref:n #1
{
\exp_not:N \int_value:w
- \cs_if_exist:NTF \tex_pdffeedback:D
- { \exp_not:N \tex_pdffeedback:D pageref }
- { \exp_not:N \tex_pdfpageref:D }
+%<*luatex>
+ \exp_not:N \tex_pdffeedback:D pageref
+%</luatex>
+%<*pdftex>
+ \exp_not:N \tex_pdfpageref:D
+%</pdftex>
\c_space_tl #1 \c_space_tl \c_space_tl \c_space_tl 0 ~ R
}
% \end{macrocode}
@@ -1054,13 +1085,16 @@
% \begin{macro}{\@@_backend_objcompresslevel:n}
% Simply pass data to the engine.
% \begin{macrocode}
-\cs_new_protected:Npx \@@_backend_compresslevel:n #1
+\cs_new_protected:Npn \@@_backend_compresslevel:n #1
{
- \exp_not:N \tex_global:D
- \cs_if_exist:NTF \tex_pdfcompresslevel:D
- { \tex_pdfcompresslevel:D }
- { \tex_pdfvariable:D compresslevel }
- \exp_not:N \int_value:w \exp_not:N \int_eval:n {#1} \scan_stop:
+ \tex_global:D
+%<*luatex>
+ \tex_pdfvariable:D compresslevel
+%</luatex>
+%<*pdftex>
+ \tex_pdfcompresslevel:D
+%</pdftex>
+ \int_value:w \int_eval:n {#1} \scan_stop:
}
\cs_new_protected:Npn \@@_backend_compress_objects:n #1
{
@@ -1068,13 +1102,16 @@
{ \@@_backend_objcompresslevel:n { 2 } }
{ \@@_backend_objcompresslevel:n { 0 } }
}
-\cs_new_protected:Npx \@@_backend_objcompresslevel:n #1
+\cs_new_protected:Npn \@@_backend_objcompresslevel:n #1
{
- \exp_not:N \tex_global:D
- \cs_if_exist:NTF \tex_pdfobjcompresslevel:D
- { \tex_pdfobjcompresslevel:D }
- { \tex_pdfvariable:D objcompresslevel }
- #1 \scan_stop:
+ \tex_global:D
+%<*luatex>
+ \tex_pdfvariable:D objcompresslevel
+%</luatex>
+%<*pdftex>
+ \tex_pdfobjcompresslevel:D
+%</pdftex>
+ #1 \scan_stop:
}
% \end{macrocode}
% \end{macro}
@@ -1083,61 +1120,65 @@
%
% \begin{macro}
% {\@@_backend_version_major_gset:n, \@@_backend_version_minor_gset:n}
-% At present, we don't have a primitive for the major version in \pdfTeX{},
-% but we anticipate one \ldots
+% The availability of the primitive is not universal, so we have to test
+% at load time.
% \begin{macrocode}
\cs_new_protected:Npx \@@_backend_version_major_gset:n #1
{
- \cs_if_exist:NTF \tex_pdfvariable:D
+%<*luatex>
+ \int_compare:nNnT \tex_luatexversion:D > { 106 }
{
- \int_compare:nNnT \tex_luatexversion:D > { 106 }
- {
- \exp_not:N \tex_global:D \tex_pdfvariable:D majorversion
- \exp_not:N \int_eval:n {#1} \scan_stop:
- }
+ \exp_not:N \tex_global:D \tex_pdfvariable:D majorversion
+ \exp_not:N \int_eval:n {#1} \scan_stop:
}
+%</luatex>
+%<*pdftex>
+ \cs_if_exist:NT \tex_pdfmajorversion:D
{
- \cs_if_exist:NT \tex_pdfmajorversion:D
- {
- \exp_not:N \tex_global:D \tex_pdfmajorversion:D
- \exp_not:N \int_eval:n {#1} \scan_stop:
- }
+ \exp_not:N \tex_global:D \tex_pdfmajorversion:D
+ \exp_not:N \int_eval:n {#1} \scan_stop:
}
+%</pdftex>
}
-\cs_new_protected:Npx \@@_backend_version_minor_gset:n #1
+\cs_new_protected:Npn \@@_backend_version_minor_gset:n #1
{
- \exp_not:N \tex_global:D
- \cs_if_exist:NTF \tex_pdfminorversion:D
- { \exp_not:N \tex_pdfminorversion:D }
- { \tex_pdfvariable:D minorversion }
- \exp_not:N \int_eval:n {#1} \scan_stop:
+ \tex_global:D
+%<*luatex>
+ \tex_pdfvariable:D minorversion
+%</luatex>
+%<*pdftex>
+ \tex_pdfminorversion:D
+%</pdftex>
+ \int_eval:n {#1} \scan_stop:
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]{\@@_backend_version_major:, \@@_backend_version_minor:}
-% At present, we don't have a primitive for the major version!
+% As above.
% \begin{macrocode}
\cs_new:Npx \@@_backend_version_major:
{
- \cs_if_exist:NTF \tex_pdfvariable:D
- {
- \int_compare:nNnTF \tex_luatexversion:D > { 106 }
- { \exp_not:N \tex_the:D \tex_pdfvariable:D majorversion }
- { 1 }
- }
- {
- \cs_if_exist:NTF \tex_pdfmajorversion:D
- { \exp_not:N \tex_the:D \tex_pdfmajorversion:D }
- { 1 }
- }
+%<*luatex>
+ \int_compare:nNnTF \tex_luatexversion:D > { 106 }
+ { \exp_not:N \tex_the:D \tex_pdfvariable:D majorversion }
+ { 1 }
+%</luatex>
+%<*pdftex>
+ \cs_if_exist:NTF \tex_pdfmajorversion:D
+ { \exp_not:N \tex_the:D \tex_pdfmajorversion:D }
+ { 1 }
+%</pdftex>
}
-\cs_new:Npx \@@_backend_version_minor:
+\cs_new:Npn \@@_backend_version_minor:
{
- \exp_not:N \tex_the:D
- \cs_if_exist:NTF \tex_pdfminorversion:D
- { \exp_not:N \tex_pdfminorversion:D }
- { \tex_pdfvariable:D minorversion }
+ \tex_the:D
+%<*luatex>
+ \tex_pdfvariable:D minorversion
+%</luatex>
+%<*pdftex>
+ \tex_pdfminorversion:D
+%</pdftex>
}
% \end{macrocode}
% \end{macro}
@@ -1158,13 +1199,13 @@
% \end{macro}
%
% \begin{macrocode}
-%</pdfmode>
+%</luatex|pdftex>
% \end{macrocode}
%
% \subsection{\texttt{dvipdfmx} backend}
%
% \begin{macrocode}
-%<*dvipdfmx|xdvipdfmx>
+%<*dvipdfmx|xetex>
% \end{macrocode}
%
% \begin{macro}{\@@_backend:n, \@@_backend:x}
@@ -1290,7 +1331,7 @@
% \end{macro}
%
% \begin{macro}[EXP]{\@@_backend_pageobject_ref:n}
-% Page references are easy in \texttt{(x)dvipdfmx}.
+% Page references are easy in \texttt{dvipdfmx}/\XeTeX{}.
% \begin{macrocode}
\cs_new:Npn \@@_backend_pageobject_ref:n #1
{ @page #1 }
@@ -1300,7 +1341,7 @@
% \subsubsection{Annotations}
%
% \begin{variable}{\g_@@_landscape_bool}
-% There is a bug in \texttt{(x)dvipdfmx} which means annotations do
+% There is a bug in \texttt{dvipdfmx}/\XeTeX{} which means annotations do
% not rotate. As such, we need to know if landscape is active.
% \begin{macrocode}
\bool_new:N \g_@@_landscape_bool
@@ -1524,7 +1565,7 @@
% \end{macro}
%
% \begin{macrocode}
-%</dvipdfmx|xdvipdfmx>
+%</dvipdfmx|xetex>
% \end{macrocode}
%
% \subsection{\texttt{dvisvgm} backend}
diff --git a/macros/latex/contrib/l3backend/l3backend.ins b/macros/latex/contrib/l3backend/l3backend.ins
index 1c5289b116..3babb97da1 100644
--- a/macros/latex/contrib/l3backend/l3backend.ins
+++ b/macros/latex/contrib/l3backend/l3backend.ins
@@ -96,26 +96,38 @@ and all files in that bundle must be distributed together.
}
\generate
{
- \file{l3backend-pdfmode.def}
+ \file{l3backend-luatex.def}
{
- \from{l3backend-basics.dtx} {package,pdfmode}
- \from{l3backend-color.dtx} {package,pdfmode}
- \from{l3backend-box.dtx} {package,pdfmode}
- \from{l3backend-draw.dtx} {package,pdfmode}
- \from{l3backend-graphics.dtx}{package,pdfmode}
- \from{l3backend-pdf.dtx} {package,pdfmode}
+ \from{l3backend-basics.dtx} {package,luatex}
+ \from{l3backend-color.dtx} {package,luatex}
+ \from{l3backend-box.dtx} {package,luatex}
+ \from{l3backend-draw.dtx} {package,luatex}
+ \from{l3backend-graphics.dtx}{package,luatex}
+ \from{l3backend-pdf.dtx} {package,luatex}
}
}
\generate
{
- \file{l3backend-xdvipdfmx.def}
+ \file{l3backend-pdftex.def}
{
- \from{l3backend-basics.dtx} {package,xdvipdfmx}
- \from{l3backend-color.dtx} {package,xdvipdfmx}
- \from{l3backend-box.dtx} {package,xdvipdfmx}
- \from{l3backend-draw.dtx} {package,xdvipdfmx}
- \from{l3backend-graphics.dtx}{package,xdvipdfmx}
- \from{l3backend-pdf.dtx} {package,xdvipdfmx}
+ \from{l3backend-basics.dtx} {package,pdftex}
+ \from{l3backend-color.dtx} {package,pdftex}
+ \from{l3backend-box.dtx} {package,pdftex}
+ \from{l3backend-draw.dtx} {package,pdftex}
+ \from{l3backend-graphics.dtx}{package,pdftex}
+ \from{l3backend-pdf.dtx} {package,pdftex}
+ }
+ }
+\generate
+ {
+ \file{l3backend-xetex.def}
+ {
+ \from{l3backend-basics.dtx} {package,xetex}
+ \from{l3backend-color.dtx} {package,xetex}
+ \from{l3backend-box.dtx} {package,xetex}
+ \from{l3backend-draw.dtx} {package,xetex}
+ \from{l3backend-graphics.dtx}{package,xetex}
+ \from{l3backend-pdf.dtx} {package,xetex}
}
}
diff --git a/macros/latex/contrib/l3experimental/CHANGELOG.md b/macros/latex/contrib/l3experimental/CHANGELOG.md
index bf4577912b..4a8085effb 100644
--- a/macros/latex/contrib/l3experimental/CHANGELOG.md
+++ b/macros/latex/contrib/l3experimental/CHANGELOG.md
@@ -7,6 +7,19 @@ this project uses date-based 'snapshot' version identifiers.
## [Unreleased]
+## [2020-09-01]
+
+### Added
+- Support for `Gray` color model
+- Support for `hsb` color model
+- Support for `wave` color model
+
+### Changed
+- Better support for color separations
+
+### Fixed
+- Integer range for `HSB` color model
+
## [2020-08-07]
### Changed
@@ -155,7 +168,8 @@ this project uses date-based 'snapshot' version identifiers.
- New `l3color` module using `xcolor`-like expression syntax
- New `l3draw` module, based on `pgf` layer of the TikZ system
-[Unreleased]: https://github.com/latex3/latex3/compare/2020-08-07...HEAD
+[Unreleased]: https://github.com/latex3/latex3/compare/2020-09-01...HEAD
+[2020-09-01]: https://github.com/latex3/latex3/compare/2020-08-07...2020-09-01
[2020-08-07]: https://github.com/latex3/latex3/compare/2020-07-17...2020-08-07
[2020-07-17]: https://github.com/latex3/latex3/compare/2020-06-18...2020-07-17
[2020-06-18]: https://github.com/latex3/latex3/compare/2020-06-03...2020-06-18
diff --git a/macros/latex/contrib/l3experimental/README.md b/macros/latex/contrib/l3experimental/README.md
index 9831aaadf0..a84954d21f 100644
--- a/macros/latex/contrib/l3experimental/README.md
+++ b/macros/latex/contrib/l3experimental/README.md
@@ -1,7 +1,7 @@
Experimental LaTeX3 Concepts
============================
-Release 2020-08-07
+Release 2020-09-01
Overview
--------
diff --git a/macros/latex/contrib/l3experimental/l3benchmark.dtx b/macros/latex/contrib/l3experimental/l3benchmark.dtx
index 05058bdef6..80079c1c41 100644
--- a/macros/latex/contrib/l3experimental/l3benchmark.dtx
+++ b/macros/latex/contrib/l3experimental/l3benchmark.dtx
@@ -46,7 +46,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -129,7 +129,7 @@
% \end{macrocode}
%
% \begin{macrocode}
-\ProvidesExplPackage{l3benchmark}{2020-08-07}{}
+\ProvidesExplPackage{l3benchmark}{2020-09-01}{}
{L3 Experimental benchmarking}
% \end{macrocode}
%
diff --git a/macros/latex/contrib/l3experimental/l3benchmark.pdf b/macros/latex/contrib/l3experimental/l3benchmark.pdf
index adfca31546..f16030cee7 100644
--- a/macros/latex/contrib/l3experimental/l3benchmark.pdf
+++ b/macros/latex/contrib/l3experimental/l3benchmark.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3experimental/l3color.dtx b/macros/latex/contrib/l3experimental/l3color.dtx
index 42151e2a41..ec8266d06f 100644
--- a/macros/latex/contrib/l3experimental/l3color.dtx
+++ b/macros/latex/contrib/l3experimental/l3color.dtx
@@ -46,7 +46,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -59,7 +59,7 @@
% or print. Parameter-based models can describe a very large number of unique
% colors, and have a varying number of \emph{axes} which define a color
% space. In contrast, various proprietary models are available which define
-% \emph{spot} colors.
+% \emph{spot} colors (more formally separations).
%
% Core models are used to pass color information to output; these are
% \enquote{native} to \pkg{l3color}. Core models use real numbers in the range
@@ -71,31 +71,38 @@
% the components
% \item \texttt{cmyk} Cyan-magenta-yellow-black color, with four axes, one for
% each of the components
-% \item \texttt{spot} Spot color, with one value, the name of the color
-% (see \url{https://helpx.adobe.com/indesign/using/spot-process-colors.html}
-% for details of the use of spot colors in print)
% \end{itemize}
% There are also interface models: these are convenient for users but have
% to be manipulated before storing/passing to the backend. Interface models
% are primarily integer-based: see below for more detail. The supported
% interface models are
% \begin{itemize}
+% \item \texttt{Gray} Grayscale color, with a single axis running from
+% $0$ (fully black) to $15$ (fully white)
+% \item \texttt{hsb} Hue-saturation-brightness color, with three axes,all
+% real values in the range $[0,1]$ for hue saturation and brightness
% \item \texttt{Hsb} Hue-saturation-brightness color, with three axes, integer
% in the range $[0,360]$ for hue, real values in the range $[0,1]$ for
% saturation and brightness
-% \item \texttt{HSB} Hue-saturation-brightness color, with three axes, integer
-% in the range $[0,360]$ for hue, integer values in the range $[0,255]$ for
-% saturation and brightness
+% \item \texttt{HSB} Hue-saturation-brightness color, with three axes, integers
+% in the range $[0,240]$ for hue, saturation and brightness
% \item \texttt{HTML} HTML format representation of RGB color given as a
% single six-digit hexadecimal number
% \item \texttt{RGB} Red-green-blue color, with three axes, one for each of
% the components, values as integers from $0$ to $255$
+% \item \texttt{wave} Light wavelength, a real number in the range
+% $380$ to $780$ (nanometres)
% \end{itemize}
% All interface models are internally stored as |rgb|.
%
-% Additional models may be created to allow mixing of spot colors
+% To allow parsing of data from \pkg{xcolor}, any leading model up the first
+% \texttt{:} will be discarded; the approach of selecting an internal form
+% for data is \emph{not} used in \pkg{l3color}.
+%
+% Additional models may be created to allow mixing of separation colors
% with each other or with those from other models. See
-% Section~\ref{l3color:sec:new-models} for more detail of spot color support.
+% Section~\ref{l3color:sec:new-models} for more detail of color support
+% for additional models.
%
% When color is selected by model, the \meta{values} given are specified as
% a comma-separated list. The length of the list will therefore be determined
@@ -327,7 +334,7 @@
% \meta{tl}.
% \end{function}
%
-% \begin{function}{\color_export:nnN}
+% \begin{function}{\color_export:nnnN}
% \begin{syntax}
% \cs{color_export:nnnN} \Arg{model} \Arg{value(s)} \Arg{format} \Arg{tl}
% \end{syntax}
@@ -405,7 +412,7 @@
% \end{macrocode}
%
% \begin{macrocode}
-\ProvidesExplPackage{l3color}{2020-08-07}{}
+\ProvidesExplPackage{l3color}{2020-09-01}{}
{L3 Experimental color support}
% \end{macrocode}
%
@@ -593,14 +600,12 @@
% \begin{macrocode}
\cs_new_protected:Npx \@@_parse:nN #1#2
{
-%<*package>
\exp_not:N \@@_backend_pickup:N \exp_not:N \l_@@_current_tl
\tl_set:Nx \exp_not:c { l_@@_named_ . _tl }
{ \exp_not:N \@@_model:N \exp_not:N \l_@@_current_tl }
\prop_put:NVx \exp_not:c { l_@@_named_ . _prop }
\exp_not:c { l_@@_named_ . _tl }
{ \exp_not:N \@@_values:N \exp_not:N \l_@@_current_tl }
-%</package>
\exp_not:N \exp_args:Ne \exp_not:N \@@_parse_aux:nN
{ \exp_not:N \tl_to_str:n {#1} } #2
}
@@ -822,11 +827,10 @@
% \begin{macro}[EXP]
% {
% \@@_parse_model_gray:w, \@@_parse_model_rgb:w,
-% \@@_parse_model_cmyk:w, \@@_parse_model_spot:w
+% \@@_parse_model_cmyk:w
% }
% \begin{macro}[EXP]{\@@_parse_number:n}
% \begin{macro}[EXP]{\@@_parse_number:w}
-% \begin{macro}[EXP]{\@@_parse_spot_aux:w}
% Turn the input into internal form, also tidying up the number quickly.
% \begin{macrocode}
\cs_new:Npn \@@_parse_model_gray:w #1 , #2 \s_@@_stop
@@ -850,13 +854,6 @@
\@@_parse_number:n {#4}
}
}
-\cs_new:Npn \@@_parse_model_spot:w #1 , #2 \s_@@_stop
- {
- { spot }
- { \@@_parse_spot_aux:w #1 ! 100 ! \s_@@_stop }
- }
-\cs_new:Npn \@@_parse_spot_aux:w #1 ! #2 ! #3 \s_@@_stop
- { #1 ~ \fp_eval:n { #2 / 100 } }
\cs_new:Npn \@@_parse_number:n #1
{ \@@_parse_number:w #1 . 0 . \s_@@_stop }
\cs_new:Npn \@@_parse_number:w #1 . #2 . #3 \s_@@_stop
@@ -865,14 +862,34 @@
% \end{macro}
% \end{macro}
% \end{macro}
-% \end{macro}
%
% \begin{macro}[EXP]
% {
+% \@@_parse_model_Gray:w, \@@_parse_model_hsb:w,
% \@@_parse_model_Hsb:w, \@@_parse_model_HSB:w,
% \@@_parse_model_HTML:w, \@@_parse_model_RGB:w
% }
+% \begin{macro}[EXP]{\@@_parse_model_hsb:nnn, \@@_parse_model_hsb_aux:nnn}
+% \begin{macro}[EXP]{\@@_parse_model_hsb:nnnn}
+% \begin{macro}[EXP]{\@@_parse_model_hsb:nnnnn}
+% \begin{macro}[EXP]
+% {
+% \@@_parse_model_hsb_0:nnnn ,
+% \@@_parse_model_hsb_1:nnnn ,
+% \@@_parse_model_hsb_2:nnnn ,
+% \@@_parse_model_hsb_3:nnnn ,
+% \@@_parse_model_hsb_4:nnnn ,
+% \@@_parse_model_hsb_5:nnnn
+% }
+% \begin{macro}[EXP]{\@@_parse_model_wave:w}
+% \begin{macro}[EXP]
+% {\@@_parse_model_wave_auxi:nn, \@@_parse_model_wave_auxii:nn}
+% \begin{macro}[EXP]{\@@_parse_model_wave_rho:n}
% \begin{macrocode}
+\cs_new:Npn \@@_parse_model_Gray:w #1 , #2 \s_@@_stop
+ { { gray } { \fp_eval:n { #1 / 15 } } }
+\cs_new:Npn \@@_parse_model_hsb:w #1 , #2 , #3 , #4 \s_@@_stop
+ { \@@_parse_model_hsb:nnn {#1} {#2} {#3} }
\cs_new:Npn \@@_parse_model_Hsb:w #1 , #2 , #3 , #4 \s_@@_stop
{
\exp_args:Ne \@@_parse_model_hsb:nnn { \fp_eval:n { #1 / 360 } }
@@ -923,9 +940,9 @@
\cs_new:Npn \@@_parse_model_HSB:w #1 , #2 , #3 , #4 \s_@@_stop
{
\exp_args:Neee \@@_parse_model_hsb:nnn
- { \fp_eval:n {#1 / 360} }
- { \fp_eval:n {#2 / 255} }
- { \fp_eval:n {#3 / 255} }
+ { \fp_eval:n {#1 / 240} }
+ { \fp_eval:n {#2 / 240} }
+ { \fp_eval:n {#3 / 240} }
}
\cs_new:Npn \@@_parse_model_HTML:w #1 , #2 \s_@@_stop
{ \@@_parse_model_HTML_aux:w #1 0 0 0 0 0 0 \s_@@_stop }
@@ -948,6 +965,83 @@
}
}
% \end{macrocode}
+% Following the description in the \pkg{xcolor} manual. As we always use |rgb|,
+% there is no need to find the sixth, we just pas the information straight
+% to the |hsb| auxiliary defined earlier.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_model_wave:w #1 , #2 \s_@@_stop
+ {
+ { rgb }
+ {
+ \fp_compare:nNnTF {#1} < { 420 }
+ { \@@_parse_model_wave_auxi:nn {#1} { 0.3 + 0.7 * (#1 - 380) / 40 }
+ }
+ {
+ \fp_compare:nNnTF {#1} > { 700 }
+ { \@@_parse_model_wave_auxi:nn {#1} { 0.3 + 0.7 * (#1 - 780) / -80 } }
+ { \@@_parse_model_wave_auxi:nn {#1} { 1 } }
+ }
+ }
+ }
+\cs_new:Npn \@@_parse_model_wave_auxi:nn #1#2
+ {
+ \fp_compare:nNnTF {#1} < { 440 }
+ {
+ \@@_parse_model_wave_auxii:nn
+ { 4 + \@@_parse_model_wave_rho:n { (#1 - 440) / -60 } }
+ {#2}
+ }
+ {
+ \fp_compare:nNnTF {#1} < { 490 }
+ {
+ \@@_parse_model_wave_auxii:nn
+ { 4 - \@@_parse_model_wave_rho:n { (#1 - 440) / 50 } }
+ {#2}
+ }
+ {
+ \fp_compare:nNnTF {#1} < { 510 }
+ {
+ \@@_parse_model_wave_auxii:nn
+ { 2 + \@@_parse_model_wave_rho:n { (#1 - 510) / -20 } }
+ {#2}
+ }
+ {
+ \fp_compare:nNnTF {#1} < { 580 }
+ {
+ \@@_parse_model_wave_auxii:nn
+ { 2 - \@@_parse_model_wave_rho:n { (#1 - 510) / 70 } }
+ {#2}
+ }
+ {
+ \fp_compare:nNnTF {#1} < { 645 }
+ {
+ \@@_parse_model_wave_auxii:nn
+ { \@@_parse_model_wave_rho:n { (#1 - 645) / -65 } }
+ {#2}
+ }
+ { \@@_parse_model_wave_auxii:nn { 0 } {#2} }
+ }
+ }
+ }
+ }
+ }
+\cs_new:Npn \@@_parse_model_wave_auxii:nn #1#2
+ {
+ \exp_args:Neee \@@_parse_model_hsb_aux:nnn
+ { \fp_eval:n {#1} }
+ { 1 }
+ { \@@_parse_model_wave_rho:n {#2} }
+ }
+\cs_new:Npn \@@_parse_model_wave_rho:n #1
+ { \fp_eval:n { min(1, max(0,#1) ) } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
% \end{macro}
%
% \subsection{Selecting colors (and color models)}
@@ -1127,6 +1221,7 @@
% \begin{macro}{\@@_set:nn}
% \begin{macro}{\@@_set:nnw}
% \begin{macro}{\color_set:nnn}
+% \begin{macro}{\@@_set_colon:nnw}
% \begin{macro}{\@@_set_loop:nw}
% \begin{macro}{\color_set_eq:nn}
% Defining named colors means working through the model list and saving
@@ -1189,15 +1284,28 @@
}
}
}
-\cs_new_protected:Npn \color_set:nnn #1#2#3
+\cs_new_protected:Npx \color_set:nnn #1#2#3
{
- \str_if_eq:nnF {#1} { . }
+ \exp_not:N \str_if_eq:nnF {#1} { . }
{
\tl_clear_new:c { l_@@_named_ #1 _tl }
\prop_clear_new:c { l_@@_named_ #1 _prop }
- \@@_set_loop:nw {#1} #2 / / \s_@@_mark #3 / / \s_@@_stop
+ \exp_not:N \@@_set_colon:nnw {#1} {#3}
+ #2 \c_colon_str \c_colon_str \exp_not:N \s_@@_stop
}
}
+\use:x
+ {
+ \cs_new_protected:Npn \exp_not:N \@@_set_colon:nnw
+ ##1##2 ##3 \c_colon_str ##4 \c_colon_str
+ ##5 \exp_not:N \s_@@_stop
+ }
+ {
+ \tl_if_blank:nTF {#4}
+ { \@@_set_loop:nw {#1} #3 }
+ { \@@_set_loop:nw {#1} #4 }
+ / / \s_@@_mark #2 / / \s_@@_stop
+ }
\cs_new_protected:Npn \@@_set_loop:nw
#1#2 / #3 \s_@@_mark #4 / #5 \s_@@_stop
{
@@ -1242,9 +1350,10 @@
% \end{macro}
% \end{macro}
% \end{macro}
+% \end{macro}
%
% A small set of colors are always defined.
-% \begin{macrocode}
+% \begin{macrocode}
\color_set:nnn { black } { gray } { 0 }
\color_set:nnn { white } { gray } { 1 }
\color_set:nnn { cyan } { cmyk } { 1 , 0 , 0 , 0 }
@@ -1253,7 +1362,7 @@
\color_set:nnn { red } { rgb } { 1 , 0 , 0 }
\color_set:nnn { green } { rgb } { 0 , 1 , 0 }
\color_set:nnn { blue } { rgb } { 0 , 0 , 1 }
-% \end{macrocode}
+% \end{macrocode}
%
% \begin{variable}{\l_@@_named_._prop, \l_@@_named_._tl}
% A special named color: this is always defined though not fixed in
@@ -1457,9 +1566,6 @@
% \begin{macro}{\@@_model_convert:nnn}
% \begin{macro}{\@@_model_separation_cielab:nnnnnn}
% \begin{macro}{\@@_model_separation_cielab:nnnnnnn}
-% \begin{macro}{\@@_model_separation_init:nnnnn}
-% \begin{macro}{\@@_model_separation_init_cielab:n}
-% \begin{macro}{\@@_model_separation_init_cielab:nnnnn}
% Set up a new model: in general this has to be handled by a family-dependent
% function. To avoid some \enquote{interesting} questions with casing, we
% fold the case of the family name. The key--value list should always be
@@ -1590,7 +1696,7 @@
}
\@@_model_convert:nnn {#1} { cmyk } { rgb }
\@@_model_convert:nnn {#1} { cmyk } { gray }
- \@@_model_separation_init:nnnnn {#2} { /DeviceCMYK } { }
+ \@@_backend_separation_init:nnnnn {#2} { /DeviceCMYK } { }
{ 0 ~ 0 ~ 0 ~ 0 } { #3 ~ #4 ~ #5 ~ #6 }
}
\cs_new_protected:Npn \@@_model_separation_rgb:nnnnnn #1#2#3#4#5#6
@@ -1603,7 +1709,7 @@
}
\@@_model_convert:nnn {#1} { rgb } { cmyk }
\@@_model_convert:nnn {#1} { rgb } { gray }
- \@@_model_separation_init:nnnnn {#2} { /DeviceRGB } { }
+ \@@_backend_separation_init:nnnnn {#2} { /DeviceRGB } { }
{ 0 ~ 0 ~ 0 } { #3 ~ #4 ~ #5 }
}
\cs_new_protected:Npn \@@_model_separation_gray:nnnnnn #1#2#3#4#5#6
@@ -1623,7 +1729,7 @@
\fp_eval:n {##1 * #3} ~
\fp_eval:n {##1 * #3}
}
- \@@_model_separation_init:nnnnn {#2} { /DeviceGray } { } { 0 } {#3}
+ \@@_backend_separation_init:nnnnn {#2} { /DeviceGray } { } { 0 } {#3}
}
% \end{macrocode}
% Generic model conversion \emph{via} an alternative intermediate.
@@ -1665,8 +1771,8 @@
{
\tl_if_exist:cTF { c_@@_model_whitepoint_cielab_ #1 _tl }
{
- \@@_model_separation_init_cielab:n {#1}
- \@@_model_separation_init_cielab:nnnnn {#2} {#3} {#4} {#5} {#6}
+ \@@_backend_separation_init_cielab:n {#1}
+ \@@_backend_separation_init_cielab:nnnnn {#2} {#3} {#4} {#5} {#6}
\cs_new:cpn { @@_convert_ #2 _cmyk:w } ##1 ~ ##2 \s_@@_stop
{ 0 ~ 0 ~ 0 ~ 1 }
\cs_new:cpn { @@_convert_ #2 _rgb:w } ##1 ~ ##2 \s_@@_stop
@@ -1680,66 +1786,6 @@
}
}
% \end{macrocode}
-% Initialising the PDF structures needs two parts: creating an object
-% containing the \enquote{real} name of the Separation, then adding a reference
-% to that to each page. The latter uses the internal name of the \texttt{cs}.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_model_separation_init:nnnnn #1#2#3#4#5
- {
- \pdf_object_now:nx { array }
- {
- /Separation
- / \str_convert_pdfname:n {#1} ~ #2 ~
- <<
- /FunctionType ~ 2
- /Domain ~ [0 ~ 1]
- \tl_if_blank:nF {#3} { /Range ~ [#3] }
- /C0 ~ [#4] ~
- /C1 ~ [#5] /N ~ 1
- >>
- }
- \use:x
- {
- \pdfcoredict_gput:nnn
- { Page / Resources / ColorSpace }
- { color \int_use:N \g_@@_separation_int }
- { \pdf_object_last: }
- }
- }
-\cs_if_exist:NF \pdf_object_now:nn
- { \cs_gset_protected:Npn \@@_model_separation_init:nnnnn #1#2#3#4#5 { } }
-% \end{macrocode}
-% For CIELAB colors, we need one object per document for the illuminant,
-% plus initialisation of the color space referencing that object.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_model_separation_init_cielab:n #1
- {
- \pdf_object_new:nn { @@_illuminant_cielab_ #1 } { array }
- \pdf_object_write:nx { @@_illuminant_cielab_ #1 }
- {
- /Lab ~
- <<
- /WhitePoint ~
- [ \tl_use:c { c_@@_model_whitepoint_cielab_ #1 _tl } ]
- /Range ~ [ \c_@@_model_range_lab_tl ]
- >>
- }
- }
-\cs_if_exist:NF \pdf_object_new:nn
- { \cs_gset_protected:Npn \@@_model_separation_init_cielab:n #1 { } }
-\cs_new_protected:Npn \@@_model_separation_init_cielab:nnnnn #1#2#3#4#5
- {
- \@@_model_separation_init:nnnnn
- {#2}
- { \pdf_object_ref:n { @@_illuminant_cielab_ #1 } }
- { \c_@@_model_range_lab_tl }
- { 100 ~ 0 ~ 0 }
- { #3 ~ #4 ~ #5 }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
diff --git a/macros/latex/contrib/l3experimental/l3color.pdf b/macros/latex/contrib/l3experimental/l3color.pdf
index 321bc7cc28..304b1941e3 100644
--- a/macros/latex/contrib/l3experimental/l3color.pdf
+++ b/macros/latex/contrib/l3experimental/l3color.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3experimental/l3draw-boxes.dtx b/macros/latex/contrib/l3experimental/l3draw-boxes.dtx
index 8ab5d0c59c..940dd8c31d 100644
--- a/macros/latex/contrib/l3experimental/l3draw-boxes.dtx
+++ b/macros/latex/contrib/l3experimental/l3draw-boxes.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3experimental/l3draw-code.pdf b/macros/latex/contrib/l3experimental/l3draw-code.pdf
index d66a262ce7..196604bf26 100644
--- a/macros/latex/contrib/l3experimental/l3draw-code.pdf
+++ b/macros/latex/contrib/l3experimental/l3draw-code.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3experimental/l3draw-layers.dtx b/macros/latex/contrib/l3experimental/l3draw-layers.dtx
index ad1238cd2f..50a8fd81c1 100644
--- a/macros/latex/contrib/l3experimental/l3draw-layers.dtx
+++ b/macros/latex/contrib/l3experimental/l3draw-layers.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3experimental/l3draw-paths.dtx b/macros/latex/contrib/l3experimental/l3draw-paths.dtx
index 5da166a75d..cba6efdb76 100644
--- a/macros/latex/contrib/l3experimental/l3draw-paths.dtx
+++ b/macros/latex/contrib/l3experimental/l3draw-paths.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3experimental/l3draw-points.dtx b/macros/latex/contrib/l3experimental/l3draw-points.dtx
index 3c2b8395a9..b6d9ba0837 100644
--- a/macros/latex/contrib/l3experimental/l3draw-points.dtx
+++ b/macros/latex/contrib/l3experimental/l3draw-points.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3experimental/l3draw-scopes.dtx b/macros/latex/contrib/l3experimental/l3draw-scopes.dtx
index 7ecb49df28..88d0888884 100644
--- a/macros/latex/contrib/l3experimental/l3draw-scopes.dtx
+++ b/macros/latex/contrib/l3experimental/l3draw-scopes.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3experimental/l3draw-softpath.dtx b/macros/latex/contrib/l3experimental/l3draw-softpath.dtx
index e232869980..0ca26af807 100644
--- a/macros/latex/contrib/l3experimental/l3draw-softpath.dtx
+++ b/macros/latex/contrib/l3experimental/l3draw-softpath.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3experimental/l3draw-state.dtx b/macros/latex/contrib/l3experimental/l3draw-state.dtx
index 6701026948..4b3298e0d1 100644
--- a/macros/latex/contrib/l3experimental/l3draw-state.dtx
+++ b/macros/latex/contrib/l3experimental/l3draw-state.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3experimental/l3draw-transforms.dtx b/macros/latex/contrib/l3experimental/l3draw-transforms.dtx
index e9a06f67d0..6329c05fb9 100644
--- a/macros/latex/contrib/l3experimental/l3draw-transforms.dtx
+++ b/macros/latex/contrib/l3experimental/l3draw-transforms.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -70,8 +70,12 @@
% these to fully understand them.
% \item \cs{pgftransformarrow}: Likely to be done when other arrow functions
% are added.
+% \item \cs{pgftransformationadjustments}: Used mainly by CircuiTi\textit{k}Z
+% although also for shapes, likely needs more use cases before addressing.
% \item \cs{pgflowlevelsynccm}, \cs{pgflowlevel}: Likely to be added when
% use cases are encountered in other parts of the code.
+% \item \cs{pgfviewboxscope}: Seems very speicalied, need to understand the
+% requirements here.
% \end{itemize}
%
% \begin{variable}{\l_@@_matrix_active_bool}
diff --git a/macros/latex/contrib/l3experimental/l3draw.dtx b/macros/latex/contrib/l3experimental/l3draw.dtx
index 11ed7487c1..841eae28c0 100644
--- a/macros/latex/contrib/l3experimental/l3draw.dtx
+++ b/macros/latex/contrib/l3experimental/l3draw.dtx
@@ -110,7 +110,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -1136,7 +1136,7 @@
% \end{macrocode}
%
% \begin{macrocode}
-\ProvidesExplPackage{l3draw}{2020-08-07}{}
+\ProvidesExplPackage{l3draw}{2020-09-01}{}
{L3 Experimental core drawing support}
% \end{macrocode}
%
diff --git a/macros/latex/contrib/l3experimental/l3draw.pdf b/macros/latex/contrib/l3experimental/l3draw.pdf
index 9a2f1341e0..e094bdd4ad 100644
--- a/macros/latex/contrib/l3experimental/l3draw.pdf
+++ b/macros/latex/contrib/l3experimental/l3draw.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3experimental/l3galley.dtx b/macros/latex/contrib/l3experimental/l3galley.dtx
index 8ed82bcce4..73779d70a3 100644
--- a/macros/latex/contrib/l3experimental/l3galley.dtx
+++ b/macros/latex/contrib/l3experimental/l3galley.dtx
@@ -61,7 +61,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -686,7 +686,7 @@
% \end{macrocode}
%
% \begin{macrocode}
-\ProvidesExplPackage{l3galley}{2020-08-07}{}
+\ProvidesExplPackage{l3galley}{2020-09-01}{}
{L3 Experimental galley code}
% \end{macrocode}
%
diff --git a/macros/latex/contrib/l3experimental/l3galley.pdf b/macros/latex/contrib/l3experimental/l3galley.pdf
index 4dbe5eae6a..0987073e2b 100644
--- a/macros/latex/contrib/l3experimental/l3galley.pdf
+++ b/macros/latex/contrib/l3experimental/l3galley.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3experimental/l3graphics.dtx b/macros/latex/contrib/l3experimental/l3graphics.dtx
index fd030ce643..15f963e60d 100644
--- a/macros/latex/contrib/l3experimental/l3graphics.dtx
+++ b/macros/latex/contrib/l3experimental/l3graphics.dtx
@@ -46,7 +46,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -240,7 +240,7 @@
% \end{macrocode}
%
% \begin{macrocode}
-\ProvidesExplPackage{l3graphics}{2020-08-07}{}
+\ProvidesExplPackage{l3graphics}{2020-09-01}{}
{L3 Experimental graphics inclusion support}
% \end{macrocode}
%
diff --git a/macros/latex/contrib/l3experimental/l3graphics.pdf b/macros/latex/contrib/l3experimental/l3graphics.pdf
index 82fda2baf3..2faf2c17dc 100644
--- a/macros/latex/contrib/l3experimental/l3graphics.pdf
+++ b/macros/latex/contrib/l3experimental/l3graphics.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3experimental/l3pdf-code.pdf b/macros/latex/contrib/l3experimental/l3pdf-code.pdf
index 5b479c4e2f..7f78070720 100644
--- a/macros/latex/contrib/l3experimental/l3pdf-code.pdf
+++ b/macros/latex/contrib/l3experimental/l3pdf-code.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3experimental/l3pdf.dtx b/macros/latex/contrib/l3experimental/l3pdf.dtx
index 403410f99d..7be0907d0b 100644
--- a/macros/latex/contrib/l3experimental/l3pdf.dtx
+++ b/macros/latex/contrib/l3experimental/l3pdf.dtx
@@ -46,7 +46,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -190,7 +190,7 @@
% \end{macrocode}
%
% \begin{macrocode}
-\ProvidesExplPackage{l3pdf}{2020-08-07}{}
+\ProvidesExplPackage{l3pdf}{2020-09-01}{}
{L3 Experimental core PDF support}
% \end{macrocode}
%
diff --git a/macros/latex/contrib/l3experimental/l3pdf.pdf b/macros/latex/contrib/l3experimental/l3pdf.pdf
index 572423103f..c52018c46a 100644
--- a/macros/latex/contrib/l3experimental/l3pdf.pdf
+++ b/macros/latex/contrib/l3experimental/l3pdf.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3experimental/l3str-format.dtx b/macros/latex/contrib/l3experimental/l3str-format.dtx
index e44bde9dff..8264409fb4 100644
--- a/macros/latex/contrib/l3experimental/l3str-format.dtx
+++ b/macros/latex/contrib/l3experimental/l3str-format.dtx
@@ -48,7 +48,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -166,7 +166,7 @@
% \end{macrocode}
%
% \begin{macrocode}
-\ProvidesExplPackage{l3str-format}{2020-08-07}{}
+\ProvidesExplPackage{l3str-format}{2020-09-01}{}
{L3 Experimental string formatting}
% \end{macrocode}
%
diff --git a/macros/latex/contrib/l3experimental/l3str-format.pdf b/macros/latex/contrib/l3experimental/l3str-format.pdf
index d3c96701b0..d245bb68bc 100644
--- a/macros/latex/contrib/l3experimental/l3str-format.pdf
+++ b/macros/latex/contrib/l3experimental/l3str-format.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3experimental/l3sys-shell.dtx b/macros/latex/contrib/l3experimental/l3sys-shell.dtx
index e368a92582..f3a06c643b 100644
--- a/macros/latex/contrib/l3experimental/l3sys-shell.dtx
+++ b/macros/latex/contrib/l3experimental/l3sys-shell.dtx
@@ -46,7 +46,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -135,7 +135,7 @@
% \end{macrocode}
%
% \begin{macrocode}
-\ProvidesExplPackage{l3sys-shell}{2020-08-07}{}
+\ProvidesExplPackage{l3sys-shell}{2020-09-01}{}
{L3 Experimental system shell functions}
% \end{macrocode}
%
diff --git a/macros/latex/contrib/l3experimental/l3sys-shell.pdf b/macros/latex/contrib/l3experimental/l3sys-shell.pdf
index ebb8a0f9c6..98c66b8421 100644
--- a/macros/latex/contrib/l3experimental/l3sys-shell.pdf
+++ b/macros/latex/contrib/l3experimental/l3sys-shell.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3experimental/xcoffins.dtx b/macros/latex/contrib/l3experimental/xcoffins.dtx
index 7e030c8e3b..d890d28428 100644
--- a/macros/latex/contrib/l3experimental/xcoffins.dtx
+++ b/macros/latex/contrib/l3experimental/xcoffins.dtx
@@ -56,7 +56,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -675,7 +675,7 @@
% \end{macrocode}
%
% \begin{macrocode}
-\ProvidesExplPackage{xcoffins}{2020-08-07}{}
+\ProvidesExplPackage{xcoffins}{2020-09-01}{}
{L3 Experimental design level coffins}
% \end{macrocode}
%
diff --git a/macros/latex/contrib/l3experimental/xcoffins.pdf b/macros/latex/contrib/l3experimental/xcoffins.pdf
index 91e71514d8..b13cdfe00c 100644
--- a/macros/latex/contrib/l3experimental/xcoffins.pdf
+++ b/macros/latex/contrib/l3experimental/xcoffins.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3experimental/xgalley.dtx b/macros/latex/contrib/l3experimental/xgalley.dtx
index 0d9bf34149..77557731ad 100644
--- a/macros/latex/contrib/l3experimental/xgalley.dtx
+++ b/macros/latex/contrib/l3experimental/xgalley.dtx
@@ -47,7 +47,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -734,7 +734,7 @@
% \end{macrocode}
%
% \begin{macrocode}
-\ProvidesExplPackage{xgalley}{2020-08-07}{}
+\ProvidesExplPackage{xgalley}{2020-09-01}{}
{L3 Experimental galley}
\RequirePackage{xparse,xtemplate,l3galley}
% \end{macrocode}
diff --git a/macros/latex/contrib/l3experimental/xgalley.pdf b/macros/latex/contrib/l3experimental/xgalley.pdf
index 47f63bdd6d..4935f6eded 100644
--- a/macros/latex/contrib/l3experimental/xgalley.pdf
+++ b/macros/latex/contrib/l3experimental/xgalley.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/CHANGELOG.md b/macros/latex/contrib/l3kernel/CHANGELOG.md
index 8a40579449..e388a2f941 100644
--- a/macros/latex/contrib/l3kernel/CHANGELOG.md
+++ b/macros/latex/contrib/l3kernel/CHANGELOG.md
@@ -7,6 +7,23 @@ this project uses date-based 'snapshot' version identifiers.
## [Unreleased]
+## [2020-09-01]
+
+### Added
+- `\hbox_overlap_center:n`
+
+### Changed
+- Backend setting for direct PDF output
+- Backend setting for XeTeX support
+
+### Deprecated
+- Backend setting `pdfmode`
+
+### Fixed
+- `\file_compare_timestamp:nNn(TF)` in LuaTeX (issue #792)
+- Text case changing and expansion where an excluded command is equivalent
+ to `\use:n`
+
## [2020-08-07]
### Changed
@@ -27,6 +44,7 @@ this project uses date-based 'snapshot' version identifiers.
### Fixed
- File lookup with `\input@path`
+- 8-bit encodings in `\str_set_convert:Nnnn`
### Changed
- Implementation of `\file_parse_full_name:nNNN` now uses
@@ -37,6 +55,9 @@ this project uses date-based 'snapshot' version identifiers.
### Removed
- Functions deprecated at end of 2019
+### Deprecated
+- `\str_declare_eight_bit_encoding:nnn`
+
## [2020-06-18]
### Changed
@@ -734,7 +755,8 @@ this project uses date-based 'snapshot' version identifiers.
- Step func­tions have been added for dim vari­ables,
e.g. `\dim_step_in­line:nnnn`
-[Unreleased]: https://github.com/latex3/latex3/compare/2020-08-07...HEAD
+[Unreleased]: https://github.com/latex3/latex3/compare/2020-09-01...HEAD
+[2020-09-01]: https://github.com/latex3/latex3/compare/2020-08-07...2020-09-01
[2020-08-07]: https://github.com/latex3/latex3/compare/2020-07-17...2020-08-07
[2020-07-17]: https://github.com/latex3/latex3/compare/2020-06-18...2020-07-17
[2020-06-18]: https://github.com/latex3/latex3/compare/2020-06-03...2020-06-18
diff --git a/macros/latex/contrib/l3kernel/README.md b/macros/latex/contrib/l3kernel/README.md
index d239d38035..f63e3bc73a 100644
--- a/macros/latex/contrib/l3kernel/README.md
+++ b/macros/latex/contrib/l3kernel/README.md
@@ -1,7 +1,7 @@
LaTeX3 Programming Conventions
==============================
-Release 2020-08-07
+Release 2020-09-01
Overview
--------
diff --git a/macros/latex/contrib/l3kernel/expl3.dtx b/macros/latex/contrib/l3kernel/expl3.dtx
index 85284e594a..9e38bfb6db 100644
--- a/macros/latex/contrib/l3kernel/expl3.dtx
+++ b/macros/latex/contrib/l3kernel/expl3.dtx
@@ -24,7 +24,7 @@
%
%<*driver|generic|package|2ekernel>
%</driver|generic|package|2ekernel>
-\def\ExplFileDate{2020-08-07}%
+\def\ExplFileDate{2020-09-01}%
%<*driver>
\documentclass[full]{l3doc}
\usepackage{graphicx}
@@ -51,7 +51,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -924,10 +924,13 @@
% \item[dvips] Use the \texttt{dvips} driver.
% \item[dvipdfmx] Use the \texttt{dvipdfmx} driver.
% \item[dvisvgm] Use the \texttt{dvisvgm} driver.
-% \item[pdfmode] Use the \texttt{pdfmode} driver (direct PDF output from
-% \pdfTeX{} or \LuaTeX{}).
-% \item[xdvipdfmx] Use the \texttt{xdvipdfmx} driver (\XeTeX{} only).
+% \item[luatex] Use the direct PDF output mode of \LuaTeX{}
+% \item[pdftex] Use the direct PDF output mode of \pdfTeX{}
+% \item[xetex] Use the \XeTeX{} version of the \texttt{dvipdfmx} driver.
% \end{itemize}
+% For historical reasons, there is also \texttt{pdfmode} as an equivalent of
+% \texttt{luatex} or \texttt{pdftex}, and \texttt{xdvipdfmx} as
+% an equivalent to \texttt{xetex}, but these are deprecated
%
% \DescribeOption{suppress-backend-headers}
% The \texttt{suppress-backend-headers} option suppresses loading of
@@ -1064,8 +1067,10 @@
% \url{https://github.com/latex3/latex3/issues/781}).
% \begin{macrocode}
%<*2ekernel>
-\global\expandafter\let\csname\detokenize
- {c__kernel_expl_date_tl}\endcsname\ExplFileDate
+\unless\ifcsname\detokenize{c__kernel_expl_date_tl}\endcsname
+ \global\expandafter\let\csname\detokenize
+ {c__kernel_expl_date_tl}\endcsname\ExplFileDate
+\fi
%</2ekernel>
% \end{macrocode}
% \end{macro}
@@ -1243,86 +1248,50 @@
%<@@=expl>
% \end{macrocode}
%
-% Several times users reported this error when loading \pkg{expl3}:
-% \begin{verbatim}
-% ! Undefined control sequence.
-% l.67 \bool
-% _new:N \g__expl_reload_bool
-% \end{verbatim}
-% raised in the reload block below. This happens because the reload
-% check below assumes that if the boolean \cs{g_@@_reload_bool} doesn't
-% exist, this file is being loaded for the first time, and \pkg{expl3}
-% syntax is on. This is a bit of a stretch for assumptions, but it's
-% valid as long as everything's in sync. However the problem reported
-% happened because of a stray format file in the user tree which didn't
-% have the reload code defined here (commit \texttt{1d16336}), so the
-% \cs{g_@@_reload_bool} doesn't exist, but \pkg{expl3} syntax is off,
-% thus the error.
-%
-% At this point, if we have \cs{c__kernel_expl_date_tl} defined, the
-% situation is straightforward: if it matches \cs{ExplLoaderFileDate},
-% then everything's as expected, so no need to worry. If it doesn't,
-% then the current version of \pkg{expl3} differs from the one in the
-% format, so raise a fatal error: the bahaviour is too unpredictable to
-% continue safely. Also, if the error is to be raised, then we're
-% reloading, which means that \pkg{expl3} syntax is off, so we turn it
-% on for the message.
+% At this point, if we have \cs{c__kernel_expl_date_tl} defined, just
+% call the \cs{__kernel_dependency_version_check:Nn} auxiliary to check
+% if it matches \cs{ExplLoaderFileDate}. Here the test is performed
+% only if \cs{c__kernel_expl_date_tl} exists because this file can be
+% loaded in a \LaTeXe{} format without \pkg{expl3} preloaded, where that
+% token list doesn't exist.
+%
+% This is all done in the \texttt{package} \pkg{docstrip} guard because
+% it doesn't apply to \pkg{expl3.ltx}.
% \begin{macrocode}
+%<*package>
\ifcsname\detokenize{c__kernel_expl_date_tl}\endcsname
- \expandafter\ifx\csname\detokenize
- {c__kernel_expl_date_tl}\endcsname\ExplLoaderFileDate
- \else
- \ExplSyntaxOn
- \__kernel_msg_set:nnn { kernel } { mismatched-expl3 }
- {
- Mismatched~expl3~detected!~Loading~expl3~will~abort.
- \\ \\
- The~version~of~expl3~preloaded~in~LaTeX~is~
- \c__kernel_expl_date_tl,~but~the~version~of~expl3~you~are~
- trying~to~load~is~dated~\ExplLoaderFileDate.~This~is~most~
- likely~due~to~a~stray~format~file~in~the~user~tree.~Please~
- make~sure~that~your~LaTeX~format~is~updated.
- }
- \exp_after:wN \ExplSyntaxOff \use:n
- {
- \__kernel_msg_critical:nn { kernel } { mismatched-expl3 }
- \use:c { fi: } \use:c { fi: }
- }
- \fi
+ \expandafter\@firstofone
+\else
% \end{macrocode}
-% If \cs{c__kernel_expl_date_tl} does \emph{not} exist, then we're on
-% uncharted lands (that is, any time prior to the version that
-% introduced this token list :-). Two cases might be here, depending
-% whether \pkg{expl3} is loaded into the kernel or not. If we're loading
-% \pkg{expl3} \enquote{normally} as a package, \pkg{expl3} syntax is on.
-% Otherwise it's already loaded in the kernel and we're reloading
-% \file{expl3.sty} so (\file{expl3-code.tex} doesn't load again and)
-% \pkg{expl3} syntax is off.
+% If \cs{c__kernel_expl_date_tl} does \emph{not} exist we may be loading
+% in a format without \pkg{expl3} preloaded or in the earlier (although
+% still compatible) version in which the error mentioned above showed
+% up. If loading as a package, \file{expl3-code.tex} got read and here
+% the \pkg{expl3} syntax is on. Otherwise it was already loaded in a
+% sligtly older kernel, so we fire the incompatibility error message and
+% abort loading.
% \begin{macrocode}
-\else
\ifodd\csname\detokenize{l__kernel_expl_bool}\endcsname
% \end{macrocode}
-% Package mode; all should be fine, since \file{expl3.sty} and
-% \file{expl3-code.tex} are both loaded in one go, so versions should
-% match (if they don't, it's detected above).
-% Also, we've just tested that \pkg{expl3} syntax is on, so the reload
-% test below will return false and \cs{bool_new:N} will run correctly.
+% In package mode all files are loaded in one go, so versions will
+% match. We just have to set \cs{c__kernel_expl_date_tl} so that
+% further dependencies don't break:
% \begin{macrocode}
+ \global\expandafter\let\csname\detokenize
+ {c__kernel_expl_date_tl}\endcsname\ExplLoaderFileDate
+ \expandafter\expandafter
+ \expandafter\@gobble
\else
% \end{macrocode}
-% In this branch we're reloading, but there are still two cases to
-% consider (sigh\ldots); whether the version preloaded in the format
-% is recent enough to have \cs{g_@@_reload_bool} (2020-06-18 and
-% later) or not. If the boolean is there, we have to do nothing
-% because right ahead we deal with this case.
-% If it is not, we just have to create it:
+% And reloading in an incompatible version is an error:
% \begin{macrocode}
- \ExplSyntaxOn
- \bool_if_exist:NF \g_@@_reload_bool
- { \bool_new:N \g_@@_reload_bool }
- \ExplSyntaxOff
+ \expandafter\expandafter
+ \expandafter\@firstofone
\fi
\fi
+ {\csname\detokenize{__kernel_dependency_version_check:Nn}\endcsname
+ \ExplLoaderFileDate{expl3.sty}}%
+%</package>
% \end{macrocode}
%
% Here we can also detect whether we're reloading. This code goes into
@@ -1403,7 +1372,7 @@
\keys_define:nn { sys }
{
backend .choices:nn =
- { dvipdfmx , dvips , dvisvgm , pdfmode , xdvipdfmx }
+ { dvipdfmx , dvips , dvisvgm , luatex , pdftex , pdfmode , xdvipdfmx , xetex }
{ \sys_load_backend:n {#1} } ,
check-declarations .code:n =
{
diff --git a/macros/latex/contrib/l3kernel/expl3.pdf b/macros/latex/contrib/l3kernel/expl3.pdf
index 34f0d20a6b..dc73326538 100644
--- a/macros/latex/contrib/l3kernel/expl3.pdf
+++ b/macros/latex/contrib/l3kernel/expl3.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/interface3.pdf b/macros/latex/contrib/l3kernel/interface3.pdf
index 57ea709c8e..8d8514f9a7 100644
--- a/macros/latex/contrib/l3kernel/interface3.pdf
+++ b/macros/latex/contrib/l3kernel/interface3.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/interface3.tex b/macros/latex/contrib/l3kernel/interface3.tex
index 268de9b805..7015a2fc69 100644
--- a/macros/latex/contrib/l3kernel/interface3.tex
+++ b/macros/latex/contrib/l3kernel/interface3.tex
@@ -54,7 +54,7 @@ for those people who are interested.
{latex-team@latex-project.org}%
}%
}
-\date{Released 2020-08-07}
+\date{Released 2020-09-01}
\pagenumbering{roman}
\maketitle
diff --git a/macros/latex/contrib/l3kernel/l3basics.dtx b/macros/latex/contrib/l3kernel/l3basics.dtx
index ba422a7961..c6559136c1 100644
--- a/macros/latex/contrib/l3kernel/l3basics.dtx
+++ b/macros/latex/contrib/l3kernel/l3basics.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3bootstrap.dtx b/macros/latex/contrib/l3kernel/l3bootstrap.dtx
index cf749116d6..bcb2f71562 100644
--- a/macros/latex/contrib/l3kernel/l3bootstrap.dtx
+++ b/macros/latex/contrib/l3kernel/l3bootstrap.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3box.dtx b/macros/latex/contrib/l3kernel/l3box.dtx
index 8adeb3fb6d..30ba3c7553 100644
--- a/macros/latex/contrib/l3kernel/l3box.dtx
+++ b/macros/latex/contrib/l3kernel/l3box.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -370,6 +370,14 @@
% and then stores the result inside the \meta{box}.
% \end{function}
%
+% \begin{function}[added = 2020-08-25]{\hbox_overlap_center:n}
+% \begin{syntax}
+% \cs{hbox_overlap_center:n} \Arg{contents}
+% \end{syntax}
+% Typesets the \meta{contents} into a horizontal box of zero width
+% such that material protrudes equally to both sides of the insertion point.
+% \end{function}
+%
% \begin{function}[updated = 2017-04-05]{\hbox_overlap_right:n}
% \begin{syntax}
% \cs{hbox_overlap_right:n} \Arg{contents}
@@ -1381,10 +1389,12 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}{\hbox_overlap_left:n, \hbox_overlap_right:n}
+% \begin{macro}{\hbox_overlap_center:n, \hbox_overlap_left:n, \hbox_overlap_right:n}
% Put a zero-sized box with the contents pushed against one side (which
% makes it stick out on the other) directly into the input stream.
% \begin{macrocode}
+\cs_new_protected:Npn \hbox_overlap_center:n #1
+ { \hbox_to_zero:n { \tex_hss:D #1 \tex_hss:D } }
\cs_new_protected:Npn \hbox_overlap_left:n #1
{ \hbox_to_zero:n { \tex_hss:D #1 } }
\cs_new_protected:Npn \hbox_overlap_right:n #1
diff --git a/macros/latex/contrib/l3kernel/l3candidates.dtx b/macros/latex/contrib/l3kernel/l3candidates.dtx
index 7e2cf8df90..fc5d83dcd5 100644
--- a/macros/latex/contrib/l3kernel/l3candidates.dtx
+++ b/macros/latex/contrib/l3kernel/l3candidates.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -206,7 +206,7 @@
%
% \begin{function}[added = 2019-05-08]{\ior_shell_open:Nn}
% \begin{syntax}
-% \cs{ior_shell_open:nN} \meta{stream} \Arg{shell~command}
+% \cs{ior_shell_open:Nn} \meta{stream} \Arg{shell~command}
% \end{syntax}
% Opens the \emph{pseudo}-file created by the output of the
% \meta{shell command} for reading using \meta{stream} as the
diff --git a/macros/latex/contrib/l3kernel/l3cctab.dtx b/macros/latex/contrib/l3kernel/l3cctab.dtx
index a8c063b944..2d908820f7 100644
--- a/macros/latex/contrib/l3kernel/l3cctab.dtx
+++ b/macros/latex/contrib/l3kernel/l3cctab.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3clist.dtx b/macros/latex/contrib/l3kernel/l3clist.dtx
index f32ad49748..e050d06553 100644
--- a/macros/latex/contrib/l3kernel/l3clist.dtx
+++ b/macros/latex/contrib/l3kernel/l3clist.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3coffins.dtx b/macros/latex/contrib/l3kernel/l3coffins.dtx
index f828834daf..b9f73a8f1c 100644
--- a/macros/latex/contrib/l3kernel/l3coffins.dtx
+++ b/macros/latex/contrib/l3kernel/l3coffins.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3color-base.dtx b/macros/latex/contrib/l3kernel/l3color-base.dtx
index 628a4c6f23..10199c298e 100644
--- a/macros/latex/contrib/l3kernel/l3color-base.dtx
+++ b/macros/latex/contrib/l3kernel/l3color-base.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -66,6 +66,7 @@
% \cs{color_group_end:}
% \end{syntax}
% Creates a color group: one used to \enquote{trap} color settings.
+% This grouping is built in to for example \cs{hbox_set:Nn}.
% \end{function}
%
% \begin{function}[added = 2011-09-03]{\color_ensure_current:}
diff --git a/macros/latex/contrib/l3kernel/l3debug.dtx b/macros/latex/contrib/l3kernel/l3debug.dtx
index 5f8f0b93e9..c7c0f70058 100644
--- a/macros/latex/contrib/l3kernel/l3debug.dtx
+++ b/macros/latex/contrib/l3kernel/l3debug.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3deprecation.dtx b/macros/latex/contrib/l3kernel/l3deprecation.dtx
index 10dae76668..6eebef3b6b 100644
--- a/macros/latex/contrib/l3kernel/l3deprecation.dtx
+++ b/macros/latex/contrib/l3kernel/l3deprecation.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -662,6 +662,10 @@
%
% \subsection{Deprecated \pkg{l3str} functions}
%
+% \begin{macrocode}
+%<@@=str>
+% \end{macrocode}
+%
% \begin{macro}[EXP, deprecated = 2022-07-01]
% {
% \str_lower_case:n, \str_lower_case:f,
@@ -684,6 +688,18 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}[EXP, deprecated = 2022-07-01]
+% {\str_declare_eight_bit_encoding:nnn}
+% This command was made internal, with one more argument. There is no
+% easy way to compute a reasonable value for that extra argument so we
+% take a value that is big enough to accomodate all of Unicode.
+% \begin{macrocode}
+\__kernel_patch_deprecation:nnNNpn { 2022-01-01 } { }
+\cs_gset_protected:Npn \str_declare_eight_bit_encoding:nnn #1
+ { \@@_declare_eight_bit_encoding:nnnn {#1} { 1114112 } }
+% \end{macrocode}
+% \end{macro}
+%
% \subsection{Deprecated \pkg{l3seq} functions}
%
% \begin{macro}[EXP, deprecated = 2023-01-01]
diff --git a/macros/latex/contrib/l3kernel/l3doc.dtx b/macros/latex/contrib/l3kernel/l3doc.dtx
index 9e7498e265..8721d50f4b 100644
--- a/macros/latex/contrib/l3kernel/l3doc.dtx
+++ b/macros/latex/contrib/l3kernel/l3doc.dtx
@@ -61,7 +61,7 @@ and all files in that bundle must be distributed together.
%</driver|class>
%
%<*driver>
-\ProvidesFile{l3doc.dtx}[2017/03/18 L3 Experimental documentation class]
+\ProvidesFile{l3doc.dtx}[2020/08/21 L3 Experimental documentation class]
\documentclass{l3doc}
\usepackage{framed,lipsum}
\begin{document}
@@ -79,7 +79,7 @@ and all files in that bundle must be distributed together.
%
% \title{The \cls{l3doc} class}
% \author{\Team}
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
% \maketitle
% \tableofcontents
%
@@ -3154,7 +3154,10 @@ and all files in that bundle must be distributed together.
\vbox_set:Nn \l_@@_macro_box
{
\vbox_unpack_drop:N \l_@@_macro_box
- \hbox { \llap { \@@_print_macroname:nN {#1} #2 \ } }
+ \hbox { \llap { \__codedoc_print_macroname:nN {#1} #2
+ \MacroFont % <----- without it the \ is in lmr10 if a link is made
+ \
+ } }
}
\int_incr:N \l_@@_macro_int
}
@@ -3716,7 +3719,7 @@ and all files in that bundle must be distributed together.
{ \cs_set:Npn \currentfile{#1.dtx} }
\int_compare:nNnTF \@auxout = \@partaux
{ \@latexerr{\string\include\space cannot~be~nested}\@eha }
- { \@docinclude #1 }
+ { \@docinclude {#1} }
}
% \end{macrocode}
%
@@ -3750,7 +3753,7 @@ and all files in that bundle must be distributed together.
{
\cs_set_eq:NN \ttfamily\relax
\cs_gset:Npx \filekey
- { \filekey, \thepart = { \ttfamily \currentfile } }
+ { \filekey,~ \thepart = { \ttfamily \currentfile } }
}
\DocInput{\currentfile}
\cs_set_eq:NN \PrintIndex \@ltxdoc@PrintIndex
diff --git a/macros/latex/contrib/l3kernel/l3docstrip.dtx b/macros/latex/contrib/l3kernel/l3docstrip.dtx
index 24a061d192..e8a835dfb6 100644
--- a/macros/latex/contrib/l3kernel/l3docstrip.dtx
+++ b/macros/latex/contrib/l3kernel/l3docstrip.dtx
@@ -63,7 +63,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3docstrip.pdf b/macros/latex/contrib/l3kernel/l3docstrip.pdf
index c5e42ecbc2..dea9eac6bc 100644
--- a/macros/latex/contrib/l3kernel/l3docstrip.pdf
+++ b/macros/latex/contrib/l3kernel/l3docstrip.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3expan.dtx b/macros/latex/contrib/l3kernel/l3expan.dtx
index d2ef71dac4..df3b71d9a8 100644
--- a/macros/latex/contrib/l3kernel/l3expan.dtx
+++ b/macros/latex/contrib/l3kernel/l3expan.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -504,6 +504,7 @@
% {
% \exp_args:NNNo,
% \exp_args:NNNV,
+% \exp_args:NNNv,
% \exp_args:Nccc,
% \exp_args:NcNc,
% \exp_args:NcNo,
@@ -1365,7 +1366,8 @@
%
% \begin{macro}[EXP]
% {
-% \exp_args:NNNV, \exp_args:NcNc, \exp_args:NcNo,
+% \exp_args:NNNV, \exp_args:NNNv,
+% \exp_args:NcNc, \exp_args:NcNo,
% \exp_args:Ncco,
% }
% A few more that we can hand-tune.
@@ -1377,6 +1379,13 @@
\exp_after:wN #3
\exp_after:wN { \exp:w \@@_eval_register:N #4 }
}
+\cs_new:Npn \exp_args:NNNv #1#2#3#4
+ {
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \exp_after:wN #3
+ \exp_after:wN { \exp:w \@@_eval_register:c {#4} }
+ }
\cs_new:Npn \exp_args:NcNc #1#2#3#4
{
\exp_after:wN #1
diff --git a/macros/latex/contrib/l3kernel/l3file.dtx b/macros/latex/contrib/l3kernel/l3file.dtx
index 553c5419cb..81e509bcbc 100644
--- a/macros/latex/contrib/l3kernel/l3file.dtx
+++ b/macros/latex/contrib/l3kernel/l3file.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -2868,12 +2868,10 @@
% \end{macro}
% \end{macro}
% \begin{variable}{\g_@@_internal_ior}
-% A reserved stream to test for file existence, if required.
+% A reserved stream to test for file existence (if required), and for
+% opening a shell.
% \begin{macrocode}
-\bool_lazy_or:nnF
- { \cs_if_exist_p:N \tex_filesize:D }
- { \sys_if_engine_luatex_p: }
- { \ior_new:N \g_@@_internal_ior }
+\ior_new:N \g_@@_internal_ior
% \end{macrocode}
% \end{variable}
%
@@ -3180,7 +3178,7 @@
}
}
{ \cs_new_eq:NN \@@_timestamp:n \tex_filemoddate:D }
-\cs_if_exist:NF \tex_filemoddate:D
+\cs_if_exist:NF \@@_timestamp:n
{
\prg_set_conditional:Npnn \file_compare_timestamp:nNn #1#2#3
{ p , T , F , TF }
@@ -3471,7 +3469,7 @@
}
% \end{macrocode}
%
-% \subsection{GetIfInfo}
+% \subsection{GetIdInfo}
%
% \begin{macro}{\GetIdInfo}
% \begin{macro}{\@@_id_info_auxi:w, \@@_id_info_auxii:w, \@@_id_info_auxiii:w}
@@ -3545,6 +3543,131 @@
% \end{macro}
% \end{macro}
%
+% \subsection{Checking the version of kernel dependencies}
+%
+% \begin{macro}{\__kernel_dependency_version_check:Nn}
+% \begin{macro}{\__kernel_dependency_version_check:nn}
+% \begin{macro}{\@@_kernel_dependency_compare:nnn,\@@_parse_version:w}
+% This function is responsible for checking if dependencies of the
+% \LaTeX3 kernel match the version preloaded in the \LaTeXe{} kernel.
+% If versions don't match, the function attempts to tell why by
+% searching for a possible stray format file.
+%
+% The function starts by checking that the kernel date is defined, and
+% if not zero is used to force the error route. The kernel date is
+% then compared with the argument requested date (ususally the
+% packaging date of the dependency). If the kernel date is less than
+% the required date, it's an error and the loading should abort.
+% \begin{macrocode}
+\cs_new_protected:Npn \__kernel_dependency_version_check:Nn #1
+ { \exp_args:NV \__kernel_dependency_version_check:nn #1 }
+\cs_new_protected:Npn \__kernel_dependency_version_check:nn #1
+ {
+ \cs_if_exist:NTF \c__kernel_expl_date_tl
+ {
+ \exp_args:NV \@@_kernel_dependency_compare:nnn
+ \c__kernel_expl_date_tl {#1}
+ }
+ { \@@_kernel_dependency_compare:nnn { 0000-00-00 } {#1} }
+ }
+\cs_new_protected:Npn \@@_kernel_dependency_compare:nnn #1 #2 #3
+ {
+ \int_compare:nNnT
+ { \@@_parse_version:w #1 \s_@@_stop } <
+ { \@@_parse_version:w #2 \s_@@_stop }
+ { \@@_mismatched_dependency_error:nn {#2} {#3} }
+ }
+\cs_new:Npn \@@_parse_version:w #1 - #2 - #3 \s_@@_stop {#1#2#3}
+% \end{macrocode}
+%
+% \begin{macro}{\@@_mismatched_dependency_error:nn}
+% If the versions differ, then we try to give the user some guidance.
+% This function starts by taking the engine name \cs{c_sys_engine_str}
+% and replacing |tex| by |latex|, then building a command of the form:
+% \begin{texttt}
+% kpsewhich --all --engine=\meta{engine} \meta{format}[-dev].fmt
+% \end{texttt}
+% to query the format files available. A shell is opened and each
+% line is read into a sequence.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_mismatched_dependency_error:nn #1 #2
+ {
+ \exp_args:NNx \ior_shell_open:Nn \g_@@_internal_ior
+ {
+ kpsewhich ~ --all ~
+ --engine = \c_sys_engine_exec_str
+ \c_space_tl \c_sys_engine_format_str
+ \tl_if_empty:NF \development@branch@name { -dev } .fmt
+ }
+ \seq_clear:N \l_@@_tmp_seq
+ \ior_map_inline:Nn \g_@@_internal_ior
+ { \seq_put_right:Nn \l_@@_tmp_seq {##1} }
+ \ior_close:N \g_@@_internal_ior
+% \end{macrocode}
+% Now define a some shorthands so that we can use \cs{@latex@error}
+% (almost) easily:
+% \begin{macrocode}
+ \group_begin:
+ \cs_set:Npn \\ { \MessageBreak }
+ \cs_set_eq:NN \ \c_space_tl
+ \@latex@error
+ {
+ Mismatched~LaTeX~support~files~detected. \\
+ Loading~'#2'~aborted!
+% \end{macrocode}
+% \cs{c__kernel_expl_date_tl} may not exist, due to an older format,
+% so only print the dates when the sentinel token list exists:
+% \begin{macrocode}
+ \tl_if_exist:NT \c__kernel_expl_date_tl
+ {
+ \\ \\
+ The~L3~programming~layer~in~the~LaTeX~format \\
+ is~dated~\c__kernel_expl_date_tl,~but~in~your~TeX~
+ tree~the~files~require \\ at~least~#1.
+ }
+ \use_none:n
+ }
+ {
+% \end{macrocode}
+% The sequence containing the format files should have exactly one
+% item: the format file currently being run. If that's the case, the
+% cause of the error is not that, so print a generic help with some
+% possible causes. If more than one format file was found, then print
+% the list to the user, with appropriate indications of what's in the
+% system and what's in the user tree.
+% \begin{macrocode}
+ \int_compare:nNnTF { \seq_count:N \l_@@_tmp_seq } > 1
+ {
+ The~cause~seems~to~be~an~old~format~file~in~the~user~tree. \\
+ LaTeX~found~these~files:
+ \seq_map_tokens:Nn \l_@@_tmp_seq { \\~-~\use:n } \\
+ Try~deleting~the~file~in~the~user~tree~then~run~LaTeX~again.
+ }
+ {
+ The~most~likely~causes~are:
+ \\~-~A~recent~format~generation~failed;
+ \\~-~A~stray~format~file~in~the~user~tree~which~needs~
+ to~be~removed~or~rebuilt;
+ \\~-~You~are~running~a~manually~installed~version~of~#2 \\
+ \ \ \ which~is~incompatible~with~the~version~in~LaTeX. \\
+ }
+ \\
+ LaTeX~will~abort~loading~the~incompatible~support~files~
+ but~this~may~lead~to \\ later~errors.~Please~ensure~that~
+ your~LaTeX~format~is~correctly~regenerated.
+ }
+ \group_end:
+% \end{macrocode}
+% And finish by ending the current file.
+% \begin{macrocode}
+ \tex_endinput:D
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
% \subsection{Messages}
%
% \begin{macrocode}
diff --git a/macros/latex/contrib/l3kernel/l3flag.dtx b/macros/latex/contrib/l3kernel/l3flag.dtx
index 9bc6f9de6f..a45167ea89 100644
--- a/macros/latex/contrib/l3kernel/l3flag.dtx
+++ b/macros/latex/contrib/l3kernel/l3flag.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-assign.dtx b/macros/latex/contrib/l3kernel/l3fp-assign.dtx
index 8f06b76ea4..3476c0349c 100644
--- a/macros/latex/contrib/l3kernel/l3fp-assign.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-assign.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
% \maketitle
%
% \begin{documentation}
diff --git a/macros/latex/contrib/l3kernel/l3fp-aux.dtx b/macros/latex/contrib/l3kernel/l3fp-aux.dtx
index 38fd8b1366..82b4dad329 100644
--- a/macros/latex/contrib/l3kernel/l3fp-aux.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-aux.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-basics.dtx b/macros/latex/contrib/l3kernel/l3fp-basics.dtx
index ae77fc4be2..9cfc1c0bd0 100644
--- a/macros/latex/contrib/l3kernel/l3fp-basics.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-basics.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-convert.dtx b/macros/latex/contrib/l3kernel/l3fp-convert.dtx
index e16a947e6c..252ecb7ce0 100644
--- a/macros/latex/contrib/l3kernel/l3fp-convert.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-convert.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-expo.dtx b/macros/latex/contrib/l3kernel/l3fp-expo.dtx
index fc8789101d..13ee5ed192 100644
--- a/macros/latex/contrib/l3kernel/l3fp-expo.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-expo.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-extended.dtx b/macros/latex/contrib/l3kernel/l3fp-extended.dtx
index f7566ff062..f6e24d3074 100644
--- a/macros/latex/contrib/l3kernel/l3fp-extended.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-extended.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-logic.dtx b/macros/latex/contrib/l3kernel/l3fp-logic.dtx
index d36cbb3003..45712a48b5 100644
--- a/macros/latex/contrib/l3kernel/l3fp-logic.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-logic.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-parse.dtx b/macros/latex/contrib/l3kernel/l3fp-parse.dtx
index e56abc6bb1..5d6f46a238 100644
--- a/macros/latex/contrib/l3kernel/l3fp-parse.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-parse.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-random.dtx b/macros/latex/contrib/l3kernel/l3fp-random.dtx
index 6dd9a63d70..458575e3dc 100644
--- a/macros/latex/contrib/l3kernel/l3fp-random.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-random.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-round.dtx b/macros/latex/contrib/l3kernel/l3fp-round.dtx
index 487f48fa7c..21892fcb94 100644
--- a/macros/latex/contrib/l3kernel/l3fp-round.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-round.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-traps.dtx b/macros/latex/contrib/l3kernel/l3fp-traps.dtx
index 8f7ef9afdc..8b748ed363 100644
--- a/macros/latex/contrib/l3kernel/l3fp-traps.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-traps.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
% \maketitle
%
% \begin{documentation}
diff --git a/macros/latex/contrib/l3kernel/l3fp-trig.dtx b/macros/latex/contrib/l3kernel/l3fp-trig.dtx
index c5c85d20a3..3fd98aeb8e 100644
--- a/macros/latex/contrib/l3kernel/l3fp-trig.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-trig.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp.dtx b/macros/latex/contrib/l3kernel/l3fp.dtx
index f1743be720..0f9a1c301a 100644
--- a/macros/latex/contrib/l3kernel/l3fp.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp.dtx
@@ -49,7 +49,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fparray.dtx b/macros/latex/contrib/l3kernel/l3fparray.dtx
index 1a2775935b..3dafd98881 100644
--- a/macros/latex/contrib/l3kernel/l3fparray.dtx
+++ b/macros/latex/contrib/l3kernel/l3fparray.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3int.dtx b/macros/latex/contrib/l3kernel/l3int.dtx
index ac08971cd0..e9e1503644 100644
--- a/macros/latex/contrib/l3kernel/l3int.dtx
+++ b/macros/latex/contrib/l3kernel/l3int.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3intarray.dtx b/macros/latex/contrib/l3kernel/l3intarray.dtx
index 208ec1cfe5..b80aee9039 100644
--- a/macros/latex/contrib/l3kernel/l3intarray.dtx
+++ b/macros/latex/contrib/l3kernel/l3intarray.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3kernel-functions.dtx b/macros/latex/contrib/l3kernel/l3kernel-functions.dtx
index 793ea28031..b28b06a307 100644
--- a/macros/latex/contrib/l3kernel/l3kernel-functions.dtx
+++ b/macros/latex/contrib/l3kernel/l3kernel-functions.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -101,6 +101,19 @@
% the \meta{follow-on}.
% \end{function}
%
+% \begin{function}{
+% \__kernel_dependency_version_check:Nn,
+% \__kernel_dependency_version_check:nn,
+% }
+% \begin{syntax}
+% \cs{__kernel_dependency_version_check:Nn} \Arg{\cs{date}} \Arg{file}
+% \cs{__kernel_dependency_version_check:nn} \Arg{date} \Arg{file}
+% \end{syntax}
+% Checks if the loaded version of the \pkg{expl3} kernel is at least \meta{date},
+% required by \meta{file}. If the kernel date is older than \meta{date}, the
+% loading of \meta{file} is aborted and an error is raised.
+% \end{function}
+%
% \begin{function}{\__kernel_deprecation_code:nn}
% \begin{syntax}
% \cs{__kernel_deprecation_code:nn} \Arg{error code} \Arg{working code}
@@ -125,6 +138,11 @@
% set by \cs{ExplSyntaxOn}/\cs{ExplSyntaxOff}.
% \end{variable}
%
+% \begin{variable}{\c__kernel_expl_date_tl}
+% A token list containing the release date of the \pkg{l3kernel} preloaded
+% in \LaTeXe{} used to check if dependencies match.
+% \end{variable}
+%
% \begin{function}{\__kernel_file_missing:n}
% \begin{syntax}
% \cs{__kernel_file_missing:n} \Arg{name}
diff --git a/macros/latex/contrib/l3kernel/l3keys.dtx b/macros/latex/contrib/l3kernel/l3keys.dtx
index 9c5216ceb6..fcbee8893d 100644
--- a/macros/latex/contrib/l3kernel/l3keys.dtx
+++ b/macros/latex/contrib/l3kernel/l3keys.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3legacy.dtx b/macros/latex/contrib/l3kernel/l3legacy.dtx
index 33d3749515..f3ca1a1af8 100644
--- a/macros/latex/contrib/l3kernel/l3legacy.dtx
+++ b/macros/latex/contrib/l3kernel/l3legacy.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3luatex.dtx b/macros/latex/contrib/l3kernel/l3luatex.dtx
index 01686ced0d..deb78363d0 100644
--- a/macros/latex/contrib/l3kernel/l3luatex.dtx
+++ b/macros/latex/contrib/l3kernel/l3luatex.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3msg.dtx b/macros/latex/contrib/l3kernel/l3msg.dtx
index f95f4ddabd..fa5c81c7da 100644
--- a/macros/latex/contrib/l3kernel/l3msg.dtx
+++ b/macros/latex/contrib/l3kernel/l3msg.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3names.dtx b/macros/latex/contrib/l3kernel/l3names.dtx
index d070bb2952..9b53598aca 100644
--- a/macros/latex/contrib/l3kernel/l3names.dtx
+++ b/macros/latex/contrib/l3kernel/l3names.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3news.pdf b/macros/latex/contrib/l3kernel/l3news.pdf
index f37b45a703..8603809e6e 100644
--- a/macros/latex/contrib/l3kernel/l3news.pdf
+++ b/macros/latex/contrib/l3kernel/l3news.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news01.pdf b/macros/latex/contrib/l3kernel/l3news01.pdf
index 03f8ad6669..4235ff9765 100644
--- a/macros/latex/contrib/l3kernel/l3news01.pdf
+++ b/macros/latex/contrib/l3kernel/l3news01.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news02.pdf b/macros/latex/contrib/l3kernel/l3news02.pdf
index 1495f21dcd..7967d775a9 100644
--- a/macros/latex/contrib/l3kernel/l3news02.pdf
+++ b/macros/latex/contrib/l3kernel/l3news02.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news03.pdf b/macros/latex/contrib/l3kernel/l3news03.pdf
index d18a6f04fb..7113bfe72b 100644
--- a/macros/latex/contrib/l3kernel/l3news03.pdf
+++ b/macros/latex/contrib/l3kernel/l3news03.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news04.pdf b/macros/latex/contrib/l3kernel/l3news04.pdf
index 717b0aa96b..c0cb2eb4e1 100644
--- a/macros/latex/contrib/l3kernel/l3news04.pdf
+++ b/macros/latex/contrib/l3kernel/l3news04.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news05.pdf b/macros/latex/contrib/l3kernel/l3news05.pdf
index fc12886e94..28b76bc9c7 100644
--- a/macros/latex/contrib/l3kernel/l3news05.pdf
+++ b/macros/latex/contrib/l3kernel/l3news05.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news06.pdf b/macros/latex/contrib/l3kernel/l3news06.pdf
index 858b05d977..add439aefc 100644
--- a/macros/latex/contrib/l3kernel/l3news06.pdf
+++ b/macros/latex/contrib/l3kernel/l3news06.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news07.pdf b/macros/latex/contrib/l3kernel/l3news07.pdf
index 58479d7dc1..a2f62f8b78 100644
--- a/macros/latex/contrib/l3kernel/l3news07.pdf
+++ b/macros/latex/contrib/l3kernel/l3news07.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news08.pdf b/macros/latex/contrib/l3kernel/l3news08.pdf
index 3d8c621445..fb2cd9e8c4 100644
--- a/macros/latex/contrib/l3kernel/l3news08.pdf
+++ b/macros/latex/contrib/l3kernel/l3news08.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news09.pdf b/macros/latex/contrib/l3kernel/l3news09.pdf
index 1ae9972b0e..16ffff9d6b 100644
--- a/macros/latex/contrib/l3kernel/l3news09.pdf
+++ b/macros/latex/contrib/l3kernel/l3news09.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news10.pdf b/macros/latex/contrib/l3kernel/l3news10.pdf
index 4b5e51d743..26b83ebaea 100644
--- a/macros/latex/contrib/l3kernel/l3news10.pdf
+++ b/macros/latex/contrib/l3kernel/l3news10.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news11.pdf b/macros/latex/contrib/l3kernel/l3news11.pdf
index 7170e1db61..dced90194c 100644
--- a/macros/latex/contrib/l3kernel/l3news11.pdf
+++ b/macros/latex/contrib/l3kernel/l3news11.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news12.pdf b/macros/latex/contrib/l3kernel/l3news12.pdf
index a1f3d50fef..616e208760 100644
--- a/macros/latex/contrib/l3kernel/l3news12.pdf
+++ b/macros/latex/contrib/l3kernel/l3news12.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3prefixes.pdf b/macros/latex/contrib/l3kernel/l3prefixes.pdf
index ed6fc27f00..9ad063187f 100644
--- a/macros/latex/contrib/l3kernel/l3prefixes.pdf
+++ b/macros/latex/contrib/l3kernel/l3prefixes.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3prg.dtx b/macros/latex/contrib/l3kernel/l3prg.dtx
index c993560bf7..2b65561400 100644
--- a/macros/latex/contrib/l3kernel/l3prg.dtx
+++ b/macros/latex/contrib/l3kernel/l3prg.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3prop.dtx b/macros/latex/contrib/l3kernel/l3prop.dtx
index d8923d2177..79f5eaa2dc 100644
--- a/macros/latex/contrib/l3kernel/l3prop.dtx
+++ b/macros/latex/contrib/l3kernel/l3prop.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3quark.dtx b/macros/latex/contrib/l3kernel/l3quark.dtx
index d0adf2a00c..b03af55b49 100644
--- a/macros/latex/contrib/l3kernel/l3quark.dtx
+++ b/macros/latex/contrib/l3kernel/l3quark.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3regex.dtx b/macros/latex/contrib/l3kernel/l3regex.dtx
index dcc408e48b..1987116693 100644
--- a/macros/latex/contrib/l3kernel/l3regex.dtx
+++ b/macros/latex/contrib/l3kernel/l3regex.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3seq.dtx b/macros/latex/contrib/l3kernel/l3seq.dtx
index b0a1638170..337fd89183 100644
--- a/macros/latex/contrib/l3kernel/l3seq.dtx
+++ b/macros/latex/contrib/l3kernel/l3seq.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3skip.dtx b/macros/latex/contrib/l3kernel/l3skip.dtx
index 9987d4f57c..7aad033c33 100644
--- a/macros/latex/contrib/l3kernel/l3skip.dtx
+++ b/macros/latex/contrib/l3kernel/l3skip.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3sort.dtx b/macros/latex/contrib/l3kernel/l3sort.dtx
index 808d6214d0..fdfe7dc3ad 100644
--- a/macros/latex/contrib/l3kernel/l3sort.dtx
+++ b/macros/latex/contrib/l3kernel/l3sort.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3str-convert.dtx b/macros/latex/contrib/l3kernel/l3str-convert.dtx
index 324066cd41..fed3e38c49 100644
--- a/macros/latex/contrib/l3kernel/l3str-convert.dtx
+++ b/macros/latex/contrib/l3kernel/l3str-convert.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -199,19 +199,6 @@
% basis with non-ASCII codepoints escaped using hashes.
% \end{function}
%
-% \section[Creating 8-bit mappings]{Creating $8$-bit mappings}
-%
-% \begin{function}{\str_declare_eight_bit_encoding:nnn}
-% \begin{syntax}
-% \cs{str_declare_eight_bit_encoding:nnn} \Arg{name} \Arg{mapping} \Arg{missing}
-% \end{syntax}
-% Declares the encoding \meta{name} to map bytes to Unicode
-% characters according to the \meta{mapping}, and map those bytes
-% which are not mentioned in the \meta{mapping} either to the
-% replacement character (if they appear in \meta{missing}), or to
-% themselves.
-% \end{function}
-%
% \section{Possibilities, and things to do}
%
% Encoding/escaping-related tasks.
@@ -261,16 +248,13 @@
% \subsubsection{Variables and constants}
%
% \begin{macro}{\@@_tmp:w}
-% \begin{variable}{\l_@@_internal_int}
% \begin{variable}{\l_@@_internal_tl}
% Internal scratch space for some functions.
% \begin{macrocode}
\cs_new_protected:Npn \@@_tmp:w { }
\tl_new:N \l_@@_internal_tl
-\int_new:N \l_@@_internal_int
% \end{macrocode}
% \end{variable}
-% \end{variable}
% \end{macro}
%
% \begin{variable}{\g_@@_result_tl}
@@ -1093,159 +1077,193 @@
%
% \subsubsection{8-bit encodings}
%
-% This section will be entirely rewritten: it is not yet clear in what
-% situations 8-bit encodings are used, hence I don't know what exactly
-% should be optimized. The current approach is reasonably efficient to
-% convert long strings, and it scales well when using many different
-% encodings. An approach based on csnames would have a smaller constant
-% load time for each individual conversion, but has a large hash table
-% cost. Using a range of \tn{count} registers works for decoding, but
-% not for encoding: one possibility there would be to use a binary tree
-% for the mapping of Unicode characters to bytes, stored as a box, one
-% per encoding.
-%
-% Since the section is going to be rewritten, documentation lacks.
-%
-% All the 8-bit encodings which \pkg{l3str} supports rely on the same
-% internal functions.
-%
-% \begin{macro}{\str_declare_eight_bit_encoding:nnn}
-% All the 8-bit encoding definition file start with
-% \cs{str_declare_eight_bit_encoding:nnn} \Arg{encoding name}
-% \Arg{mapping} \Arg{missing bytes}. The \meta{mapping} argument is a
-% token list of pairs \Arg{byte} \Arg{Unicode} expressed in uppercase
-% hexadecimal notation. The \meta{missing} argument is a token list
-% of \Arg{byte}. Every \meta{byte} which does not appear in the
-% \meta{mapping} nor the \meta{missing} lists maps to the same code
-% point in Unicode.
-% \begin{macrocode}
-\cs_new_protected:Npn \str_declare_eight_bit_encoding:nnn #1#2#3
+% It is not clear in what situations 8-bit encodings are used, hence it
+% is not clear what should be optimized. The current approach is
+% reasonably efficient to convert long strings, and it scales well when
+% using many different encodings.
+%
+% The data needed to support a given 8-bit encoding is stored in a file
+% that consists of a single function call
+% \begin{quote}\ttfamily
+% \cs{@@_declare_eight_bit_encoding:nnnn} \Arg{name} \Arg{modulo}
+% \Arg{mapping} \Arg{missing}
+% \end{quote}
+% This declares the encoding \meta{name} to map bytes to Unicode
+% characters according to the \meta{mapping}, and map those bytes which
+% are not mentioned in the \meta{mapping} either to the replacement
+% character (if they appear in \meta{missing}), or to themselves. The
+% \meta{mapping} argument is a token list of pairs \Arg{byte}
+% \Arg{Unicode} expressed in uppercase hexadecimal notation. The
+% \meta{missing} argument is a token list of \Arg{byte}. Every
+% \meta{byte} which does not appear in the \meta{mapping} nor the
+% \meta{missing} lists maps to itself in Unicode, so for instance the
+% \texttt{latin1} encoding has empty \meta{mapping} and \meta{missing}
+% lists. The \meta{modulo} is a (decimal) integer between $256$ and
+% $558$ inclusive, modulo which all Unicode code points supported by the
+% encodings must be different.
+%
+% We use two integer arrays per encoding. When decoding we only use the
+% \texttt{decode} integer array, with entry $n+1$ (offset needed because
+% integer array indices start at~$1$) equal to the Unicode code point
+% that corresponds to the $n$-th byte in the encoding under
+% consideration, or $-1$ if the given byte is invalid in this encoding.
+% When encoding we use both arrays: upon seeing a code point~$n$, we
+% look up the entry ($1$~plus) $n$ modulo some number $M$ in the
+% \texttt{encode} array, which tells us the byte that might encode the
+% given Unicode code point, then we check in the \texttt{decode} array
+% that indeed this byte encodes the Unicode code point we want. Here,
+% $M$ is an encoding-dependent integer between $256$ and $558$ (it turns
+% out), chosen so that among the Unicode code points that can be validly
+% represented in the given encoding, no pair of code points have the
+% same value modulo~$M$.
+%
+% \begin{macro}
+% {
+% \@@_declare_eight_bit_encoding:nnnn,
+% \@@_declare_eight_bit_aux:NNnnn,
+% \@@_declare_eight_bit_loop:Nnn,
+% \@@_declare_eight_bit_loop:Nn
+% }
+% Loop through both lists of bytes to fill in the \texttt{decode}
+% integer array, then fill the \texttt{encode} array accordingly.
+% For bytes that are invalid in the given encoding, store $-1$ in the
+% \texttt{decode} array.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_declare_eight_bit_encoding:nnnn #1
{
\tl_set:Nn \l_@@_internal_tl {#1}
\cs_new_protected:cpn { @@_convert_decode_#1: }
{ \@@_convert_decode_eight_bit:n {#1} }
\cs_new_protected:cpn { @@_convert_encode_#1: }
{ \@@_convert_encode_eight_bit:n {#1} }
- \tl_const:cn { c_@@_encoding_#1_tl } {#2}
- \tl_const:cn { c_@@_encoding_#1_missing_tl } {#3}
+ \exp_args:Ncc \@@_declare_eight_bit_aux:NNnnn
+ { g_@@_decode_#1_intarray } { g_@@_encode_#1_intarray }
+ }
+\cs_new_protected:Npn \@@_declare_eight_bit_aux:NNnnn #1#2#3#4#5
+ {
+ \intarray_new:Nn #1 { 256 }
+ \int_step_inline:nnn { 0 } { 255 }
+ { \intarray_gset:Nnn #1 { 1 + ##1 } {##1} }
+ \@@_declare_eight_bit_loop:Nnn #1
+ #4 { \s_@@_stop \prg_break: } { }
+ \prg_break_point:
+ \@@_declare_eight_bit_loop:Nn #1
+ #5 { \s_@@_stop \prg_break: }
+ \prg_break_point:
+ \intarray_new:Nn #2 {#3}
+ \int_step_inline:nnn { 0 } { 255 }
+ {
+ \int_compare:nNnF { \intarray_item:Nn #1 { 1 + ##1 } } = { -1 }
+ {
+ \intarray_gset:Nnn #2
+ {
+ 1 +
+ \int_mod:nn { \intarray_item:Nn #1 { 1 + ##1 } }
+ { \intarray_count:N #2 }
+ }
+ {##1}
+ }
+ }
+ }
+\cs_new_protected:Npn \@@_declare_eight_bit_loop:Nnn #1#2#3
+ {
+ \@@_use_none_delimit_by_s_stop:w #2 \s_@@_stop
+ \intarray_gset:Nnn #1 { 1 + "#2 } { "#3 }
+ \@@_declare_eight_bit_loop:Nnn #1
+ }
+\cs_new_protected:Npn \@@_declare_eight_bit_loop:Nn #1#2
+ {
+ \@@_use_none_delimit_by_s_stop:w #2 \s_@@_stop
+ \intarray_gset:Nnn #1 { 1 + "#2 } { -1 }
+ \@@_declare_eight_bit_loop:Nn #1
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_convert_decode_eight_bit:n}
-% \begin{macro}{\@@_decode_eight_bit_load:nn}
-% \begin{macro}{\@@_decode_eight_bit_load_missing:n}
-% \begin{macro}[EXP]{\@@_decode_eight_bit_char:N}
-%^^A todo: document
+% \begin{macro}[rEXP]{\@@_decode_eight_bit_aux:n, \@@_decode_eight_bit_aux:Nn}
+% The map from bytes to Unicode code points is in the \texttt{decode}
+% array corresponding to the given encoding. Define \cs{@@_tmp:w} and
+% pass it successively all bytes in the string. It produces an
+% internal representation with suitable \cs{s_@@} inserted, and the
+% corresponding code point is obtained by looking it up in the integer
+% array. If the entry is $-1$ then issue a replacement character and
+% raise the flag indicating that there was an error.
% \begin{macrocode}
\cs_new_protected:Npn \@@_convert_decode_eight_bit:n #1
{
- \group_begin:
- \int_zero:N \l_@@_internal_int
- \exp_last_unbraced:Nx \@@_decode_eight_bit_load:nn
- { \tl_use:c { c_@@_encoding_#1_tl } }
- { \s_@@_stop \prg_break: } { }
- \prg_break_point:
- \exp_last_unbraced:Nx \@@_decode_eight_bit_load_missing:n
- { \tl_use:c { c_@@_encoding_#1_missing_tl } }
- { \s_@@_stop \prg_break: }
- \prg_break_point:
- \flag_clear:n { str_error }
- \@@_convert_gmap:N \@@_decode_eight_bit_char:N
- \@@_if_flag_error:nnx { str_error } { decode-8-bit } {#1}
- \group_end:
- }
-\cs_new_protected:Npn \@@_decode_eight_bit_load:nn #1#2
- {
- \@@_use_none_delimit_by_s_stop:w #1 \s_@@_stop
- \tex_dimen:D "#1 = \l_@@_internal_int sp \scan_stop:
- \tex_skip:D \l_@@_internal_int = "#1 sp \scan_stop:
- \tex_toks:D \l_@@_internal_int \exp_after:wN { \int_value:w "#2 }
- \int_incr:N \l_@@_internal_int
- \@@_decode_eight_bit_load:nn
+ \cs_set:Npx \@@_tmp:w
+ {
+ \exp_not:N \@@_decode_eight_bit_aux:Nn
+ \exp_not:c { g_@@_decode_#1_intarray }
+ }
+ \flag_clear:n { str_error }
+ \@@_convert_gmap:N \@@_tmp:w
+ \@@_if_flag_error:nnx { str_error } { decode-8-bit } {#1}
}
-\cs_new_protected:Npn \@@_decode_eight_bit_load_missing:n #1
+\cs_new:Npn \@@_decode_eight_bit_aux:Nn #1#2
{
- \@@_use_none_delimit_by_s_stop:w #1 \s_@@_stop
- \tex_dimen:D "#1 = \l_@@_internal_int sp \scan_stop:
- \tex_skip:D \l_@@_internal_int = "#1 sp \scan_stop:
- \tex_toks:D \l_@@_internal_int \exp_after:wN
- { \int_use:N \c_@@_replacement_char_int }
- \int_incr:N \l_@@_internal_int
- \@@_decode_eight_bit_load_missing:n
+ #2 \s_@@
+ \exp_args:Nf \@@_decode_eight_bit_aux:n
+ { \intarray_item:Nn #1 { 1 + `#2 } }
+ \s_@@
}
-\cs_new:Npn \@@_decode_eight_bit_char:N #1
+\cs_new:Npn \@@_decode_eight_bit_aux:n #1
{
- #1 \s_@@
- \if_int_compare:w \tex_dimen:D `#1 < \l_@@_internal_int
- \if_int_compare:w \tex_skip:D \tex_dimen:D `#1 = `#1 \exp_stop_f:
- \tex_the:D \tex_toks:D \tex_dimen:D
- \fi:
+ \if_int_compare:w #1 < \c_zero_int
+ \flag_raise:n { str_error }
+ \int_value:w \c_@@_replacement_char_int
+ \else:
+ #1
\fi:
- \int_value:w `#1 \s_@@
}
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
-% \end{macro}
%
% \begin{macro}{\@@_convert_encode_eight_bit:n}
-% \begin{macro}{\@@_encode_eight_bit_load:nn}
-% \begin{macro}[rEXP]{\@@_encode_eight_bit_char:n}
-% \begin{macro}[rEXP]{\@@_encode_eight_bit_char_aux:n}
-%^^A todo: document
-% \begin{macrocode}
+% \begin{macro}[rEXP]{\@@_encode_eight_bit_aux:nnN, \@@_encode_eight_bit_aux:NNn}
+% It is not practical to make an integer array with indices in the
+% full Unicode range, so we work modulo some number, which is simply
+% the size of the \texttt{encode} integer array for the given
+% encoding. This gives us a candidate byte for representing a given
+% Unicode code point. Of course taking the modulo leads to collisions
+% so we check in the \texttt{decode} array that the byte we got is
+% indeed correct. Otherwise the Unicode code point we started from is
+% simply not representable in the given encoding.
+% \begin{macrocode}
+\int_new:N \l_@@_modulo_int
\cs_new_protected:Npn \@@_convert_encode_eight_bit:n #1
{
- \group_begin:
- \int_zero:N \l_@@_internal_int
- \exp_last_unbraced:Nx \@@_encode_eight_bit_load:nn
- { \tl_use:c { c_@@_encoding_#1_tl } }
- { \s_@@_stop \prg_break: } { }
- \prg_break_point:
- \flag_clear:n { str_error }
- \@@_convert_gmap_internal:N \@@_encode_eight_bit_char:n
- \@@_if_flag_error:nnx { str_error } { encode-8-bit } {#1}
- \group_end:
- }
-\cs_new_protected:Npn \@@_encode_eight_bit_load:nn #1#2
- {
- \@@_use_none_delimit_by_s_stop:w #1 \s_@@_stop
- \tex_dimen:D "#2 = \l_@@_internal_int sp \scan_stop:
- \tex_skip:D \l_@@_internal_int = "#2 sp \scan_stop:
- \exp_args:NNf \tex_toks:D \l_@@_internal_int
- { \@@_output_byte:n { "#1 } }
- \int_incr:N \l_@@_internal_int
- \@@_encode_eight_bit_load:nn
+ \cs_set:Npx \@@_tmp:w
+ {
+ \exp_not:N \@@_encode_eight_bit_aux:NNn
+ \exp_not:c { g_@@_encode_#1_intarray }
+ \exp_not:c { g_@@_decode_#1_intarray }
+ }
+ \flag_clear:n { str_error }
+ \@@_convert_gmap_internal:N \@@_tmp:w
+ \@@_if_flag_error:nnx { str_error } { encode-8-bit } {#1}
}
-\cs_new:Npn \@@_encode_eight_bit_char:n #1
+\cs_new:Npn \@@_encode_eight_bit_aux:NNn #1#2#3
{
- \if_int_compare:w #1 > \c_max_register_int
- \flag_raise:n { str_error }
- \else:
- \if_int_compare:w \tex_dimen:D #1 < \l_@@_internal_int
- \if_int_compare:w \tex_skip:D \tex_dimen:D #1 = #1 \exp_stop_f:
- \tex_the:D \tex_toks:D \tex_dimen:D #1 \exp_stop_f:
- \exp_after:wN \exp_after:wN \exp_after:wN \use_none:nn
- \fi:
- \fi:
- \@@_encode_eight_bit_char_aux:n {#1}
- \fi:
+ \exp_args:Nf \@@_encode_eight_bit_aux:nnN
+ {
+ \intarray_item:Nn #1
+ { 1 + \int_mod:nn {#3} { \intarray_count:N #1 } }
+ }
+ {#3}
+ #2
}
-\cs_new:Npn \@@_encode_eight_bit_char_aux:n #1
+\cs_new:Npn \@@_encode_eight_bit_aux:nnN #1#2#3
{
- \if_int_compare:w #1 > \c_@@_max_byte_int
- \flag_raise:n { str_error }
- \else:
- \@@_output_byte:n {#1}
- \fi:
+ \int_compare:nNnTF { \intarray_item:Nn #3 { 1 + #1 } } = {#2}
+ { \@@_output_byte:n {#1} }
+ { \flag_raise:n { str_error } }
}
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
-% \end{macro}
%
% \subsection{Messages}
%
@@ -2664,7 +2682,7 @@
% family, we keep track only of differences, and of unassigned bytes.
% \begin{macrocode}
%<*iso88591>
-\str_declare_eight_bit_encoding:nnn { iso88591 }
+\@@_declare_eight_bit_encoding:nnnn { iso88591 } { 256 }
{
}
{
@@ -2674,7 +2692,7 @@
%
% \begin{macrocode}
%<*iso88592>
-\str_declare_eight_bit_encoding:nnn { iso88592 }
+\@@_declare_eight_bit_encoding:nnnn { iso88592 } { 399 }
{
{ A1 } { 0104 }
{ A2 } { 02D8 }
@@ -2741,7 +2759,7 @@
%
% \begin{macrocode}
%<*iso88593>
-\str_declare_eight_bit_encoding:nnn { iso88593 }
+\@@_declare_eight_bit_encoding:nnnn { iso88593 } { 384 }
{
{ A1 } { 0126 }
{ A2 } { 02D8 }
@@ -2786,7 +2804,7 @@
%
% \begin{macrocode}
%<*iso88594>
-\str_declare_eight_bit_encoding:nnn { iso88594 }
+\@@_declare_eight_bit_encoding:nnnn { iso88594 } { 383 }
{
{ A1 } { 0104 }
{ A2 } { 0138 }
@@ -2846,7 +2864,7 @@
%
% \begin{macrocode}
%<*iso88595>
-\str_declare_eight_bit_encoding:nnn { iso88595 }
+\@@_declare_eight_bit_encoding:nnnn { iso88595 } { 374 }
{
{ A1 } { 0401 }
{ A2 } { 0402 }
@@ -2950,7 +2968,7 @@
%
% \begin{macrocode}
%<*iso88596>
-\str_declare_eight_bit_encoding:nnn { iso88596 }
+\@@_declare_eight_bit_encoding:nnnn { iso88596 } { 344 }
{
{ AC } { 060C }
{ BB } { 061B }
@@ -3040,7 +3058,7 @@
%
% \begin{macrocode}
%<*iso88597>
-\str_declare_eight_bit_encoding:nnn { iso88597 }
+\@@_declare_eight_bit_encoding:nnnn { iso88597 } { 498 }
{
{ A1 } { 2018 }
{ A2 } { 2019 }
@@ -3129,7 +3147,7 @@
%
% \begin{macrocode}
%<*iso88598>
-\str_declare_eight_bit_encoding:nnn { iso88598 }
+\@@_declare_eight_bit_encoding:nnnn { iso88598 } { 308 }
{
{ AA } { 00D7 }
{ BA } { 00F7 }
@@ -3206,7 +3224,7 @@
%
% \begin{macrocode}
%<*iso88599>
-\str_declare_eight_bit_encoding:nnn { iso88599 }
+\@@_declare_eight_bit_encoding:nnnn { iso88599 } { 352 }
{
{ D0 } { 011E }
{ DD } { 0130 }
@@ -3222,7 +3240,7 @@
%
% \begin{macrocode}
%<*iso885910>
-\str_declare_eight_bit_encoding:nnn { iso885910 }
+\@@_declare_eight_bit_encoding:nnnn { iso885910 } { 383 }
{
{ A1 } { 0104 }
{ A2 } { 0112 }
@@ -3278,7 +3296,7 @@
%
% \begin{macrocode}
%<*iso885911>
-\str_declare_eight_bit_encoding:nnn { iso885911 }
+\@@_declare_eight_bit_encoding:nnnn { iso885911 } { 369 }
{
{ A1 } { 0E01 }
{ A2 } { 0E02 }
@@ -3379,7 +3397,7 @@
%
% \begin{macrocode}
%<*iso885913>
-\str_declare_eight_bit_encoding:nnn { iso885913 }
+\@@_declare_eight_bit_encoding:nnnn { iso885913 } { 399 }
{
{ A1 } { 201D }
{ A5 } { 201E }
@@ -3445,7 +3463,7 @@
%
% \begin{macrocode}
%<*iso885914>
-\str_declare_eight_bit_encoding:nnn { iso885914 }
+\@@_declare_eight_bit_encoding:nnnn { iso885914 } { 529 }
{
{ A1 } { 1E02 }
{ A2 } { 1E03 }
@@ -3486,7 +3504,7 @@
%
% \begin{macrocode}
%<*iso885915>
-\str_declare_eight_bit_encoding:nnn { iso885915 }
+\@@_declare_eight_bit_encoding:nnnn { iso885915 } { 383 }
{
{ A4 } { 20AC }
{ A6 } { 0160 }
@@ -3504,7 +3522,7 @@
%
% \begin{macrocode}
%<*iso885916>
-\str_declare_eight_bit_encoding:nnn { iso885916 }
+\@@_declare_eight_bit_encoding:nnnn { iso885916 } { 558 }
{
{ A1 } { 0104 }
{ A2 } { 0105 }
diff --git a/macros/latex/contrib/l3kernel/l3str.dtx b/macros/latex/contrib/l3kernel/l3str.dtx
index 466519ac8c..9685c6d40f 100644
--- a/macros/latex/contrib/l3kernel/l3str.dtx
+++ b/macros/latex/contrib/l3kernel/l3str.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3styleguide.pdf b/macros/latex/contrib/l3kernel/l3styleguide.pdf
index 271e8e5916..b05698dd65 100644
--- a/macros/latex/contrib/l3kernel/l3styleguide.pdf
+++ b/macros/latex/contrib/l3kernel/l3styleguide.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3styleguide.tex b/macros/latex/contrib/l3kernel/l3styleguide.tex
index 9124a30577..8bed24ebce 100644
--- a/macros/latex/contrib/l3kernel/l3styleguide.tex
+++ b/macros/latex/contrib/l3kernel/l3styleguide.tex
@@ -32,7 +32,7 @@ The released version of this bundle is available from CTAN.
{latex-team@latex-project.org}%
}%
}
-\date{Released 2020-08-07}
+\date{Released 2020-09-01}
\begin{document}
diff --git a/macros/latex/contrib/l3kernel/l3syntax-changes.pdf b/macros/latex/contrib/l3kernel/l3syntax-changes.pdf
index 1c33b67b33..f4d44d9738 100644
--- a/macros/latex/contrib/l3kernel/l3syntax-changes.pdf
+++ b/macros/latex/contrib/l3kernel/l3syntax-changes.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3syntax-changes.tex b/macros/latex/contrib/l3kernel/l3syntax-changes.tex
index 4c8fe53915..c5bacf26a2 100644
--- a/macros/latex/contrib/l3kernel/l3syntax-changes.tex
+++ b/macros/latex/contrib/l3kernel/l3syntax-changes.tex
@@ -32,7 +32,7 @@ The released version of this bundle is available from CTAN.
{latex-team@latex-project.org}%
}%
}
-\date{Released 2020-08-07}
+\date{Released 2020-09-01}
\newcommand{\TF}{\textit{(TF)}}
diff --git a/macros/latex/contrib/l3kernel/l3sys.dtx b/macros/latex/contrib/l3kernel/l3sys.dtx
index 16cdfe6f3d..b7dd54d2e8 100644
--- a/macros/latex/contrib/l3kernel/l3sys.dtx
+++ b/macros/latex/contrib/l3kernel/l3sys.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -105,6 +105,22 @@
% |luatex|, |pdftex|, |ptex|, |uptex| or |xetex|.
% \end{variable}
%
+% \begin{variable}[added = 2020-08-20]{\c_sys_engine_exec_str}
+% The name of the standard executable for the current \TeX{} engine given
+% as a lower case string: one of |luatex|,
+% |luahbtex|, |pdftex|, |eptex|, |euptex| or |xetex|.
+% \end{variable}
+%
+% \begin{variable}[added = 2020-08-20]{\c_sys_engine_format_str}
+% The name of the preloaded format for the current \TeX{} run given
+% as a lower case string: one of
+% |lualatex| (or |dvilualatex|),
+% |pdflatex| (or |latex|), |platex|, |uplatex| or |xelatex| for \LaTeX{},
+% similar names for plain \TeX{} (except \pdfTeX{} in DVI mode yields
+% |etex|), and |cont-en| for Con\TeX{}t (i.e.~the
+% \tn{fmtname}).
+% \end{variable}
+%
% \section{Output format}
%
% \begin{function}[added = 2015-09-19, EXP, pTF]
@@ -252,7 +268,7 @@
% Execute \meta{tokens} through shell escape at shipout.
% \end{function}
%
-% \subsection{Loading configuration data}
+% \section{Loading configuration data}
%
% \begin{function}[added = 2019-09-12]{\sys_load_backend:n}
% \begin{syntax}
@@ -277,7 +293,7 @@
% back deprecations, respectively.
% \end{function}
%
-% \subsection{Final settins}
+% \subsection{Final settings}
%
% \begin{function}[added = 2019-10-06]{\sys_finalise:}
% \begin{syntax}
@@ -361,6 +377,72 @@
% \end{variable}
% \end{macro}
%
+% \begin{variable}{\c_sys_engine_exec_str,\c_sys_engine_format_str}
+% Take the functions defined above, and set up the engine and format
+% names. \cs{c_sys_engine_exec_str} differs from \cs{c_sys_engine_str}
+% as it is the \emph{actual} engine name, not a \enquote{filtered}
+% version. It differs for |ptex| and |uptex|, which have a leading
+% |e|, and for |luatex|, because \LaTeX{} uses the \Lua HB\TeX{}
+% engine.
+%
+% \cs{c_sys_engine_format_str} is quite similar to
+% \cs{c_sys_engine_str}, except that it differentiates |pdflatex| from
+% |latex| (which is \pdfTeX{} in DVI mode). This differentiation,
+% however, is reliable only if the user doesn't change
+% \cs{tex_pdfoutput:D} before loading this code.
+% \begin{macrocode}
+\str_const:Nx \c_sys_engine_exec_str
+ {
+ \sys_if_engine_pdftex:T { pdf }
+ \sys_if_engine_xetex:T { xe }
+ \sys_if_engine_ptex:T { ep }
+ \sys_if_engine_uptex:T { eup }
+ \sys_if_engine_luatex:T
+ {
+ lua \lua_now:e
+ {
+ if (pcall(require, 'luaharfbuzz')) then ~
+ tex.print("hb") ~
+ end
+ }
+ }
+ tex
+ }
+\str_const:Nx \c_sys_engine_format_str
+ {
+ \cs_if_exist:NTF \fmtname
+ {
+ \bool_lazy_or:nnTF
+ { \str_if_eq_p:Vn \fmtname { plain } }
+ { \str_if_eq_p:Vn \fmtname { LaTeX2e } }
+ {
+ \sys_if_engine_pdftex:T
+ { \int_compare:nNnT { \tex_pdfoutput:D } = { 1 } { pdf } }
+ \sys_if_engine_xetex:T { xe }
+ \sys_if_engine_ptex:T { p }
+ \sys_if_engine_uptex:T { up }
+ \sys_if_engine_luatex:T
+ {
+ \int_compare:nNnT { \tex_pdfoutput:D } = { 0 } { dvi }
+ lua
+ }
+ \str_if_eq:VnTF \fmtname { LaTeX2e }
+ { latex }
+ {
+ \bool_lazy_and:nnT
+ { \sys_if_engine_pdftex_p: }
+ { \int_compare_p:nNn { \tex_pdfoutput:D } = { 0 } }
+ { e }
+ tex
+ }
+ }
+ { \fmtname }
+ }
+ { unknown }
+ }
+% \end{macrocode}
+% \end{variable}
+%
% \subsubsection{Randomness}
%
% This candidate function is placed there because
@@ -415,22 +497,35 @@
\str_case:VnF #1
{
{ dvisvgm } { }
- { xdvipdfmx } { }
+ { xdvipdfmx } { \tl_gset:Nn #1 { xetex } }
+ { xetex } { }
}
{
\__kernel_msg_error:nnxx { sys } { wrong-backend }
- #1 { xdvipdfmx }
- \tl_gset:Nn #1 { xdvipdfmx }
+ #1 { xetex }
+ \tl_gset:Nn #1 { xetex }
}
}
{
\sys_if_output_pdf:TF
{
- \str_if_eq:VnF #1 { pdfmode }
+ \str_if_eq:VnTF #1 { pdfmode }
{
- \__kernel_msg_error:nnxx { sys } { wrong-backend }
- #1 { pdfmode }
- \tl_gset:Nn #1 { pdfmode }
+ \sys_if_engine_luatex:TF
+ { \tl_gset:Nn #1 { luatex } }
+ { \tl_gset:Nn #1 { pdftex } }
+ }
+ {
+ \bool_lazy_or:nnF
+ { \str_if_eq_p:Vn #1 { luatex } }
+ { \str_if_eq_p:Vn #1 { pdftex } }
+ {
+ \__kernel_msg_error:nnxx { sys } { wrong-backend }
+ #1 { \sys_if_engine_luatex:TF { luatex } { pdftex } }
+ \sys_if_engine_luatex:TF
+ { \tl_gset:Nn #1 { luatex } }
+ { \tl_gset:Nn #1 { pdftex } }
+ }
}
}
{
diff --git a/macros/latex/contrib/l3kernel/l3term-glossary.pdf b/macros/latex/contrib/l3kernel/l3term-glossary.pdf
index 3b214dcca7..0d5e144605 100644
--- a/macros/latex/contrib/l3kernel/l3term-glossary.pdf
+++ b/macros/latex/contrib/l3kernel/l3term-glossary.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3term-glossary.tex b/macros/latex/contrib/l3kernel/l3term-glossary.tex
index 3ac84ac64e..6bbadb3300 100644
--- a/macros/latex/contrib/l3kernel/l3term-glossary.tex
+++ b/macros/latex/contrib/l3kernel/l3term-glossary.tex
@@ -32,7 +32,7 @@ The released version of this bundle is available from CTAN.
{latex-team@latex-project.org}%
}%
}
-\date{Released 2020-08-07}
+\date{Released 2020-09-01}
\newcommand{\TF}{\textit{(TF)}}
diff --git a/macros/latex/contrib/l3kernel/l3text-case.dtx b/macros/latex/contrib/l3kernel/l3text-case.dtx
index 0f56576b23..23d0b331f0 100644
--- a/macros/latex/contrib/l3kernel/l3text-case.dtx
+++ b/macros/latex/contrib/l3kernel/l3text-case.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -408,7 +408,7 @@
{
\@@_if_recursion_tail_stop_do:Nn #4
{ \use:c { @@_change_case_letterlike_ #1 :nnN } {#1} {#2} #3 }
- \cs_if_eq:NNTF #3 #4
+ \str_if_eq:nnTF {#3} {#4}
{
\@@_use_i_delimit_by_q_recursion_stop:nw
{ \@@_change_case_exclude:nnNn {#1} {#2} #3 }
diff --git a/macros/latex/contrib/l3kernel/l3text-purify.dtx b/macros/latex/contrib/l3kernel/l3text-purify.dtx
index 9978eb3cc0..3dfb06a8a3 100644
--- a/macros/latex/contrib/l3kernel/l3text-purify.dtx
+++ b/macros/latex/contrib/l3kernel/l3text-purify.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3text.dtx b/macros/latex/contrib/l3kernel/l3text.dtx
index b1246336da..a8774c069b 100644
--- a/macros/latex/contrib/l3kernel/l3text.dtx
+++ b/macros/latex/contrib/l3kernel/l3text.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
@@ -875,7 +875,7 @@
{
\@@_if_recursion_tail_stop_do:Nn #2
{ \@@_expand_letterlike:N #1 }
- \cs_if_eq:NNTF #2 #1
+ \str_if_eq:nnTF {#1} {#2}
{
\@@_use_i_delimit_by_q_recursion_stop:nw
{ \@@_expand_exclude:Nn #1 }
diff --git a/macros/latex/contrib/l3kernel/l3tl-analysis.dtx b/macros/latex/contrib/l3kernel/l3tl-analysis.dtx
index 14af0c466e..5636086567 100644
--- a/macros/latex/contrib/l3kernel/l3tl-analysis.dtx
+++ b/macros/latex/contrib/l3kernel/l3tl-analysis.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3tl.dtx b/macros/latex/contrib/l3kernel/l3tl.dtx
index 5e088e4558..315db1ace0 100644
--- a/macros/latex/contrib/l3kernel/l3tl.dtx
+++ b/macros/latex/contrib/l3kernel/l3tl.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3token.dtx b/macros/latex/contrib/l3kernel/l3token.dtx
index 11f4fc4bcd..544a721886 100644
--- a/macros/latex/contrib/l3kernel/l3token.dtx
+++ b/macros/latex/contrib/l3kernel/l3token.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3unicode.dtx b/macros/latex/contrib/l3kernel/l3unicode.dtx
index 3c55fdfc85..35f71b70ca 100644
--- a/macros/latex/contrib/l3kernel/l3unicode.dtx
+++ b/macros/latex/contrib/l3kernel/l3unicode.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-08-07}
+% \date{Released 2020-09-01}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/source3.pdf b/macros/latex/contrib/l3kernel/source3.pdf
index 18b0ab1e9b..9e4fc4fc28 100644
--- a/macros/latex/contrib/l3kernel/source3.pdf
+++ b/macros/latex/contrib/l3kernel/source3.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/source3.tex b/macros/latex/contrib/l3kernel/source3.tex
index 4bc27dfc38..6c19a94176 100644
--- a/macros/latex/contrib/l3kernel/source3.tex
+++ b/macros/latex/contrib/l3kernel/source3.tex
@@ -53,7 +53,7 @@ for those people who are interested.
{latex-team@latex-project.org}%
}%
}
-\date{Released 2020-08-07}
+\date{Released 2020-09-01}
\pagenumbering{roman}
\maketitle
diff --git a/macros/latex/contrib/metastr/README.txt b/macros/latex/contrib/metastr/README.txt
index f91ab5a62d..fcdaecdd3e 100644
--- a/macros/latex/contrib/metastr/README.txt
+++ b/macros/latex/contrib/metastr/README.txt
@@ -1,4 +1,4 @@
-metastr v1.1.1
+metastr v1.1.2
Copyright 2020 Niklas Beisert
metastr is a LaTeX2e package
diff --git a/macros/latex/contrib/metastr/metastr.dtx b/macros/latex/contrib/metastr/metastr.dtx
index 6f70de93a5..4a68d29a96 100644
--- a/macros/latex/contrib/metastr/metastr.dtx
+++ b/macros/latex/contrib/metastr/metastr.dtx
@@ -18,10 +18,10 @@
% and the derived files metastr.sty and metasamp.tex.
%
%<package|sample>\NeedsTeXFormat{LaTeX2e}[1996/12/01]
-%<package>\ProvidesPackage{metastr}[2020/08/27 v1.1.1 Metadata Strings Storage]
-%<sample>\ProvidesFile{metasamp.tex}[2020/08/27 v1.1.1 sample for metastr]
+%<package>\ProvidesPackage{metastr}[2020/09/02 v1.1.2 Metadata Strings Storage]
+%<sample>\ProvidesFile{metasamp.tex}[2020/09/02 v1.1.2 sample for metastr]
%<*driver>
-\def\thedate#1{2020/08/27}\def\theversion#1{v1.1.1}
+\def\thedate#1{2020/09/02}\def\theversion#1{v1.1.2}
\ProvidesFile{metastr.dtx}[\thedate{} \theversion{} metastr reference manual file]
\PassOptionsToClass{10pt,a4paper}{article}
\documentclass{ltxdoc}
@@ -1398,6 +1398,26 @@ Make use of the \textsf{babel} package for translations of basic terms.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Revision History}
+\iffalse
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\paragraph{vXXX+:} YYYY/MM/DD+
+
+\begin{itemize}
+\item
+\ldots
+\end{itemize}
+
+\fi
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\paragraph{v1.1.2:} 2020/09/02
+
+\begin{itemize}
+\item
+improve hook processing to set |pdflang| at the right moment
+\end{itemize}
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph{v1.1.1:} 2020/08/27
@@ -2099,27 +2119,38 @@ some representations of the selected license:
% \end{macrocode}
% \macro{\mstr@begindoc}
+% \macro{\mstr@begindocpreamble}
% Hook for writing data to PDF file;
-% this is the last chance to write the preamble set of data to the PDF:
+% this is the last chance to write the preamble set of data to the PDF
+% (|pdflang| must be declared before \textsf{hyperxmp}
+% detects languages at the end of the preamble
+% and before \textsf{hyperref} sets it at the beginning of the document):
% \begin{macrocode}
\newcommand{\mstr@begindoc}{%
- \mstr@ifwritepdf[preamble]{\metawritepdfpreamble}%
- \mstr@ifwritepdf[auto]{\metawritepdf}%
-}
+ \mstr@ifwritepdf[auto]{\metawritepdf}}
+\newcommand{\mstr@begindocpreamble}{%
+ \mstr@ifwritepdf[preamble]{\metawritepdfpreamble}}
% \end{macrocode}
% Hook |\mstr@begindoc| to begining of |document| block
-% before hooks by \textsf{hyperref} are called;
+% (before hooks by \textsf{hyperref} and \textsf{hyperxmp} are called,
+% just in case);
+% hook |\mstr@begindocpreamble| to begining of |document| block
+% before hooks by \textsf{hyperxmp} are called;
% legacy code for latex releases earlier than 2020-10
% to add hook before all other hooks are called:
% \begin{macrocode}
\ifdefined\AddToHook
\DeclareHookRule{begindocument}{metastr}{before}{hyperref}
+\DeclareHookRule{begindocument}{metastr}{before}{hyperxmp}
\AddToHook{begindocument}{\mstr@begindoc}
+\DeclareHookRule{begindocument/before}{metastr}{before}{hyperxmp}
+\AddToHook{begindocument/before}{\mstr@begindocpreamble}
\else
+\AtBeginDocument{\mstr@begindoc}
\begingroup
-\toks@\expandafter{\expandafter\mstr@begindoc\@begindocumenthook}%
-\xdef\@begindocumenthook{\the\toks@}%
+\toks@\expandafter{\expandafter\mstr@begindocpreamble\@begindocumenthook}
+\xdef\@begindocumenthook{\the\toks@}
\endgroup
\fi
% \end{macrocode}
diff --git a/macros/latex/contrib/metastr/metastr.pdf b/macros/latex/contrib/metastr/metastr.pdf
index fa578dc143..5301e90930 100644
--- a/macros/latex/contrib/metastr/metastr.pdf
+++ b/macros/latex/contrib/metastr/metastr.pdf
Binary files differ
diff --git a/macros/latex/contrib/newverbs/README b/macros/latex/contrib/newverbs/README
index 3012c3c67d..09968f8584 100644
--- a/macros/latex/contrib/newverbs/README
+++ b/macros/latex/contrib/newverbs/README
@@ -1,7 +1,7 @@
The 'newverbs' LaTeX package
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Copyright (c) 2010-2019 by Martin Scharrer <martin@scharrer-online.de>
-Code repository: https://bitbucket.org/martin_scharrer/newverbs
+Copyright (c) 2010-2020 by Martin Scharrer <martin@scharrer-online.de>
+Code repository: https://sourceforge.net/projects/newfloat/
This package allows the definition of \verb variants which add TeX code before
and after the verbatim text (e.g. quotes or \fbox{}). When used together with
diff --git a/macros/latex/contrib/newverbs/newverbs.dtx b/macros/latex/contrib/newverbs/newverbs.dtx
index f2a79d35fd..efc74a3981 100644
--- a/macros/latex/contrib/newverbs/newverbs.dtx
+++ b/macros/latex/contrib/newverbs/newverbs.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%<=*COPYRIGHT>
-%% Copyright (C) 2012-2019 by Martin Scharrer <martin@scharrer-online.de>
+%% Copyright (C) 2012-2020 by Martin Scharrer <martin@scharrer-online.de>
%% --------------------------------------------------------------------
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public License, either version 1.3
@@ -23,10 +23,10 @@
%<*driver>
\ProvidesFile{newverbs.dtx}[%
%<=*DATE>
- 2019/09/09
+ 2010/09/02
%<=/DATE>
%<=*VERSION>
- v1.4
+ v1.5
%<=/VERSION>
newverbs DTX file]
\documentclass{ydoc}
@@ -44,7 +44,7 @@
%</driver>
% \fi
%
-% \CheckSum{458}
+% \CheckSum{465}
%
% \CharacterTable
% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
@@ -69,6 +69,7 @@
% \changes{v1.2a}{2011/03/19}{Removed spurious spaces.}
% \changes{v1.3}{2011/07/24}{Added macros to collect verbatim arguments.}
% \changes{v1.4}{2019/09/09}{Added several suggested changes.}
+% \changes{v1.5}{2020/09/02}{Added support for mathmode.}
%
% \DoNotIndex{\newcommand,\newenvironment,\providecommand}
%
@@ -294,6 +295,7 @@
\let\newverbs@end\@empty
\def\new@@verbcommand#1#2[#3]#4#5{%
#1*#2{%
+ \relax\ifmmode\hbox\else\leavevmode\null\fi
\bgroup
\newverbcommand@settings
\ifx\newverbs@end\@empty
diff --git a/macros/latex/contrib/newverbs/newverbs.pdf b/macros/latex/contrib/newverbs/newverbs.pdf
index 017a5c7ef6..6d914fab80 100644
--- a/macros/latex/contrib/newverbs/newverbs.pdf
+++ b/macros/latex/contrib/newverbs/newverbs.pdf
Binary files differ
diff --git a/macros/luatex/generic/lualibs/NEWS b/macros/luatex/generic/lualibs/NEWS
index 486b82bf79..af54318e6e 100644
--- a/macros/luatex/generic/lualibs/NEWS
+++ b/macros/luatex/generic/lualibs/NEWS
@@ -1,4 +1,7 @@
History of the lualibs package
+2020/08/31 v2.72/
+ * sync with Context current as of 2020/08/31.
+
2020/05/01 v2.71/
* sync with Context current as of 2020/04/30.
diff --git a/macros/luatex/generic/lualibs/README.md b/macros/luatex/generic/lualibs/README.md
index bbbf6993fa..351930040c 100644
--- a/macros/luatex/generic/lualibs/README.md
+++ b/macros/luatex/generic/lualibs/README.md
@@ -1,10 +1,10 @@
# The Lualibs Package
-VERSION: 2.71
+VERSION: 2.72
-DATE: 2020-05-01
+DATE: 2020-08-31
-FONTLOADERDATE: 2020-04-30
+FONTLOADERDATE: 2020-08-31
Lualibs is a collection of Lua modules useful for general programming.
diff --git a/macros/luatex/generic/lualibs/lualibs-basic-merged.lua b/macros/luatex/generic/lualibs/lualibs-basic-merged.lua
index 24a62e3d17..147cc33fa9 100644
--- a/macros/luatex/generic/lualibs/lualibs-basic-merged.lua
+++ b/macros/luatex/generic/lualibs/lualibs-basic-merged.lua
@@ -1,6 +1,6 @@
-- merged file : lualibs-basic-merged.lua
-- parent file : lualibs-basic.lua
--- merge date : 2020-05-01 15:49
+-- merge date : Mon Aug 31 23:16:26 2020
do -- begin closure to overcome local limits and interference
@@ -99,9 +99,6 @@ function optionalrequire(...)
return result
end
end
-if lua then
- lua.mask=load([[τεχ = 1]]) and "utf" or "ascii"
-end
local flush=io.flush
if flush then
local execute=os.execute if execute then function os.execute(...) flush() return execute(...) end end
@@ -397,19 +394,22 @@ function helpers.loaded(name)
level=level+1
for i=1,#sequence do
local method=sequence[i]
- if helpers.trace then
- helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name)
- end
- local result,rest=methods[method](name)
- if type(result)=="function" then
+ local lookup=method and methods[method]
+ if type(lookup)=="function" then
if helpers.trace then
- helpers.report("%s, level '%s', method '%s', name '%s'","found",level,method,name)
+ helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name)
end
- if helpers.traceused then
- used[#used+1]={ level=level,name=name }
+ local result,rest=lookup(name)
+ if type(result)=="function" then
+ if helpers.trace then
+ helpers.report("%s, level '%s', method '%s', name '%s'","found",level,method,name)
+ end
+ if helpers.traceused then
+ used[#used+1]={ level=level,name=name }
+ end
+ level=level-1
+ return result,rest
end
- level=level-1
- return result,rest
end
end
level=level-1
@@ -542,11 +542,13 @@ local fullstripper=whitespace^0*C((whitespace^0*nonwhitespace^1)^0)
local collapser=Cs(spacer^0/""*nonspacer^0*((spacer^0/" "*nonspacer^1)^0))
local nospacer=Cs((whitespace^1/""+nonwhitespace^1)^0)
local b_collapser=Cs(whitespace^0/""*(nonwhitespace^1+whitespace^1/" ")^0)
-local e_collapser=Cs((whitespace^1*endofstring/""+nonwhitespace^1+whitespace^1/" ")^0)
local m_collapser=Cs((nonwhitespace^1+whitespace^1/" ")^0)
+local e_collapser=Cs((whitespace^1*endofstring/""+nonwhitespace^1+whitespace^1/" ")^0)
+local x_collapser=Cs((nonwhitespace^1+whitespace^1/"" )^0)
local b_stripper=Cs(spacer^0/""*(nonspacer^1+spacer^1/" ")^0)
-local e_stripper=Cs((spacer^1*endofstring/""+nonspacer^1+spacer^1/" ")^0)
local m_stripper=Cs((nonspacer^1+spacer^1/" ")^0)
+local e_stripper=Cs((spacer^1*endofstring/""+nonspacer^1+spacer^1/" ")^0)
+local x_stripper=Cs((nonspacer^1+spacer^1/"" )^0)
patterns.stripper=stripper
patterns.fullstripper=fullstripper
patterns.collapser=collapser
@@ -554,9 +556,11 @@ patterns.nospacer=nospacer
patterns.b_collapser=b_collapser
patterns.m_collapser=m_collapser
patterns.e_collapser=e_collapser
+patterns.x_collapser=x_collapser
patterns.b_stripper=b_stripper
patterns.m_stripper=m_stripper
patterns.e_stripper=e_stripper
+patterns.x_stripper=x_stripper
patterns.lowercase=lowercase
patterns.uppercase=uppercase
patterns.letter=patterns.lowercase+patterns.uppercase
@@ -3525,11 +3529,19 @@ local function isleapyear(year)
end
os.isleapyear=isleapyear
local days={ 31,28,31,30,31,30,31,31,30,31,30,31 }
-local function nofdays(year,month)
+local function nofdays(year,month,day)
if not month then
return isleapyear(year) and 365 or 364
- else
+ elseif not day then
return month==2 and isleapyear(year) and 29 or days[month]
+ else
+ for i=1,month-1 do
+ day=day+days[i]
+ end
+ if month>2 and isleapyear(year) then
+ day=day+1
+ end
+ return day
end
end
os.nofdays=nofdays
@@ -4665,6 +4677,7 @@ do -- begin closure to overcome local limits and interference
if not modules then modules={} end modules ['l-unicode']={
version=1.001,
+ optimize=true,
comment="companion to luat-lib.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
diff --git a/macros/luatex/generic/lualibs/lualibs-extended-merged.lua b/macros/luatex/generic/lualibs/lualibs-extended-merged.lua
index 2c6ab0cf52..89d384ac8a 100644
--- a/macros/luatex/generic/lualibs/lualibs-extended-merged.lua
+++ b/macros/luatex/generic/lualibs/lualibs-extended-merged.lua
@@ -1,6 +1,6 @@
-- merged file : lualibs-extended-merged.lua
-- parent file : lualibs-extended.lua
--- merge date : 2020-05-01 15:49
+-- merge date : Mon Aug 31 23:16:16 2020
do -- begin closure to overcome local limits and interference
@@ -658,33 +658,36 @@ local format_extension=function(extensions,f,name)
local extension=extensions[name] or "tostring(%s)"
local f=tonumber(f) or 1
local w=find(extension,"%.%.%.")
- if w then
- if f==0 then
+ if f==0 then
+ if w then
extension=gsub(extension,"%.%.%.","")
- return extension
- elseif f==1 then
+ end
+ return extension
+ elseif f==1 then
+ if w then
extension=gsub(extension,"%.%.%.","%%s")
- n=n+1
- local a="a"..n
- return format(extension,a,a)
- elseif f<0 then
+ end
+ n=n+1
+ local a="a"..n
+ return format(extension,a,a)
+ elseif f<0 then
+ if w then
+ extension=gsub(extension,"%.%.%.","")
+ return extension
+ else
local a="a"..(n+f+1)
return format(extension,a,a)
- else
- extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s")
- local t={}
- for i=1,f do
- n=n+1
- t[i]="a"..n
- end
- return format(extension,unpack(t))
end
else
- extension=gsub(extension,"%%s",function()
+ if w then
+ extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s")
+ end
+ local t={}
+ for i=1,f do
n=n+1
- return "a"..n
- end)
- return extension
+ t[i]="a"..n
+ end
+ return format(extension,unpack(t))
end
end
local builder=Cs { "start",
@@ -2096,7 +2099,7 @@ local lpeg,table,string=lpeg,table,string
local P,R,V,S,C,Ct,Cs,Carg,Cc,Cg,Cf,Cp=lpeg.P,lpeg.R,lpeg.V,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg,lpeg.Cc,lpeg.Cg,lpeg.Cf,lpeg.Cp
local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns
local concat,gmatch,find=table.concat,string.gmatch,string.find
-local tostring,type,next,rawset=tostring,type,next,rawset
+local tonumber,tostring,type,next,rawset=tonumber,tostring,type,next,rawset
local mod,div=math.mod,math.div
utilities=utilities or {}
local parsers=utilities.parsers or {}
@@ -2488,13 +2491,15 @@ function parsers.csvsplitter(specification)
specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification
local separator=specification.separator
local quotechar=specification.quote
+ local numbers=specification.numbers
local separator=S(separator~="" and separator or ",")
local whatever=C((1-separator-newline)^0)
if quotechar and quotechar~="" then
local quotedata=nil
for chr in gmatch(quotechar,".") do
local quotechar=P(chr)
- local quoteword=quotechar*C((1-quotechar)^0)*quotechar
+ local quoteitem=(1-quotechar)^0
+ local quoteword=quotechar*(numbers and (quoteitem/tonumber) or C(quoteitem))*quotechar
if quotedata then
quotedata=quotedata+quoteword
else
@@ -2510,12 +2515,14 @@ function parsers.csvsplitter(specification)
end
function parsers.rfc4180splitter(specification)
specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification
+ local numbers=specification.numbers
local separator=specification.separator
local quotechar=P(specification.quote)
local dquotechar=quotechar*quotechar
/specification.quote
local separator=S(separator~="" and separator or ",")
- local escaped=quotechar*Cs((dquotechar+(1-quotechar))^0)*quotechar
+ local whatever=(dquotechar+(1-quotechar))^0
+ local escaped=quotechar*(numbers and (whatever/tonumber) or Cs(whatever))*quotechar
local non_escaped=C((1-quotechar-newline-separator)^1)
local field=escaped+non_escaped+Cc("")
local record=Ct(field*(separator*field)^1)
@@ -3389,18 +3396,11 @@ function statistics.show()
return format("%s, type: %s, binary subtree: %s",
os.platform or "unknown",os.type or "unknown",environment.texos or "unknown")
end)
- if LUATEXENGINE=="luametatex" then
- register("used engine",function()
- return format("%s version: %s, functionality level: %s, format id: %s, compiler: %s",
- LUATEXENGINE,LUATEXVERSION,LUATEXFUNCTIONALITY,LUATEXFORMATID,status.used_compiler)
- end)
- else
- register("used engine",function()
- return format("%s version: %s, functionality level: %s, banner: %s",
- LUATEXENGINE,LUATEXVERSION,LUATEXFUNCTIONALITY,lower(status.banner))
- end)
- end
- register("control sequences",function()
+ register("used engine",function()
+ return format("%s version: %s, functionality level: %s, banner: %s",
+ LUATEXENGINE,LUATEXVERSION,LUATEXFUNCTIONALITY,lower(status.banner))
+ end)
+ register("used hash slots",function()
return format("%s of %s + %s",status.cs_count,status.hash_size,status.hash_extra)
end)
register("callbacks",statistics.callbacks)
@@ -3414,15 +3414,10 @@ function statistics.show()
end
end
register("lua properties",function()
- local hashchar=tonumber(status.luatex_hashchars)
- local mask=lua.mask or "ascii"
+ local hash=2^status.luatex_hashchars
+ local mask=load([[τεχ = 1]]) and "utf" or "ascii"
return format("engine: %s %s, used memory: %s, hash chars: min(%i,40), symbol mask: %s (%s)",
- jit and "luajit" or "lua",
- LUAVERSION,
- statistics.memused(),
- hashchar and 2^hashchar or "unknown",
- mask,
- mask=="utf" and "τεχ" or "tex")
+ jit and "luajit" or "lua",LUAVERSION,statistics.memused(),hash,mask,mask=="utf" and "τεχ" or "tex")
end)
register("runtime",statistics.runtime)
logs.newline()
@@ -3478,6 +3473,13 @@ function statistics.tracefunction(base,tag,...)
statistics.register(formatters["%s.%s"](tag,name),function() return serialize(stat,"calls") end)
end
end
+function status.getreadstate()
+ return {
+ filename=status.filename or "?",
+ linenumber=status.linenumber or 0,
+ iocode=status.inputid or 0,
+ }
+end
end -- closure
diff --git a/macros/luatex/generic/lualibs/lualibs-lpeg.lua b/macros/luatex/generic/lualibs/lualibs-lpeg.lua
index 7979a40fb9..b0868ba488 100644
--- a/macros/luatex/generic/lualibs/lualibs-lpeg.lua
+++ b/macros/luatex/generic/lualibs/lualibs-lpeg.lua
@@ -203,12 +203,14 @@ local collapser = Cs(spacer^0/"" * nonspacer^0 * ((spacer^0/" " * nonspac
local nospacer = Cs((whitespace^1/"" + nonwhitespace^1)^0)
local b_collapser = Cs( whitespace^0 /"" * (nonwhitespace^1 + whitespace^1/" ")^0)
-local e_collapser = Cs((whitespace^1 * endofstring/"" + nonwhitespace^1 + whitespace^1/" ")^0)
local m_collapser = Cs( (nonwhitespace^1 + whitespace^1/" ")^0)
+local e_collapser = Cs((whitespace^1 * endofstring/"" + nonwhitespace^1 + whitespace^1/" ")^0)
+local x_collapser = Cs( (nonwhitespace^1 + whitespace^1/"" )^0)
local b_stripper = Cs( spacer^0 /"" * (nonspacer^1 + spacer^1/" ")^0)
-local e_stripper = Cs((spacer^1 * endofstring/"" + nonspacer^1 + spacer^1/" ")^0)
local m_stripper = Cs( (nonspacer^1 + spacer^1/" ")^0)
+local e_stripper = Cs((spacer^1 * endofstring/"" + nonspacer^1 + spacer^1/" ")^0)
+local x_stripper = Cs( (nonspacer^1 + spacer^1/"" )^0)
patterns.stripper = stripper
patterns.fullstripper = fullstripper
@@ -218,10 +220,12 @@ patterns.nospacer = nospacer
patterns.b_collapser = b_collapser
patterns.m_collapser = m_collapser
patterns.e_collapser = e_collapser
+patterns.x_collapser = x_collapser
patterns.b_stripper = b_stripper
patterns.m_stripper = m_stripper
patterns.e_stripper = e_stripper
+patterns.x_stripper = x_stripper
patterns.lowercase = lowercase
patterns.uppercase = uppercase
diff --git a/macros/luatex/generic/lualibs/lualibs-lua.lua b/macros/luatex/generic/lualibs/lualibs-lua.lua
index f411230d4a..00989c5cea 100644
--- a/macros/luatex/generic/lualibs/lualibs-lua.lua
+++ b/macros/luatex/generic/lualibs/lualibs-lua.lua
@@ -195,12 +195,6 @@ function optionalrequire(...)
end
end
--- nice for non ascii scripts (this might move):
-
-if lua then
- lua.mask = load([[τεχ = 1]]) and "utf" or "ascii"
-end
-
local flush = io.flush
if flush then
diff --git a/macros/luatex/generic/lualibs/lualibs-os.lua b/macros/luatex/generic/lualibs/lualibs-os.lua
index 9aa8b8aa78..1e01350947 100644
--- a/macros/luatex/generic/lualibs/lualibs-os.lua
+++ b/macros/luatex/generic/lualibs/lualibs-os.lua
@@ -604,11 +604,19 @@ os.isleapyear = isleapyear
local days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
-local function nofdays(year,month)
+local function nofdays(year,month,day)
if not month then
return isleapyear(year) and 365 or 364
- else
+ elseif not day then
return month == 2 and isleapyear(year) and 29 or days[month]
+ else
+ for i=1,month-1 do
+ day = day + days[i]
+ end
+ if month > 2 and isleapyear(year) then
+ day = day + 1
+ end
+ return day
end
end
diff --git a/macros/luatex/generic/lualibs/lualibs-package.lua b/macros/luatex/generic/lualibs/lualibs-package.lua
index 0dd71e5eca..94607d4368 100644
--- a/macros/luatex/generic/lualibs/lualibs-package.lua
+++ b/macros/luatex/generic/lualibs/lualibs-package.lua
@@ -54,7 +54,7 @@ local function lualibfile(name)
return lpegmatch(pattern,name) or name
end
-local offset = luarocks and 1 or 0 -- todo: also check other extras
+local offset = luarocks and 1 or 0 -- todo: also check other extras ... we'll drop this luarocks anyway
local helpers = package.helpers or {
cleanpath = cleanpath,
@@ -346,19 +346,22 @@ function helpers.loaded(name)
level = level + 1
for i=1,#sequence do
local method = sequence[i]
- if helpers.trace then
- helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name)
- end
- local result, rest = methods[method](name)
- if type(result) == "function" then
+ local lookup = method and methods[method]
+ if type(lookup) == "function" then
if helpers.trace then
- helpers.report("%s, level '%s', method '%s', name '%s'","found",level,method,name)
+ helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name)
end
- if helpers.traceused then
- used[#used+1] = { level = level, name = name }
+ local result, rest = lookup(name)
+ if type(result) == "function" then
+ if helpers.trace then
+ helpers.report("%s, level '%s', method '%s', name '%s'","found",level,method,name)
+ end
+ if helpers.traceused then
+ used[#used+1] = { level = level, name = name }
+ end
+ level = level - 1
+ return result, rest
end
- level = level - 1
- return result, rest
end
end
-- safeguard, we never come here
diff --git a/macros/luatex/generic/lualibs/lualibs-trac-inf.lua b/macros/luatex/generic/lualibs/lualibs-trac-inf.lua
index 244ba4604a..3db912be1f 100644
--- a/macros/luatex/generic/lualibs/lualibs-trac-inf.lua
+++ b/macros/luatex/generic/lualibs/lualibs-trac-inf.lua
@@ -223,21 +223,11 @@ function statistics.show()
return format("%s, type: %s, binary subtree: %s",
os.platform or "unknown",os.type or "unknown", environment.texos or "unknown")
end)
- -- register("luatex banner", function()
- -- return lower(status.banner)
- -- end)
- if LUATEXENGINE == "luametatex" then
- register("used engine", function()
- return format("%s version: %s, functionality level: %s, format id: %s, compiler: %s",
- LUATEXENGINE, LUATEXVERSION, LUATEXFUNCTIONALITY, LUATEXFORMATID, status.used_compiler)
- end)
- else
- register("used engine", function()
- return format("%s version: %s, functionality level: %s, banner: %s",
- LUATEXENGINE, LUATEXVERSION, LUATEXFUNCTIONALITY, lower(status.banner))
- end)
- end
- register("control sequences", function()
+ register("used engine", function()
+ return format("%s version: %s, functionality level: %s, banner: %s",
+ LUATEXENGINE, LUATEXVERSION, LUATEXFUNCTIONALITY, lower(status.banner))
+ end)
+ register("used hash slots", function()
return format("%s of %s + %s", status.cs_count, status.hash_size,status.hash_extra)
end)
register("callbacks", statistics.callbacks)
@@ -251,17 +241,11 @@ function statistics.show()
end
end
-- so far
- -- collectgarbage("collect")
register("lua properties",function()
- local hashchar = tonumber(status.luatex_hashchars)
- local mask = lua.mask or "ascii"
+ local hash = 2^status.luatex_hashchars
+ local mask = load([[τεχ = 1]]) and "utf" or "ascii"
return format("engine: %s %s, used memory: %s, hash chars: min(%i,40), symbol mask: %s (%s)",
- jit and "luajit" or "lua",
- LUAVERSION,
- statistics.memused(),
- hashchar and 2^hashchar or "unknown",
- mask,
- mask == "utf" and "τεχ" or "tex")
+ jit and "luajit" or "lua", LUAVERSION, statistics.memused(), hash, mask, mask == "utf" and "τεχ" or "tex")
end)
register("runtime",statistics.runtime)
logs.newline() -- initial newline
@@ -328,3 +312,12 @@ function statistics.tracefunction(base,tag,...)
statistics.register(formatters["%s.%s"](tag,name),function() return serialize(stat,"calls") end)
end
end
+
+function status.getreadstate()
+ return {
+ filename = status.filename or "?",
+ linenumber = status.linenumber or 0,
+ iocode = status.inputid or 0,
+ }
+end
+
diff --git a/macros/luatex/generic/lualibs/lualibs-unicode.lua b/macros/luatex/generic/lualibs/lualibs-unicode.lua
index 2708d14760..5d9a7149bd 100644
--- a/macros/luatex/generic/lualibs/lualibs-unicode.lua
+++ b/macros/luatex/generic/lualibs/lualibs-unicode.lua
@@ -1,5 +1,6 @@
if not modules then modules = { } end modules ['l-unicode'] = {
version = 1.001,
+ optimize = true,
comment = "companion to luat-lib.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
diff --git a/macros/luatex/generic/lualibs/lualibs-util-prs.lua b/macros/luatex/generic/lualibs/lualibs-util-prs.lua
index 3154bf6c28..6d2f8c19e0 100644
--- a/macros/luatex/generic/lualibs/lualibs-util-prs.lua
+++ b/macros/luatex/generic/lualibs/lualibs-util-prs.lua
@@ -10,7 +10,7 @@ local lpeg, table, string = lpeg, table, string
local P, R, V, S, C, Ct, Cs, Carg, Cc, Cg, Cf, Cp = lpeg.P, lpeg.R, lpeg.V, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cs, lpeg.Carg, lpeg.Cc, lpeg.Cg, lpeg.Cf, lpeg.Cp
local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
local concat, gmatch, find = table.concat, string.gmatch, string.find
-local tostring, type, next, rawset = tostring, type, next, rawset
+local tonumber, tostring, type, next, rawset = tonumber, tostring, type, next, rawset
local mod, div = math.mod, math.div
utilities = utilities or {}
@@ -373,6 +373,8 @@ hashes.settings_to_set = table.setmetatableindex(function(t,k) -- experiment, n
return v
end)
+-- as we use a next, we are not sure when the gc kicks in
+
getmetatable(hashes.settings_to_set).__mode = "kv" -- could be an option (maybe sharing makes sense)
function parsers.simple_hash_to_string(h, separator)
@@ -538,13 +540,15 @@ function parsers.csvsplitter(specification)
specification = specification and setmetatableindex(specification,defaultspecification) or defaultspecification
local separator = specification.separator
local quotechar = specification.quote
+ local numbers = specification.numbers
local separator = S(separator ~= "" and separator or ",")
local whatever = C((1 - separator - newline)^0)
if quotechar and quotechar ~= "" then
local quotedata = nil
for chr in gmatch(quotechar,".") do
local quotechar = P(chr)
- local quoteword = quotechar * C((1 - quotechar)^0) * quotechar
+ local quoteitem = (1 - quotechar)^0
+ local quoteword = quotechar * (numbers and (quoteitem/tonumber) or C(quoteitem)) * quotechar
if quotedata then
quotedata = quotedata + quoteword
else
@@ -559,29 +563,29 @@ function parsers.csvsplitter(specification)
end
end
--- and this is a slightly patched version of a version posted by Philipp Gesang
-
--- local mycsvsplitter = parsers.rfc4180splitter()
-
-- local crap = [[
-- first,second,third,fourth
-- "1","2","3","4"
--- "a","b","c","d"
--- "foo","bar""baz","boogie","xyzzy"
+-- "5","6","7","8"
-- ]]
+--
+-- local mycsvsplitter = parsers.csvsplitter { numbers = true }
+--
+-- local list = mycsvsplitter(crap) inspect(list)
--- local list, names = mycsvsplitter(crap,true) inspect(list) inspect(names)
--- local list, names = mycsvsplitter(crap) inspect(list) inspect(names)
+-- and this is a slightly patched version of a version posted by Philipp Gesang
function parsers.rfc4180splitter(specification)
specification = specification and setmetatableindex(specification,defaultspecification) or defaultspecification
+ local numbers = specification.numbers
local separator = specification.separator --> rfc: COMMA
local quotechar = P(specification.quote) --> DQUOTE
local dquotechar = quotechar * quotechar --> 2DQUOTE
/ specification.quote
local separator = S(separator ~= "" and separator or ",")
+ local whatever = (dquotechar + (1 - quotechar))^0
local escaped = quotechar
- * Cs((dquotechar + (1 - quotechar))^0)
+ * (numbers and (whatever/tonumber) or Cs(whatever))
* quotechar
local non_escaped = C((1 - quotechar - newline - separator)^1)
local field = escaped + non_escaped + Cc("")
@@ -601,6 +605,18 @@ function parsers.rfc4180splitter(specification)
end
end
+-- local mycsvsplitter = parsers.rfc4180splitter { numbers = true }
+--
+-- local crap = [[
+-- first,second,third,fourth
+-- "1","2","3","4"
+-- "a","b","c","d"
+-- "foo","bar""baz","boogie","xyzzy"
+-- ]]
+--
+-- local list, names = mycsvsplitter(crap,true) inspect(list) inspect(names)
+-- local list, names = mycsvsplitter(crap) inspect(list) inspect(names)
+
-- parsers.stepper("1,7-",9,function(i) print(">>>",i) end)
-- parsers.stepper("1-3,7,8,9")
-- parsers.stepper("1-3,6,7",function(i) print(">>>",i) end)
diff --git a/macros/luatex/generic/lualibs/lualibs-util-str.lua b/macros/luatex/generic/lualibs/lualibs-util-str.lua
index aba7859c31..2d3f4d669f 100644
--- a/macros/luatex/generic/lualibs/lualibs-util-str.lua
+++ b/macros/luatex/generic/lualibs/lualibs-util-str.lua
@@ -1057,76 +1057,44 @@ local format_rest = function(s)
return format("%q",s) -- catches " and \n and such
end
--- local format_extension = function(extensions,f,name)
--- local extension = extensions[name] or "tostring(%s)"
--- local f = tonumber(f) or 1
--- local w = find(extension,"%.%.%.")
--- if f == 0 then
--- if w then
--- extension = gsub(extension,"%.%.%.","")
--- end
--- return extension
--- elseif f == 1 then
--- if w then
--- extension = gsub(extension,"%.%.%.","%%s")
--- end
--- n = n + 1
--- local a = "a" .. n
--- return format(extension,a,a) -- maybe more times?
--- elseif f < 0 then
--- local a = "a" .. (n + f + 1)
--- return format(extension,a,a)
--- else
--- if w then
--- extension = gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s")
--- end
--- -- we could fill an array and then n = n + 1 unpack(t,n,n+f) but as we
--- -- cache we don't save much and there are hardly any extensions anyway
--- local t = { }
--- for i=1,f do
--- n = n + 1
--- -- t[#t+1] = "a" .. n
--- t[i] = "a" .. n
--- end
--- return format(extension,unpack(t))
--- end
--- end
-
local format_extension = function(extensions,f,name)
local extension = extensions[name] or "tostring(%s)"
local f = tonumber(f) or 1
local w = find(extension,"%.%.%.")
- if w then
- -- we have a wildcard
- if f == 0 then
+ if f == 0 then
+ if w then
extension = gsub(extension,"%.%.%.","")
- return extension
- elseif f == 1 then
+ end
+ return extension
+ elseif f == 1 then
+ if w then
extension = gsub(extension,"%.%.%.","%%s")
- n = n + 1
- local a = "a" .. n
- return format(extension,a,a) -- maybe more times?
- elseif f < 0 then
+ end
+ n = n + 1
+ local a = "a" .. n
+ return format(extension,a,a) -- maybe more times?
+ elseif f < 0 then
+ if w then
+ -- not supported
+ extension = gsub(extension,"%.%.%.","")
+ return extension
+ else
local a = "a" .. (n + f + 1)
return format(extension,a,a)
- else
- extension = gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s")
- -- we could fill an array and then n = n + 1 unpack(t,n,n+f) but as we
- -- cache we don't save much and there are hardly any extensions anyway
- local t = { }
- for i=1,f do
- n = n + 1
- -- t[#t+1] = "a" .. n
- t[i] = "a" .. n
- end
- return format(extension,unpack(t))
end
else
- extension = gsub(extension,"%%s",function()
+ if w then
+ extension = gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s")
+ end
+ -- we could fill an array and then n = n + 1 unpack(t,n,n+f) but as we
+ -- cache we don't save much and there are hardly any extensions anyway
+ local t = { }
+ for i=1,f do
n = n + 1
- return "a" .. n
- end)
- return extension
+ -- t[#t+1] = "a" .. n
+ t[i] = "a" .. n
+ end
+ return format(extension,unpack(t))
end
end
diff --git a/macros/luatex/generic/lualibs/lualibs-util-tab.lua b/macros/luatex/generic/lualibs/lualibs-util-tab.lua
index 4dafb2acd6..9f7112eb91 100644
--- a/macros/luatex/generic/lualibs/lualibs-util-tab.lua
+++ b/macros/luatex/generic/lualibs/lualibs-util-tab.lua
@@ -961,3 +961,12 @@ function table.ordered(t)
return function() end
end
end
+
+-- function table.randomremove(t,n)
+-- if not n then
+-- n = #t
+-- end
+-- if n > 0 then
+-- return remove(t,random(1,n))
+-- end
+-- end
diff --git a/macros/luatex/generic/lualibs/lualibs.dtx b/macros/luatex/generic/lualibs/lualibs.dtx
index e93eaac5df..c98c752765 100644
--- a/macros/luatex/generic/lualibs/lualibs.dtx
+++ b/macros/luatex/generic/lualibs/lualibs.dtx
@@ -37,7 +37,7 @@
\input docstrip.tex
\Msg{************************************************************************}
\Msg{* Installation}
-\Msg{* Package: lualibs 2020-05-01 v2.71 Lua additional functions.}
+\Msg{* Package: lualibs 2020-08-31 v2.72 Lua additional functions.}
\Msg{************************************************************************}
\keepsilent
@@ -107,7 +107,7 @@ and lualibs-extended.lua.
%<*driver>
\NeedsTeXFormat{LaTeX2e}
\ProvidesFile{lualibs.drv}
- [2020/05/01 v2.71 Lua Libraries.]
+ [2020/08/31 v2.72 Lua Libraries.]
\documentclass{ltxdoc}
\usepackage{fancyvrb,xspace}
\usepackage[x11names]{xcolor}
@@ -208,7 +208,7 @@ and lualibs-extended.lua.
% \GetFileInfo{lualibs.drv}
%
% \title{The \identifier{lualibs} package}
-% \date{2020/05/01 v2.71}
+% \date{2020/08/31 v2.72}
% \author{Élie Roux · \email{elie.roux@telecom-bretagne.eu}\\
% Philipp Gesang · \email{phg@phi-gamma.net}\\
% The \LaTeX3 Project · \email{https://github.com/latex3/lualibs/}\\
@@ -429,8 +429,8 @@ lualibs = lualibs or { }
lualibs.module_info = {
name = "lualibs",
- version = "2.71", --TAGVERSION
- date = "2020-05-01", --TAGDATE
+ version = "2.72", --TAGVERSION
+ date = "2020-08-31", --TAGDATE
description = "ConTeXt Lua standard libraries.",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -583,8 +583,8 @@ local loadmodule = lualibs.loadmodule
local lualibs_basic_module = {
name = "lualibs-basic",
- version = "2.71", --TAGVERSION
- date = "2020-05-01", --TAGDATE
+ version = "2.72", --TAGVERSION
+ date = "2020-08-31", --TAGDATE
description = "ConTeXt Lua libraries -- basic collection.",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -665,8 +665,8 @@ lualibs = lualibs or { }
local lualibs_extended_module = {
name = "lualibs-extended",
- version = "2.71", --TAGVERSION
- date = "2020-05-01", --TAGDATE
+ version = "2.72", --TAGVERSION
+ date = "2020-08-31", --TAGDATE
description = "ConTeXt Lua libraries -- extended collection.",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang",
copyright = "PRAGMA ADE / ConTeXt Development Team",
diff --git a/macros/luatex/generic/lualibs/lualibs.pdf b/macros/luatex/generic/lualibs/lualibs.pdf
index 6c5ff03540..031fc8158e 100644
--- a/macros/luatex/generic/lualibs/lualibs.pdf
+++ b/macros/luatex/generic/lualibs/lualibs.pdf
Binary files differ
diff --git a/macros/luatex/generic/luaotfload/NEWS b/macros/luatex/generic/luaotfload/NEWS
index cec3defd4c..658c5d420e 100644
--- a/macros/luatex/generic/luaotfload/NEWS
+++ b/macros/luatex/generic/luaotfload/NEWS
@@ -1,5 +1,24 @@
Change History
--------------
+2020-08-31 luaotfload v3.15
+ * The font database is updated more reliably if fonts get deleted.
+ * In multiple error cases, error messages are shown instead of silently
+ generating bad output.
+ * Write glyph ids instead of internal identifiers to DVI files. This
+ allows using OpenType fonts when working with dvilualatex.
+ (This requires additional support from the DVI reader)
+ * The set of font features which are enabled by default has been
+ changed to be more similar to HarfBuzz.
+ Especially Above-base mark Positioning (abvm),
+ Below-base mark Positioning (blwm), Contextual
+ Alternates (calt), Cursive Positioning (curs),
+ Distances (dist), and Required Contextual Alternates
+ (rclt) are now enabled by default for all scripts.
+ * Added a mathfontdimen font feature which allows emulating
+ fontdimen values from xetex or traditional \TeX\ math fonts.
+ * Initial support for variable fonts in node mode.
+
+
2020-05-01 luaotfload v3.14
* bug fix for luaotfload-tool, luaotfload-tool --list=basename failed (texlive list)
* fontloader patched to resolve issue #124
diff --git a/macros/luatex/generic/luaotfload/README.md b/macros/luatex/generic/luaotfload/README.md
index 7ceb1797fb..626e1c9b8b 100644
--- a/macros/luatex/generic/luaotfload/README.md
+++ b/macros/luatex/generic/luaotfload/README.md
@@ -1,8 +1,8 @@
# The Luaotfload Package
-VERSION: 3.14
+VERSION: 3.15
-DATE: 2020-05-06
+DATE: 2020-09-02
## Description
diff --git a/macros/luatex/generic/luaotfload/filegraph.pdf b/macros/luatex/generic/luaotfload/filegraph.pdf
index 4b8c2922fb..5e90db1544 100644
--- a/macros/luatex/generic/luaotfload/filegraph.pdf
+++ b/macros/luatex/generic/luaotfload/filegraph.pdf
Binary files differ
diff --git a/macros/luatex/generic/luaotfload/filegraph.tex b/macros/luatex/generic/luaotfload/filegraph.tex
index 297816671a..ee76912b78 100644
--- a/macros/luatex/generic/luaotfload/filegraph.tex
+++ b/macros/luatex/generic/luaotfload/filegraph.tex
@@ -9,7 +9,7 @@
\pgfsetlayers{container,background,main,foreground}
\usepackage {fontspec}
\usepackage {unicode-math}
-\usepackage{tikzmarmots,tikzducks}
+\usepackage{tikzlings-marmots,tikzducks}
\setmainfont[
% Numbers = OldStyle, %% buggy with font cache
@@ -263,4 +263,4 @@ at ([yshift=1cm,xshift=-0.5cm]bill)
\end{scope}
\end{tikzpicture}
-\end{document} \ No newline at end of file
+\end{document}
diff --git a/macros/luatex/generic/luaotfload/fontloader-2020-05-06.lua b/macros/luatex/generic/luaotfload/fontloader-2020-08-31.lua
index 418ca726ba..01e1f8300c 100644
--- a/macros/luatex/generic/luaotfload/fontloader-2020-05-06.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-2020-08-31.lua
@@ -1,6 +1,6 @@
--[[info-----------------------------------------------------------------------
Luaotfload fontloader package
- build 2020-05-01 16:08:24
+ build 2020-08-31 23:33:48
-------------------------------------------------------------------------------
© 2020 PRAGMA ADE / ConTeXt Development Team
@@ -8,7 +8,7 @@
The code in this file is provided under the GPL v2.0 license. See the
file COPYING in the Luaotfload repository for details.
- Report bugs to github.com/u-fischer/luaotfload
+ Report bugs to https://github.com/latex3/luaotfload
This file has been assembled from components taken from Context. See
the Luaotfload documentation for details:
@@ -50,6 +50,7 @@
· fontloader-fonts-tfm.lua
· fontloader-font-lua.lua
· fontloader-font-def.lua
+ · fontloader-font-shp.lua
· fontloader-fonts-def.lua
· fontloader-fonts-ext.lua
· fontloader-font-imp-tex.lua
@@ -62,7 +63,7 @@
--info]]-----------------------------------------------------------------------
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “data-con” de6ae0997b0e70a23bcc9afff5d8b072] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “data-con” de6ae0997b0e70a23bcc9afff5d8b072] ---
if not modules then modules={} end modules ['data-con']={
version=1.100,
@@ -183,10 +184,10 @@ function containers.cleanname(name)
return (gsub(lower(name),"[^%w\128-\255]+","-"))
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “data-con”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “data-con”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “basics-nod” 68226d7dadd241bca55171af9ce1f243] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “basics-nod” e296bfb03d5654a596b43612348c4191] ---
if not modules then modules={} end modules ['luatex-fonts-nod']={
version=1.001,
@@ -239,6 +240,7 @@ end
nodes.nodecodes=nodecodes
nodes.glyphcodes=glyphcodes
nodes.disccodes=disccodes
+nodes.dirvalues={ lefttoright=0,righttoleft=1 }
nodes.handlers.protectglyphs=node.protect_glyphs
nodes.handlers.unprotectglyphs=node.unprotect_glyphs
local direct=node.direct
@@ -435,10 +437,10 @@ do
end
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “basics-nod”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “basics-nod”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “basics-chr” 58b7ef0c486e06090b362971b9f85e27] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “basics-chr” 58b7ef0c486e06090b362971b9f85e27] ---
characters=characters or {}
@@ -4048,10 +4050,10 @@ characters.indicgroups={
},
}
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “basics-chr”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “basics-chr”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-ini” 4dee96e1e1474d324dd126bd5d375df8] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ini” 4dee96e1e1474d324dd126bd5d375df8] ---
if not modules then modules={} end modules ['font-ini']={
version=1.001,
@@ -4092,10 +4094,10 @@ if node and not tex.getfontoffamily then
tex.getfontoffamily=node.family_font
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-ini”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ini”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “fonts-mis” bc9eb43c27f63ce9d0fff67e104fe1c6] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-mis” bc9eb43c27f63ce9d0fff67e104fe1c6] ---
if not modules then modules={} end modules ['luatex-font-mis']={
version=1.001,
@@ -4127,10 +4129,10 @@ function font.each()
return table.sortedhash(fonts.hashes.identifiers)
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “fonts-mis”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-mis”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-con” 40e3a857b2f31be1959dc6d445aaa9c4] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-con” cbccccc4a5016196d62332a365aa8b72] ---
if not modules then modules={} end modules ['font-con']={
version=1.001,
@@ -4251,6 +4253,9 @@ function constructors.assignmathparameters(target,original)
if not mathparameters.FractionDelimiterDisplayStyleSize then
targetmathparameters.FractionDelimiterDisplayStyleSize=2.40*targetparameters.size
end
+ if not targetmathparameters.SpaceBeforeScript then
+ targetmathparameters.SpaceBeforeScript=targetmathparameters.SpaceAfterScript
+ end
target.mathparameters=targetmathparameters
end
end
@@ -4258,31 +4263,40 @@ function constructors.beforecopyingcharacters(target,original)
end
function constructors.aftercopyingcharacters(target,original)
end
-constructors.sharefonts=false
-constructors.nofsharedfonts=0
-local sharednames={}
+local nofinstances=0
+local instances=setmetatableindex(function(t,k)
+ nofinstances=nofinstances+1
+ t[k]=nofinstances
+ return nofinstances
+end)
function constructors.trytosharefont(target,tfmdata)
- if constructors.sharefonts then
- local characters=target.characters
- local n=1
- local t={ target.psname }
- local u=sortedkeys(characters)
- for i=1,#u do
- local k=u[i]
- n=n+1;t[n]=k
- n=n+1;t[n]=characters[k].index or k
- end
- local h=md5.HEX(concat(t," "))
- local s=sharednames[h]
- if s then
- if trace_defining then
- report_defining("font %a uses backend resources of font %a",target.fullname,s)
- end
- target.fullname=s
- constructors.nofsharedfonts=constructors.nofsharedfonts+1
- target.properties.sharedwith=s
+ local properties=target.properties
+ local instance=properties.instance
+ if instance then
+ local fullname=target.fullname
+ local fontname=target.fontname
+ local psname=target.psname
+ local format=tfmdata.properties.format
+ if format=="opentype" then
+ target.streamprovider=1
+ elseif format=="truetype" then
+ target.streamprovider=2
else
- sharednames[h]=target.fullname
+ target.streamprovider=0
+ end
+ if target.streamprovider>0 then
+ if fullname then
+ fullname=fullname..":"..instances[instance]
+ target.fullname=fullname
+ end
+ if fontname then
+ fontname=fontname..":"..instances[instance]
+ target.fontname=fontname
+ end
+ if psname then
+ psname=psname..":"..instances[instance]
+ target.psname=psname
+ end
end
end
end
@@ -4448,12 +4462,14 @@ function constructors.scale(tfmdata,specification)
target.cidinfo=properties.cidinfo
target.format=properties.format
target.cache=constructors.cacheintex and "yes" or "renew"
+ local original=properties.original or tfmdata.original
local fontname=properties.fontname or tfmdata.fontname
local fullname=properties.fullname or tfmdata.fullname
local filename=properties.filename or tfmdata.filename
local psname=properties.psname or tfmdata.psname
local name=properties.name or tfmdata.name
local psname,psfixed=fixedpsname(psname,fontname or fullname or file.nameonly(filename))
+ target.original=original
target.fontname=fontname
target.fullname=fullname
target.filename=filename
@@ -4543,6 +4559,14 @@ function constructors.scale(tfmdata,specification)
targetparameters.x_height=targetx_height
targetparameters.quad=targetquad
targetparameters.extra_space=targetextra_space
+ local hshift=parameters.hshift
+ if hshift then
+ targetparameters.hshift=delta*hshift
+ end
+ local vshift=parameters.vshift
+ if vshift then
+ targetparameters.vshift=delta*vshift
+ end
local ascender=parameters.ascender
if ascender then
targetparameters.ascender=delta*ascender
@@ -5473,10 +5497,10 @@ function constructors.addcoreunicodes(unicodes)
return unicodes
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-con”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-con”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “fonts-enc” 3e71a54297e8f85a1ac438bb0f20dd79] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-enc” 3e71a54297e8f85a1ac438bb0f20dd79] ---
if not modules then modules={} end modules ['luatex-font-enc']={
version=1.001,
@@ -5545,10 +5569,10 @@ function encodings.load(filename)
return containers.write(encodings.cache,name,data)
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “fonts-enc”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-enc”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-cid” 4d87988efa86020a14708ee03c23415f] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-cid” 4d87988efa86020a14708ee03c23415f] ---
if not modules then modules={} end modules ['font-cid']={
version=1.001,
@@ -5699,13 +5723,14 @@ function cid.getmap(specification)
return found
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-cid”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-cid”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-map” 51d0362c19d2d0f621e5cb750410a809] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-map” a03653ea3c5f042b457d54ed678d6df3] ---
if not modules then modules={} end modules ['font-map']={
version=1.001,
+ optimize=true,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -5790,6 +5815,7 @@ end
local hash={}
local conc={}
table.setmetatableindex(hash,function(t,k)
+ local v
if k<0xD7FF or (k>0xDFFF and k<=0xFFFF) then
v=f_single(k)
else
@@ -6108,10 +6134,10 @@ function mappings.addtounicode(data,filename,checklookups,forceligatures)
end
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-map”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-map”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-vfc” 94937140f2c909e9c831ba021f1ab303] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-vfc” 04fa0ffad5c51198c7c19462949f54ed] ---
if not modules then modules={} end modules ['font-vfc']={
version=1.001,
@@ -6125,7 +6151,6 @@ local insert=table.insert
local fonts=fonts
local helpers=fonts.helpers
local setmetatableindex=table.setmetatableindex
-local makeweak=table.makeweak
local push={ "push" }
local pop={ "pop" }
local dummy={ "comment" }
@@ -6209,13 +6234,14 @@ helpers.commands=utilities.storage.allocate {
dummy=dummy,
}
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-vfc”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-vfc”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-otr” d96724dcb40c673ac294df7044a39925] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-otr” 7a2f7a9e9627b29158e1822ea3c650ab] ---
if not modules then modules={} end modules ['font-otr']={
version=1.001,
+ optimize=true,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -7657,17 +7683,11 @@ local function readtable(tag,f,fontdata,specification,...)
reader(f,fontdata,specification,...)
end
end
-local variablefonts_supported=(context and true) or (logs and logs.application and true) or false
local function readdata(f,offset,specification)
local fontdata,tables=loadtables(f,specification,offset)
if specification.glyphs then
prepareglyps(fontdata)
end
- if not variablefonts_supported then
- specification.instance=nil
- specification.variable=nil
- specification.factors=nil
- end
fontdata.temporary={}
readtable("name",f,fontdata,specification)
local askedname=specification.askedname
@@ -7682,60 +7702,58 @@ local function readdata(f,offset,specification)
readtable("stat",f,fontdata,specification)
readtable("avar",f,fontdata,specification)
readtable("fvar",f,fontdata,specification)
- if variablefonts_supported then
- local variabledata=fontdata.variabledata
- if variabledata then
- local instances=variabledata.instances
- local axis=variabledata.axis
- if axis and (not instances or #instances==0) then
- instances={}
- variabledata.instances=instances
- local function add(n,subfamily,value)
- local values={}
- for i=1,#axis do
- local a=axis[i]
- values[i]={
- axis=a.tag,
- value=i==n and value or a.default,
- }
- end
- instances[#instances+1]={
- subfamily=subfamily,
- values=values,
- }
- end
+ local variabledata=fontdata.variabledata
+ if variabledata then
+ local instances=variabledata.instances
+ local axis=variabledata.axis
+ if axis and (not instances or #instances==0) then
+ instances={}
+ variabledata.instances=instances
+ local function add(n,subfamily,value)
+ local values={}
for i=1,#axis do
local a=axis[i]
- local tag=a.tag
- add(i,"default"..tag,a.default)
- add(i,"minimum"..tag,a.minimum)
- add(i,"maximum"..tag,a.maximum)
- end
- end
- end
- if not specification.factors then
- local instance=specification.instance
- if type(instance)=="string" then
- local factors=helpers.getfactors(fontdata,instance)
- if factors then
- specification.factors=factors
- fontdata.factors=factors
- fontdata.instance=instance
- report("user instance: %s, factors: % t",instance,factors)
- else
- report("user instance: %s, bad factors",instance)
+ values[i]={
+ axis=a.tag,
+ value=i==n and value or a.default,
+ }
end
+ instances[#instances+1]={
+ subfamily=subfamily,
+ values=values,
+ }
+ end
+ for i=1,#axis do
+ local a=axis[i]
+ local tag=a.tag
+ add(i,"default"..tag,a.default)
+ add(i,"minimum"..tag,a.minimum)
+ add(i,"maximum"..tag,a.maximum)
end
end
- if not fontdata.factors then
- if fontdata.variabledata then
- local factors=helpers.getfactors(fontdata,true)
- if factors then
- specification.factors=factors
- fontdata.factors=factors
- end
+ end
+ if not specification.factors then
+ local instance=specification.instance
+ if type(instance)=="string" then
+ local factors=helpers.getfactors(fontdata,instance)
+ if factors then
+ specification.factors=factors
+ fontdata.factors=factors
+ fontdata.instance=instance
+ report("user instance: %s, factors: % t",instance,factors)
else
+ report("user instance: %s, bad factors",instance)
+ end
+ end
+ end
+ if not fontdata.factors then
+ if fontdata.variabledata then
+ local factors=helpers.getfactors(fontdata,true)
+ if factors then
+ specification.factors=factors
+ fontdata.factors=factors
end
+ else
end
end
readtable("os/2",f,fontdata,specification)
@@ -7959,6 +7977,7 @@ function readers.loadfont(filename,n,instance)
hascolor=fontdata.hascolor or false,
instance=fontdata.instance,
factors=fontdata.factors,
+ nofsubfonts=fontdata.subfonts and #fontdata.subfonts or nil,
},
resources={
filename=filename,
@@ -8062,10 +8081,10 @@ function readers.extend(fontdata)
end
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-otr”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-otr”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-oti” dbae7722baae24d917a17176553825cf] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-oti” dbae7722baae24d917a17176553825cf] ---
if not modules then modules={} end modules ['font-oti']={
version=1.001,
@@ -8208,10 +8227,10 @@ function otffeatures.checkeddefaultlanguage(featuretype,autolanguage,languages)
end
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-oti”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-oti”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-ott” aba6d8335a5f38a5a62d3631492f3392] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ott” 1249b7018dba80e080fc478a38aa6756] ---
if not modules then modules={} end modules ["font-ott"]={
version=1.001,
@@ -9288,9 +9307,6 @@ function otffeatures.normalize(features,wrap)
h.script=rawget(verbosescripts,v) or (scripts[v] and v) or "dflt"
elseif k=="axis" then
h[k]=normalizedaxis(value)
- if not callbacks.supported.glyph_stream_provider then
- h.variableshapes=true
- end
else
local uk=usedfeatures[key]
local uv=uk[value]
@@ -9330,13 +9346,14 @@ function otffeatures.normalize(features,wrap)
end
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-ott”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ott”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-cff” 155821e11e84021437869ff973e75d93] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-cff” aa9038651d9fedd2b76cacd1f69fd742] ---
if not modules then modules={} end modules ['font-cff']={
version=1.001,
+ optimize=true,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -9784,12 +9801,15 @@ do
local p_dictionary=(
p_byte+p_positive+p_negative+p_short+p_long+p_nibbles+p_single+p_double+p_unsupported
)^1
- parsedictionaries=function(data,dictionaries,what)
+ parsedictionaries=function(data,dictionaries,version)
stack={}
strings=data.strings
+ if trace_charstrings then
+ report("charstring format %a",version)
+ end
for i=1,#dictionaries do
top=0
- result=what=="cff" and {
+ result=version=="cff" and {
monospaced=false,
italicangle=0,
underlineposition=-100,
@@ -10588,6 +10608,7 @@ do
end
end
else
+ top=top-nofregions*n
end
end
local actions={ [0]=unsupported,
@@ -11163,8 +11184,8 @@ do
processshape(tab,index-1)
end
end
-local function readglobals(f,data)
- local routines=readlengths(f)
+local function readglobals(f,data,version)
+ local routines=readlengths(f,version=="cff2")
for i=1,#routines do
routines[i]=readbytetable(f,routines[i])
end
@@ -11218,14 +11239,14 @@ local function readprivates(f,data)
private.data=readstring(f,private.size)
end
end
-local function readlocals(f,data,dictionary)
+local function readlocals(f,data,dictionary,version)
local header=data.header
local private=dictionary.private
if private then
local subroutineoffset=private.data.subroutines
if subroutineoffset~=0 then
setposition(f,header.offset+private.offset+subroutineoffset)
- local subroutines=readlengths(f)
+ local subroutines=readlengths(f,version=="cff2")
for i=1,#subroutines do
subroutines[i]=readbytetable(f,subroutines[i])
end
@@ -11238,7 +11259,7 @@ local function readlocals(f,data,dictionary)
dictionary.subroutines={}
end
end
-local function readcharstrings(f,data,what)
+local function readcharstrings(f,data,version)
local header=data.header
local dictionaries=data.dictionaries
local dictionary=dictionaries[1]
@@ -11247,7 +11268,7 @@ local function readcharstrings(f,data,what)
if type(offset)~="number" then
elseif stringtype==2 then
setposition(f,header.offset+offset)
- local charstrings=readlengths(f,what=="cff2")
+ local charstrings=readlengths(f,version=="cff2")
local nofglyphs=#charstrings
for i=1,nofglyphs do
charstrings[i]=readstring(f,charstrings[i])
@@ -11277,7 +11298,8 @@ readers.parsecharstrings=parsecharstrings
local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams)
local dictionaries=data.dictionaries
local dictionary=dictionaries[1]
- readglobals(f,data)
+ local cid=not dictionary.private and dictionary.cid
+ readglobals(f,data,version)
readcharstrings(f,data,version)
if version=="cff2" then
dictionary.charset=nil
@@ -11285,9 +11307,27 @@ local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams)
readencodings(f,data)
readcharsets(f,data,dictionary)
end
+ if cid then
+ local fdarray=cid.fdarray
+ if fdarray then
+ setposition(f,data.header.offset+fdarray)
+ local dictionaries=readlengths(f,version=="cff2")
+ local nofdictionaries=#dictionaries
+ if nofdictionaries>0 then
+ for i=1,nofdictionaries do
+ dictionaries[i]=readstring(f,dictionaries[i])
+ end
+ parsedictionaries(data,dictionaries)
+ dictionary.private=dictionaries[1].private
+ if nofdictionaries>1 then
+ report("ignoring dictionaries > 1 in cid font")
+ end
+ end
+ end
+ end
readprivates(f,data)
parseprivates(data,data.dictionaries)
- readlocals(f,data,dictionary)
+ readlocals(f,data,dictionary,version)
startparsing(fontdata,data,streams)
parsecharstrings(fontdata,data,glyphs,doshapes,version,streams)
stopparsing(fontdata,data)
@@ -11298,7 +11338,7 @@ local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams)
local dictionary=dictionaries[1]
local cid=dictionary.cid
local cidselect=cid and cid.fdselect
- readglobals(f,data)
+ readglobals(f,data,version)
readcharstrings(f,data,version)
if version~="cff2" then
readencodings(f,data)
@@ -11342,7 +11382,7 @@ local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams)
local cidarray=cid.fdarray
if cidarray then
setposition(f,header.offset+cidarray)
- local dictionaries=readlengths(f)
+ local dictionaries=readlengths(f,version=="cff2")
for i=1,#dictionaries do
dictionaries[i]=readstring(f,dictionaries[i])
end
@@ -11350,7 +11390,7 @@ local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams)
cid.dictionaries=dictionaries
readcidprivates(f,data)
for i=1,#dictionaries do
- readlocals(f,data,dictionaries[i])
+ readlocals(f,data,dictionaries[i],version)
end
startparsing(fontdata,data,streams)
for i=1,#charstrings do
@@ -11504,13 +11544,14 @@ function readers.cffcheck(filename)
end
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-cff”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-cff”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-ttf” 44e61cef50dab9b1aaf48130f9367c34] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ttf” 807599f6d56c775d53cf6f358d741f34] ---
if not modules then modules={} end modules ['font-ttf']={
version=1.001,
+ optimize=true,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -12677,13 +12718,14 @@ function readers.gvar(f,fontdata,specification,glyphdata,shapedata)
end
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-ttf”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ttf”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-dsp” 618e5e760ec5dceb0c898a83816dbe61] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-dsp” e1c275ded4770aa6cbe0b1afbdfd0dde] ---
if not modules then modules={} end modules ['font-dsp']={
version=1.001,
+ optimize=true,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -15957,10 +15999,10 @@ function readers.mvar(f,fontdata,specification)
end
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-dsp”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-dsp”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-oup” 1700a2dac4f8b105c187d4e5b84cecdf] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-oup” 1700a2dac4f8b105c187d4e5b84cecdf] ---
if not modules then modules={} end modules ['font-oup']={
version=1.001,
@@ -18601,10 +18643,10 @@ function readers.expand(data)
expandlookups(sublookups)
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-oup”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-oup”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-otl” f111f9ac18d24049fadeb8883e4e8da5] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-otl” f111f9ac18d24049fadeb8883e4e8da5] ---
if not modules then modules={} end modules ['font-otl']={
version=1.001,
@@ -19308,10 +19350,10 @@ otf.coverup={
end
}
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-otl”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-otl”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-oto” 24238a7c600d090a8ee88312321dd9b3] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-oto” 24238a7c600d090a8ee88312321dd9b3] ---
if not modules then modules={} end modules ['font-oto']={
version=1.001,
@@ -19769,13 +19811,14 @@ registerotffeature {
}
otf.basemodeinitializer=featuresinitializer
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-oto”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-oto”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-otj” c9ded1d935bfa43020657e1f408fb820] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-otj” a37a1007b8a92c9e7d24064180c2a772] ---
if not modules then modules={} end modules ['font-otj']={
version=1.001,
+ optimize=true,
comment="companion to font-lib.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -21266,10 +21309,10 @@ function injections.handler(head,where)
end
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-otj”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-otj”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-ota” dd5f1c8ba28abaf4505fd960d04a3a98] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ota” f31232af3a694ae3d50380a5a92f88d3] ---
if not modules then modules={} end modules ['font-ota']={
version=1.001,
@@ -21279,6 +21322,7 @@ if not modules then modules={} end modules ['font-ota']={
license="see context related readme files"
}
local type=type
+local setmetatableindex=table.setmetatableindex
if not trackers then trackers={ register=function() end } end
local fonts,nodes,node=fonts,nodes,node
local allocate=utilities.storage.allocate
@@ -21492,7 +21536,7 @@ if not classifiers then
local f_mandiac,l_mandiac=characters.blockrange("mandiac")
local f_nko,l_nko=characters.blockrange("nko")
local f_ext_a,l_ext_a=characters.blockrange("arabicextendeda")
- classifiers=table.setmetatableindex(function(t,k)
+ classifiers=setmetatableindex(function(t,k)
if type(k)=="number" then
local c=chardata[k]
local v=false
@@ -21658,17 +21702,118 @@ end
methods.syrc=methods.arab
methods.mand=methods.arab
methods.nko=methods.arab
+do
+ local joining=setmetatableindex(function(t,k)
+ if type(k)=="number" then
+ local c=chardata[k]
+ local v=false
+ if c then
+ local mongolian=c.mongolian
+ v=mongolian
+ end
+ t[k]=v
+ return v
+ end
+ end)
+ function methods.mong(head,font,attr)
+ local first,last
+ local current=head
+ local done=false
+ local prevjoin=nil
+ local prestate=nil
+ current=tonut(current)
+ local function wrapup()
+ if last then
+ if last~=first then
+ local s=getstate(last)
+ if s==s_medi then
+ setstate(last,s_fina)
+ elseif s==s_init then
+ setstate(last,s_isol)
+ end
+ end
+ last=nil
+ first=nil
+ prevjoin=nil
+ prestate=nil
+ end
+ end
+ while current do
+ local char,id=ischar(current,font)
+ if char and not getstate(current) then
+ local currjoin=joining[char]
+ done=true
+ if not last then
+ setstate(current,s_isol)
+ prevjoin=currjoin
+ first=current
+ last=current
+ prevstate=s_isol
+ elseif currjoin=="t" then
+ last=current
+ elseif prevjoin=="d" or prevjoin=="jc" or prevjoin=="l" then
+ if currjoin=="d" or prevjoin=="jc" or prevjoin=="r" then
+ local s=getstate(last)
+ if s==s_isol then
+ setstate(last,s_init)
+ elseif s==s_fina then
+ setstate(last,s_medi)
+ end
+ setstate(current,s_fina)
+ prevstate=s_fina
+ elseif prevjoin=="nj" or prevjoin=="l" then
+ local s=getstate(last)
+ if s==s_medi then
+ setstate(last,s_fina)
+ elseif s==s_init then
+ setstate(last,s_isol)
+ end
+ setstate(current,s_isol)
+ prevstate=s_isol
+ end
+ prevjoin=currjoin
+ last=current
+ elseif prevjoin=="nj" or prevjoin=="r" then
+ if s==s_medi then
+ setstate(last,s_fina)
+ elseif s==s_init then
+ setstate(last,s_isol)
+ end
+ setstate(current,s_isol)
+ prevjoin=currjoin
+ prevstate=s_isol
+ last=current
+ elseif last then
+ wrapup()
+ end
+ else
+ if last then
+ wrapup()
+ end
+ if id==math_code then
+ current=end_of_math(current)
+ end
+ end
+ current=getnext(current)
+ end
+ if last then
+ wrapup()
+ end
+ return head,done
+ end
+end
directives.register("otf.analyze.useunicodemarks",function(v)
analyzers.useunicodemarks=v
end)
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-ota”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ota”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-ots” 113b7ad0c40d4786bb026706e479c3f3] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ots” c507280651dcbc549f1d8a5622da8667] ---
if not modules then modules={} end modules ['font-ots']={
version=1.001,
+ optimize=true,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -21771,6 +21916,8 @@ local disc_code=nodecodes.disc
local math_code=nodecodes.math
local dir_code=nodecodes.dir
local localpar_code=nodecodes.localpar
+local lefttoright_code=nodes.dirvalues.lefttoright
+local righttoleft_code=nodes.dirvalues.righttoleft
local discretionarydisc_code=disccodes.discretionary
local ligatureglyph_code=glyphcodes.ligature
local a_noligature=attributes.private("noligature")
@@ -23274,6 +23421,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
local sweepnode=sweepnode
local sweeptype=sweeptype
local sweepoverflow=false
+ local checkdisc=getprev(head)
local keepdisc=not sweepnode
local lookaheaddisc=nil
local backtrackdisc=nil
@@ -23397,7 +23545,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
local current=prev
local i=f
local t=sweeptype=="pre" or sweeptype=="replace"
- if not current and t and current==checkdisk then
+ if not current and t and current==checkdisc then
current=getprev(sweepnode)
end
while current and i>1 do
@@ -23425,7 +23573,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
end
end
current=getprev(current)
- if t and current==checkdisk then
+ if t and current==checkdisc then
current=getprev(sweepnode)
end
end
@@ -23610,6 +23758,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
local l=ck[5]
local current=start
local last=start
+ if s==1 then
+ goto next
+ end
if l>f then
local discfound
local n=f+1
@@ -23675,6 +23826,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
break
end
end
+ if n<=l then
+ notmatchpre[last]=true
+ end
else
notmatchpre[last]=true
end
@@ -24620,8 +24774,6 @@ local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,datase
end
local txtdirstate,pardirstate do
local getdirection=nuts.getdirection
- local lefttoright=0
- local righttoleft=1
txtdirstate=function(start,stack,top,rlparmode)
local dir,pop=getdirection(start)
if pop then
@@ -24629,19 +24781,19 @@ local txtdirstate,pardirstate do
return 0,rlparmode
else
top=top-1
- if stack[top]==righttoleft then
+ if stack[top]==righttoleft_code then
return top,-1
else
return top,1
end
end
- elseif dir==lefttoright then
+ elseif dir==lefttoright_code then
top=top+1
- stack[top]=lefttoright
+ stack[top]=lefttoright_code
return top,1
- elseif dir==righttoleft then
+ elseif dir==righttoleft_code then
top=top+1
- stack[top]=righttoleft
+ stack[top]=righttoleft_code
return top,-1
else
return top,rlparmode
@@ -24649,13 +24801,9 @@ local txtdirstate,pardirstate do
end
pardirstate=function(start)
local dir=getdirection(start)
- if dir==lefttoright then
- return 1,1
- elseif dir==righttoleft then
- return -1,-1
- elseif dir=="TLT" then
+ if dir==lefttoright_code then
return 1,1
- elseif dir=="TRT" then
+ elseif dir==righttoleft_code then
return -1,-1
else
return 0,0
@@ -24710,7 +24858,7 @@ do
local initialrl=0
if getid(head)==localpar_code and start_of_par(head) then
initialrl=pardirstate(head)
- elseif direction==1 or direction=="TRT" then
+ elseif direction==righttoleft_code then
initialrl=-1
end
local datasets=otfdataset(tfmdata,font,attr)
@@ -24934,7 +25082,7 @@ do
local done=false
local dirstack={ nil }
local start=head
- local initialrl=(direction==1 or direction=="TRT") and -1 or 0
+ local initialrl=(direction==righttoleft_code) and -1 or 0
local rlmode=initialrl
local rlparmode=initialrl
local topstack=0
@@ -25253,10 +25401,10 @@ registerotffeature {
},
}
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-ots”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ots”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-osd” 61f05fcf91add1aa5dac9bc8b235adc9] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-osd” 61f05fcf91add1aa5dac9bc8b235adc9] ---
if not modules then modules={} end modules ['font-osd']={
version=1.001,
@@ -27689,10 +27837,10 @@ for i=1,nofscripts do
methods[scripts_two[i]]=method_two
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-osd”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-osd”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-ocl” e6b45379971219a6227e8655cda14aff] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ocl” ab81576f20e2d37bc8707e1dbd3decf2] ---
if not modules then modules={} end modules ['font-ocl']={
version=1.001,
@@ -27701,9 +27849,6 @@ if not modules then modules={} end modules ['font-ocl']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-if CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 then
- return
-end
local tostring,tonumber,next=tostring,tonumber,next
local round,max=math.round,math.round
local gsub,find=string.gsub,string.find
@@ -27808,7 +27953,7 @@ local function convert(t,k)
t[k]=v
return v
end
-local start={ "pdf","mode","font" }
+local mode={ "pdf","mode","font" }
local push={ "pdf","page","q" }
local pop={ "pdf","page","Q" }
local function initializeoverlay(tfmdata,kind,value)
@@ -27853,7 +27998,7 @@ local function initializeoverlay(tfmdata,kind,value)
local s=#colorlist
local goback=w~=0 and leftcommand[w] or nil
local t={
- start,
+ mode,
not u and actualb or { "pdf","page",(getactualtext(tounicode(u))) },
push,
}
@@ -27977,7 +28122,7 @@ do
local loaddata=io.loaddata
local savedata=io.savedata
local remove=os.remove
- if context and xml.convert then
+if context then
local xmlconvert=xml.convert
local xmlfirst=xml.first
function otfsvg.filterglyph(entry,index)
@@ -27986,11 +28131,11 @@ do
local data=root and tostring(root)
return data
end
- else
+else
function otfsvg.filterglyph(entry,index)
return entry.data
end
- end
+end
local runner=sandbox and sandbox.registerrunner {
name="otfsvg",
program="inkscape",
@@ -28003,6 +28148,14 @@ do
return io.popen("inkscape --export-area-drawing --shell > temp-otf-svg-shape.log","w")
end
end
+ local new=nil
+ local function inkscapeformat(suffix)
+ if new==nil then
+ new=os.resultof("inkscape --version") or ""
+ new=new=="" or not find(new,"Inkscape%s*0")
+ end
+ return new and "filename" or suffix
+ end
function otfsvg.topdf(svgshapes,tfmdata)
local pdfshapes={}
local inkscape=runner()
@@ -28011,7 +28164,7 @@ do
local nofshapes=#svgshapes
local f_svgfile=formatters["temp-otf-svg-shape-%i.svg"]
local f_pdffile=formatters["temp-otf-svg-shape-%i.pdf"]
- local f_convert=formatters["%s --export-pdf=%s\n"]
+ local f_convert=formatters["%s --export-%s=%s\n"]
local filterglyph=otfsvg.filterglyph
local nofdone=0
local processed={}
@@ -28025,7 +28178,7 @@ do
local svgfile=f_svgfile(index)
local pdffile=f_pdffile(index)
savedata(svgfile,data)
- inkscape:write(f_convert(svgfile,pdffile))
+ inkscape:write(f_convert(svgfile,inkscapeformat("pdf"),pdffile))
processed[index]=true
nofdone=nofdone+1
if nofdone%25==0 then
@@ -28230,10 +28383,10 @@ if context then
}
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-ocl”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ocl”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-otc” 1204a2fdc436e644127c0aa38ab69607] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-otc” 1204a2fdc436e644127c0aa38ab69607] ---
if not modules then modules={} end modules ['font-otc']={
version=1.001,
@@ -28990,13 +29143,14 @@ end
otf.enhancers.enhance=enhance
otf.enhancers.register("check extra features",enhance)
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-otc”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-otc”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-onr” 22572ec0f86f53631e14b6d1ed43ee51] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-onr” 7a9ece7bf3e36b5f0adf295a9a2a2989] ---
if not modules then modules={} end modules ['font-onr']={
version=1.001,
+ optimize=true,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -29365,13 +29519,14 @@ function readers.getinfo(filename)
end
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-onr”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-onr”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-one” 987c5c5ed3754ad2feab80985067d59e] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-one” 1402ae8e4e96186c848fa2742388fb24] ---
if not modules then modules={} end modules ['font-one']={
version=1.001,
+ optimize=true,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -30079,10 +30234,10 @@ registerafmenhancer("normalize features",enhance_normalize_features)
registerafmenhancer("check extra features",otfenhancers.enhance)
registerafmenhancer("fix names",enhance_fix_names)
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-one”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-one”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-afk” 54d554530e75c57c56ee76234724e26d] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-afk” 54d554530e75c57c56ee76234724e26d] ---
if not modules then modules={} end modules ['font-afk']={
version=1.001,
@@ -30249,10 +30404,10 @@ fonts.handlers.afm.helpdata={
}
}
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-afk”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-afk”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “fonts-tfm” 3bbba3214fd0b8c6f35ad85592fc2917] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-tfm” 3bbba3214fd0b8c6f35ad85592fc2917] ---
if not modules then modules={} end modules ['luatex-fonts-tfm']={
version=1.001,
@@ -30767,10 +30922,10 @@ registertfmfeature {
}
}
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “fonts-tfm”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-tfm”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-lua” 55b281fb98f7bd848fc19928f376f647] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-lua” 55b281fb98f7bd848fc19928f376f647] ---
if not modules then modules={} end modules ['font-lua']={
version=1.001,
@@ -30810,10 +30965,10 @@ function readers.lua(specification)
return check_lua(specification,fullname)
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-lua”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-lua”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-def” c525b9f55da1c736a1f6939c0a6f8f00] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-def” 226b4d26ede7fa7be8e45b7f0d93e781] ---
if not modules then modules={} end modules ['font-def']={
version=1.001,
@@ -31178,8 +31333,9 @@ function definers.read(specification,size,id)
report_defining("already hashed: %s",hash)
end
else
- tfmdata=definers.loadfont(specification)
+ tfmdata=definers.loadfont(specification)
if tfmdata then
+ tfmdata.original=specification.specification
if trace_defining then
report_defining("loaded and hashed: %s",hash)
end
@@ -31212,10 +31368,378 @@ if not context then
callbacks.register('define_font',definers.read,"definition of fonts (tfmdata preparation)")
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-def”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-def”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “fonts-def” 5ad79120ebc5e60f4d322fb3ee13bffe] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-shp” c4a8c14513597ce3579d3ad4c580fe51] ---
+
+if not modules then modules={} end modules ['font-shp']={
+ version=1.001,
+ comment="companion to font-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local tonumber,next=tonumber,next
+local concat=table.concat
+local formatters=string.formatters
+local otf=fonts.handlers.otf
+local afm=fonts.handlers.afm
+local pfb=fonts.handlers.pfb
+local hashes=fonts.hashes
+local identifiers=hashes.identifiers
+local version=0.009
+local shapescache=containers.define("fonts","shapes",version,true)
+local streamscache=containers.define("fonts","streams",version,true)
+local compact_streams=false
+directives.register("fonts.streams.compact",function(v) compact_streams=v end)
+local function packoutlines(data,makesequence)
+ local subfonts=data.subfonts
+ if subfonts then
+ for i=1,#subfonts do
+ packoutlines(subfonts[i],makesequence)
+ end
+ return
+ end
+ local common=data.segments
+ if common then
+ return
+ end
+ local glyphs=data.glyphs
+ if not glyphs then
+ return
+ end
+ if makesequence then
+ for index=0,#glyphs do
+ local glyph=glyphs[index]
+ if glyph then
+ local segments=glyph.segments
+ if segments then
+ local sequence={}
+ local nofsequence=0
+ for i=1,#segments do
+ local segment=segments[i]
+ local nofsegment=#segment
+ nofsequence=nofsequence+1
+ sequence[nofsequence]=segment[nofsegment]
+ for i=1,nofsegment-1 do
+ nofsequence=nofsequence+1
+ sequence[nofsequence]=segment[i]
+ end
+ end
+ glyph.sequence=sequence
+ glyph.segments=nil
+ end
+ end
+ end
+ else
+ local hash={}
+ local common={}
+ local reverse={}
+ local last=0
+ for index=0,#glyphs do
+ local glyph=glyphs[index]
+ if glyph then
+ local segments=glyph.segments
+ if segments then
+ for i=1,#segments do
+ local h=concat(segments[i]," ")
+ hash[h]=(hash[h] or 0)+1
+ end
+ end
+ end
+ end
+ for index=0,#glyphs do
+ local glyph=glyphs[index]
+ if glyph then
+ local segments=glyph.segments
+ if segments then
+ for i=1,#segments do
+ local segment=segments[i]
+ local h=concat(segment," ")
+ if hash[h]>1 then
+ local idx=reverse[h]
+ if not idx then
+ last=last+1
+ reverse[h]=last
+ common[last]=segment
+ idx=last
+ end
+ segments[i]=idx
+ end
+ end
+ end
+ end
+ end
+ if last>0 then
+ data.segments=common
+ end
+ end
+end
+local function unpackoutlines(data)
+ local subfonts=data.subfonts
+ if subfonts then
+ for i=1,#subfonts do
+ unpackoutlines(subfonts[i])
+ end
+ return
+ end
+ local common=data.segments
+ if not common then
+ return
+ end
+ local glyphs=data.glyphs
+ if not glyphs then
+ return
+ end
+ for index=0,#glyphs do
+ local glyph=glyphs[index]
+ if glyph then
+ local segments=glyph.segments
+ if segments then
+ for i=1,#segments do
+ local c=common[segments[i]]
+ if c then
+ segments[i]=c
+ end
+ end
+ end
+ end
+ end
+ data.segments=nil
+end
+local readers=otf.readers
+local cleanname=otf.readers.helpers.cleanname
+local function makehash(filename,sub,instance)
+ local name=cleanname(file.basename(filename))
+ if instance then
+ return formatters["%s-%s-%s"](name,sub or 0,cleanname(instance))
+ else
+ return formatters["%s-%s"] (name,sub or 0)
+ end
+end
+local function loadoutlines(cache,filename,sub,instance)
+ local base=file.basename(filename)
+ local name=file.removesuffix(base)
+ local kind=file.suffix(filename)
+ local attr=lfs.attributes(filename)
+ local size=attr and attr.size or 0
+ local time=attr and attr.modification or 0
+ local sub=tonumber(sub)
+ if size>0 and (kind=="otf" or kind=="ttf" or kind=="tcc") then
+ local hash=makehash(filename,sub,instance)
+ data=containers.read(cache,hash)
+ if not data or data.time~=time or data.size~=size then
+ data=otf.readers.loadshapes(filename,sub,instance)
+ if data then
+ data.size=size
+ data.format=data.format or (kind=="otf" and "opentype") or "truetype"
+ data.time=time
+ packoutlines(data)
+ containers.write(cache,hash,data)
+ data=containers.read(cache,hash)
+ end
+ end
+ unpackoutlines(data)
+ elseif size>0 and (kind=="pfb") then
+ local hash=containers.cleanname(base)
+ data=containers.read(cache,hash)
+ if not data or data.time~=time or data.size~=size then
+ data=afm.readers.loadshapes(filename)
+ if data then
+ data.size=size
+ data.format="type1"
+ data.time=time
+ packoutlines(data)
+ containers.write(cache,hash,data)
+ data=containers.read(cache,hash)
+ end
+ end
+ unpackoutlines(data)
+ else
+ data={
+ filename=filename,
+ size=0,
+ time=time,
+ format="unknown",
+ units=1000,
+ glyphs={}
+ }
+ end
+ return data
+end
+local function cachethem(cache,hash,data)
+ containers.write(cache,hash,data,compact_streams)
+ return containers.read(cache,hash)
+end
+local function loadstreams(cache,filename,sub,instance)
+ local base=file.basename(filename)
+ local name=file.removesuffix(base)
+ local kind=file.suffix(filename)
+ local attr=lfs.attributes(filename)
+ local size=attr and attr.size or 0
+ local time=attr and attr.modification or 0
+ local sub=tonumber(sub)
+ if size>0 and (kind=="otf" or kind=="ttf" or kind=="ttc") then
+ local hash=makehash(filename,sub,instance)
+ data=containers.read(cache,hash)
+ if not data or data.time~=time or data.size~=size then
+ data=otf.readers.loadshapes(filename,sub,instance,true)
+ if data then
+ local glyphs=data.glyphs
+ local streams={}
+ if glyphs then
+ for i=0,#glyphs do
+ local glyph=glyphs[i]
+ if glyph then
+ streams[i]=glyph.stream or ""
+ else
+ streams[i]=""
+ end
+ end
+ end
+ data.streams=streams
+ data.glyphs=nil
+ data.size=size
+ data.format=data.format or (kind=="otf" and "opentype") or "truetype"
+ data.time=time
+ data=cachethem(cache,hash,data)
+ end
+ end
+ elseif size>0 and (kind=="pfb") then
+ local hash=makehash(filename,sub,instance)
+ data=containers.read(cache,hash)
+ if not data or data.time~=time or data.size~=size then
+ local names,encoding,streams,metadata=pfb.loadvector(filename,false,true)
+ if streams then
+ local fontbbox=metadata.fontbbox or { 0,0,0,0 }
+ for i=0,#streams do
+ streams[i]=streams[i].stream or "\14"
+ end
+ data={
+ filename=filename,
+ size=size,
+ time=time,
+ format="type1",
+ streams=streams,
+ fontheader={
+ fontversion=metadata.version,
+ units=1000,
+ xmin=fontbbox[1],
+ ymin=fontbbox[2],
+ xmax=fontbbox[3],
+ ymax=fontbbox[4],
+ },
+ horizontalheader={
+ ascender=0,
+ descender=0,
+ },
+ maximumprofile={
+ nofglyphs=#streams+1,
+ },
+ names={
+ copyright=metadata.copyright,
+ family=metadata.familyname,
+ fullname=metadata.fullname,
+ fontname=metadata.fontname,
+ subfamily=metadata.subfamilyname,
+ trademark=metadata.trademark,
+ notice=metadata.notice,
+ version=metadata.version,
+ },
+ cffinfo={
+ familyname=metadata.familyname,
+ fullname=metadata.fullname,
+ italicangle=metadata.italicangle,
+ monospaced=metadata.isfixedpitch and true or false,
+ underlineposition=metadata.underlineposition,
+ underlinethickness=metadata.underlinethickness,
+ weight=metadata.weight,
+ },
+ }
+ data=cachethem(cache,hash,data)
+ end
+ end
+ else
+ data={
+ filename=filename,
+ size=0,
+ time=time,
+ format="unknown",
+ streams={}
+ }
+ end
+ return data
+end
+local loadedshapes={}
+local loadedstreams={}
+local function loadoutlinedata(fontdata,streams)
+ local properties=fontdata.properties
+ local filename=properties.filename
+ local subindex=fontdata.subindex
+ local instance=properties.instance
+ local hash=makehash(filename,subindex,instance)
+ local loaded=loadedshapes[hash]
+ if not loaded then
+ loaded=loadoutlines(shapescache,filename,subindex,instance)
+ loadedshapes[hash]=loaded
+ end
+ return loaded
+end
+hashes.shapes=table.setmetatableindex(function(t,k)
+ local f=identifiers[k]
+ if f then
+ return loadoutlinedata(f)
+ end
+end)
+local function getstreamhash(fontid)
+ local fontdata=identifiers[fontid]
+ if fontdata then
+ local properties=fontdata.properties
+ return makehash(properties.filename,properties.subfont,properties.instance)
+ end
+end
+local function loadstreamdata(fontdata)
+ local properties=fontdata.properties
+ local shared=fontdata.shared
+ local rawdata=shared and shared.rawdata
+ local metadata=rawdata and rawdata.metadata
+ local filename=properties.filename
+ local subindex=metadata and metadata.subfontindex
+ local instance=properties.instance
+ local hash=makehash(filename,subindex,instance)
+ local loaded=loadedstreams[hash]
+ if not loaded then
+ loaded=loadstreams(streamscache,filename,subindex,instance)
+ loadedstreams[hash]=loaded
+ end
+ return loaded
+end
+hashes.streams=table.setmetatableindex(function(t,k)
+ local f=identifiers[k]
+ if f then
+ return loadstreamdata(f)
+ end
+end)
+otf.loadoutlinedata=loadoutlinedata
+otf.loadstreamdata=loadstreamdata
+otf.loadshapes=loadshapes
+otf.getstreamhash=getstreamhash
+local streams=fonts.hashes.streams
+callback.register("glyph_stream_provider",function(id,index,mode)
+ if id>0 then
+ local streams=streams[id].streams
+ if streams then
+ return streams[index] or ""
+ end
+ end
+ return ""
+end)
+
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-shp”] ---
+
+
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-def” 5ad79120ebc5e60f4d322fb3ee13bffe] ---
if not modules then modules={} end modules ['luatex-fonts-def']={
version=1.001,
@@ -31296,10 +31820,10 @@ function fonts.definers.applypostprocessors(tfmdata)
return tfmdata
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “fonts-def”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-def”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “fonts-ext” 01015ab3758cdc2af29394e6d502a91a] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-ext” 01015ab3758cdc2af29394e6d502a91a] ---
if not modules then modules={} end modules ['luatex-fonts-ext']={
version=1.001,
@@ -31485,10 +32009,10 @@ registerotffeature {
}
}
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “fonts-ext”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-ext”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-imp-tex” 77c374b0ef00c2fb12188ec42beb4257] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-imp-tex” 77c374b0ef00c2fb12188ec42beb4257] ---
if not modules then modules={} end modules ['font-imp-tex']={
version=1.001,
@@ -31587,10 +32111,10 @@ registerotffeature {
description="arabic digits",
}
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-imp-tex”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-imp-tex”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-imp-ligatures” 043daa4fcccf2560868da359d71d3a4a] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-imp-ligatures” 043daa4fcccf2560868da359d71d3a4a] ---
if not modules then modules={} end modules ['font-imp-ligatures']={
version=1.001,
@@ -31704,10 +32228,10 @@ if context then
}
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-imp-ligatures”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-imp-ligatures”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-imp-italics” fe1ca80fb5ea4a2f8d2d5c484e7ba913] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-imp-italics” 058fb834c11c6ac30c280b29e496966e] ---
if not modules then modules={} end modules ['font-imp-italics']={
version=1.001,
@@ -31776,8 +32300,6 @@ if context then
}
registerotffeature(specification)
registerafmfeature(specification)
-end
-if context then
local letter=characters.is_letter
local always=true
local function collapseitalics(tfmdata,key,value)
@@ -31813,10 +32335,10 @@ if context then
registerafmfeature(dimensions_specification)
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-imp-italics”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-imp-italics”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “font-imp-effects” 73a660359a0ec71e44cc2b7225a715ac] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-imp-effects” 582f9dd5031e9d67fff389efd16a874f] ---
if not modules then modules={} end modules ['font-imp-effects']={
version=1.001,
@@ -32049,6 +32571,7 @@ local function setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze
end
end
end
+local shiftmode=CONTEXTLMTXMODE>0
local function manipulateeffect(tfmdata)
local effect=tfmdata.properties.effect
if effect then
@@ -32070,38 +32593,45 @@ local function manipulateeffect(tfmdata)
local factor=(1+effect.factor)*factor
local hfactor=(1+effect.hfactor)*hfactor
local vfactor=(1+effect.vfactor)*vfactor
- local vshift=vshift~=0 and upcommand[vshift] or false
+ if shiftmode then
+ parameters.hshift=hshift
+ parameters.vshift=vshift
+ else
+ vshift=vshift~=0 and upcommand[vshift] or false
+ hshift=rightcommand[hshift]
+ end
for unicode,character in next,characters do
local oldwidth=character.width
local oldheight=character.height
local olddepth=character.depth
if oldwidth and oldwidth>0 then
character.width=oldwidth+wdelta
- local commands=character.commands
- local hshift=rightcommand[hshift]
- if vshift then
- if commands then
- prependcommands (commands,
- hshift,
- vshift
- )
- else
- character.commands={
- hshift,
- vshift,
- charcommand[unicode]
- }
- end
- else
- if commands then
- prependcommands (commands,
- hshift
- )
+ if not shiftmode then
+ local commands=character.commands
+ if vshift then
+ if commands then
+ prependcommands (commands,
+ hshift,
+ vshift
+ )
+ else
+ character.commands={
+ hshift,
+ vshift,
+ charcommand[unicode]
+ }
+ end
else
- character.commands={
- hshift,
- charcommand[unicode]
- }
+ if commands then
+ prependcommands (commands,
+ hshift
+ )
+ else
+ character.commands={
+ hshift,
+ charcommand[unicode]
+ }
+ end
end
end
end
@@ -32173,10 +32703,10 @@ local specification={
registerotffeature(specification)
registerafmfeature(specification)
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “font-imp-effects”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-imp-effects”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “fonts-lig” b9dbe77ce747d4c35bb2a20ffbe5aa51] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-lig” b9dbe77ce747d4c35bb2a20ffbe5aa51] ---
fonts.handlers.otf.addfeature {
@@ -34245,10 +34775,10 @@ fonts.handlers.otf.addfeature {
["type"]="ligature",
}
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “fonts-lig”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-lig”] ---
-do --- [luaotfload, fontloader-2020-05-01.lua scope for “fonts-gbn” d25472d54c4841db43a745764a63533e] ---
+do --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-gbn” d25472d54c4841db43a745764a63533e] ---
if not modules then modules={} end modules ['luatex-fonts-gbn']={
version=1.001,
@@ -34513,7 +35043,7 @@ function nodes.simple_font_handler(head,groupcode,size,packtype,direction)
return head
end
-end --- [luaotfload, fontloader-2020-05-01.lua scope for “fonts-gbn”] ---
+end --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-gbn”] ---
--- vim:ft=lua:sw=2:ts=8:et:tw=79
diff --git a/macros/luatex/generic/luaotfload/fontloader-basics-gen.lua b/macros/luatex/generic/luaotfload/fontloader-basics-gen.lua
index f52fec6967..5a6e90ceee 100644
--- a/macros/luatex/generic/luaotfload/fontloader-basics-gen.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-basics-gen.lua
@@ -105,14 +105,14 @@ utilities.parsers = utilities.parsers or {
end,
settings_to_hash = function(s)
local t = { }
- for k, v in gmatch(s,"([^%s,=]+)=([^%s,]+)") do
+ for k, v in gmatch((gsub(s,"^{(.*)}$", "%1")),"([^%s,=]+)=([^%s,]+)") do
t[k] = v
end
return t
end,
settings_to_hash_colon_too = function(s)
local t = { }
- for k, v in gmatch(s,"([^%s,=:]+)[=:]([^%s,]+)") do
+ for k, v in gmatch((gsub(s,"^{(.*)}$", "%1")),"([^%s,=:]+)[=:]([^%s,]+)") do
t[k] = v
end
return t
@@ -189,7 +189,7 @@ local readables = { }
local usingjit = jit
if not caches.namespace or caches.namespace == "" or caches.namespace == "context" then
- caches.namespace = 'generic-dev'
+ caches.namespace = 'generic'
end
do
diff --git a/macros/luatex/generic/luaotfload/fontloader-basics-nod.lua b/macros/luatex/generic/luaotfload/fontloader-basics-nod.lua
index 0fb768cf83..67abf707b1 100644
--- a/macros/luatex/generic/luaotfload/fontloader-basics-nod.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-basics-nod.lua
@@ -66,9 +66,10 @@ for k, v in next, disccodes do
disccodes[v] = k
end
-nodes.nodecodes = nodecodes
-nodes.glyphcodes = glyphcodes
-nodes.disccodes = disccodes
+nodes.nodecodes = nodecodes
+nodes.glyphcodes = glyphcodes
+nodes.disccodes = disccodes
+nodes.dirvalues = { lefttoright = 0, righttoleft = 1 }
nodes.handlers.protectglyphs = node.protect_glyphs -- beware: nodes!
nodes.handlers.unprotectglyphs = node.unprotect_glyphs -- beware: nodes!
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-cff.lua b/macros/luatex/generic/luaotfload/fontloader-font-cff.lua
index 72b0a038f1..b7d45392d6 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-cff.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-cff.lua
@@ -1,5 +1,6 @@
if not modules then modules = { } end modules ['font-cff'] = {
version = 1.001,
+ optimize = true,
comment = "companion to font-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -609,12 +610,15 @@ do
+ p_unsupported
)^1
- parsedictionaries = function(data,dictionaries,what)
+ parsedictionaries = function(data,dictionaries,version)
stack = { }
strings = data.strings
+ if trace_charstrings then
+ report("charstring format %a",version)
+ end
for i=1,#dictionaries do
top = 0
- result = what == "cff" and {
+ result = version == "cff" and {
monospaced = false,
italicangle = 0,
underlineposition = -100,
@@ -1517,7 +1521,7 @@ do
end
end
else
- -- error
+ top = top - nofregions * n
end
end
@@ -2261,8 +2265,8 @@ do
end
-local function readglobals(f,data)
- local routines = readlengths(f)
+local function readglobals(f,data,version)
+ local routines = readlengths(f,version == "cff2")
for i=1,#routines do
routines[i] = readbytetable(f,routines[i])
end
@@ -2320,14 +2324,14 @@ local function readprivates(f,data)
end
end
-local function readlocals(f,data,dictionary)
+local function readlocals(f,data,dictionary,version)
local header = data.header
local private = dictionary.private
if private then
local subroutineoffset = private.data.subroutines
if subroutineoffset ~= 0 then
setposition(f,header.offset+private.offset+subroutineoffset)
- local subroutines = readlengths(f)
+ local subroutines = readlengths(f,version == "cff2")
for i=1,#subroutines do
subroutines[i] = readbytetable(f,subroutines[i])
end
@@ -2344,7 +2348,7 @@ end
-- These charstrings are little programs and described in: Technical Note #5177. A truetype
-- font has only one dictionary.
-local function readcharstrings(f,data,what)
+local function readcharstrings(f,data,version)
local header = data.header
local dictionaries = data.dictionaries
local dictionary = dictionaries[1]
@@ -2355,7 +2359,7 @@ local function readcharstrings(f,data,what)
elseif stringtype == 2 then
setposition(f,header.offset+offset)
-- could be a metatable .. delayed loading
- local charstrings = readlengths(f,what=="cff2")
+ local charstrings = readlengths(f,version=="cff2")
local nofglyphs = #charstrings
for i=1,nofglyphs do
charstrings[i] = readstring(f,charstrings[i])
@@ -2390,7 +2394,8 @@ readers.parsecharstrings = parsecharstrings -- used in font-onr.lua (type 1)
local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams)
local dictionaries = data.dictionaries
local dictionary = dictionaries[1]
- readglobals(f,data)
+ local cid = not dictionary.private and dictionary.cid
+ readglobals(f,data,version)
readcharstrings(f,data,version)
if version == "cff2" then
dictionary.charset = nil
@@ -2398,9 +2403,27 @@ local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams)
readencodings(f,data)
readcharsets(f,data,dictionary)
end
+ if cid then
+ local fdarray = cid.fdarray
+ if fdarray then
+ setposition(f,data.header.offset + fdarray)
+ local dictionaries = readlengths(f,version=="cff2")
+ local nofdictionaries = #dictionaries
+ if nofdictionaries > 0 then
+ for i=1,nofdictionaries do
+ dictionaries[i] = readstring(f,dictionaries[i])
+ end
+ parsedictionaries(data,dictionaries)
+ dictionary.private = dictionaries[1].private
+ if nofdictionaries > 1 then
+ report("ignoring dictionaries > 1 in cid font")
+ end
+ end
+ end
+ end
readprivates(f,data)
parseprivates(data,data.dictionaries)
- readlocals(f,data,dictionary)
+ readlocals(f,data,dictionary,version)
startparsing(fontdata,data,streams)
parsecharstrings(fontdata,data,glyphs,doshapes,version,streams)
stopparsing(fontdata,data)
@@ -2412,7 +2435,7 @@ local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams)
local dictionary = dictionaries[1]
local cid = dictionary.cid
local cidselect = cid and cid.fdselect
- readglobals(f,data)
+ readglobals(f,data,version)
readcharstrings(f,data,version)
if version ~= "cff2" then
readencodings(f,data)
@@ -2458,7 +2481,7 @@ local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams)
local cidarray = cid.fdarray
if cidarray then
setposition(f,header.offset+cidarray)
- local dictionaries = readlengths(f)
+ local dictionaries = readlengths(f,version == "cff2")
for i=1,#dictionaries do
dictionaries[i] = readstring(f,dictionaries[i])
end
@@ -2466,7 +2489,7 @@ local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams)
cid.dictionaries = dictionaries
readcidprivates(f,data)
for i=1,#dictionaries do
- readlocals(f,data,dictionaries[i])
+ readlocals(f,data,dictionaries[i],version)
end
startparsing(fontdata,data,streams)
for i=1,#charstrings do
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-con.lua b/macros/luatex/generic/luaotfload/fontloader-font-con.lua
index 1bb63aa519..7162338c66 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-con.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-con.lua
@@ -191,6 +191,9 @@ function constructors.assignmathparameters(target,original) -- simple variant, n
if not mathparameters.FractionDelimiterDisplayStyleSize then
targetmathparameters.FractionDelimiterDisplayStyleSize = 2.40 * targetparameters.size
end
+ if not targetmathparameters.SpaceBeforeScript then
+ targetmathparameters.SpaceBeforeScript = targetmathparameters.SpaceAfterScript
+ end
target.mathparameters = targetmathparameters
end
end
@@ -210,60 +213,45 @@ end
-- we default to false, so a macro package has to enable it explicitly. In
-- LuaTeX the fullname is used to identify a font as being unique.
-constructors.sharefonts = false
-constructors.nofsharedfonts = 0
-local sharednames = { }
+local nofinstances = 0
+local instances = setmetatableindex(function(t,k)
+ nofinstances = nofinstances + 1
+ t[k] = nofinstances
+ return nofinstances
+end)
function constructors.trytosharefont(target,tfmdata)
- if constructors.sharefonts then -- not robust !
- local characters = target.characters
- local n = 1
- local t = { target.psname }
- local u = sortedkeys(characters)
- for i=1,#u do
- local k = u[i]
- n = n + 1 ; t[n] = k
- n = n + 1 ; t[n] = characters[k].index or k
+ local properties = target.properties
+ local instance = properties.instance
+ if instance then
+ local fullname = target.fullname
+ local fontname = target.fontname
+ local psname = target.psname
+ local format = tfmdata.properties.format
+ if format == "opentype" then
+ target.streamprovider = 1
+ elseif format == "truetype" then
+ target.streamprovider = 2
+ else
+ target.streamprovider = 0
end
- local h = md5.HEX(concat(t," "))
- local s = sharednames[h]
- if s then
- if trace_defining then
- report_defining("font %a uses backend resources of font %a",target.fullname,s)
+ if target.streamprovider > 0 then
+ if fullname then
+ fullname = fullname .. ":" .. instances[instance]
+ target.fullname = fullname
+ end
+ if fontname then
+ fontname = fontname .. ":" .. instances[instance]
+ target.fontname = fontname
+ end
+ if psname then
+ psname = psname .. ":" .. instances[instance]
+ target.psname = psname
end
- target.fullname = s
- constructors.nofsharedfonts = constructors.nofsharedfonts + 1
- target.properties.sharedwith = s
- else
- sharednames[h] = target.fullname
end
end
end
--- function constructors.enhanceparameters(parameters)
--- local xheight = parameters.x_height
--- local quad = parameters.quad
--- local space = parameters.space
--- local stretch = parameters.space_stretch
--- local shrink = parameters.space_shrink
--- local extra = parameters.extra_space
--- local slant = parameters.slant
--- -- synonyms
--- parameters.xheight = xheight
--- parameters.spacestretch = stretch
--- parameters.spaceshrink = shrink
--- parameters.extraspace = extra
--- parameters.em = quad
--- parameters.ex = xheight
--- parameters.slantperpoint = slant
--- parameters.spacing = {
--- width = space,
--- stretch = stretch,
--- shrink = shrink,
--- extra = extra,
--- }
--- end
-
local synonyms = {
exheight = "x_height",
xheight = "x_height",
@@ -463,6 +451,7 @@ function constructors.scale(tfmdata,specification)
target.format = properties.format
target.cache = constructors.cacheintex and "yes" or "renew"
--
+ local original = properties.original or tfmdata.original
local fontname = properties.fontname or tfmdata.fontname
local fullname = properties.fullname or tfmdata.fullname
local filename = properties.filename or tfmdata.filename
@@ -474,6 +463,7 @@ function constructors.scale(tfmdata,specification)
--
local psname, psfixed = fixedpsname(psname,fontname or fullname or file.nameonly(filename))
--
+ target.original = original
target.fontname = fontname
target.fullname = fullname
target.filename = filename
@@ -578,6 +568,15 @@ function constructors.scale(tfmdata,specification)
targetparameters.quad = targetquad
targetparameters.extra_space = targetextra_space
--
+ local hshift = parameters.hshift
+ if hshift then
+ targetparameters.hshift = delta * hshift
+ end
+ local vshift = parameters.vshift
+ if vshift then
+ targetparameters.vshift = delta * vshift
+ end
+ --
local ascender = parameters.ascender
if ascender then
targetparameters.ascender = delta * ascender
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-def.lua b/macros/luatex/generic/luaotfload/fontloader-font-def.lua
index e287bf79ce..b752b3258c 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-def.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-def.lua
@@ -207,9 +207,6 @@ function resolvers.name(specification)
features.normal = normal
end
normal.instance = instance
- -- if not callbacks.supported.glyph_stream_provider then
- -- normal.variableshapes = true -- for the moment
- -- end
end
--
local suffix = lower(suffixonly(resolved))
@@ -492,7 +489,9 @@ function definers.read(specification,size,id) -- id can be optional, name can al
end
else
tfmdata = definers.loadfont(specification) -- can be overloaded
+-- put in properties instead
if tfmdata then
+ tfmdata.original = specification.specification
if trace_defining then
report_defining("loaded and hashed: %s",hash)
end
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-dsp.lua b/macros/luatex/generic/luaotfload/fontloader-font-dsp.lua
index 3058be37b9..0cff896e8d 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-dsp.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-dsp.lua
@@ -1,5 +1,6 @@
if not modules then modules = { } end modules ['font-dsp'] = {
version = 1.001,
+ optimize = true,
comment = "companion to font-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -302,7 +303,7 @@ end)
-- values can be anything the min/max permits so we can either think of
-- real values of a fraction along the axis (probably easier)
--- wght:400,wdth:100,ital:1
+-- wght=400,wdth=100,ital=1
local function axistofactors(str)
local t = settings_to_hash(str)
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-imp-effects.lua b/macros/luatex/generic/luaotfload/fontloader-font-imp-effects.lua
index cc6e4c0bf8..bd6cce8795 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-imp-effects.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-imp-effects.lua
@@ -280,6 +280,9 @@ end
-- local show_effect = { "lua", "print('!')" }
+----- shiftmode = false -- test in mkiv and lmtx
+local shiftmode = CONTEXTLMTXMODE > 0
+
local function manipulateeffect(tfmdata)
local effect = tfmdata.properties.effect
if effect then
@@ -301,42 +304,49 @@ local function manipulateeffect(tfmdata)
local factor = (1 + effect.factor) * factor
local hfactor = (1 + effect.hfactor) * hfactor
local vfactor = (1 + effect.vfactor) * vfactor
- local vshift = vshift ~= 0 and upcommand[vshift] or false
+ if shiftmode then
+ parameters.hshift = hshift
+ parameters.vshift = vshift
+ else
+ vshift = vshift ~= 0 and upcommand[vshift] or false
+ hshift = rightcommand[hshift]
+ end
for unicode, character in next, characters do
local oldwidth = character.width
local oldheight = character.height
local olddepth = character.depth
if oldwidth and oldwidth > 0 then
character.width = oldwidth + wdelta
- local commands = character.commands
- local hshift = rightcommand[hshift]
- if vshift then
- if commands then
- prependcommands ( commands,
--- show_effect,
- hshift,
- vshift
- )
- else
- character.commands = {
--- show_effect,
- hshift,
- vshift,
- charcommand[unicode]
- }
- end
- else
- if commands then
- prependcommands ( commands,
--- show_effect,
- hshift
- )
+ if not shiftmode then
+ local commands = character.commands
+ if vshift then
+ if commands then
+ prependcommands ( commands,
+ -- show_effect,
+ hshift,
+ vshift
+ )
+ else
+ character.commands = {
+ -- show_effect,
+ hshift,
+ vshift,
+ charcommand[unicode]
+ }
+ end
else
- character.commands = {
--- show_effect,
- hshift,
- charcommand[unicode]
- }
+ if commands then
+ prependcommands ( commands,
+ -- show_effect,
+ hshift
+ )
+ else
+ character.commands = {
+ -- show_effect,
+ hshift,
+ charcommand[unicode]
+ }
+ end
end
end
end
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-imp-italics.lua b/macros/luatex/generic/luaotfload/fontloader-font-imp-italics.lua
index 83c785d387..3e172bedee 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-imp-italics.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-imp-italics.lua
@@ -79,33 +79,25 @@ if context then
registerotffeature(specification)
registerafmfeature(specification)
-end
-
--- no longer used
-
--- if context then
---
--- -- local function initializemathitalics(tfmdata,value) -- yes no delay
--- -- tfmdata.properties.mathitalics = toboolean(value)
--- -- end
--- --
--- -- local specification = {
--- -- name = "mathitalics",
--- -- description = "use alternative math italic correction",
--- -- initializers = {
--- -- base = initializemathitalics,
--- -- node = initializemathitalics,
--- -- }
--- -- }
--- --
--- -- registerotffeature(specification)
--- -- registerafmfeature(specification)
---
--- end
-
--- -- also not used, only when testing
-
-if context then
+ -- no longer used
+
+ -- local function initializemathitalics(tfmdata,value) -- yes no delay
+ -- tfmdata.properties.mathitalics = toboolean(value)
+ -- end
+ --
+ -- local specification = {
+ -- name = "mathitalics",
+ -- description = "use alternative math italic correction",
+ -- initializers = {
+ -- base = initializemathitalics,
+ -- node = initializemathitalics,
+ -- }
+ -- }
+ --
+ -- registerotffeature(specification)
+ -- registerafmfeature(specification)
+
+ -- only used when testing
local letter = characters.is_letter
local always = true
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-map.lua b/macros/luatex/generic/luaotfload/fontloader-font-map.lua
index 84a28a8b7e..c983ea9634 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-map.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-map.lua
@@ -1,5 +1,6 @@
if not modules then modules = { } end modules ['font-map'] = {
version = 1.001,
+ optimize = true,
comment = "companion to font-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -103,6 +104,7 @@ local hash = { }
local conc = { }
table.setmetatableindex(hash,function(t,k)
+ local v
if k < 0xD7FF or (k > 0xDFFF and k <= 0xFFFF) then
v = f_single(k)
else
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-ocl.lua b/macros/luatex/generic/luaotfload/fontloader-font-ocl.lua
index 094e8b88ee..e6a38af5c3 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-ocl.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-ocl.lua
@@ -5,12 +5,8 @@ if not modules then modules = { } end modules ['font-ocl'] = {
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
--- patched version 2020-05-06 UF (colr/restorefix --
--- todo : user list of colors
-if CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 then
- return
-end
+-- todo : user list of colors
local tostring, tonumber, next = tostring, tonumber, next
local round, max = math.round, math.round
@@ -151,85 +147,17 @@ local function convert(t,k)
return v
end
-local start = { "pdf", "mode", "font" } -- force text mode (so get q Q right)
------ stop = { "pdf", "mode", "page" } -- force page mode (else overlap)
-local push = { "pdf", "page", "q" }
-local pop = { "pdf", "page", "Q" }
-
--- -- This one results in color directives inside BT ET but has less q Q pairs. It
--- -- only shows the first glyph in acrobat and nothing more. No problem with other
--- -- renderers.
---
--- local function initializeoverlay(tfmdata,kind,value) -- hm, always value
--- if value then
--- local resources = tfmdata.resources
--- local palettes = resources.colorpalettes
--- if palettes then
--- --
--- local converted = resources.converted
--- if not converted then
--- converted = setmetatableindex(convert)
--- resources.converted = converted
--- end
--- local colorvalues = sharedpalettes[value] or converted[palettes[tonumber(value) or 1] or palettes[1]] or { }
--- local classes = #colorvalues
--- if classes == 0 then
--- return
--- end
--- --
--- local characters = tfmdata.characters
--- local descriptions = tfmdata.descriptions
--- local properties = tfmdata.properties
--- --
--- properties.virtualized = true
--- tfmdata.fonts = {
--- { id = 0 }
--- }
--- --
--- local getactualtext = otf.getactualtext
--- local default = colorvalues[#colorvalues]
--- local b, e = getactualtext(tounicode(0xFFFD))
--- local actualb = { "pdf", "page", b } -- saves tables
--- local actuale = { "pdf", "page", e } -- saves tables
--- --
--- for unicode, character in next, characters do
--- local description = descriptions[unicode]
--- if description then
--- local colorlist = description.colors
--- if colorlist then
--- local u = description.unicode or characters[unicode].unicode
--- local w = character.width or 0
--- local s = #colorlist
--- local goback = w ~= 0 and leftcommand[w] or nil -- needs checking: are widths the same
--- local t = {
--- start,
--- not u and actualb or { "pdf", "page", (getactualtext(tounicode(u))) },
--- push,
--- }
--- local n = 3
--- local l = nil
--- for i=1,s do
--- local entry = colorlist[i]
--- local v = colorvalues[entry.class] or default
--- if v and l ~= v then
--- n = n + 1 t[n] = v
--- l = v
--- end
--- n = n + 1 t[n] = charcommand[entry.slot]
--- if s > 1 and i < s and goback then
--- n = n + 1 t[n] = goback
--- end
--- end
--- n = n + 1 t[n] = pop
--- n = n + 1 t[n] = actuale
--- n = n + 1 t[n] = stop
--- character.commands = t
--- end
--- end
--- end
--- end
--- end
--- end
+-- At some point 'font' mode was added to the engine and we can assume that most distributions
+-- ship a luatex that has it; ancient versions are no longer supported anyway. Begin 2020 there
+-- was an actualtext related mail exchange with RM etc. that might result in similar mode keys
+-- in other tex->pdf programs because there is a bit of inconsistency in the way this is dealt
+-- with. Best is not to touch this code too much.
+
+local mode = { "pdf", "mode", "font" }
+local push = { "pdf", "page", "q" }
+local pop = { "pdf", "page", "Q" }
+
+-- see context git repository for older variant (pre 20200501 cleanup)
local function initializeoverlay(tfmdata,kind,value)
if value then
@@ -278,7 +206,7 @@ local function initializeoverlay(tfmdata,kind,value)
local s = #colorlist
local goback = w ~= 0 and leftcommand[w] or nil -- needs checking: are widths the same
local t = {
- start,
+ mode,
not u and actualb or { "pdf", "page", (getactualtext(tounicode(u))) },
push,
}
@@ -437,7 +365,7 @@ do
local savedata = io.savedata
local remove = os.remove
- if context and xml.convert then
+if context then
local xmlconvert = xml.convert
local xmlfirst = xml.first
@@ -452,13 +380,13 @@ do
return data
end
- else
+else
function otfsvg.filterglyph(entry,index) -- can be overloaded
return entry.data
end
- end
+end
local runner = sandbox and sandbox.registerrunner {
name = "otfsvg",
@@ -485,6 +413,16 @@ do
-- Because a generic setup can be flawed we need to catch bad inkscape runs which add a bit of
-- ugly overhead. Bah.
+ local new = nil
+
+ local function inkscapeformat(suffix)
+ if new == nil then
+ new = os.resultof("inkscape --version") or ""
+ new = new == "" or not find(new,"Inkscape%s*0")
+ end
+ return new and "filename" or suffix
+ end
+
function otfsvg.topdf(svgshapes,tfmdata)
local pdfshapes = { }
local inkscape = runner()
@@ -494,7 +432,7 @@ do
local nofshapes = #svgshapes
local f_svgfile = formatters["temp-otf-svg-shape-%i.svg"]
local f_pdffile = formatters["temp-otf-svg-shape-%i.pdf"]
- local f_convert = formatters["%s --export-pdf=%s\n"]
+ local f_convert = formatters["%s --export-%s=%s\n"]
local filterglyph = otfsvg.filterglyph
local nofdone = 0
local processed = { }
@@ -508,7 +446,7 @@ do
local svgfile = f_svgfile(index)
local pdffile = f_pdffile(index)
savedata(svgfile,data)
- inkscape:write(f_convert(svgfile,pdffile))
+ inkscape:write(f_convert(svgfile,inkscapeformat("pdf"),pdffile))
processed[index] = true
nofdone = nofdone + 1
if nofdone % 25 == 0 then
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-one.lua b/macros/luatex/generic/luaotfload/fontloader-font-one.lua
index 5387516b4d..a76c929859 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-one.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-one.lua
@@ -1,5 +1,6 @@
if not modules then modules = { } end modules ['font-one'] = {
version = 1.001,
+ optimize = true,
comment = "companion to font-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-onr.lua b/macros/luatex/generic/luaotfload/fontloader-font-onr.lua
index fc6bead588..c33b09f9e2 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-onr.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-onr.lua
@@ -1,5 +1,6 @@
if not modules then modules = { } end modules ['font-onr'] = {
version = 1.001,
+ optimize = true,
comment = "companion to font-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-ota.lua b/macros/luatex/generic/luaotfload/fontloader-font-ota.lua
index 6cbf4bb86f..ce1b22b50d 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-ota.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-ota.lua
@@ -9,6 +9,7 @@ if not modules then modules = { } end modules ['font-ota'] = {
-- context only
local type = type
+local setmetatableindex = table.setmetatableindex
if not trackers then trackers = { register = function() end } end
@@ -285,7 +286,7 @@ if not classifiers then
local f_nko, l_nko = characters.blockrange("nko")
local f_ext_a, l_ext_a = characters.blockrange("arabicextendeda")
- classifiers = table.setmetatableindex(function(t,k)
+ classifiers = setmetatableindex(function(t,k)
if type(k) == "number" then
local c = chardata[k]
local v = false
@@ -461,6 +462,119 @@ methods.syrc = methods.arab
methods.mand = methods.arab
methods.nko = methods.arab
+-- a quick first attemp .. more later
+
+do
+
+ -- https://github.com/n8willis/opentype-shaping-documents/blob/master/opentype-shaping-mongolian.md#joining-properties
+ -- todo syrc
+
+ local joining = setmetatableindex(function(t,k)
+ if type(k) == "number" then
+ local c = chardata[k]
+ local v = false
+ if c then
+ local mongolian = c.mongolian
+ --
+ v = mongolian
+ end
+ t[k] = v
+ return v
+ end
+ end)
+
+ function methods.mong(head,font,attr)
+ local first, last
+ local current = head
+ local done = false
+ local prevjoin = nil
+ local prestate = nil
+ current = tonut(current)
+
+ local function wrapup()
+ if last then
+ if last ~= first then
+ local s = getstate(last)
+ if s == s_medi then
+ setstate(last,s_fina)
+ elseif s == s_init then
+ setstate(last,s_isol)
+ end
+ end
+ last = nil
+ first = nil
+ prevjoin = nil
+ prestate = nil
+ end
+ end
+
+ while current do
+ local char, id = ischar(current,font)
+ if char and not getstate(current) then
+ local currjoin = joining[char]
+ done = true
+ if not last then
+ setstate(current,s_isol)
+ prevjoin = currjoin
+ first = current
+ last = current
+ prevstate = s_isol
+ elseif currjoin == "t" then -- transparent
+ -- keep state
+ last = current
+ elseif prevjoin == "d" or prevjoin == "jc" or prevjoin == "l" then
+ if currjoin == "d" or prevjoin == "jc" or prevjoin == "r" then
+ local s = getstate(last)
+ if s == s_isol then
+ setstate(last,s_init)
+ elseif s == s_fina then
+ setstate(last,s_medi)
+ end
+ setstate(current,s_fina)
+ prevstate = s_fina
+ elseif prevjoin == "nj" or prevjoin == "l" then
+ local s = getstate(last)
+ if s == s_medi then
+ setstate(last,s_fina)
+ elseif s == s_init then
+ setstate(last,s_isol)
+ end
+ setstate(current,s_isol)
+ prevstate = s_isol
+ end
+ prevjoin = currjoin
+ last = current
+ elseif prevjoin == "nj" or prevjoin == "r" then
+ if s == s_medi then
+ setstate(last,s_fina)
+ elseif s == s_init then
+ setstate(last,s_isol)
+ end
+ setstate(current,s_isol)
+ prevjoin = currjoin
+ prevstate = s_isol
+ last = current
+ elseif last then
+ wrapup()
+ end
+ else
+ if last then
+ wrapup()
+ end
+ if id == math_code then -- a bit duplicate as we test for glyphs twice
+ current = end_of_math(current)
+ end
+ end
+ current = getnext(current)
+ end
+ if last then
+ wrapup()
+ end
+ return head, done
+ end
+
+end
+
directives.register("otf.analyze.useunicodemarks",function(v)
analyzers.useunicodemarks = v
end)
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-otj.lua b/macros/luatex/generic/luaotfload/fontloader-font-otj.lua
index bec52d813f..bb02044dca 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-otj.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-otj.lua
@@ -1,5 +1,6 @@
if not modules then modules = { } end modules ['font-otj'] = {
version = 1.001,
+ optimize = true,
comment = "companion to font-lib.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-otr.lua b/macros/luatex/generic/luaotfload/fontloader-font-otr.lua
index e726053202..531f665de7 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-otr.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-otr.lua
@@ -1,5 +1,6 @@
if not modules then modules = { } end modules ['font-otr'] = {
version = 1.001,
+ optimize = true,
comment = "companion to font-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -2084,8 +2085,6 @@ local function readtable(tag,f,fontdata,specification,...)
end
end
-local variablefonts_supported = (context and true) or (logs and logs.application and true) or false
-
local function readdata(f,offset,specification)
local fontdata, tables = loadtables(f,specification,offset)
@@ -2094,12 +2093,6 @@ local function readdata(f,offset,specification)
prepareglyps(fontdata)
end
- if not variablefonts_supported then
- specification.instance = nil
- specification.variable = nil
- specification.factors = nil
- end
-
fontdata.temporary = { }
readtable("name",f,fontdata,specification)
@@ -2118,71 +2111,66 @@ local function readdata(f,offset,specification)
readtable("avar",f,fontdata,specification)
readtable("fvar",f,fontdata,specification)
- if variablefonts_supported then
-
- local variabledata = fontdata.variabledata
-
- if variabledata then
- local instances = variabledata.instances
- local axis = variabledata.axis
- if axis and (not instances or #instances == 0) then
- instances = { }
- variabledata.instances = instances
- local function add(n,subfamily,value)
- local values = { }
- for i=1,#axis do
- local a = axis[i]
- values[i] = {
- axis = a.tag,
- value = i == n and value or a.default,
- }
- end
- instances[#instances+1] = {
- subfamily = subfamily,
- values = values,
- }
- end
+ local variabledata = fontdata.variabledata
+
+ if variabledata then
+ local instances = variabledata.instances
+ local axis = variabledata.axis
+ if axis and (not instances or #instances == 0) then
+ instances = { }
+ variabledata.instances = instances
+ local function add(n,subfamily,value)
+ local values = { }
for i=1,#axis do
- local a = axis[i]
- local tag = a.tag
- add(i,"default"..tag,a.default)
- add(i,"minimum"..tag,a.minimum)
- add(i,"maximum"..tag,a.maximum)
+ local a = axis[i]
+ values[i] = {
+ axis = a.tag,
+ value = i == n and value or a.default,
+ }
end
- -- report("%i fake instances added",#instances)
+ instances[#instances+1] = {
+ subfamily = subfamily,
+ values = values,
+ }
end
- end
-
- if not specification.factors then
- local instance = specification.instance
- if type(instance) == "string" then
- local factors = helpers.getfactors(fontdata,instance)
- if factors then
- specification.factors = factors
- fontdata.factors = factors
- fontdata.instance = instance
- report("user instance: %s, factors: % t",instance,factors)
- else
- report("user instance: %s, bad factors",instance)
- end
+ for i=1,#axis do
+ local a = axis[i]
+ local tag = a.tag
+ add(i,"default"..tag,a.default)
+ add(i,"minimum"..tag,a.minimum)
+ add(i,"maximum"..tag,a.maximum)
end
+ -- report("%i fake instances added",#instances)
end
-
- if not fontdata.factors then
- if fontdata.variabledata then
- local factors = helpers.getfactors(fontdata,true)
- if factors then
- specification.factors = factors
- fontdata.factors = factors
- -- report("factors: % t",factors)
- -- else
- -- report("bad factors")
- end
+ end
+ if not specification.factors then
+ local instance = specification.instance
+ if type(instance) == "string" then
+ local factors = helpers.getfactors(fontdata,instance)
+ if factors then
+ specification.factors = factors
+ fontdata.factors = factors
+ fontdata.instance = instance
+ report("user instance: %s, factors: % t",instance,factors)
else
- -- report("unknown instance")
+ report("user instance: %s, bad factors",instance)
end
end
+ end
+ if not fontdata.factors then
+ if fontdata.variabledata then
+ local factors = helpers.getfactors(fontdata,true)
+ if factors then
+ specification.factors = factors
+ fontdata.factors = factors
+ -- report("factors: % t",factors)
+ -- else
+ -- report("bad factors")
+ end
+ else
+ -- report("unknown instance")
+ end
end
readtable("os/2",f,fontdata,specification)
@@ -2433,6 +2421,7 @@ function readers.loadfont(filename,n,instance)
hascolor = fontdata.hascolor or false,
instance = fontdata.instance,
factors = fontdata.factors,
+ nofsubfonts = fontdata.subfonts and #fontdata.subfonts or nil,
},
resources = {
-- filename = fontdata.filename,
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-ots.lua b/macros/luatex/generic/luaotfload/fontloader-font-ots.lua
index 3b6ea6a726..490f28de69 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-ots.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-ots.lua
@@ -1,5 +1,6 @@
if not modules then modules = { } end modules ['font-ots'] = { -- sequences
version = 1.001,
+ optimize = true,
comment = "companion to font-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -25,7 +26,7 @@ effect that suddenly fonts behave differently. We don't want to catch all font
issues.</p>
<p>After a lot of experiments (mostly by Taco, me and Idris) the first implementation
-becaus quite useful. When it did most of what we wanted, a more optimized version
+was already quite useful. When it did most of what we wanted, a more optimized version
evolved. Of course all errors are mine and of course the code can be improved. There
are quite some optimizations going on here and processing speed is currently quite
acceptable and has been improved over time. Many complex scripts are not yet supported
@@ -252,6 +253,9 @@ local math_code = nodecodes.math
local dir_code = nodecodes.dir
local localpar_code = nodecodes.localpar
+local lefttoright_code = nodes.dirvalues.lefttoright
+local righttoleft_code = nodes.dirvalues.righttoleft
+
local discretionarydisc_code = disccodes.discretionary
local ligatureglyph_code = glyphcodes.ligature
@@ -2056,6 +2060,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
local sweepnode = sweepnode
local sweeptype = sweeptype
local sweepoverflow = false
+ local checkdisc = getprev(head)
local keepdisc = not sweepnode
local lookaheaddisc = nil
local backtrackdisc = nil
@@ -2089,6 +2094,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
sweepnode = current
current = getnext(current)
else
+ -- we can use an iterator
while replace and i <= l do
if getid(replace) == glyph_code then
i = i + 1
@@ -2189,7 +2195,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
local current = prev
local i = f
local t = sweeptype == "pre" or sweeptype == "replace"
- if not current and t and current == checkdisk then
+ if not current and t and current == checkdisc then
current = getprev(sweepnode)
end
while current and i > 1 do -- missing getprev added / moved outside
@@ -2218,7 +2224,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
end
end
current = getprev(current)
- if t and current == checkdisk then
+ if t and current == checkdisc then
current = getprev(sweepnode)
end
end
@@ -2443,6 +2449,10 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
local current = start
local last = start
+ if s == 1 then
+ goto next
+ end
+
-- current match
if l > f then
@@ -2512,10 +2522,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
break
end
end
- -- commented, for Kai to check
- -- if n <= l then
- -- notmatchpre[last] = true
- -- end
+ if n <= l then
+ notmatchpre[last] = true
+ end
else
notmatchpre[last] = true
end
@@ -3620,8 +3629,6 @@ end
local txtdirstate, pardirstate do -- this might change (no need for nxt in pardirstate)
local getdirection = nuts.getdirection
- local lefttoright = 0
- local righttoleft = 1
txtdirstate = function(start,stack,top,rlparmode)
local dir, pop = getdirection(start)
@@ -3630,19 +3637,19 @@ local txtdirstate, pardirstate do -- this might change (no need for nxt in pard
return 0, rlparmode
else
top = top - 1
- if stack[top] == righttoleft then
+ if stack[top] == righttoleft_code then
return top, -1
else
return top, 1
end
end
- elseif dir == lefttoright then
+ elseif dir == lefttoright_code then
top = top + 1
- stack[top] = lefttoright
+ stack[top] = lefttoright_code
return top, 1
- elseif dir == righttoleft then
+ elseif dir == righttoleft_code then
top = top + 1
- stack[top] = righttoleft
+ stack[top] = righttoleft_code
return top, -1
else
return top, rlparmode
@@ -3651,14 +3658,9 @@ local txtdirstate, pardirstate do -- this might change (no need for nxt in pard
pardirstate = function(start)
local dir = getdirection(start)
- if dir == lefttoright then
- return 1, 1
- elseif dir == righttoleft then
- return -1, -1
- -- for old times sake we we handle strings too
- elseif dir == "TLT" then
+ if dir == lefttoright_code then
return 1, 1
- elseif dir == "TRT" then
+ elseif dir == righttoleft_code then
return -1, -1
else
return 0, 0
@@ -3759,7 +3761,7 @@ do
if getid(head) == localpar_code and start_of_par(head) then
initialrl = pardirstate(head)
- elseif direction == 1 or direction == "TRT" then
+ elseif direction == righttoleft_code then
initialrl = -1
end
@@ -4054,7 +4056,7 @@ do
local done = false
local dirstack = { nil } -- could move outside function but we can have local runs (maybe a few more nils)
local start = head
- local initialrl = (direction == 1 or direction == "TRT") and -1 or 0
+ local initialrl = (direction == righttoleft_code) and -1 or 0
local rlmode = initialrl
local rlparmode = initialrl
local topstack = 0
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-ott.lua b/macros/luatex/generic/luaotfload/fontloader-font-ott.lua
index c9e467f225..f4d7e05a13 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-ott.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-ott.lua
@@ -1117,41 +1117,6 @@ local checkers = {
end
}
--- Keep this:
---
--- function otf.features.normalize(features)
--- if features then
--- local h = { }
--- for k, v in next, features do
--- k = lower(k)
--- if k == "language" then
--- v = gsub(lower(v),"[^a-z0-9]","")
--- h.language = rawget(verboselanguages,v) or (languages[v] and v) or "dflt" -- auto adds
--- elseif k == "script" then
--- v = gsub(lower(v),"[^a-z0-9]","")
--- h.script = rawget(verbosescripts,v) or (scripts[v] and v) or "dflt" -- auto adds
--- else
--- if type(v) == "string" then
--- local b = is_boolean(v)
--- if type(b) == "nil" then
--- v = tonumber(v) or lower(v)
--- else
--- v = b
--- end
--- end
--- if not rawget(features,k) then
--- k = rawget(verbosefeatures,k) or k
--- end
--- local c = checkers[k]
--- h[k] = c and c(v) or v
--- end
--- end
--- return h
--- end
--- end
-
--- inspect(fonts.handlers.otf.statistics.usedfeatures)
-
if not storage then
return
end
@@ -1178,9 +1143,6 @@ function otffeatures.normalize(features,wrap) -- wrap is for context
h.script = rawget(verbosescripts,v) or (scripts[v] and v) or "dflt" -- auto adds
elseif k == "axis" then
h[k] = normalizedaxis(value)
- if not callbacks.supported.glyph_stream_provider then
- h.variableshapes = true -- for the moment
- end
else
local uk = usedfeatures[key]
local uv = uk[value]
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-shp.lua b/macros/luatex/generic/luaotfload/fontloader-font-shp.lua
new file mode 100644
index 0000000000..c3fea6d460
--- /dev/null
+++ b/macros/luatex/generic/luaotfload/fontloader-font-shp.lua
@@ -0,0 +1,395 @@
+if not modules then modules = { } end modules ['font-shp'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local tonumber, next = tonumber, next
+local concat = table.concat
+local formatters = string.formatters
+
+local otf = fonts.handlers.otf
+local afm = fonts.handlers.afm
+local pfb = fonts.handlers.pfb
+
+local hashes = fonts.hashes
+local identifiers = hashes.identifiers
+
+local version = 0.009
+local shapescache = containers.define("fonts", "shapes", version, true)
+local streamscache = containers.define("fonts", "streams", version, true)
+
+-- shapes (can be come a separate file at some point)
+
+local compact_streams = false
+
+directives.register("fonts.streams.compact", function(v) compact_streams = v end)
+
+local function packoutlines(data,makesequence)
+ local subfonts = data.subfonts
+ if subfonts then
+ for i=1,#subfonts do
+ packoutlines(subfonts[i],makesequence)
+ end
+ return
+ end
+ local common = data.segments
+ if common then
+ return
+ end
+ local glyphs = data.glyphs
+ if not glyphs then
+ return
+ end
+ if makesequence then
+ for index=0,#glyphs do
+ local glyph = glyphs[index]
+ if glyph then
+ local segments = glyph.segments
+ if segments then
+ local sequence = { }
+ local nofsequence = 0
+ for i=1,#segments do
+ local segment = segments[i]
+ local nofsegment = #segment
+ -- why last first ... needs documenting
+ nofsequence = nofsequence + 1
+ sequence[nofsequence] = segment[nofsegment]
+ for i=1,nofsegment-1 do
+ nofsequence = nofsequence + 1
+ sequence[nofsequence] = segment[i]
+ end
+ end
+ glyph.sequence = sequence
+ glyph.segments = nil
+ end
+ end
+ end
+ else
+ local hash = { }
+ local common = { }
+ local reverse = { }
+ local last = 0
+ for index=0,#glyphs do
+ local glyph = glyphs[index]
+ if glyph then
+ local segments = glyph.segments
+ if segments then
+ for i=1,#segments do
+ local h = concat(segments[i]," ")
+ hash[h] = (hash[h] or 0) + 1
+ end
+ end
+ end
+ end
+ for index=0,#glyphs do
+ local glyph = glyphs[index]
+ if glyph then
+ local segments = glyph.segments
+ if segments then
+ for i=1,#segments do
+ local segment = segments[i]
+ local h = concat(segment," ")
+ if hash[h] > 1 then -- minimal one shared in order to hash
+ local idx = reverse[h]
+ if not idx then
+ last = last + 1
+ reverse[h] = last
+ common[last] = segment
+ idx = last
+ end
+ segments[i] = idx
+ end
+ end
+ end
+ end
+ end
+ if last > 0 then
+ data.segments = common
+ end
+ end
+end
+
+local function unpackoutlines(data)
+ local subfonts = data.subfonts
+ if subfonts then
+ for i=1,#subfonts do
+ unpackoutlines(subfonts[i])
+ end
+ return
+ end
+ local common = data.segments
+ if not common then
+ return
+ end
+ local glyphs = data.glyphs
+ if not glyphs then
+ return
+ end
+ for index=0,#glyphs do
+ local glyph = glyphs[index]
+ if glyph then
+ local segments = glyph.segments
+ if segments then
+ for i=1,#segments do
+ local c = common[segments[i]]
+ if c then
+ segments[i] = c
+ end
+ end
+ end
+ end
+ end
+ data.segments = nil
+end
+
+-- todo: loaders per format
+
+local readers = otf.readers
+local cleanname = otf.readers.helpers.cleanname
+
+local function makehash(filename,sub,instance)
+ local name = cleanname(file.basename(filename))
+ if instance then
+ return formatters["%s-%s-%s"](name,sub or 0,cleanname(instance))
+ else
+ return formatters["%s-%s"] (name,sub or 0)
+ end
+end
+
+local function loadoutlines(cache,filename,sub,instance)
+ local base = file.basename(filename)
+ local name = file.removesuffix(base)
+ local kind = file.suffix(filename)
+ local attr = lfs.attributes(filename)
+ local size = attr and attr.size or 0
+ local time = attr and attr.modification or 0
+ local sub = tonumber(sub)
+
+ -- fonts.formats
+
+ if size > 0 and (kind == "otf" or kind == "ttf" or kind == "tcc") then
+ local hash = makehash(filename,sub,instance)
+ data = containers.read(cache,hash)
+ if not data or data.time ~= time or data.size ~= size then
+ data = otf.readers.loadshapes(filename,sub,instance)
+ if data then
+ data.size = size
+ data.format = data.format or (kind == "otf" and "opentype") or "truetype"
+ data.time = time
+ packoutlines(data)
+ containers.write(cache,hash,data)
+ data = containers.read(cache,hash) -- frees old mem
+ end
+ end
+ unpackoutlines(data)
+ elseif size > 0 and (kind == "pfb") then
+ local hash = containers.cleanname(base) -- including suffix
+ data = containers.read(cache,hash)
+ if not data or data.time ~= time or data.size ~= size then
+ data = afm.readers.loadshapes(filename)
+ if data then
+ data.size = size
+ data.format = "type1"
+ data.time = time
+ packoutlines(data)
+ containers.write(cache,hash,data)
+ data = containers.read(cache,hash) -- frees old mem
+ end
+ end
+ unpackoutlines(data)
+ else
+ data = {
+ filename = filename,
+ size = 0,
+ time = time,
+ format = "unknown",
+ units = 1000,
+ glyphs = { }
+ }
+ end
+ return data
+end
+
+local function cachethem(cache,hash,data)
+ containers.write(cache,hash,data,compact_streams) -- arg 4 aka fast
+ return containers.read(cache,hash) -- frees old mem
+end
+
+local function loadstreams(cache,filename,sub,instance)
+ local base = file.basename(filename)
+ local name = file.removesuffix(base)
+ local kind = file.suffix(filename)
+ local attr = lfs.attributes(filename)
+ local size = attr and attr.size or 0
+ local time = attr and attr.modification or 0
+ local sub = tonumber(sub)
+ if size > 0 and (kind == "otf" or kind == "ttf" or kind == "ttc") then
+ local hash = makehash(filename,sub,instance)
+ data = containers.read(cache,hash)
+ if not data or data.time ~= time or data.size ~= size then
+ data = otf.readers.loadshapes(filename,sub,instance,true)
+ if data then
+ local glyphs = data.glyphs
+ local streams = { }
+ if glyphs then
+ for i=0,#glyphs do
+ local glyph = glyphs[i]
+ if glyph then
+ streams[i] = glyph.stream or ""
+ else
+ streams[i] = ""
+ end
+ end
+ end
+ data.streams = streams
+ data.glyphs = nil
+ data.size = size
+ data.format = data.format or (kind == "otf" and "opentype") or "truetype"
+ data.time = time
+ data = cachethem(cache,hash,data)
+ end
+ end
+ elseif size > 0 and (kind == "pfb") then
+ local hash = makehash(filename,sub,instance)
+ data = containers.read(cache,hash)
+ if not data or data.time ~= time or data.size ~= size then
+ local names, encoding, streams, metadata = pfb.loadvector(filename,false,true)
+ if streams then
+ local fontbbox = metadata.fontbbox or { 0, 0, 0, 0 }
+ for i=0,#streams do
+ streams[i] = streams[i].stream or "\14"
+ end
+ data = {
+ filename = filename,
+ size = size,
+ time = time,
+ format = "type1",
+ streams = streams,
+ fontheader = {
+ fontversion = metadata.version,
+ units = 1000, -- can this be different?
+ xmin = fontbbox[1],
+ ymin = fontbbox[2],
+ xmax = fontbbox[3],
+ ymax = fontbbox[4],
+ },
+ horizontalheader = {
+ ascender = 0,
+ descender = 0,
+ },
+ maximumprofile = {
+ nofglyphs = #streams + 1,
+ },
+ names = {
+ copyright = metadata.copyright,
+ family = metadata.familyname,
+ fullname = metadata.fullname,
+ fontname = metadata.fontname,
+ subfamily = metadata.subfamilyname,
+ trademark = metadata.trademark,
+ notice = metadata.notice,
+ version = metadata.version,
+ },
+ cffinfo = {
+ familyname = metadata.familyname,
+ fullname = metadata.fullname,
+ italicangle = metadata.italicangle,
+ monospaced = metadata.isfixedpitch and true or false,
+ underlineposition = metadata.underlineposition,
+ underlinethickness = metadata.underlinethickness,
+ weight = metadata.weight,
+ },
+ }
+ data = cachethem(cache,hash,data)
+ end
+ end
+ else
+ data = {
+ filename = filename,
+ size = 0,
+ time = time,
+ format = "unknown",
+ streams = { }
+ }
+ end
+ return data
+end
+
+local loadedshapes = { }
+local loadedstreams = { }
+
+local function loadoutlinedata(fontdata,streams)
+ local properties = fontdata.properties
+ local filename = properties.filename
+ local subindex = fontdata.subindex
+ local instance = properties.instance
+ local hash = makehash(filename,subindex,instance)
+ local loaded = loadedshapes[hash]
+ if not loaded then
+ loaded = loadoutlines(shapescache,filename,subindex,instance)
+ loadedshapes[hash] = loaded
+ end
+ return loaded
+end
+
+hashes.shapes = table.setmetatableindex(function(t,k)
+ local f = identifiers[k]
+ if f then
+ return loadoutlinedata(f)
+ end
+end)
+
+local function getstreamhash(fontid)
+ local fontdata = identifiers[fontid]
+ if fontdata then
+ local properties = fontdata.properties
+ return makehash(properties.filename,properties.subfont,properties.instance)
+ end
+end
+
+local function loadstreamdata(fontdata)
+ local properties = fontdata.properties
+ local shared = fontdata.shared
+ local rawdata = shared and shared.rawdata
+ local metadata = rawdata and rawdata.metadata
+ local filename = properties.filename
+ local subindex = metadata and metadata.subfontindex
+ local instance = properties.instance
+ local hash = makehash(filename,subindex,instance)
+ local loaded = loadedstreams[hash]
+ if not loaded then
+ loaded = loadstreams(streamscache,filename,subindex,instance)
+ loadedstreams[hash] = loaded
+ end
+ return loaded
+end
+
+hashes.streams = table.setmetatableindex(function(t,k)
+ local f = identifiers[k]
+ if f then
+ return loadstreamdata(f)
+ end
+end)
+
+otf.loadoutlinedata = loadoutlinedata -- not public
+otf.loadstreamdata = loadstreamdata -- not public
+otf.loadshapes = loadshapes
+otf.getstreamhash = getstreamhash -- not public, might move to other namespace
+
+local streams = fonts.hashes.streams
+
+-- we can now assume that luatex has this one
+
+callback.register("glyph_stream_provider",function(id,index,mode)
+ if id > 0 then
+ local streams = streams[id].streams
+ -- print(id,index,streams[index])
+ if streams then
+ return streams[index] or ""
+ end
+ end
+ return ""
+end)
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-ttf.lua b/macros/luatex/generic/luaotfload/fontloader-font-ttf.lua
index 651ede17e2..865f8e6e30 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-ttf.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-ttf.lua
@@ -1,5 +1,6 @@
if not modules then modules = { } end modules ['font-ttf'] = {
version = 1.001,
+ optimize = true,
comment = "companion to font-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-vfc.lua b/macros/luatex/generic/luaotfload/fontloader-font-vfc.lua
index dfe6b3afc4..eff0aa6c63 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-vfc.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-vfc.lua
@@ -13,7 +13,7 @@ local fonts = fonts
local helpers = fonts.helpers
local setmetatableindex = table.setmetatableindex
-local makeweak = table.makeweak
+----- makeweak = table.makeweak
-- Helpers dealing with virtual fonts: beware, these are final values so
-- don't change the content of tables gotten this way!
diff --git a/macros/luatex/generic/luaotfload/fontloader-l-lpeg.lua b/macros/luatex/generic/luaotfload/fontloader-l-lpeg.lua
index 7979a40fb9..b0868ba488 100644
--- a/macros/luatex/generic/luaotfload/fontloader-l-lpeg.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-l-lpeg.lua
@@ -203,12 +203,14 @@ local collapser = Cs(spacer^0/"" * nonspacer^0 * ((spacer^0/" " * nonspac
local nospacer = Cs((whitespace^1/"" + nonwhitespace^1)^0)
local b_collapser = Cs( whitespace^0 /"" * (nonwhitespace^1 + whitespace^1/" ")^0)
-local e_collapser = Cs((whitespace^1 * endofstring/"" + nonwhitespace^1 + whitespace^1/" ")^0)
local m_collapser = Cs( (nonwhitespace^1 + whitespace^1/" ")^0)
+local e_collapser = Cs((whitespace^1 * endofstring/"" + nonwhitespace^1 + whitespace^1/" ")^0)
+local x_collapser = Cs( (nonwhitespace^1 + whitespace^1/"" )^0)
local b_stripper = Cs( spacer^0 /"" * (nonspacer^1 + spacer^1/" ")^0)
-local e_stripper = Cs((spacer^1 * endofstring/"" + nonspacer^1 + spacer^1/" ")^0)
local m_stripper = Cs( (nonspacer^1 + spacer^1/" ")^0)
+local e_stripper = Cs((spacer^1 * endofstring/"" + nonspacer^1 + spacer^1/" ")^0)
+local x_stripper = Cs( (nonspacer^1 + spacer^1/"" )^0)
patterns.stripper = stripper
patterns.fullstripper = fullstripper
@@ -218,10 +220,12 @@ patterns.nospacer = nospacer
patterns.b_collapser = b_collapser
patterns.m_collapser = m_collapser
patterns.e_collapser = e_collapser
+patterns.x_collapser = x_collapser
patterns.b_stripper = b_stripper
patterns.m_stripper = m_stripper
patterns.e_stripper = e_stripper
+patterns.x_stripper = x_stripper
patterns.lowercase = lowercase
patterns.uppercase = uppercase
diff --git a/macros/luatex/generic/luaotfload/fontloader-l-lua.lua b/macros/luatex/generic/luaotfload/fontloader-l-lua.lua
index f411230d4a..00989c5cea 100644
--- a/macros/luatex/generic/luaotfload/fontloader-l-lua.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-l-lua.lua
@@ -195,12 +195,6 @@ function optionalrequire(...)
end
end
--- nice for non ascii scripts (this might move):
-
-if lua then
- lua.mask = load([[τεχ = 1]]) and "utf" or "ascii"
-end
-
local flush = io.flush
if flush then
diff --git a/macros/luatex/generic/luaotfload/fontloader-l-unicode.lua b/macros/luatex/generic/luaotfload/fontloader-l-unicode.lua
index c57aaf33eb..03016ed901 100644
--- a/macros/luatex/generic/luaotfload/fontloader-l-unicode.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-l-unicode.lua
@@ -1,5 +1,6 @@
if not modules then modules = { } end modules ['l-unicode'] = {
version = 1.001,
+ optimize = true,
comment = "companion to luat-lib.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
diff --git a/macros/luatex/generic/luaotfload/fontloader-reference-load-order.lua b/macros/luatex/generic/luaotfload/fontloader-reference-load-order.lua
index 9f45408b1b..d6c03108a2 100644
--- a/macros/luatex/generic/luaotfload/fontloader-reference-load-order.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-reference-load-order.lua
@@ -44,9 +44,30 @@ if not modules then modules = { } end modules ['luatex-fonts'] = {
-- and interferences between mechanisms between macro packages. We use the rendering in context
-- and luatex-plain as reference for issues.
+-- I might as well remove some code that is not used in generic (or not used by generic users)
+-- like color fonts (emoji etc) and variable fonts thereby making the code base smaller. However
+-- I might keep ity just for the sake of testing the plain loader that comes with context. We'll
+-- see.
+
+-- As a side effect of cleaning up some context code, like code meant for older version of luatex,
+-- as well replacing code for more recent versions (post 1.12) there can be changes in the modules
+-- used here, especially where we check for 'context' being used. Hopefully there are no side
+-- effects. Because we can now assume that the the glyph injection callback is in recent texlive
+-- installations, the variable font code is now enabled in the generic version that comes with
+-- context (as unofficial bonus; when it was demonstrated at bachotex 2017 it worked ok for the
+-- generic loader but was kind of disabled there as no one needs it). I waited with adding the
+-- pending code for type 3 support till texlive 2020 was fozen but it will be in texlive 2021 (it
+-- is already tested in context back in 2019 and I wanted to release it at the canceled BT 2020
+-- meeting, so I consider it stable, read: this is it). To what extend and when I will adapt the
+-- generic code (for color support) to that is yet to be decided because in context we do things
+-- a bit differently. We anyway have to wait a few years till that callback is omnipresent so I'm
+-- not in that much of a hurry. (There will be a TB article about it first and after that I will
+-- add some examples to the manual.)
+
utf = utf or (unicode and unicode.utf8) or { }
--- We have some (global) hooks (for latex):
+-- We have some (global) hooks (for latex). Maybe I'll use this signal to disable some of the
+-- more tricky features like variable fonts and emoji (because afaik latex uses hb for that).
if not non_generic_context then
non_generic_context = { }
@@ -262,20 +283,20 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then
-- outside context so in retrospect there was no need for it being generic.
loadmodule('font-otr.lua')
- loadmodule('font-oti.lua')
- loadmodule('font-ott.lua')
loadmodule('font-cff.lua')
loadmodule('font-ttf.lua')
loadmodule('font-dsp.lua')
- loadmodule('font-oup.lua')
+ loadmodule('font-oti.lua')
+ loadmodule('font-ott.lua')
loadmodule('font-otl.lua')
loadmodule('font-oto.lua')
loadmodule('font-otj.lua')
+ loadmodule('font-oup.lua')
loadmodule('font-ota.lua')
loadmodule('font-ots.lua')
+ loadmodule('font-otc.lua')
loadmodule('font-osd.lua')
loadmodule('font-ocl.lua')
- loadmodule('font-otc.lua')
-- The code for type one fonts.
@@ -291,6 +312,7 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then
loadmodule('font-lua.lua')
loadmodule('font-def.lua')
+ loadmodule('font-shp.lua')
-- We support xetex compatible specifiers (plain/latex only).
diff --git a/macros/luatex/generic/luaotfload/fontloader-reference.lua b/macros/luatex/generic/luaotfload/fontloader-reference.lua
index 9f381d358a..df4f3593c2 100644
--- a/macros/luatex/generic/luaotfload/fontloader-reference.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-reference.lua
@@ -1,7 +1,6 @@
-- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua
-- parent file : c:/data/develop/context/sources/luatex-fonts.lua
--- merge date : 2020-04-30 11:10
--- patched on 2020-05-06 (colr-restore fix
+-- merge date : 2020-08-31 22:01
do -- begin closure to overcome local limits and interference
@@ -100,9 +99,6 @@ function optionalrequire(...)
return result
end
end
-if lua then
- lua.mask=load([[τεχ = 1]]) and "utf" or "ascii"
-end
local flush=io.flush
if flush then
local execute=os.execute if execute then function os.execute(...) flush() return execute(...) end end
@@ -226,11 +222,13 @@ local fullstripper=whitespace^0*C((whitespace^0*nonwhitespace^1)^0)
local collapser=Cs(spacer^0/""*nonspacer^0*((spacer^0/" "*nonspacer^1)^0))
local nospacer=Cs((whitespace^1/""+nonwhitespace^1)^0)
local b_collapser=Cs(whitespace^0/""*(nonwhitespace^1+whitespace^1/" ")^0)
-local e_collapser=Cs((whitespace^1*endofstring/""+nonwhitespace^1+whitespace^1/" ")^0)
local m_collapser=Cs((nonwhitespace^1+whitespace^1/" ")^0)
+local e_collapser=Cs((whitespace^1*endofstring/""+nonwhitespace^1+whitespace^1/" ")^0)
+local x_collapser=Cs((nonwhitespace^1+whitespace^1/"" )^0)
local b_stripper=Cs(spacer^0/""*(nonspacer^1+spacer^1/" ")^0)
-local e_stripper=Cs((spacer^1*endofstring/""+nonspacer^1+spacer^1/" ")^0)
local m_stripper=Cs((nonspacer^1+spacer^1/" ")^0)
+local e_stripper=Cs((spacer^1*endofstring/""+nonspacer^1+spacer^1/" ")^0)
+local x_stripper=Cs((nonspacer^1+spacer^1/"" )^0)
patterns.stripper=stripper
patterns.fullstripper=fullstripper
patterns.collapser=collapser
@@ -238,9 +236,11 @@ patterns.nospacer=nospacer
patterns.b_collapser=b_collapser
patterns.m_collapser=m_collapser
patterns.e_collapser=e_collapser
+patterns.x_collapser=x_collapser
patterns.b_stripper=b_stripper
patterns.m_stripper=m_stripper
patterns.e_stripper=e_stripper
+patterns.x_stripper=x_stripper
patterns.lowercase=lowercase
patterns.uppercase=uppercase
patterns.letter=patterns.lowercase+patterns.uppercase
@@ -3762,33 +3762,36 @@ local format_extension=function(extensions,f,name)
local extension=extensions[name] or "tostring(%s)"
local f=tonumber(f) or 1
local w=find(extension,"%.%.%.")
- if w then
- if f==0 then
+ if f==0 then
+ if w then
extension=gsub(extension,"%.%.%.","")
- return extension
- elseif f==1 then
+ end
+ return extension
+ elseif f==1 then
+ if w then
extension=gsub(extension,"%.%.%.","%%s")
- n=n+1
- local a="a"..n
- return format(extension,a,a)
- elseif f<0 then
+ end
+ n=n+1
+ local a="a"..n
+ return format(extension,a,a)
+ elseif f<0 then
+ if w then
+ extension=gsub(extension,"%.%.%.","")
+ return extension
+ else
local a="a"..(n+f+1)
return format(extension,a,a)
- else
- extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s")
- local t={}
- for i=1,f do
- n=n+1
- t[i]="a"..n
- end
- return format(extension,unpack(t))
end
else
- extension=gsub(extension,"%%s",function()
+ if w then
+ extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s")
+ end
+ local t={}
+ for i=1,f do
n=n+1
- return "a"..n
- end)
- return extension
+ t[i]="a"..n
+ end
+ return format(extension,unpack(t))
end
end
local builder=Cs { "start",
@@ -3990,6 +3993,7 @@ do -- begin closure to overcome local limits and interference
if not modules then modules={} end modules ['util-fil']={
version=1.001,
+ optimize=true,
comment="companion to luat-lib.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -4438,14 +4442,14 @@ utilities.parsers=utilities.parsers or {
end,
settings_to_hash=function(s)
local t={}
- for k,v in gmatch(s,"([^%s,=]+)=([^%s,]+)") do
+ for k,v in gmatch((gsub(s,"^{(.*)}$","%1")),"([^%s,=]+)=([^%s,]+)") do
t[k]=v
end
return t
end,
settings_to_hash_colon_too=function(s)
local t={}
- for k,v in gmatch(s,"([^%s,=:]+)[=:]([^%s,]+)") do
+ for k,v in gmatch((gsub(s,"^{(.*)}$","%1")),"([^%s,=:]+)[=:]([^%s,]+)") do
t[k]=v
end
return t
@@ -4910,6 +4914,7 @@ end
nodes.nodecodes=nodecodes
nodes.glyphcodes=glyphcodes
nodes.disccodes=disccodes
+nodes.dirvalues={ lefttoright=0,righttoleft=1 }
nodes.handlers.protectglyphs=node.protect_glyphs
nodes.handlers.unprotectglyphs=node.unprotect_glyphs
local direct=node.direct
@@ -8917,6 +8922,9 @@ function constructors.assignmathparameters(target,original)
if not mathparameters.FractionDelimiterDisplayStyleSize then
targetmathparameters.FractionDelimiterDisplayStyleSize=2.40*targetparameters.size
end
+ if not targetmathparameters.SpaceBeforeScript then
+ targetmathparameters.SpaceBeforeScript=targetmathparameters.SpaceAfterScript
+ end
target.mathparameters=targetmathparameters
end
end
@@ -8924,31 +8932,40 @@ function constructors.beforecopyingcharacters(target,original)
end
function constructors.aftercopyingcharacters(target,original)
end
-constructors.sharefonts=false
-constructors.nofsharedfonts=0
-local sharednames={}
+local nofinstances=0
+local instances=setmetatableindex(function(t,k)
+ nofinstances=nofinstances+1
+ t[k]=nofinstances
+ return nofinstances
+end)
function constructors.trytosharefont(target,tfmdata)
- if constructors.sharefonts then
- local characters=target.characters
- local n=1
- local t={ target.psname }
- local u=sortedkeys(characters)
- for i=1,#u do
- local k=u[i]
- n=n+1;t[n]=k
- n=n+1;t[n]=characters[k].index or k
- end
- local h=md5.HEX(concat(t," "))
- local s=sharednames[h]
- if s then
- if trace_defining then
- report_defining("font %a uses backend resources of font %a",target.fullname,s)
- end
- target.fullname=s
- constructors.nofsharedfonts=constructors.nofsharedfonts+1
- target.properties.sharedwith=s
+ local properties=target.properties
+ local instance=properties.instance
+ if instance then
+ local fullname=target.fullname
+ local fontname=target.fontname
+ local psname=target.psname
+ local format=tfmdata.properties.format
+ if format=="opentype" then
+ target.streamprovider=1
+ elseif format=="truetype" then
+ target.streamprovider=2
else
- sharednames[h]=target.fullname
+ target.streamprovider=0
+ end
+ if target.streamprovider>0 then
+ if fullname then
+ fullname=fullname..":"..instances[instance]
+ target.fullname=fullname
+ end
+ if fontname then
+ fontname=fontname..":"..instances[instance]
+ target.fontname=fontname
+ end
+ if psname then
+ psname=psname..":"..instances[instance]
+ target.psname=psname
+ end
end
end
end
@@ -9114,12 +9131,14 @@ function constructors.scale(tfmdata,specification)
target.cidinfo=properties.cidinfo
target.format=properties.format
target.cache=constructors.cacheintex and "yes" or "renew"
+ local original=properties.original or tfmdata.original
local fontname=properties.fontname or tfmdata.fontname
local fullname=properties.fullname or tfmdata.fullname
local filename=properties.filename or tfmdata.filename
local psname=properties.psname or tfmdata.psname
local name=properties.name or tfmdata.name
local psname,psfixed=fixedpsname(psname,fontname or fullname or file.nameonly(filename))
+ target.original=original
target.fontname=fontname
target.fullname=fullname
target.filename=filename
@@ -9209,6 +9228,14 @@ function constructors.scale(tfmdata,specification)
targetparameters.x_height=targetx_height
targetparameters.quad=targetquad
targetparameters.extra_space=targetextra_space
+ local hshift=parameters.hshift
+ if hshift then
+ targetparameters.hshift=delta*hshift
+ end
+ local vshift=parameters.vshift
+ if vshift then
+ targetparameters.vshift=delta*vshift
+ end
local ascender=parameters.ascender
if ascender then
targetparameters.ascender=delta*ascender
@@ -10370,6 +10397,7 @@ do -- begin closure to overcome local limits and interference
if not modules then modules={} end modules ['font-map']={
version=1.001,
+ optimize=true,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -10454,6 +10482,7 @@ end
local hash={}
local conc={}
table.setmetatableindex(hash,function(t,k)
+ local v
if k<0xD7FF or (k>0xDFFF and k<=0xFFFF) then
v=f_single(k)
else
@@ -10865,7 +10894,6 @@ local insert=table.insert
local fonts=fonts
local helpers=fonts.helpers
local setmetatableindex=table.setmetatableindex
-local makeweak=table.makeweak
local push={ "push" }
local pop={ "pop" }
local dummy={ "comment" }
@@ -10955,6 +10983,7 @@ do -- begin closure to overcome local limits and interference
if not modules then modules={} end modules ['font-otr']={
version=1.001,
+ optimize=true,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -12396,17 +12425,11 @@ local function readtable(tag,f,fontdata,specification,...)
reader(f,fontdata,specification,...)
end
end
-local variablefonts_supported=(context and true) or (logs and logs.application and true) or false
local function readdata(f,offset,specification)
local fontdata,tables=loadtables(f,specification,offset)
if specification.glyphs then
prepareglyps(fontdata)
end
- if not variablefonts_supported then
- specification.instance=nil
- specification.variable=nil
- specification.factors=nil
- end
fontdata.temporary={}
readtable("name",f,fontdata,specification)
local askedname=specification.askedname
@@ -12421,62 +12444,60 @@ local function readdata(f,offset,specification)
readtable("stat",f,fontdata,specification)
readtable("avar",f,fontdata,specification)
readtable("fvar",f,fontdata,specification)
- if variablefonts_supported then
- local variabledata=fontdata.variabledata
- if variabledata then
- local instances=variabledata.instances
- local axis=variabledata.axis
- if axis and (not instances or #instances==0) then
- instances={}
- variabledata.instances=instances
- local function add(n,subfamily,value)
- local values={}
- for i=1,#axis do
- local a=axis[i]
- values[i]={
- axis=a.tag,
- value=i==n and value or a.default,
- }
- end
- instances[#instances+1]={
- subfamily=subfamily,
- values=values,
- }
- end
+ local variabledata=fontdata.variabledata
+ if variabledata then
+ local instances=variabledata.instances
+ local axis=variabledata.axis
+ if axis and (not instances or #instances==0) then
+ instances={}
+ variabledata.instances=instances
+ local function add(n,subfamily,value)
+ local values={}
for i=1,#axis do
local a=axis[i]
- local tag=a.tag
- add(i,"default"..tag,a.default)
- add(i,"minimum"..tag,a.minimum)
- add(i,"maximum"..tag,a.maximum)
- end
- end
- end
- if not specification.factors then
- local instance=specification.instance
- if type(instance)=="string" then
- local factors=helpers.getfactors(fontdata,instance)
- if factors then
- specification.factors=factors
- fontdata.factors=factors
- fontdata.instance=instance
- report("user instance: %s, factors: % t",instance,factors)
- else
- report("user instance: %s, bad factors",instance)
+ values[i]={
+ axis=a.tag,
+ value=i==n and value or a.default,
+ }
end
+ instances[#instances+1]={
+ subfamily=subfamily,
+ values=values,
+ }
+ end
+ for i=1,#axis do
+ local a=axis[i]
+ local tag=a.tag
+ add(i,"default"..tag,a.default)
+ add(i,"minimum"..tag,a.minimum)
+ add(i,"maximum"..tag,a.maximum)
end
end
- if not fontdata.factors then
- if fontdata.variabledata then
- local factors=helpers.getfactors(fontdata,true)
- if factors then
- specification.factors=factors
- fontdata.factors=factors
- end
+ end
+ if not specification.factors then
+ local instance=specification.instance
+ if type(instance)=="string" then
+ local factors=helpers.getfactors(fontdata,instance)
+ if factors then
+ specification.factors=factors
+ fontdata.factors=factors
+ fontdata.instance=instance
+ report("user instance: %s, factors: % t",instance,factors)
else
+ report("user instance: %s, bad factors",instance)
end
end
end
+ if not fontdata.factors then
+ if fontdata.variabledata then
+ local factors=helpers.getfactors(fontdata,true)
+ if factors then
+ specification.factors=factors
+ fontdata.factors=factors
+ end
+ else
+ end
+ end
readtable("os/2",f,fontdata,specification)
readtable("head",f,fontdata,specification)
readtable("maxp",f,fontdata,specification)
@@ -12698,6 +12719,7 @@ function readers.loadfont(filename,n,instance)
hascolor=fontdata.hascolor or false,
instance=fontdata.instance,
factors=fontdata.factors,
+ nofsubfonts=fontdata.subfonts and #fontdata.subfonts or nil,
},
resources={
filename=filename,
@@ -12805,1274 +12827,9 @@ end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules={} end modules ['font-oti']={
- version=1.001,
- comment="companion to font-ini.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
-}
-local lower=string.lower
-local fonts=fonts
-local constructors=fonts.constructors
-local otf=constructors.handlers.otf
-local otffeatures=constructors.features.otf
-local registerotffeature=otffeatures.register
-local otftables=otf.tables or {}
-otf.tables=otftables
-local allocate=utilities.storage.allocate
-registerotffeature {
- name="features",
- description="initialization of feature handler",
- default=true,
-}
-local function setmode(tfmdata,value)
- if value then
- tfmdata.properties.mode=lower(value)
- end
-end
-otf.modeinitializer=setmode
-local function setlanguage(tfmdata,value)
- if value then
- local cleanvalue=lower(value)
- local languages=otftables and otftables.languages
- local properties=tfmdata.properties
- if not languages then
- properties.language=cleanvalue
- elseif languages[value] then
- properties.language=cleanvalue
- else
- properties.language="dflt"
- end
- end
-end
-local function setscript(tfmdata,value)
- if value then
- local cleanvalue=lower(value)
- local scripts=otftables and otftables.scripts
- local properties=tfmdata.properties
- if not scripts then
- properties.script=cleanvalue
- elseif scripts[value] then
- properties.script=cleanvalue
- else
- properties.script="dflt"
- end
- end
-end
-registerotffeature {
- name="mode",
- description="mode",
- initializers={
- base=setmode,
- node=setmode,
- plug=setmode,
- }
-}
-registerotffeature {
- name="language",
- description="language",
- initializers={
- base=setlanguage,
- node=setlanguage,
- plug=setlanguage,
- }
-}
-registerotffeature {
- name="script",
- description="script",
- initializers={
- base=setscript,
- node=setscript,
- plug=setscript,
- }
-}
-otftables.featuretypes=allocate {
- gpos_single="position",
- gpos_pair="position",
- gpos_cursive="position",
- gpos_mark2base="position",
- gpos_mark2ligature="position",
- gpos_mark2mark="position",
- gpos_context="position",
- gpos_contextchain="position",
- gsub_single="substitution",
- gsub_multiple="substitution",
- gsub_alternate="substitution",
- gsub_ligature="substitution",
- gsub_context="substitution",
- gsub_contextchain="substitution",
- gsub_reversecontextchain="substitution",
- gsub_reversesub="substitution",
-}
-function otffeatures.checkeddefaultscript(featuretype,autoscript,scripts)
- if featuretype=="position" then
- local default=scripts.dflt
- if default then
- if autoscript=="position" or autoscript==true then
- return default
- else
- report_otf("script feature %s not applied, enable default positioning")
- end
- else
- end
- elseif featuretype=="substitution" then
- local default=scripts.dflt
- if default then
- if autoscript=="substitution" or autoscript==true then
- return default
- end
- end
- end
-end
-function otffeatures.checkeddefaultlanguage(featuretype,autolanguage,languages)
- if featuretype=="position" then
- local default=languages.dflt
- if default then
- if autolanguage=="position" or autolanguage==true then
- return default
- else
- report_otf("language feature %s not applied, enable default positioning")
- end
- else
- end
- elseif featuretype=="substitution" then
- local default=languages.dflt
- if default then
- if autolanguage=="substitution" or autolanguage==true then
- return default
- end
- end
- end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ["font-ott"]={
- version=1.001,
- comment="companion to font-ini.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files",
-}
-local type,next,tonumber,tostring,rawget,rawset=type,next,tonumber,tostring,rawget,rawset
-local gsub,lower,format,match,gmatch,find=string.gsub,string.lower,string.format,string.match,string.gmatch,string.find
-local sequenced=table.sequenced
-local is_boolean=string.is_boolean
-local setmetatableindex=table.setmetatableindex
-local setmetatablenewindex=table.setmetatablenewindex
-local allocate=utilities.storage.allocate
-local fonts=fonts
-local otf=fonts.handlers.otf
-local otffeatures=otf.features
-local tables=otf.tables or {}
-otf.tables=tables
-local statistics=otf.statistics or {}
-otf.statistics=statistics
-local scripts=allocate {
- ["adlm"]="adlam",
- ["aghb"]="caucasian albanian",
- ["ahom"]="ahom",
- ["arab"]="arabic",
- ["armi"]="imperial aramaic",
- ["armn"]="armenian",
- ["avst"]="avestan",
- ["bali"]="balinese",
- ["bamu"]="bamum",
- ["bass"]="bassa vah",
- ["batk"]="batak",
- ["beng"]="bengali",
- ["bhks"]="bhaiksuki",
- ["bng2"]="bengali variant 2",
- ["bopo"]="bopomofo",
- ["brah"]="brahmi",
- ["brai"]="braille",
- ["bugi"]="buginese",
- ["buhd"]="buhid",
- ["byzm"]="byzantine music",
- ["cakm"]="chakma",
- ["cans"]="canadian syllabics",
- ["cari"]="carian",
- ["cham"]="cham",
- ["cher"]="cherokee",
- ["copt"]="coptic",
- ["cprt"]="cypriot syllabary",
- ["cyrl"]="cyrillic",
- ["dev2"]="devanagari variant 2",
- ["deva"]="devanagari",
- ["dogr"]="dogra",
- ["dsrt"]="deseret",
- ["dupl"]="duployan",
- ["egyp"]="egyptian heiroglyphs",
- ["elba"]="elbasan",
- ["ethi"]="ethiopic",
- ["geor"]="georgian",
- ["gjr2"]="gujarati variant 2",
- ["glag"]="glagolitic",
- ["gong"]="gunjala gondi",
- ["gonm"]="masaram gondi",
- ["goth"]="gothic",
- ["gran"]="grantha",
- ["grek"]="greek",
- ["gujr"]="gujarati",
- ["gur2"]="gurmukhi variant 2",
- ["guru"]="gurmukhi",
- ["hang"]="hangul",
- ["hani"]="cjk ideographic",
- ["hano"]="hanunoo",
- ["hatr"]="hatran",
- ["hebr"]="hebrew",
- ["hluw"]="anatolian hieroglyphs",
- ["hmng"]="pahawh hmong",
- ["hung"]="old hungarian",
- ["ital"]="old italic",
- ["jamo"]="hangul jamo",
- ["java"]="javanese",
- ["kali"]="kayah li",
- ["kana"]="hiragana and katakana",
- ["khar"]="kharosthi",
- ["khmr"]="khmer",
- ["khoj"]="khojki",
- ["knd2"]="kannada variant 2",
- ["knda"]="kannada",
- ["kthi"]="kaithi",
- ["lana"]="tai tham",
- ["lao" ]="lao",
- ["latn"]="latin",
- ["lepc"]="lepcha",
- ["limb"]="limbu",
- ["lina"]="linear a",
- ["linb"]="linear b",
- ["lisu"]="lisu",
- ["lyci"]="lycian",
- ["lydi"]="lydian",
- ["mahj"]="mahajani",
- ["maka"]="makasar",
- ["mand"]="mandaic and mandaean",
- ["mani"]="manichaean",
- ["marc"]="marchen",
- ["math"]="mathematical alphanumeric symbols",
- ["medf"]="medefaidrin",
- ["mend"]="mende kikakui",
- ["merc"]="meroitic cursive",
- ["mero"]="meroitic hieroglyphs",
- ["mlm2"]="malayalam variant 2",
- ["mlym"]="malayalam",
- ["modi"]="modi",
- ["mong"]="mongolian",
- ["mroo"]="mro",
- ["mtei"]="meitei Mayek",
- ["mult"]="multani",
- ["musc"]="musical symbols",
- ["mym2"]="myanmar variant 2",
- ["mymr"]="myanmar",
- ["narb"]="old north arabian",
- ["nbat"]="nabataean",
- ["newa"]="newa",
- ["nko" ]='n"ko',
- ["nshu"]="nüshu",
- ["ogam"]="ogham",
- ["olck"]="ol chiki",
- ["orkh"]="old turkic and orkhon runic",
- ["ory2"]="odia variant 2",
- ["orya"]="oriya",
- ["osge"]="osage",
- ["osma"]="osmanya",
- ["palm"]="palmyrene",
- ["pauc"]="pau cin hau",
- ["perm"]="old permic",
- ["phag"]="phags-pa",
- ["phli"]="inscriptional pahlavi",
- ["phlp"]="psalter pahlavi",
- ["phnx"]="phoenician",
- ["plrd"]="miao",
- ["prti"]="inscriptional parthian",
- ["rjng"]="rejang",
- ["rohg"]="hanifi rohingya",
- ["runr"]="runic",
- ["samr"]="samaritan",
- ["sarb"]="old south arabian",
- ["saur"]="saurashtra",
- ["sgnw"]="sign writing",
- ["shaw"]="shavian",
- ["shrd"]="sharada",
- ["sidd"]="siddham",
- ["sind"]="khudawadi",
- ["sinh"]="sinhala",
- ["sogd"]="sogdian",
- ["sogo"]="old sogdian",
- ["sora"]="sora sompeng",
- ["soyo"]="soyombo",
- ["sund"]="sundanese",
- ["sylo"]="syloti nagri",
- ["syrc"]="syriac",
- ["tagb"]="tagbanwa",
- ["takr"]="takri",
- ["tale"]="tai le",
- ["talu"]="tai lu",
- ["taml"]="tamil",
- ["tang"]="tangut",
- ["tavt"]="tai viet",
- ["tel2"]="telugu variant 2",
- ["telu"]="telugu",
- ["tfng"]="tifinagh",
- ["tglg"]="tagalog",
- ["thaa"]="thaana",
- ["thai"]="thai",
- ["tibt"]="tibetan",
- ["tirh"]="tirhuta",
- ["tml2"]="tamil variant 2",
- ["ugar"]="ugaritic cuneiform",
- ["vai" ]="vai",
- ["wara"]="warang citi",
- ["xpeo"]="old persian cuneiform",
- ["xsux"]="sumero-akkadian cuneiform",
- ["yi" ]="yi",
- ["zanb"]="zanabazar square",
-}
-local languages=allocate {
- ["aba" ]="abaza",
- ["abk" ]="abkhazian",
- ["ach" ]="acholi",
- ["acr" ]="achi",
- ["ady" ]="adyghe",
- ["afk" ]="afrikaans",
- ["afr" ]="afar",
- ["agw" ]="agaw",
- ["aio" ]="aiton",
- ["aka" ]="akan",
- ["als" ]="alsatian",
- ["alt" ]="altai",
- ["amh" ]="amharic",
- ["ang" ]="anglo-saxon",
- ["apph"]="phonetic transcription—americanist conventions",
- ["ara" ]="arabic",
- ["arg" ]="aragonese",
- ["ari" ]="aari",
- ["ark" ]="rakhine",
- ["asm" ]="assamese",
- ["ast" ]="asturian",
- ["ath" ]="athapaskan",
- ["avr" ]="avar",
- ["awa" ]="awadhi",
- ["aym" ]="aymara",
- ["azb" ]="torki",
- ["aze" ]="azerbaijani",
- ["bad" ]="badaga",
- ["bad0"]="banda",
- ["bag" ]="baghelkhandi",
- ["bal" ]="balkar",
- ["ban" ]="balinese",
- ["bar" ]="bavarian",
- ["bau" ]="baulé",
- ["bbc" ]="batak toba",
- ["bbr" ]="berber",
- ["bch" ]="bench",
- ["bcr" ]="bible cree",
- ["bdy" ]="bandjalang",
- ["bel" ]="belarussian",
- ["bem" ]="bemba",
- ["ben" ]="bengali",
- ["bgc" ]="haryanvi",
- ["bgq" ]="bagri",
- ["bgr" ]="bulgarian",
- ["bhi" ]="bhili",
- ["bho" ]="bhojpuri",
- ["bik" ]="bikol",
- ["bil" ]="bilen",
- ["bis" ]="bislama",
- ["bjj" ]="kanauji",
- ["bkf" ]="blackfoot",
- ["bli" ]="baluchi",
- ["blk" ]="pa'o karen",
- ["bln" ]="balante",
- ["blt" ]="balti",
- ["bmb" ]="bambara (bamanankan)",
- ["bml" ]="bamileke",
- ["bos" ]="bosnian",
- ["bpy" ]="bishnupriya manipuri",
- ["bre" ]="breton",
- ["brh" ]="brahui",
- ["bri" ]="braj bhasha",
- ["brm" ]="burmese",
- ["brx" ]="bodo",
- ["bsh" ]="bashkir",
- ["bsk" ]="burushaski",
- ["bti" ]="beti",
- ["bts" ]="batak simalungun",
- ["bug" ]="bugis",
- ["byv" ]="medumba",
- ["cak" ]="kaqchikel",
- ["cat" ]="catalan",
- ["cbk" ]="zamboanga chavacano",
- ["cchn"]="chinantec",
- ["ceb" ]="cebuano",
- ["cgg" ]="chiga",
- ["cha" ]="chamorro",
- ["che" ]="chechen",
- ["chg" ]="chaha gurage",
- ["chh" ]="chattisgarhi",
- ["chi" ]="chichewa (chewa, nyanja)",
- ["chk" ]="chukchi",
- ["chk0"]="chuukese",
- ["cho" ]="choctaw",
- ["chp" ]="chipewyan",
- ["chr" ]="cherokee",
- ["chu" ]="chuvash",
- ["chy" ]="cheyenne",
- ["cja" ]="western cham",
- ["cjm" ]="eastern cham",
- ["cmr" ]="comorian",
- ["cop" ]="coptic",
- ["cor" ]="cornish",
- ["cos" ]="corsican",
- ["cpp" ]="creoles",
- ["cre" ]="cree",
- ["crr" ]="carrier",
- ["crt" ]="crimean tatar",
- ["csb" ]="kashubian",
- ["csl" ]="church slavonic",
- ["csy" ]="czech",
- ["ctg" ]="chittagonian",
- ["cuk" ]="san blas kuna",
- ["dan" ]="danish",
- ["dar" ]="dargwa",
- ["dax" ]="dayi",
- ["dcr" ]="woods cree",
- ["deu" ]="german",
- ["dgo" ]="dogri",
- ["dgr" ]="dogri",
- ["dhg" ]="dhangu",
- ["dhv" ]="divehi (dhivehi, maldivian)",
- ["diq" ]="dimli",
- ["div" ]="divehi (dhivehi, maldivian)",
- ["djr" ]="zarma",
- ["djr0"]="djambarrpuyngu",
- ["dng" ]="dangme",
- ["dnj" ]="dan",
- ["dnk" ]="dinka",
- ["dri" ]="dari",
- ["duj" ]="dhuwal",
- ["dun" ]="dungan",
- ["dzn" ]="dzongkha",
- ["ebi" ]="ebira",
- ["ecr" ]="eastern cree",
- ["edo" ]="edo",
- ["efi" ]="efik",
- ["ell" ]="greek",
- ["emk" ]="eastern maninkakan",
- ["eng" ]="english",
- ["erz" ]="erzya",
- ["esp" ]="spanish",
- ["esu" ]="central yupik",
- ["eti" ]="estonian",
- ["euq" ]="basque",
- ["evk" ]="evenki",
- ["evn" ]="even",
- ["ewe" ]="ewe",
- ["fan" ]="french antillean",
- ["fan0"]=" fang",
- ["far" ]="persian",
- ["fat" ]="fanti",
- ["fin" ]="finnish",
- ["fji" ]="fijian",
- ["fle" ]="dutch (flemish)",
- ["fmp" ]="fe’fe’",
- ["fne" ]="forest nenets",
- ["fon" ]="fon",
- ["fos" ]="faroese",
- ["fra" ]="french",
- ["frc" ]="cajun french",
- ["fri" ]="frisian",
- ["frl" ]="friulian",
- ["frp" ]="arpitan",
- ["fta" ]="futa",
- ["ful" ]="fulah",
- ["fuv" ]="nigerian fulfulde",
- ["gad" ]="ga",
- ["gae" ]="scottish gaelic (gaelic)",
- ["gag" ]="gagauz",
- ["gal" ]="galician",
- ["gar" ]="garshuni",
- ["gaw" ]="garhwali",
- ["gez" ]="ge'ez",
- ["gih" ]="githabul",
- ["gil" ]="gilyak",
- ["gil0"]="kiribati (gilbertese)",
- ["gkp" ]="kpelle (guinea)",
- ["glk" ]="gilaki",
- ["gmz" ]="gumuz",
- ["gnn" ]="gumatj",
- ["gog" ]="gogo",
- ["gon" ]="gondi",
- ["grn" ]="greenlandic",
- ["gro" ]="garo",
- ["gua" ]="guarani",
- ["guc" ]="wayuu",
- ["guf" ]="gupapuyngu",
- ["guj" ]="gujarati",
- ["guz" ]="gusii",
- ["hai" ]="haitian (haitian creole)",
- ["hal" ]="halam",
- ["har" ]="harauti",
- ["hau" ]="hausa",
- ["haw" ]="hawaiian",
- ["hay" ]="haya",
- ["haz" ]="hazaragi",
- ["hbn" ]="hammer-banna",
- ["her" ]="herero",
- ["hil" ]="hiligaynon",
- ["hin" ]="hindi",
- ["hma" ]="high mari",
- ["hmn" ]="hmong",
- ["hmo" ]="hiri motu",
- ["hnd" ]="hindko",
- ["ho" ]="ho",
- ["hri" ]="harari",
- ["hrv" ]="croatian",
- ["hun" ]="hungarian",
- ["hye" ]="armenian",
- ["hye0"]="armenian east",
- ["iba" ]="iban",
- ["ibb" ]="ibibio",
- ["ibo" ]="igbo",
- ["ido" ]="ido",
- ["ijo" ]="ijo languages",
- ["ile" ]="interlingue",
- ["ilo" ]="ilokano",
- ["ina" ]="interlingua",
- ["ind" ]="indonesian",
- ["ing" ]="ingush",
- ["inu" ]="inuktitut",
- ["ipk" ]="inupiat",
- ["ipph"]="phonetic transcription—ipa conventions",
- ["iri" ]="irish",
- ["irt" ]="irish traditional",
- ["isl" ]="icelandic",
- ["ism" ]="inari sami",
- ["ita" ]="italian",
- ["iwr" ]="hebrew",
- ["jam" ]="jamaican creole",
- ["jan" ]="japanese",
- ["jav" ]="javanese",
- ["jbo" ]="lojban",
- ["jct" ]="krymchak",
- ["jii" ]="yiddish",
- ["jud" ]="ladino",
- ["jul" ]="jula",
- ["kab" ]="kabardian",
- ["kab0"]="kabyle",
- ["kac" ]="kachchi",
- ["kal" ]="kalenjin",
- ["kan" ]="kannada",
- ["kar" ]="karachay",
- ["kat" ]="georgian",
- ["kaz" ]="kazakh",
- ["kde" ]="makonde",
- ["kea" ]="kabuverdianu (crioulo)",
- ["keb" ]="kebena",
- ["kek" ]="kekchi",
- ["kge" ]="khutsuri georgian",
- ["kha" ]="khakass",
- ["khk" ]="khanty-kazim",
- ["khm" ]="khmer",
- ["khs" ]="khanty-shurishkar",
- ["kht" ]="khamti shan",
- ["khv" ]="khanty-vakhi",
- ["khw" ]="khowar",
- ["kik" ]="kikuyu (gikuyu)",
- ["kir" ]="kirghiz (kyrgyz)",
- ["kis" ]="kisii",
- ["kiu" ]="kirmanjki",
- ["kjd" ]="southern kiwai",
- ["kjp" ]="eastern pwo karen",
- ["kjz" ]="bumthangkha",
- ["kkn" ]="kokni",
- ["klm" ]="kalmyk",
- ["kmb" ]="kamba",
- ["kmn" ]="kumaoni",
- ["kmo" ]="komo",
- ["kms" ]="komso",
- ["kmz" ]="khorasani turkic",
- ["knr" ]="kanuri",
- ["kod" ]="kodagu",
- ["koh" ]="korean old hangul",
- ["kok" ]="konkani",
- ["kom" ]="komi",
- ["kon" ]="kikongo",
- ["kon0"]="kongo",
- ["kop" ]="komi-permyak",
- ["kor" ]="korean",
- ["kos" ]="kosraean",
- ["koz" ]="komi-zyrian",
- ["kpl" ]="kpelle",
- ["kri" ]="krio",
- ["krk" ]="karakalpak",
- ["krl" ]="karelian",
- ["krm" ]="karaim",
- ["krn" ]="karen",
- ["krt" ]="koorete",
- ["ksh" ]="kashmiri",
- ["ksh0"]="ripuarian",
- ["ksi" ]="khasi",
- ["ksm" ]="kildin sami",
- ["ksw" ]="s’gaw karen",
- ["kua" ]="kuanyama",
- ["kui" ]="kui",
- ["kul" ]="kulvi",
- ["kum" ]="kumyk",
- ["kur" ]="kurdish",
- ["kuu" ]="kurukh",
- ["kuy" ]="kuy",
- ["kyk" ]="koryak",
- ["kyu" ]="western kayah",
- ["lad" ]="ladin",
- ["lah" ]="lahuli",
- ["lak" ]="lak",
- ["lam" ]="lambani",
- ["lao" ]="lao",
- ["lat" ]="latin",
- ["laz" ]="laz",
- ["lcr" ]="l-cree",
- ["ldk" ]="ladakhi",
- ["lez" ]="lezgi",
- ["lij" ]="ligurian",
- ["lim" ]="limburgish",
- ["lin" ]="lingala",
- ["lis" ]="lisu",
- ["ljp" ]="lampung",
- ["lki" ]="laki",
- ["lma" ]="low mari",
- ["lmb" ]="limbu",
- ["lmo" ]="lombard",
- ["lmw" ]="lomwe",
- ["lom" ]="loma",
- ["lrc" ]="luri",
- ["lsb" ]="lower sorbian",
- ["lsm" ]="lule sami",
- ["lth" ]="lithuanian",
- ["ltz" ]="luxembourgish",
- ["lua" ]="luba-lulua",
- ["lub" ]="luba-katanga",
- ["lug" ]="ganda",
- ["luh" ]="luyia",
- ["luo" ]="luo",
- ["lvi" ]="latvian",
- ["mad" ]="madura",
- ["mag" ]="magahi",
- ["mah" ]="marshallese",
- ["maj" ]="majang",
- ["mak" ]="makhuwa",
- ["mal" ]="malayalam reformed",
- ["mam" ]="mam",
- ["man" ]="mansi",
- ["map" ]="mapudungun",
- ["mar" ]="marathi",
- ["maw" ]="marwari",
- ["mbn" ]="mbundu",
- ["mbo" ]="mbo",
- ["mch" ]="manchu",
- ["mcr" ]="moose cree",
- ["mde" ]="mende",
- ["mdr" ]="mandar",
- ["men" ]="me'en",
- ["mer" ]="meru",
- ["mfa" ]="pattani malay",
- ["mfe" ]="morisyen",
- ["min" ]="minangkabau",
- ["miz" ]="mizo",
- ["mkd" ]="macedonian",
- ["mkr" ]="makasar",
- ["mkw" ]="kituba",
- ["mle" ]="male",
- ["mlg" ]="malagasy",
- ["mln" ]="malinke",
- ["mlr" ]="malayalam reformed",
- ["mly" ]="malay",
- ["mnd" ]="mandinka",
- ["mng" ]="mongolian",
- ["mni" ]="manipuri",
- ["mnk" ]="maninka",
- ["mnx" ]="manx",
- ["moh" ]="mohawk",
- ["mok" ]="moksha",
- ["mol" ]="moldavian",
- ["mon" ]="mon",
- ["mor" ]="moroccan",
- ["mos" ]="mossi",
- ["mri" ]="maori",
- ["mth" ]="maithili",
- ["mts" ]="maltese",
- ["mun" ]="mundari",
- ["mus" ]="muscogee",
- ["mwl" ]="mirandese",
- ["mww" ]="hmong daw",
- ["myn" ]="mayan",
- ["mzn" ]="mazanderani",
- ["nag" ]="naga-assamese",
- ["nah" ]="nahuatl",
- ["nan" ]="nanai",
- ["nap" ]="neapolitan",
- ["nas" ]="naskapi",
- ["nau" ]="nauruan",
- ["nav" ]="navajo",
- ["ncr" ]="n-cree",
- ["ndb" ]="ndebele",
- ["ndc" ]="ndau",
- ["ndg" ]="ndonga",
- ["nds" ]="low saxon",
- ["nep" ]="nepali",
- ["new" ]="newari",
- ["nga" ]="ngbaka",
- ["ngr" ]="nagari",
- ["nhc" ]="norway house cree",
- ["nis" ]="nisi",
- ["niu" ]="niuean",
- ["nkl" ]="nyankole",
- ["nko" ]="n'ko",
- ["nld" ]="dutch",
- ["noe" ]="nimadi",
- ["nog" ]="nogai",
- ["nor" ]="norwegian",
- ["nov" ]="novial",
- ["nsm" ]="northern sami",
- ["nso" ]="sotho, northern",
- ["nta" ]="northern tai",
- ["nto" ]="esperanto",
- ["nym" ]="nyamwezi",
- ["nyn" ]="norwegian nynorsk",
- ["nza" ]="mbembe tigon",
- ["oci" ]="occitan",
- ["ocr" ]="oji-cree",
- ["ojb" ]="ojibway",
- ["ori" ]="odia",
- ["oro" ]="oromo",
- ["oss" ]="ossetian",
- ["paa" ]="palestinian aramaic",
- ["pag" ]="pangasinan",
- ["pal" ]="pali",
- ["pam" ]="pampangan",
- ["pan" ]="punjabi",
- ["pap" ]="palpa",
- ["pap0"]="papiamentu",
- ["pas" ]="pashto",
- ["pau" ]="palauan",
- ["pcc" ]="bouyei",
- ["pcd" ]="picard",
- ["pdc" ]="pennsylvania german",
- ["pgr" ]="polytonic greek",
- ["phk" ]="phake",
- ["pih" ]="norfolk",
- ["pil" ]="filipino",
- ["plg" ]="palaung",
- ["plk" ]="polish",
- ["pms" ]="piemontese",
- ["pnb" ]="western panjabi",
- ["poh" ]="pocomchi",
- ["pon" ]="pohnpeian",
- ["pro" ]="provencal",
- ["ptg" ]="portuguese",
- ["pwo" ]="western pwo karen",
- ["qin" ]="chin",
- ["quc" ]="k’iche’",
- ["quh" ]="quechua (bolivia)",
- ["quz" ]="quechua",
- ["qvi" ]="quechua (ecuador)",
- ["qwh" ]="quechua (peru)",
- ["raj" ]="rajasthani",
- ["rar" ]="rarotongan",
- ["rbu" ]="russian buriat",
- ["rcr" ]="r-cree",
- ["rej" ]="rejang",
- ["ria" ]="riang",
- ["rif" ]="tarifit",
- ["rit" ]="ritarungo",
- ["rkw" ]="arakwal",
- ["rms" ]="romansh",
- ["rmy" ]="vlax romani",
- ["rom" ]="romanian",
- ["roy" ]="romany",
- ["rsy" ]="rusyn",
- ["rtm" ]="rotuman",
- ["rua" ]="kinyarwanda",
- ["run" ]="rundi",
- ["rup" ]="aromanian",
- ["rus" ]="russian",
- ["sad" ]="sadri",
- ["san" ]="sanskrit",
- ["sas" ]="sasak",
- ["sat" ]="santali",
- ["say" ]="sayisi",
- ["scn" ]="sicilian",
- ["sco" ]="scots",
- ["scs" ]="north slavey",
- ["sek" ]="sekota",
- ["sel" ]="selkup",
- ["sga" ]="old irish",
- ["sgo" ]="sango",
- ["sgs" ]="samogitian",
- ["shi" ]="tachelhit",
- ["shn" ]="shan",
- ["sib" ]="sibe",
- ["sid" ]="sidamo",
- ["sig" ]="silte gurage",
- ["sks" ]="skolt sami",
- ["sky" ]="slovak",
- ["sla" ]="slavey",
- ["slv" ]="slovenian",
- ["sml" ]="somali",
- ["smo" ]="samoan",
- ["sna" ]="sena",
- ["sna0"]="shona",
- ["snd" ]="sindhi",
- ["snh" ]="sinhala (sinhalese)",
- ["snk" ]="soninke",
- ["sog" ]="sodo gurage",
- ["sop" ]="songe",
- ["sot" ]="sotho, southern",
- ["sqi" ]="albanian",
- ["srb" ]="serbian",
- ["srd" ]="sardinian",
- ["srk" ]="saraiki",
- ["srr" ]="serer",
- ["ssl" ]="south slavey",
- ["ssm" ]="southern sami",
- ["stq" ]="saterland frisian",
- ["suk" ]="sukuma",
- ["sun" ]="sundanese",
- ["sur" ]="suri",
- ["sva" ]="svan",
- ["sve" ]="swedish",
- ["swa" ]="swadaya aramaic",
- ["swk" ]="swahili",
- ["swz" ]="swati",
- ["sxt" ]="sutu",
- ["sxu" ]="upper saxon",
- ["syl" ]="sylheti",
- ["syr" ]="syriac",
- ["syre"]="estrangela syriac",
- ["syrj"]="western syriac",
- ["syrn"]="eastern syriac",
- ["szl" ]="silesian",
- ["tab" ]="tabasaran",
- ["taj" ]="tajiki",
- ["tam" ]="tamil",
- ["tat" ]="tatar",
- ["tcr" ]="th-cree",
- ["tdd" ]="dehong dai",
- ["tel" ]="telugu",
- ["tet" ]="tetum",
- ["tgl" ]="tagalog",
- ["tgn" ]="tongan",
- ["tgr" ]="tigre",
- ["tgy" ]="tigrinya",
- ["tha" ]="thai",
- ["tht" ]="tahitian",
- ["tib" ]="tibetan",
- ["tiv" ]="tiv",
- ["tkm" ]="turkmen",
- ["tmh" ]="tamashek",
- ["tmn" ]="temne",
- ["tna" ]="tswana",
- ["tne" ]="tundra nenets",
- ["tng" ]="tonga",
- ["tod" ]="todo",
- ["tod0"]="toma",
- ["tpi" ]="tok pisin",
- ["trk" ]="turkish",
- ["tsg" ]="tsonga",
- ["tsj" ]="tshangla",
- ["tua" ]="turoyo aramaic",
- ["tul" ]="tulu",
- ["tum" ]="tulu",
- ["tuv" ]="tuvin",
- ["tvl" ]="tuvalu",
- ["twi" ]="twi",
- ["tyz" ]="tày",
- ["tzm" ]="tamazight",
- ["tzo" ]="tzotzil",
- ["udm" ]="udmurt",
- ["ukr" ]="ukrainian",
- ["umb" ]="umbundu",
- ["urd" ]="urdu",
- ["usb" ]="upper sorbian",
- ["uyg" ]="uyghur",
- ["uzb" ]="uzbek",
- ["vec" ]="venetian",
- ["ven" ]="venda",
- ["vit" ]="vietnamese",
- ["vol" ]="volapük",
- ["vro" ]="võro",
- ["wa" ]="wa",
- ["wag" ]="wagdi",
- ["war" ]="waray-waray",
- ["wcr" ]="west-cree",
- ["wel" ]="welsh",
- ["wlf" ]="wolof",
- ["wln" ]="walloon",
- ["wtm" ]="mewati",
- ["xbd" ]="lü",
- ["xhs" ]="xhosa",
- ["xjb" ]="minjangbal",
- ["xkf" ]="khengkha",
- ["xog" ]="soga",
- ["xpe" ]="kpelle (liberia)",
- ["yak" ]="sakha",
- ["yao" ]="yao",
- ["yap" ]="yapese",
- ["yba" ]="yoruba",
- ["ycr" ]="y-cree",
- ["yic" ]="yi classic",
- ["yim" ]="yi modern",
- ["zea" ]="zealandic",
- ["zgh" ]="standard morrocan tamazigh",
- ["zha" ]="zhuang",
- ["zhh" ]="chinese, hong kong sar",
- ["zhp" ]="chinese phonetic",
- ["zhs" ]="chinese simplified",
- ["zht" ]="chinese traditional",
- ["znd" ]="zande",
- ["zul" ]="zulu",
- ["zza" ]="zazaki",
-}
-local features=allocate {
- ["aalt"]="access all alternates",
- ["abvf"]="above-base forms",
- ["abvm"]="above-base mark positioning",
- ["abvs"]="above-base substitutions",
- ["afrc"]="alternative fractions",
- ["akhn"]="akhands",
- ["blwf"]="below-base forms",
- ["blwm"]="below-base mark positioning",
- ["blws"]="below-base substitutions",
- ["c2pc"]="petite capitals from capitals",
- ["c2sc"]="small capitals from capitals",
- ["calt"]="contextual alternates",
- ["case"]="case-sensitive forms",
- ["ccmp"]="glyph composition/decomposition",
- ["cfar"]="conjunct form after ro",
- ["cjct"]="conjunct forms",
- ["clig"]="contextual ligatures",
- ["cpct"]="centered cjk punctuation",
- ["cpsp"]="capital spacing",
- ["cswh"]="contextual swash",
- ["curs"]="cursive positioning",
- ["dflt"]="default processing",
- ["dist"]="distances",
- ["dlig"]="discretionary ligatures",
- ["dnom"]="denominators",
- ["dtls"]="dotless forms",
- ["expt"]="expert forms",
- ["falt"]="final glyph alternates",
- ["fin2"]="terminal forms #2",
- ["fin3"]="terminal forms #3",
- ["fina"]="terminal forms",
- ["flac"]="flattened accents over capitals",
- ["frac"]="fractions",
- ["fwid"]="full width",
- ["half"]="half forms",
- ["haln"]="halant forms",
- ["halt"]="alternate half width",
- ["hist"]="historical forms",
- ["hkna"]="horizontal kana alternates",
- ["hlig"]="historical ligatures",
- ["hngl"]="hangul",
- ["hojo"]="hojo kanji forms",
- ["hwid"]="half width",
- ["init"]="initial forms",
- ["isol"]="isolated forms",
- ["ital"]="italics",
- ["jalt"]="justification alternatives",
- ["jp04"]="jis2004 forms",
- ["jp78"]="jis78 forms",
- ["jp83"]="jis83 forms",
- ["jp90"]="jis90 forms",
- ["kern"]="kerning",
- ["lfbd"]="left bounds",
- ["liga"]="standard ligatures",
- ["ljmo"]="leading jamo forms",
- ["lnum"]="lining figures",
- ["locl"]="localized forms",
- ["ltra"]="left-to-right alternates",
- ["ltrm"]="left-to-right mirrored forms",
- ["mark"]="mark positioning",
- ["med2"]="medial forms #2",
- ["medi"]="medial forms",
- ["mgrk"]="mathematical greek",
- ["mkmk"]="mark to mark positioning",
- ["mset"]="mark positioning via substitution",
- ["nalt"]="alternate annotation forms",
- ["nlck"]="nlc kanji forms",
- ["nukt"]="nukta forms",
- ["numr"]="numerators",
- ["onum"]="old style figures",
- ["opbd"]="optical bounds",
- ["ordn"]="ordinals",
- ["ornm"]="ornaments",
- ["palt"]="proportional alternate width",
- ["pcap"]="petite capitals",
- ["pkna"]="proportional kana",
- ["pnum"]="proportional figures",
- ["pref"]="pre-base forms",
- ["pres"]="pre-base substitutions",
- ["pstf"]="post-base forms",
- ["psts"]="post-base substitutions",
- ["pwid"]="proportional widths",
- ["qwid"]="quarter widths",
- ["rand"]="randomize",
- ["rclt"]="required contextual alternates",
- ["rkrf"]="rakar forms",
- ["rlig"]="required ligatures",
- ["rphf"]="reph form",
- ["rtbd"]="right bounds",
- ["rtla"]="right-to-left alternates",
- ["rtlm"]="right to left mirrored forms",
- ["rvrn"]="required variation alternates",
- ["ruby"]="ruby notation forms",
- ["salt"]="stylistic alternates",
- ["sinf"]="scientific inferiors",
- ["size"]="optical size",
- ["smcp"]="small capitals",
- ["smpl"]="simplified forms",
- ["ssty"]="script style",
- ["stch"]="stretching glyph decomposition",
- ["subs"]="subscript",
- ["sups"]="superscript",
- ["swsh"]="swash",
- ["titl"]="titling",
- ["tjmo"]="trailing jamo forms",
- ["tnam"]="traditional name forms",
- ["tnum"]="tabular figures",
- ["trad"]="traditional forms",
- ["twid"]="third widths",
- ["unic"]="unicase",
- ["valt"]="alternate vertical metrics",
- ["vatu"]="vattu variants",
- ["vert"]="vertical writing",
- ["vhal"]="alternate vertical half metrics",
- ["vjmo"]="vowel jamo forms",
- ["vkna"]="vertical kana alternates",
- ["vkrn"]="vertical kerning",
- ["vpal"]="proportional alternate vertical metrics",
- ["vrtr"]="vertical alternates for rotation",
- ["vrt2"]="vertical rotation",
- ["zero"]="slashed zero",
- ["trep"]="traditional tex replacements",
- ["tlig"]="traditional tex ligatures",
- ["ss.."]="stylistic set ..",
- ["cv.."]="character variant ..",
- ["js.."]="justification ..",
- ["dv.."]="devanagari ..",
- ["ml.."]="malayalam ..",
-}
-local baselines=allocate {
- ["hang"]="hanging baseline",
- ["icfb"]="ideographic character face bottom edge baseline",
- ["icft"]="ideographic character face tope edige baseline",
- ["ideo"]="ideographic em-box bottom edge baseline",
- ["idtp"]="ideographic em-box top edge baseline",
- ["math"]="mathematical centered baseline",
- ["romn"]="roman baseline"
-}
-tables.scripts=scripts
-tables.languages=languages
-tables.features=features
-tables.baselines=baselines
-local acceptscripts=true directives.register("otf.acceptscripts",function(v) acceptscripts=v end)
-local acceptlanguages=true directives.register("otf.acceptlanguages",function(v) acceptlanguages=v end)
-local report_checks=logs.reporter("fonts","checks")
-if otffeatures.features then
- for k,v in next,otffeatures.features do
- features[k]=v
- end
- otffeatures.features=features
-end
-local function swapped(h)
- local r={}
- for k,v in next,h do
- r[gsub(v,"[^a-z0-9]","")]=k
- end
- return r
-end
-local verbosescripts=allocate(swapped(scripts ))
-local verboselanguages=allocate(swapped(languages))
-local verbosefeatures=allocate(swapped(features ))
-local verbosebaselines=allocate(swapped(baselines))
-local function resolve(t,k)
- if k then
- k=gsub(lower(k),"[^a-z0-9]","")
- local v=rawget(t,k)
- if v then
- return v
- end
- end
-end
-setmetatableindex(verbosescripts,resolve)
-setmetatableindex(verboselanguages,resolve)
-setmetatableindex(verbosefeatures,resolve)
-setmetatableindex(verbosebaselines,resolve)
-setmetatableindex(scripts,function(t,k)
- if k then
- k=lower(k)
- if k=="dflt" then
- return k
- end
- local v=rawget(t,k)
- if v then
- return v
- end
- k=gsub(k," ","")
- v=rawget(t,v)
- if v then
- return v
- elseif acceptscripts then
- report_checks("registering extra script %a",k)
- rawset(t,k,k)
- return k
- end
- end
- return "dflt"
-end)
-setmetatableindex(languages,function(t,k)
- if k then
- k=lower(k)
- if k=="dflt" then
- return k
- end
- local v=rawget(t,k)
- if v then
- return v
- end
- k=gsub(k," ","")
- v=rawget(t,v)
- if v then
- return v
- elseif acceptlanguages then
- report_checks("registering extra language %a",k)
- rawset(t,k,k)
- return k
- end
- end
- return "dflt"
-end)
-if setmetatablenewindex then
- setmetatablenewindex(languages,"ignore")
- setmetatablenewindex(scripts,"ignore")
- setmetatablenewindex(baselines,"ignore")
-end
-local function resolve(t,k)
- if k then
- k=lower(k)
- local v=rawget(t,k)
- if v then
- return v
- end
- k=gsub(k," ","")
- local v=rawget(t,k)
- if v then
- return v
- end
- local tag,dd=match(k,"(..)(%d+)")
- if tag and dd then
- local v=rawget(t,tag)
- if v then
- return v
- else
- local v=rawget(t,tag.."..")
- if v then
- return (gsub(v,"%.%.",tonumber(dd)))
- end
- end
- end
- end
- return k
-end
-setmetatableindex(features,resolve)
-local function assign(t,k,v)
- if k and v then
- v=lower(v)
- rawset(t,k,v)
- end
-end
-if setmetatablenewindex then
- setmetatablenewindex(features,assign)
-end
-local checkers={
- rand=function(v)
- return v==true and "random" or v
- end
-}
-if not storage then
- return
-end
-local usedfeatures=statistics.usedfeatures or {}
-statistics.usedfeatures=usedfeatures
-table.setmetatableindex(usedfeatures,function(t,k) if k then local v={} t[k]=v return v end end)
-storage.register("fonts/otf/usedfeatures",usedfeatures,"fonts.handlers.otf.statistics.usedfeatures" )
-local normalizedaxis=otf.readers.helpers.normalizedaxis or function(s) return s end
-function otffeatures.normalize(features,wrap)
- if features then
- local h={}
- for key,value in next,features do
- local k=lower(key)
- if k=="language" then
- local v=gsub(lower(value),"[^a-z0-9]","")
- h.language=rawget(verboselanguages,v) or (languages[v] and v) or "dflt"
- elseif k=="script" then
- local v=gsub(lower(value),"[^a-z0-9]","")
- h.script=rawget(verbosescripts,v) or (scripts[v] and v) or "dflt"
- elseif k=="axis" then
- h[k]=normalizedaxis(value)
- if not callbacks.supported.glyph_stream_provider then
- h.variableshapes=true
- end
- else
- local uk=usedfeatures[key]
- local uv=uk[value]
- if uv then
- else
- uv=tonumber(value)
- if uv then
- elseif type(value)=="string" then
- local b=is_boolean(value)
- if type(b)=="nil" then
- if wrap and find(value,",") then
- uv="{"..lower(value).."}"
- else
- uv=lower(value)
- end
- else
- uv=b
- end
- elseif type(value)=="table" then
- uv=sequenced(t,",")
- else
- uv=value
- end
- if not rawget(features,k) then
- k=rawget(verbosefeatures,k) or k
- end
- local c=checkers[k]
- if c then
- uv=c(uv) or vc
- end
- uk[value]=uv
- end
- h[k]=uv
- end
- end
- return h
- end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
if not modules then modules={} end modules ['font-cff']={
version=1.001,
+ optimize=true,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -14520,12 +13277,15 @@ do
local p_dictionary=(
p_byte+p_positive+p_negative+p_short+p_long+p_nibbles+p_single+p_double+p_unsupported
)^1
- parsedictionaries=function(data,dictionaries,what)
+ parsedictionaries=function(data,dictionaries,version)
stack={}
strings=data.strings
+ if trace_charstrings then
+ report("charstring format %a",version)
+ end
for i=1,#dictionaries do
top=0
- result=what=="cff" and {
+ result=version=="cff" and {
monospaced=false,
italicangle=0,
underlineposition=-100,
@@ -15324,6 +14084,7 @@ do
end
end
else
+ top=top-nofregions*n
end
end
local actions={ [0]=unsupported,
@@ -15899,8 +14660,8 @@ do
processshape(tab,index-1)
end
end
-local function readglobals(f,data)
- local routines=readlengths(f)
+local function readglobals(f,data,version)
+ local routines=readlengths(f,version=="cff2")
for i=1,#routines do
routines[i]=readbytetable(f,routines[i])
end
@@ -15954,14 +14715,14 @@ local function readprivates(f,data)
private.data=readstring(f,private.size)
end
end
-local function readlocals(f,data,dictionary)
+local function readlocals(f,data,dictionary,version)
local header=data.header
local private=dictionary.private
if private then
local subroutineoffset=private.data.subroutines
if subroutineoffset~=0 then
setposition(f,header.offset+private.offset+subroutineoffset)
- local subroutines=readlengths(f)
+ local subroutines=readlengths(f,version=="cff2")
for i=1,#subroutines do
subroutines[i]=readbytetable(f,subroutines[i])
end
@@ -15974,7 +14735,7 @@ local function readlocals(f,data,dictionary)
dictionary.subroutines={}
end
end
-local function readcharstrings(f,data,what)
+local function readcharstrings(f,data,version)
local header=data.header
local dictionaries=data.dictionaries
local dictionary=dictionaries[1]
@@ -15983,7 +14744,7 @@ local function readcharstrings(f,data,what)
if type(offset)~="number" then
elseif stringtype==2 then
setposition(f,header.offset+offset)
- local charstrings=readlengths(f,what=="cff2")
+ local charstrings=readlengths(f,version=="cff2")
local nofglyphs=#charstrings
for i=1,nofglyphs do
charstrings[i]=readstring(f,charstrings[i])
@@ -16013,7 +14774,8 @@ readers.parsecharstrings=parsecharstrings
local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams)
local dictionaries=data.dictionaries
local dictionary=dictionaries[1]
- readglobals(f,data)
+ local cid=not dictionary.private and dictionary.cid
+ readglobals(f,data,version)
readcharstrings(f,data,version)
if version=="cff2" then
dictionary.charset=nil
@@ -16021,9 +14783,27 @@ local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams)
readencodings(f,data)
readcharsets(f,data,dictionary)
end
+ if cid then
+ local fdarray=cid.fdarray
+ if fdarray then
+ setposition(f,data.header.offset+fdarray)
+ local dictionaries=readlengths(f,version=="cff2")
+ local nofdictionaries=#dictionaries
+ if nofdictionaries>0 then
+ for i=1,nofdictionaries do
+ dictionaries[i]=readstring(f,dictionaries[i])
+ end
+ parsedictionaries(data,dictionaries)
+ dictionary.private=dictionaries[1].private
+ if nofdictionaries>1 then
+ report("ignoring dictionaries > 1 in cid font")
+ end
+ end
+ end
+ end
readprivates(f,data)
parseprivates(data,data.dictionaries)
- readlocals(f,data,dictionary)
+ readlocals(f,data,dictionary,version)
startparsing(fontdata,data,streams)
parsecharstrings(fontdata,data,glyphs,doshapes,version,streams)
stopparsing(fontdata,data)
@@ -16034,7 +14814,7 @@ local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams)
local dictionary=dictionaries[1]
local cid=dictionary.cid
local cidselect=cid and cid.fdselect
- readglobals(f,data)
+ readglobals(f,data,version)
readcharstrings(f,data,version)
if version~="cff2" then
readencodings(f,data)
@@ -16078,7 +14858,7 @@ local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams)
local cidarray=cid.fdarray
if cidarray then
setposition(f,header.offset+cidarray)
- local dictionaries=readlengths(f)
+ local dictionaries=readlengths(f,version=="cff2")
for i=1,#dictionaries do
dictionaries[i]=readstring(f,dictionaries[i])
end
@@ -16086,7 +14866,7 @@ local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams)
cid.dictionaries=dictionaries
readcidprivates(f,data)
for i=1,#dictionaries do
- readlocals(f,data,dictionaries[i])
+ readlocals(f,data,dictionaries[i],version)
end
startparsing(fontdata,data,streams)
for i=1,#charstrings do
@@ -16246,6 +15026,7 @@ do -- begin closure to overcome local limits and interference
if not modules then modules={} end modules ['font-ttf']={
version=1.001,
+ optimize=true,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -17418,6 +16199,7 @@ do -- begin closure to overcome local limits and interference
if not modules then modules={} end modules ['font-dsp']={
version=1.001,
+ optimize=true,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -20695,2643 +19477,1263 @@ end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules={} end modules ['font-oup']={
+if not modules then modules={} end modules ['font-oti']={
version=1.001,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local next,type=next,type
-local P,R,S=lpeg.P,lpeg.R,lpeg.S
-local lpegmatch=lpeg.match
-local insert,remove,copy,unpack=table.insert,table.remove,table.copy,table.unpack
-local formatters=string.formatters
-local sortedkeys=table.sortedkeys
-local sortedhash=table.sortedhash
-local tohash=table.tohash
-local setmetatableindex=table.setmetatableindex
-local report_error=logs.reporter("otf reader","error")
-local report_markwidth=logs.reporter("otf reader","markwidth")
-local report_cleanup=logs.reporter("otf reader","cleanup")
-local report_optimizations=logs.reporter("otf reader","merges")
-local report_unicodes=logs.reporter("otf reader","unicodes")
-local trace_markwidth=false trackers.register("otf.markwidth",function(v) trace_markwidth=v end)
-local trace_cleanup=false trackers.register("otf.cleanups",function(v) trace_cleanups=v end)
-local trace_optimizations=false trackers.register("otf.optimizations",function(v) trace_optimizations=v end)
-local trace_unicodes=false trackers.register("otf.unicodes",function(v) trace_unicodes=v end)
-local readers=fonts.handlers.otf.readers
-local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000
-local f_private=formatters["P%05X"]
-local f_unicode=formatters["U%05X"]
-local f_index=formatters["I%05X"]
-local f_character_y=formatters["%C"]
-local f_character_n=formatters["[ %C ]"]
-local check_duplicates=true
-local check_soft_hyphen=true
-directives.register("otf.checksofthyphen",function(v)
- check_soft_hyphen=v
-end)
-local function replaced(list,index,replacement)
- if type(list)=="number" then
- return replacement
- elseif type(replacement)=="table" then
- local t={}
- local n=index-1
- for i=1,n do
- t[i]=list[i]
- end
- for i=1,#replacement do
- n=n+1
- t[n]=replacement[i]
- end
- for i=index+1,#list do
- n=n+1
- t[n]=list[i]
- end
- else
- list[index]=replacement
- return list
- end
-end
-local function unifyresources(fontdata,indices)
- local descriptions=fontdata.descriptions
- local resources=fontdata.resources
- if not descriptions or not resources then
- return
- end
- local nofindices=#indices
- local variants=fontdata.resources.variants
- if variants then
- for selector,unicodes in next,variants do
- for unicode,index in next,unicodes do
- unicodes[unicode]=indices[index]
- end
- end
- end
- local function remark(marks)
- if marks then
- local newmarks={}
- for k,v in next,marks do
- local u=indices[k]
- if u then
- newmarks[u]=v
- elseif trace_optimizations then
- report_optimizations("discarding mark %i",k)
- end
- end
- return newmarks
- end
- end
- local marks=resources.marks
- if marks then
- resources.marks=remark(marks)
- end
- local markclasses=resources.markclasses
- if markclasses then
- for class,marks in next,markclasses do
- markclasses[class]=remark(marks)
- end
- end
- local marksets=resources.marksets
- if marksets then
- for class,marks in next,marksets do
- marksets[class]=remark(marks)
- end
- end
- local done={}
- local duplicates=check_duplicates and resources.duplicates
- if duplicates and not next(duplicates) then
- duplicates=false
- end
- local function recover(cover)
- for i=1,#cover do
- local c=cover[i]
- if not done[c] then
- local t={}
- for k,v in next,c do
- local ug=indices[k]
- if ug then
- t[ug]=v
- else
- report_error("case %i, bad index in unifying %s: %s of %s",1,"coverage",k,nofindices)
- end
- end
- cover[i]=t
- done[c]=d
- end
- end
- end
- local function recursed(c,kind)
- local t={}
- for g,d in next,c do
- if type(d)=="table" then
- local ug=indices[g]
- if ug then
- t[ug]=recursed(d,kind)
- else
- report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g,nofindices)
- end
- else
- t[g]=indices[d]
- end
- end
- return t
- end
- local function unifythem(sequences)
- if not sequences then
- return
- end
- for i=1,#sequences do
- local sequence=sequences[i]
- local kind=sequence.type
- local steps=sequence.steps
- local features=sequence.features
- if steps then
- for i=1,#steps do
- local step=steps[i]
- if kind=="gsub_single" then
- local c=step.coverage
- if c then
- local t1=done[c]
- if not t1 then
- t1={}
- if duplicates then
- for g1,d1 in next,c do
- local ug1=indices[g1]
- if ug1 then
- local ud1=indices[d1]
- if ud1 then
- t1[ug1]=ud1
- local dg1=duplicates[ug1]
- if dg1 then
- for u in next,dg1 do
- t1[u]=ud1
- end
- end
- else
- report_error("case %i, bad index in unifying %s: %s of %s",3,kind,d1,nofindices)
- end
- else
- report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices)
- end
- end
- else
- for g1,d1 in next,c do
- local ug1=indices[g1]
- if ug1 then
- t1[ug1]=indices[d1]
- else
- report_error("fuzzy case %i in unifying %s: %i",2,kind,g1)
- end
- end
- end
- done[c]=t1
- end
- step.coverage=t1
- end
- elseif kind=="gpos_pair" then
- local c=step.coverage
- if c then
- local t1=done[c]
- if not t1 then
- t1={}
- for g1,d1 in next,c do
- local ug1=indices[g1]
- if ug1 then
- local t2=done[d1]
- if not t2 then
- t2={}
- for g2,d2 in next,d1 do
- local ug2=indices[g2]
- if ug2 then
- t2[ug2]=d2
- else
- report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g2,nofindices,nofindices)
- end
- end
- done[d1]=t2
- end
- t1[ug1]=t2
- else
- report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices)
- end
- end
- done[c]=t1
- end
- step.coverage=t1
- end
- elseif kind=="gsub_ligature" then
- local c=step.coverage
- if c then
- step.coverage=recursed(c,kind)
- end
- elseif kind=="gsub_alternate" or kind=="gsub_multiple" then
- local c=step.coverage
- if c then
- local t1=done[c]
- if not t1 then
- t1={}
- if duplicates then
- for g1,d1 in next,c do
- for i=1,#d1 do
- local d1i=d1[i]
- local d1u=indices[d1i]
- if d1u then
- d1[i]=d1u
- else
- report_error("case %i, bad index in unifying %s: %s of %s",1,kind,i,d1i,nofindices)
- end
- end
- local ug1=indices[g1]
- if ug1 then
- t1[ug1]=d1
- local dg1=duplicates[ug1]
- if dg1 then
- for u in next,dg1 do
- t1[u]=copy(d1)
- end
- end
- else
- report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices)
- end
- end
- else
- for g1,d1 in next,c do
- for i=1,#d1 do
- local d1i=d1[i]
- local d1u=indices[d1i]
- if d1u then
- d1[i]=d1u
- else
- report_error("case %i, bad index in unifying %s: %s of %s",2,kind,d1i,nofindices)
- end
- end
- t1[indices[g1]]=d1
- end
- end
- done[c]=t1
- end
- step.coverage=t1
- end
- elseif kind=="gpos_single" then
- local c=step.coverage
- if c then
- local t1=done[c]
- if not t1 then
- t1={}
- if duplicates then
- for g1,d1 in next,c do
- local ug1=indices[g1]
- if ug1 then
- t1[ug1]=d1
- local dg1=duplicates[ug1]
- if dg1 then
- for u in next,dg1 do
- t1[u]=d1
- end
- end
- else
- report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices)
- end
- end
- else
- for g1,d1 in next,c do
- local ug1=indices[g1]
- if ug1 then
- t1[ug1]=d1
- else
- report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices)
- end
- end
- end
- done[c]=t1
- end
- step.coverage=t1
- end
- elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" or kind=="gpos_mark2ligature" then
- local c=step.coverage
- if c then
- local t1=done[c]
- if not t1 then
- t1={}
- for g1,d1 in next,c do
- local ug1=indices[g1]
- if ug1 then
- t1[ug1]=d1
- else
- report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices)
- end
- end
- done[c]=t1
- end
- step.coverage=t1
- end
- local c=step.baseclasses
- if c then
- local t1=done[c]
- if not t1 then
- for g1,d1 in next,c do
- local t2=done[d1]
- if not t2 then
- t2={}
- for g2,d2 in next,d1 do
- local ug2=indices[g2]
- if ug2 then
- t2[ug2]=d2
- else
- report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g2,nofindices)
- end
- end
- done[d1]=t2
- end
- c[g1]=t2
- end
- done[c]=c
- end
- end
- elseif kind=="gpos_cursive" then
- local c=step.coverage
- if c then
- local t1=done[c]
- if not t1 then
- t1={}
- if duplicates then
- for g1,d1 in next,c do
- local ug1=indices[g1]
- if ug1 then
- t1[ug1]=d1
- local dg1=duplicates[ug1]
- if dg1 then
- for u in next,dg1 do
- t1[u]=copy(d1)
- end
- end
- else
- report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices)
- end
- end
- else
- for g1,d1 in next,c do
- local ug1=indices[g1]
- if ug1 then
- t1[ug1]=d1
- else
- report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices)
- end
- end
- end
- done[c]=t1
- end
- step.coverage=t1
- end
- end
- local rules=step.rules
- if rules then
- for i=1,#rules do
- local rule=rules[i]
- local before=rule.before if before then recover(before) end
- local after=rule.after if after then recover(after) end
- local current=rule.current if current then recover(current) end
- local replacements=rule.replacements
- if replacements then
- if not done[replacements] then
- local r={}
- for k,v in next,replacements do
- r[indices[k]]=indices[v]
- end
- rule.replacements=r
- done[replacements]=r
- end
- end
- end
- end
- end
- end
- end
- end
- unifythem(resources.sequences)
- unifythem(resources.sublookups)
-end
-local function copyduplicates(fontdata)
- if check_duplicates then
- local descriptions=fontdata.descriptions
- local resources=fontdata.resources
- local duplicates=resources.duplicates
- if check_soft_hyphen then
- local ds=descriptions[0xAD]
- if not ds or ds.width==0 then
- if ds then
- descriptions[0xAD]=nil
- if trace_unicodes then
- report_unicodes("patching soft hyphen")
- end
- else
- if trace_unicodes then
- report_unicodes("adding soft hyphen")
- end
- end
- if not duplicates then
- duplicates={}
- resources.duplicates=duplicates
- end
- local dh=duplicates[0x2D]
- if dh then
- dh[#dh+1]={ [0xAD]=true }
- else
- duplicates[0x2D]={ [0xAD]=true }
- end
- end
- end
- if duplicates then
- for u,d in next,duplicates do
- local du=descriptions[u]
- if du then
- local t={ f_character_y(u),"@",f_index(du.index),"->" }
- local n=0
- local m=25
- for u in next,d do
- if descriptions[u] then
- if n<m then
- t[n+4]=f_character_n(u)
- end
- else
- local c=copy(du)
- c.unicode=u
- descriptions[u]=c
- if n<m then
- t[n+4]=f_character_y(u)
- end
- end
- n=n+1
- end
- if trace_unicodes then
- if n<=m then
- report_unicodes("%i : % t",n,t)
- else
- report_unicodes("%i : % t ...",n,t)
- end
- end
- else
- end
- end
- end
- end
-end
-local ignore={
- ["notdef"]=true,
- [".notdef"]=true,
- ["null"]=true,
- [".null"]=true,
- ["nonmarkingreturn"]=true,
+local lower=string.lower
+local fonts=fonts
+local constructors=fonts.constructors
+local otf=constructors.handlers.otf
+local otffeatures=constructors.features.otf
+local registerotffeature=otffeatures.register
+local otftables=otf.tables or {}
+otf.tables=otftables
+local allocate=utilities.storage.allocate
+registerotffeature {
+ name="features",
+ description="initialization of feature handler",
+ default=true,
}
-local function checklookups(fontdata,missing,nofmissing)
- local descriptions=fontdata.descriptions
- local resources=fontdata.resources
- if missing and nofmissing and nofmissing<=0 then
- return
- end
- local singles={}
- local alternates={}
- local ligatures={}
- if not missing then
- missing={}
- nofmissing=0
- for u,d in next,descriptions do
- if not d.unicode then
- nofmissing=nofmissing+1
- missing[u]=true
- end
- end
- end
- local function collectthem(sequences)
- if not sequences then
- return
- end
- for i=1,#sequences do
- local sequence=sequences[i]
- local kind=sequence.type
- local steps=sequence.steps
- if steps then
- for i=1,#steps do
- local step=steps[i]
- if kind=="gsub_single" then
- local c=step.coverage
- if c then
- singles[#singles+1]=c
- end
- elseif kind=="gsub_alternate" then
- local c=step.coverage
- if c then
- alternates[#alternates+1]=c
- end
- elseif kind=="gsub_ligature" then
- local c=step.coverage
- if c then
- ligatures[#ligatures+1]=c
- end
- end
- end
- end
- end
- end
- collectthem(resources.sequences)
- collectthem(resources.sublookups)
- local loops=0
- while true do
- loops=loops+1
- local old=nofmissing
- for i=1,#singles do
- local c=singles[i]
- for g1,g2 in next,c do
- if missing[g1] then
- local u2=descriptions[g2].unicode
- if u2 then
- missing[g1]=false
- descriptions[g1].unicode=u2
- nofmissing=nofmissing-1
- end
- end
- if missing[g2] then
- local u1=descriptions[g1].unicode
- if u1 then
- missing[g2]=false
- descriptions[g2].unicode=u1
- nofmissing=nofmissing-1
- end
- end
- end
- end
- for i=1,#alternates do
- local c=alternates[i]
- for g1,d1 in next,c do
- if missing[g1] then
- for i=1,#d1 do
- local g2=d1[i]
- local u2=descriptions[g2].unicode
- if u2 then
- missing[g1]=false
- descriptions[g1].unicode=u2
- nofmissing=nofmissing-1
- end
- end
- end
- if not missing[g1] then
- for i=1,#d1 do
- local g2=d1[i]
- if missing[g2] then
- local u1=descriptions[g1].unicode
- if u1 then
- missing[g2]=false
- descriptions[g2].unicode=u1
- nofmissing=nofmissing-1
- end
- end
- end
- end
- end
- end
- if nofmissing<=0 then
- if trace_unicodes then
- report_unicodes("all missings done in %s loops",loops)
- end
- return
- elseif old==nofmissing then
- break
- end
- end
- local t,n
- local function recursed(c)
- for g,d in next,c do
- if g~="ligature" then
- local u=descriptions[g].unicode
- if u then
- n=n+1
- t[n]=u
- recursed(d)
- n=n-1
- end
- elseif missing[d] then
- local l={}
- local m=0
- for i=1,n do
- local u=t[i]
- if type(u)=="table" then
- for i=1,#u do
- m=m+1
- l[m]=u[i]
- end
- else
- m=m+1
- l[m]=u
- end
- end
- missing[d]=false
- descriptions[d].unicode=l
- nofmissing=nofmissing-1
- end
- end
- end
- if nofmissing>0 then
- t={}
- n=0
- local loops=0
- while true do
- loops=loops+1
- local old=nofmissing
- for i=1,#ligatures do
- recursed(ligatures[i])
- end
- if nofmissing<=0 then
- if trace_unicodes then
- report_unicodes("all missings done in %s loops",loops)
- end
- return
- elseif old==nofmissing then
- break
- end
- end
- t=nil
- n=0
- end
- if trace_unicodes and nofmissing>0 then
- local done={}
- for i,r in next,missing do
- if r then
- local data=descriptions[i]
- local name=data and data.name or f_index(i)
- if not ignore[name] then
- done[name]=true
- end
- end
- end
- if next(done) then
- report_unicodes("not unicoded: % t",sortedkeys(done))
- end
+local function setmode(tfmdata,value)
+ if value then
+ tfmdata.properties.mode=lower(value)
end
end
-local firstprivate=fonts.privateoffsets and fonts.privateoffsets.textbase or 0xF0000
-local puafirst=0xE000
-local pualast=0xF8FF
-local function unifymissing(fontdata)
- if not fonts.mappings then
- require("font-map")
- require("font-agl")
- end
- local unicodes={}
- local resources=fontdata.resources
- resources.unicodes=unicodes
- for unicode,d in next,fontdata.descriptions do
- if unicode<privateoffset then
- if unicode>=puafirst and unicode<=pualast then
- else
- local name=d.name
- if name then
- unicodes[name]=unicode
- end
- end
+otf.modeinitializer=setmode
+local function setlanguage(tfmdata,value)
+ if value then
+ local cleanvalue=lower(value)
+ local languages=otftables and otftables.languages
+ local properties=tfmdata.properties
+ if not languages then
+ properties.language=cleanvalue
+ elseif languages[value] then
+ properties.language=cleanvalue
else
+ properties.language="dflt"
end
end
- fonts.mappings.addtounicode(fontdata,fontdata.filename,checklookups)
- resources.unicodes=nil
-end
-local function unifyglyphs(fontdata,usenames)
- local private=fontdata.private or privateoffset
- local glyphs=fontdata.glyphs
- local indices={}
- local descriptions={}
- local names=usenames and {}
- local resources=fontdata.resources
- local zero=glyphs[0]
- local zerocode=zero.unicode
- if not zerocode then
- zerocode=private
- zero.unicode=zerocode
- private=private+1
- end
- descriptions[zerocode]=zero
- if names then
- local name=glyphs[0].name or f_private(zerocode)
- indices[0]=name
- names[name]=zerocode
- else
- indices[0]=zerocode
- end
- if names then
- for index=1,#glyphs do
- local glyph=glyphs[index]
- local unicode=glyph.unicode
- if not unicode then
- unicode=private
- local name=glyph.name or f_private(unicode)
- indices[index]=name
- names[name]=unicode
- private=private+1
- elseif unicode>=firstprivate then
- unicode=private
- local name=glyph.name or f_private(unicode)
- indices[index]=name
- names[name]=unicode
- private=private+1
- elseif unicode>=puafirst and unicode<=pualast then
- local name=glyph.name or f_private(unicode)
- indices[index]=name
- names[name]=unicode
- elseif descriptions[unicode] then
- unicode=private
- local name=glyph.name or f_private(unicode)
- indices[index]=name
- names[name]=unicode
- private=private+1
- else
- local name=glyph.name or f_unicode(unicode)
- indices[index]=name
- names[name]=unicode
- end
- descriptions[unicode]=glyph
- end
- elseif trace_unicodes then
- for index=1,#glyphs do
- local glyph=glyphs[index]
- local unicode=glyph.unicode
- if not unicode then
- unicode=private
- indices[index]=unicode
- private=private+1
- elseif unicode>=firstprivate then
- local name=glyph.name
- if name then
- report_unicodes("moving glyph %a indexed %05X from private %U to %U ",name,index,unicode,private)
- else
- report_unicodes("moving glyph indexed %05X from private %U to %U ",index,unicode,private)
- end
- unicode=private
- indices[index]=unicode
- private=private+1
- elseif unicode>=puafirst and unicode<=pualast then
- local name=glyph.name
- if name then
- report_unicodes("keeping private unicode %U for glyph %a indexed %05X",unicode,name,index)
- else
- report_unicodes("keeping private unicode %U for glyph indexed %05X",unicode,index)
- end
- indices[index]=unicode
- elseif descriptions[unicode] then
- local name=glyph.name
- if name then
- report_unicodes("assigning duplicate unicode %U to %U for glyph %a indexed %05X ",unicode,private,name,index)
- else
- report_unicodes("assigning duplicate unicode %U to %U for glyph indexed %05X ",unicode,private,index)
- end
- unicode=private
- indices[index]=unicode
- private=private+1
- else
- indices[index]=unicode
- end
- descriptions[unicode]=glyph
- end
- else
- for index=1,#glyphs do
- local glyph=glyphs[index]
- local unicode=glyph.unicode
- if not unicode then
- unicode=private
- indices[index]=unicode
- private=private+1
- elseif unicode>=firstprivate then
- local name=glyph.name
- unicode=private
- indices[index]=unicode
- private=private+1
- elseif unicode>=puafirst and unicode<=pualast then
- local name=glyph.name
- indices[index]=unicode
- elseif descriptions[unicode] then
- local name=glyph.name
- unicode=private
- indices[index]=unicode
- private=private+1
- else
- indices[index]=unicode
- end
- descriptions[unicode]=glyph
- end
- end
- for index=1,#glyphs do
- local math=glyphs[index].math
- if math then
- local list=math.vparts
- if list then
- for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end
- end
- local list=math.hparts
- if list then
- for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end
- end
- local list=math.vvariants
- if list then
- for i=1,#list do list[i]=indices[list[i]] end
- end
- local list=math.hvariants
- if list then
- for i=1,#list do list[i]=indices[list[i]] end
- end
- end
- end
- local colorpalettes=resources.colorpalettes
- if colorpalettes then
- for index=1,#glyphs do
- local colors=glyphs[index].colors
- if colors then
- for i=1,#colors do
- local c=colors[i]
- c.slot=indices[c.slot]
- end
- end
- end
- end
- fontdata.private=private
- fontdata.glyphs=nil
- fontdata.names=names
- fontdata.descriptions=descriptions
- fontdata.hashmethod=hashmethod
- return indices,names
end
-local p_crappyname do
- local p_hex=R("af","AF","09")
- local p_digit=R("09")
- local p_done=S("._-")^0+P(-1)
- local p_alpha=R("az","AZ")
- local p_ALPHA=R("AZ")
- p_crappyname=(
- lpeg.utfchartabletopattern({ "uni","u" },true)*S("Xx_")^0*p_hex^1
-+lpeg.utfchartabletopattern({ "identity","glyph","jamo" },true)*p_hex^1
-+lpeg.utfchartabletopattern({ "index","afii" },true)*p_digit^1
-+p_digit*p_hex^3+p_alpha*p_digit^1
-+P("aj")*p_digit^1+P("eh_")*(p_digit^1+p_ALPHA*p_digit^1)+(1-P("_"))^1*P("_uni")*p_hex^1+P("_")*P(1)^1
- )*p_done
-end
-local forcekeep=false
-directives.register("otf.keepnames",function(v)
- report_cleanup("keeping weird glyph names, expect larger files and more memory usage")
- forcekeep=v
-end)
-local function stripredundant(fontdata)
- local descriptions=fontdata.descriptions
- if descriptions then
- local n=0
- local c=0
- if (not context and fonts.privateoffsets.keepnames) or forcekeep then
- for unicode,d in next,descriptions do
- if d.class=="base" then
- d.class=nil
- c=c+1
- end
- end
+local function setscript(tfmdata,value)
+ if value then
+ local cleanvalue=lower(value)
+ local scripts=otftables and otftables.scripts
+ local properties=tfmdata.properties
+ if not scripts then
+ properties.script=cleanvalue
+ elseif scripts[value] then
+ properties.script=cleanvalue
else
- for unicode,d in next,descriptions do
- local name=d.name
- if name and lpegmatch(p_crappyname,name) then
- d.name=nil
- n=n+1
- end
- if d.class=="base" then
- d.class=nil
- c=c+1
- end
- end
- end
- if trace_cleanup then
- if n>0 then
- report_cleanup("%s bogus names removed (verbose unicode)",n)
- end
- if c>0 then
- report_cleanup("%s base class tags removed (default is base)",c)
- end
- end
- end
-end
-readers.stripredundant=stripredundant
-function readers.getcomponents(fontdata)
- local resources=fontdata.resources
- if resources then
- local sequences=resources.sequences
- if sequences then
- local collected={}
- for i=1,#sequences do
- local sequence=sequences[i]
- if sequence.type=="gsub_ligature" then
- local steps=sequence.steps
- if steps then
- local l={}
- local function traverse(p,k,v)
- if k=="ligature" then
- collected[v]={ unpack(l) }
- else
- insert(l,k)
- for k,vv in next,v do
- traverse(p,k,vv)
- end
- remove(l)
- end
- end
- for i=1,#steps do
- local c=steps[i].coverage
- if c then
- for k,v in next,c do
- traverse(k,k,v)
- end
- end
- end
- end
- end
- end
- if next(collected) then
- while true do
- local done=false
- for k,v in next,collected do
- for i=1,#v do
- local vi=v[i]
- if vi==k then
- collected[k]=nil
- break
- else
- local c=collected[vi]
- if c then
- done=true
- local t={}
- local n=i-1
- for j=1,n do
- t[j]=v[j]
- end
- for j=1,#c do
- n=n+1
- t[n]=c[j]
- end
- for j=i+1,#v do
- n=n+1
- t[n]=v[j]
- end
- collected[k]=t
- break
- end
- end
- end
- end
- if not done then
- break
- end
- end
- return collected
- end
+ properties.script="dflt"
end
end
end
-readers.unifymissing=unifymissing
-function readers.rehash(fontdata,hashmethod)
- if not (fontdata and fontdata.glyphs) then
- return
- end
- if hashmethod=="indices" then
- fontdata.hashmethod="indices"
- elseif hashmethod=="names" then
- fontdata.hashmethod="names"
- local indices=unifyglyphs(fontdata,true)
- unifyresources(fontdata,indices)
- copyduplicates(fontdata)
- unifymissing(fontdata)
- else
- fontdata.hashmethod="unicodes"
- local indices=unifyglyphs(fontdata)
- unifyresources(fontdata,indices)
- copyduplicates(fontdata)
- unifymissing(fontdata)
- stripredundant(fontdata)
- end
-end
-function readers.checkhash(fontdata)
- local hashmethod=fontdata.hashmethod
- if hashmethod=="unicodes" then
- fontdata.names=nil
- elseif hashmethod=="names" and fontdata.names then
- unifyresources(fontdata,fontdata.names)
- copyduplicates(fontdata)
- fontdata.hashmethod="unicodes"
- fontdata.names=nil
- else
- readers.rehash(fontdata,"unicodes")
- end
-end
-function readers.addunicodetable(fontdata)
- local resources=fontdata.resources
- local unicodes=resources.unicodes
- if not unicodes then
- local descriptions=fontdata.descriptions
- if descriptions then
- unicodes={}
- resources.unicodes=unicodes
- for u,d in next,descriptions do
- local n=d.name
- if n then
- unicodes[n]=u
- end
+registerotffeature {
+ name="mode",
+ description="mode",
+ initializers={
+ base=setmode,
+ node=setmode,
+ plug=setmode,
+ }
+}
+registerotffeature {
+ name="language",
+ description="language",
+ initializers={
+ base=setlanguage,
+ node=setlanguage,
+ plug=setlanguage,
+ }
+}
+registerotffeature {
+ name="script",
+ description="script",
+ initializers={
+ base=setscript,
+ node=setscript,
+ plug=setscript,
+ }
+}
+otftables.featuretypes=allocate {
+ gpos_single="position",
+ gpos_pair="position",
+ gpos_cursive="position",
+ gpos_mark2base="position",
+ gpos_mark2ligature="position",
+ gpos_mark2mark="position",
+ gpos_context="position",
+ gpos_contextchain="position",
+ gsub_single="substitution",
+ gsub_multiple="substitution",
+ gsub_alternate="substitution",
+ gsub_ligature="substitution",
+ gsub_context="substitution",
+ gsub_contextchain="substitution",
+ gsub_reversecontextchain="substitution",
+ gsub_reversesub="substitution",
+}
+function otffeatures.checkeddefaultscript(featuretype,autoscript,scripts)
+ if featuretype=="position" then
+ local default=scripts.dflt
+ if default then
+ if autoscript=="position" or autoscript==true then
+ return default
+ else
+ report_otf("script feature %s not applied, enable default positioning")
end
- end
- end
-end
-local concat,sort=table.concat,table.sort
-local next,type,tostring=next,type,tostring
-local criterium=1
-local threshold=0
-local trace_packing=false trackers.register("otf.packing",function(v) trace_packing=v end)
-local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end)
-local report_otf=logs.reporter("fonts","otf loading")
-local function tabstr_normal(t)
- local s={}
- local n=0
- for k,v in next,t do
- n=n+1
- if type(v)=="table" then
- s[n]=k..">"..tabstr_normal(v)
- elseif v==true then
- s[n]=k.."+"
- elseif v then
- s[n]=k.."="..v
- else
- s[n]=k.."-"
- end
- end
- if n==0 then
- return ""
- elseif n==1 then
- return s[1]
- else
- sort(s)
- return concat(s,",")
- end
-end
-local function tabstr_flat(t)
- local s={}
- local n=0
- for k,v in next,t do
- n=n+1
- s[n]=k.."="..v
- end
- if n==0 then
- return ""
- elseif n==1 then
- return s[1]
- else
- sort(s)
- return concat(s,",")
- end
-end
-local function tabstr_mixed(t)
- local s={}
- local n=#t
- if n==0 then
- return ""
- elseif n==1 then
- local k=t[1]
- if k==true then
- return "++"
- elseif k==false then
- return "--"
else
- return tostring(k)
end
- else
- for i=1,n do
- local k=t[i]
- if k==true then
- s[i]="++"
- elseif k==false then
- s[i]="--"
- else
- s[i]=k
+ elseif featuretype=="substitution" then
+ local default=scripts.dflt
+ if default then
+ if autoscript=="substitution" or autoscript==true then
+ return default
end
end
- return concat(s,",")
end
end
-local function tabstr_boolean(t)
- local s={}
- local n=0
- for k,v in next,t do
- n=n+1
- if v then
- s[n]=k.."+"
- else
- s[n]=k.."-"
- end
- end
- if n==0 then
- return ""
- elseif n==1 then
- return s[1]
- else
- sort(s)
- return concat(s,",")
- end
-end
-function readers.pack(data)
- if data then
- local h,t,c={},{},{}
- local hh,tt,cc={},{},{}
- local nt,ntt=0,0
- local function pack_normal(v)
- local tag=tabstr_normal(v)
- local ht=h[tag]
- if ht then
- c[ht]=c[ht]+1
- return ht
- else
- nt=nt+1
- t[nt]=v
- h[tag]=nt
- c[nt]=1
- return nt
- end
- end
- local function pack_normal_cc(v)
- local tag=tabstr_normal(v)
- local ht=h[tag]
- if ht then
- c[ht]=c[ht]+1
- return ht
- else
- v[1]=0
- nt=nt+1
- t[nt]=v
- h[tag]=nt
- c[nt]=1
- return nt
- end
- end
- local function pack_flat(v)
- local tag=tabstr_flat(v)
- local ht=h[tag]
- if ht then
- c[ht]=c[ht]+1
- return ht
- else
- nt=nt+1
- t[nt]=v
- h[tag]=nt
- c[nt]=1
- return nt
- end
- end
- local function pack_indexed(v)
- local tag=concat(v," ")
- local ht=h[tag]
- if ht then
- c[ht]=c[ht]+1
- return ht
- else
- nt=nt+1
- t[nt]=v
- h[tag]=nt
- c[nt]=1
- return nt
- end
- end
- local function pack_mixed(v)
- local tag=tabstr_mixed(v)
- local ht=h[tag]
- if ht then
- c[ht]=c[ht]+1
- return ht
- else
- nt=nt+1
- t[nt]=v
- h[tag]=nt
- c[nt]=1
- return nt
- end
- end
- local function pack_boolean(v)
- local tag=tabstr_boolean(v)
- local ht=h[tag]
- if ht then
- c[ht]=c[ht]+1
- return ht
- else
- nt=nt+1
- t[nt]=v
- h[tag]=nt
- c[nt]=1
- return nt
- end
- end
- local function pack_final(v)
- if c[v]<=criterium then
- return t[v]
- else
- local hv=hh[v]
- if hv then
- return hv
- else
- ntt=ntt+1
- tt[ntt]=t[v]
- hh[v]=ntt
- cc[ntt]=c[v]
- return ntt
- end
- end
- end
- local function pack_final_cc(v)
- if c[v]<=criterium then
- return t[v]
- else
- local hv=hh[v]
- if hv then
- return hv
- else
- ntt=ntt+1
- tt[ntt]=t[v]
- hh[v]=ntt
- cc[ntt]=c[v]
- return ntt
- end
- end
- end
- local function success(stage,pass)
- if nt==0 then
- if trace_loading or trace_packing then
- report_otf("pack quality: nothing to pack")
- end
- return false
- elseif nt>=threshold then
- local one=0
- local two=0
- local rest=0
- if pass==1 then
- for k,v in next,c do
- if v==1 then
- one=one+1
- elseif v==2 then
- two=two+1
- else
- rest=rest+1
- end
- end
- else
- for k,v in next,cc do
- if v>20 then
- rest=rest+1
- elseif v>10 then
- two=two+1
- else
- one=one+1
- end
- end
- data.tables=tt
- end
- if trace_loading or trace_packing then
- report_otf("pack quality: stage %s, pass %s, %s packed, 1-10:%s, 11-20:%s, rest:%s (criterium: %s)",
- stage,pass,one+two+rest,one,two,rest,criterium)
- end
- return true
- else
- if trace_loading or trace_packing then
- report_otf("pack quality: stage %s, pass %s, %s packed, aborting pack (threshold: %s)",
- stage,pass,nt,threshold)
- end
- return false
- end
- end
- local function packers(pass)
- if pass==1 then
- return pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc
+function otffeatures.checkeddefaultlanguage(featuretype,autolanguage,languages)
+ if featuretype=="position" then
+ local default=languages.dflt
+ if default then
+ if autolanguage=="position" or autolanguage==true then
+ return default
else
- return pack_final,pack_final,pack_final,pack_final,pack_final,pack_final_cc
- end
- end
- local resources=data.resources
- local sequences=resources.sequences
- local sublookups=resources.sublookups
- local features=resources.features
- local palettes=resources.colorpalettes
- local variable=resources.variabledata
- local chardata=characters and characters.data
- local descriptions=data.descriptions or data.glyphs
- if not descriptions then
- return
- end
- for pass=1,2 do
- if trace_packing then
- report_otf("start packing: stage 1, pass %s",pass)
- end
- local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc=packers(pass)
- for unicode,description in next,descriptions do
- local boundingbox=description.boundingbox
- if boundingbox then
- description.boundingbox=pack_indexed(boundingbox)
- end
- local math=description.math
- if math then
- local kerns=math.kerns
- if kerns then
- for tag,kern in next,kerns do
- kerns[tag]=pack_normal(kern)
- end
- end
- end
- end
- local function packthem(sequences)
- for i=1,#sequences do
- local sequence=sequences[i]
- local kind=sequence.type
- local steps=sequence.steps
- local order=sequence.order
- local features=sequence.features
- local flags=sequence.flags
- if steps then
- for i=1,#steps do
- local step=steps[i]
- if kind=="gpos_pair" then
- local c=step.coverage
- if c then
- if step.format~="pair" then
- for g1,d1 in next,c do
- c[g1]=pack_normal(d1)
- end
- elseif step.shared then
- local shared={}
- for g1,d1 in next,c do
- for g2,d2 in next,d1 do
- if not shared[d2] then
- local f=d2[1] if f and f~=true then d2[1]=pack_indexed(f) end
- local s=d2[2] if s and s~=true then d2[2]=pack_indexed(s) end
- shared[d2]=true
- end
- end
- end
- if pass==2 then
- step.shared=nil
- end
- else
- for g1,d1 in next,c do
- for g2,d2 in next,d1 do
- local f=d2[1] if f and f~=true then d2[1]=pack_indexed(f) end
- local s=d2[2] if s and s~=true then d2[2]=pack_indexed(s) end
- end
- end
- end
- end
- elseif kind=="gpos_single" then
- local c=step.coverage
- if c then
- if step.format=="single" then
- for g1,d1 in next,c do
- if d1 and d1~=true then
- c[g1]=pack_indexed(d1)
- end
- end
- else
- step.coverage=pack_normal(c)
- end
- end
- elseif kind=="gpos_cursive" then
- local c=step.coverage
- if c then
- for g1,d1 in next,c do
- local f=d1[2] if f then d1[2]=pack_indexed(f) end
- local s=d1[3] if s then d1[3]=pack_indexed(s) end
- end
- end
- elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" then
- local c=step.baseclasses
- if c then
- for g1,d1 in next,c do
- for g2,d2 in next,d1 do
- d1[g2]=pack_indexed(d2)
- end
- end
- end
- local c=step.coverage
- if c then
- for g1,d1 in next,c do
- d1[2]=pack_indexed(d1[2])
- end
- end
- elseif kind=="gpos_mark2ligature" then
- local c=step.baseclasses
- if c then
- for g1,d1 in next,c do
- for g2,d2 in next,d1 do
- for g3,d3 in next,d2 do
- d2[g3]=pack_indexed(d3)
- end
- end
- end
- end
- local c=step.coverage
- if c then
- for g1,d1 in next,c do
- d1[2]=pack_indexed(d1[2])
- end
- end
- end
- local rules=step.rules
- if rules then
- for i=1,#rules do
- local rule=rules[i]
- local r=rule.before if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
- local r=rule.after if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
- local r=rule.current if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
- local r=rule.replacements if r then rule.replacements=pack_flat (r) end
- end
- end
- end
- end
- if order then
- sequence.order=pack_indexed(order)
- end
- if features then
- for script,feature in next,features do
- features[script]=pack_normal(feature)
- end
- end
- if flags then
- sequence.flags=pack_normal(flags)
- end
- end
- end
- if sequences then
- packthem(sequences)
- end
- if sublookups then
- packthem(sublookups)
- end
- if features then
- for k,list in next,features do
- for feature,spec in next,list do
- list[feature]=pack_normal(spec)
- end
- end
- end
- if palettes then
- for i=1,#palettes do
- local p=palettes[i]
- for j=1,#p do
- p[j]=pack_indexed(p[j])
- end
- end
- end
- if variable then
- local instances=variable.instances
- if instances then
- for i=1,#instances do
- local v=instances[i].values
- for j=1,#v do
- v[j]=pack_normal(v[j])
- end
- end
- end
- local function packdeltas(main)
- if main then
- local deltas=main.deltas
- if deltas then
- for i=1,#deltas do
- local di=deltas[i]
- local d=di.deltas
- for j=1,#d do
- d[j]=pack_indexed(d[j])
- end
- di.regions=pack_indexed(di.regions)
- end
- end
- local regions=main.regions
- if regions then
- for i=1,#regions do
- local r=regions[i]
- for j=1,#r do
- r[j]=pack_normal(r[j])
- end
- end
- end
- end
- end
- packdeltas(variable.global)
- packdeltas(variable.horizontal)
- packdeltas(variable.vertical)
- packdeltas(variable.metrics)
- end
- if not success(1,pass) then
- return
+ report_otf("language feature %s not applied, enable default positioning")
end
+ else
end
- if nt>0 then
- for pass=1,2 do
- if trace_packing then
- report_otf("start packing: stage 2, pass %s",pass)
- end
- local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc=packers(pass)
- for unicode,description in next,descriptions do
- local math=description.math
- if math then
- local kerns=math.kerns
- if kerns then
- math.kerns=pack_normal(kerns)
- end
- end
- end
- local function packthem(sequences)
- for i=1,#sequences do
- local sequence=sequences[i]
- local kind=sequence.type
- local steps=sequence.steps
- local features=sequence.features
- if steps then
- for i=1,#steps do
- local step=steps[i]
- if kind=="gpos_pair" then
- local c=step.coverage
- if c then
- if step.format=="pair" then
- for g1,d1 in next,c do
- for g2,d2 in next,d1 do
- d1[g2]=pack_normal(d2)
- end
- end
- end
- end
- elseif kind=="gpos_mark2ligature" then
- local c=step.baseclasses
- if c then
- for g1,d1 in next,c do
- for g2,d2 in next,d1 do
- d1[g2]=pack_normal(d2)
- end
- end
- end
- end
- local rules=step.rules
- if rules then
- for i=1,#rules do
- local rule=rules[i]
- local r=rule.before if r then rule.before=pack_normal(r) end
- local r=rule.after if r then rule.after=pack_normal(r) end
- local r=rule.current if r then rule.current=pack_normal(r) end
- end
- end
- end
- end
- if features then
- sequence.features=pack_normal(features)
- end
- end
- end
- if sequences then
- packthem(sequences)
- end
- if sublookups then
- packthem(sublookups)
- end
- if variable then
- local function unpackdeltas(main)
- if main then
- local regions=main.regions
- if regions then
- main.regions=pack_normal(regions)
- end
- end
- end
- unpackdeltas(variable.global)
- unpackdeltas(variable.horizontal)
- unpackdeltas(variable.vertical)
- unpackdeltas(variable.metrics)
- end
- end
- for pass=1,2 do
- if trace_packing then
- report_otf("start packing: stage 3, pass %s",pass)
- end
- local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc=packers(pass)
- local function packthem(sequences)
- for i=1,#sequences do
- local sequence=sequences[i]
- local kind=sequence.type
- local steps=sequence.steps
- local features=sequence.features
- if steps then
- for i=1,#steps do
- local step=steps[i]
- if kind=="gpos_pair" then
- local c=step.coverage
- if c then
- if step.format=="pair" then
- for g1,d1 in next,c do
- c[g1]=pack_normal(d1)
- end
- end
- end
- elseif kind=="gpos_cursive" then
- local c=step.coverage
- if c then
- for g1,d1 in next,c do
- c[g1]=pack_normal_cc(d1)
- end
- end
- end
- end
- end
- end
- end
- if sequences then
- packthem(sequences)
- end
- if sublookups then
- packthem(sublookups)
- end
+ elseif featuretype=="substitution" then
+ local default=languages.dflt
+ if default then
+ if autolanguage=="substitution" or autolanguage==true then
+ return default
end
end
end
end
-local unpacked_mt={
- __index=function(t,k)
- t[k]=false
- return k
- end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules={} end modules ["font-ott"]={
+ version=1.001,
+ comment="companion to font-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files",
}
-function readers.unpack(data)
- if data then
- local tables=data.tables
- if tables then
- local resources=data.resources
- local descriptions=data.descriptions or data.glyphs
- local sequences=resources.sequences
- local sublookups=resources.sublookups
- local features=resources.features
- local palettes=resources.colorpalettes
- local variable=resources.variabledata
- local unpacked={}
- setmetatable(unpacked,unpacked_mt)
- for unicode,description in next,descriptions do
- local tv=tables[description.boundingbox]
- if tv then
- description.boundingbox=tv
- end
- local math=description.math
- if math then
- local kerns=math.kerns
- if kerns then
- local tm=tables[kerns]
- if tm then
- math.kerns=tm
- kerns=unpacked[tm]
- end
- if kerns then
- for k,kern in next,kerns do
- local tv=tables[kern]
- if tv then
- kerns[k]=tv
- end
- end
- end
- end
- end
- end
- local function unpackthem(sequences)
- for i=1,#sequences do
- local sequence=sequences[i]
- local kind=sequence.type
- local steps=sequence.steps
- local order=sequence.order
- local features=sequence.features
- local flags=sequence.flags
- local markclass=sequence.markclass
- if features then
- local tv=tables[features]
- if tv then
- sequence.features=tv
- features=tv
- end
- for script,feature in next,features do
- local tv=tables[feature]
- if tv then
- features[script]=tv
- end
- end
- end
- if steps then
- for i=1,#steps do
- local step=steps[i]
- if kind=="gpos_pair" then
- local c=step.coverage
- if c then
- if step.format=="pair" then
- for g1,d1 in next,c do
- local tv=tables[d1]
- if tv then
- c[g1]=tv
- d1=tv
- end
- for g2,d2 in next,d1 do
- local tv=tables[d2]
- if tv then
- d1[g2]=tv
- d2=tv
- end
- local f=tables[d2[1]] if f then d2[1]=f end
- local s=tables[d2[2]] if s then d2[2]=s end
- end
- end
- else
- for g1,d1 in next,c do
- local tv=tables[d1]
- if tv then
- c[g1]=tv
- end
- end
- end
- end
- elseif kind=="gpos_single" then
- local c=step.coverage
- if c then
- if step.format=="single" then
- for g1,d1 in next,c do
- local tv=tables[d1]
- if tv then
- c[g1]=tv
- end
- end
- else
- local tv=tables[c]
- if tv then
- step.coverage=tv
- end
- end
- end
- elseif kind=="gpos_cursive" then
- local c=step.coverage
- if c then
- for g1,d1 in next,c do
- local tv=tables[d1]
- if tv then
- d1=tv
- c[g1]=d1
- end
- local f=tables[d1[2]] if f then d1[2]=f end
- local s=tables[d1[3]] if s then d1[3]=s end
- end
- end
- elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" then
- local c=step.baseclasses
- if c then
- for g1,d1 in next,c do
- for g2,d2 in next,d1 do
- local tv=tables[d2]
- if tv then
- d1[g2]=tv
- end
- end
- end
- end
- local c=step.coverage
- if c then
- for g1,d1 in next,c do
- local tv=tables[d1[2]]
- if tv then
- d1[2]=tv
- end
- end
- end
- elseif kind=="gpos_mark2ligature" then
- local c=step.baseclasses
- if c then
- for g1,d1 in next,c do
- for g2,d2 in next,d1 do
- local tv=tables[d2]
- if tv then
- d2=tv
- d1[g2]=d2
- end
- for g3,d3 in next,d2 do
- local tv=tables[d2[g3]]
- if tv then
- d2[g3]=tv
- end
- end
- end
- end
- end
- local c=step.coverage
- if c then
- for g1,d1 in next,c do
- local tv=tables[d1[2]]
- if tv then
- d1[2]=tv
- end
- end
- end
- end
- local rules=step.rules
- if rules then
- for i=1,#rules do
- local rule=rules[i]
- local before=rule.before
- if before then
- local tv=tables[before]
- if tv then
- rule.before=tv
- before=tv
- end
- for i=1,#before do
- local tv=tables[before[i]]
- if tv then
- before[i]=tv
- end
- end
- end
- local after=rule.after
- if after then
- local tv=tables[after]
- if tv then
- rule.after=tv
- after=tv
- end
- for i=1,#after do
- local tv=tables[after[i]]
- if tv then
- after[i]=tv
- end
- end
- end
- local current=rule.current
- if current then
- local tv=tables[current]
- if tv then
- rule.current=tv
- current=tv
- end
- for i=1,#current do
- local tv=tables[current[i]]
- if tv then
- current[i]=tv
- end
- end
- end
- local replacements=rule.replacements
- if replacements then
- local tv=tables[replacements]
- if tv then
- rule.replacements=tv
- end
- end
- end
- end
- end
- end
- if order then
- local tv=tables[order]
- if tv then
- sequence.order=tv
- end
- end
- if flags then
- local tv=tables[flags]
- if tv then
- sequence.flags=tv
- end
- end
- end
- end
- if sequences then
- unpackthem(sequences)
- end
- if sublookups then
- unpackthem(sublookups)
- end
- if features then
- for k,list in next,features do
- for feature,spec in next,list do
- local tv=tables[spec]
- if tv then
- list[feature]=tv
- end
- end
- end
- end
- if palettes then
- for i=1,#palettes do
- local p=palettes[i]
- for j=1,#p do
- local tv=tables[p[j]]
- if tv then
- p[j]=tv
- end
- end
- end
- end
- if variable then
- local instances=variable.instances
- if instances then
- for i=1,#instances do
- local v=instances[i].values
- for j=1,#v do
- local tv=tables[v[j]]
- if tv then
- v[j]=tv
- end
- end
- end
- end
- local function unpackdeltas(main)
- if main then
- local deltas=main.deltas
- if deltas then
- for i=1,#deltas do
- local di=deltas[i]
- local d=di.deltas
- local r=di.regions
- for j=1,#d do
- local tv=tables[d[j]]
- if tv then
- d[j]=tv
- end
- end
- local tv=di.regions
- if tv then
- di.regions=tv
- end
- end
- end
- local regions=main.regions
- if regions then
- local tv=tables[regions]
- if tv then
- main.regions=tv
- regions=tv
- end
- for i=1,#regions do
- local r=regions[i]
- for j=1,#r do
- local tv=tables[r[j]]
- if tv then
- r[j]=tv
- end
- end
- end
- end
- end
- end
- unpackdeltas(variable.global)
- unpackdeltas(variable.horizontal)
- unpackdeltas(variable.vertical)
- unpackdeltas(variable.metrics)
- end
- data.tables=nil
- end
- end
-end
-local mt={
- __index=function(t,k)
- if k=="height" then
- local ht=t.boundingbox[4]
- return ht<0 and 0 or ht
- elseif k=="depth" then
- local dp=-t.boundingbox[2]
- return dp<0 and 0 or dp
- elseif k=="width" then
- return 0
- elseif k=="name" then
- return forcenotdef and ".notdef"
- end
- end
+local type,next,tonumber,tostring,rawget,rawset=type,next,tonumber,tostring,rawget,rawset
+local gsub,lower,format,match,gmatch,find=string.gsub,string.lower,string.format,string.match,string.gmatch,string.find
+local sequenced=table.sequenced
+local is_boolean=string.is_boolean
+local setmetatableindex=table.setmetatableindex
+local setmetatablenewindex=table.setmetatablenewindex
+local allocate=utilities.storage.allocate
+local fonts=fonts
+local otf=fonts.handlers.otf
+local otffeatures=otf.features
+local tables=otf.tables or {}
+otf.tables=tables
+local statistics=otf.statistics or {}
+otf.statistics=statistics
+local scripts=allocate {
+ ["adlm"]="adlam",
+ ["aghb"]="caucasian albanian",
+ ["ahom"]="ahom",
+ ["arab"]="arabic",
+ ["armi"]="imperial aramaic",
+ ["armn"]="armenian",
+ ["avst"]="avestan",
+ ["bali"]="balinese",
+ ["bamu"]="bamum",
+ ["bass"]="bassa vah",
+ ["batk"]="batak",
+ ["beng"]="bengali",
+ ["bhks"]="bhaiksuki",
+ ["bng2"]="bengali variant 2",
+ ["bopo"]="bopomofo",
+ ["brah"]="brahmi",
+ ["brai"]="braille",
+ ["bugi"]="buginese",
+ ["buhd"]="buhid",
+ ["byzm"]="byzantine music",
+ ["cakm"]="chakma",
+ ["cans"]="canadian syllabics",
+ ["cari"]="carian",
+ ["cham"]="cham",
+ ["cher"]="cherokee",
+ ["copt"]="coptic",
+ ["cprt"]="cypriot syllabary",
+ ["cyrl"]="cyrillic",
+ ["dev2"]="devanagari variant 2",
+ ["deva"]="devanagari",
+ ["dogr"]="dogra",
+ ["dsrt"]="deseret",
+ ["dupl"]="duployan",
+ ["egyp"]="egyptian heiroglyphs",
+ ["elba"]="elbasan",
+ ["ethi"]="ethiopic",
+ ["geor"]="georgian",
+ ["gjr2"]="gujarati variant 2",
+ ["glag"]="glagolitic",
+ ["gong"]="gunjala gondi",
+ ["gonm"]="masaram gondi",
+ ["goth"]="gothic",
+ ["gran"]="grantha",
+ ["grek"]="greek",
+ ["gujr"]="gujarati",
+ ["gur2"]="gurmukhi variant 2",
+ ["guru"]="gurmukhi",
+ ["hang"]="hangul",
+ ["hani"]="cjk ideographic",
+ ["hano"]="hanunoo",
+ ["hatr"]="hatran",
+ ["hebr"]="hebrew",
+ ["hluw"]="anatolian hieroglyphs",
+ ["hmng"]="pahawh hmong",
+ ["hung"]="old hungarian",
+ ["ital"]="old italic",
+ ["jamo"]="hangul jamo",
+ ["java"]="javanese",
+ ["kali"]="kayah li",
+ ["kana"]="hiragana and katakana",
+ ["khar"]="kharosthi",
+ ["khmr"]="khmer",
+ ["khoj"]="khojki",
+ ["knd2"]="kannada variant 2",
+ ["knda"]="kannada",
+ ["kthi"]="kaithi",
+ ["lana"]="tai tham",
+ ["lao" ]="lao",
+ ["latn"]="latin",
+ ["lepc"]="lepcha",
+ ["limb"]="limbu",
+ ["lina"]="linear a",
+ ["linb"]="linear b",
+ ["lisu"]="lisu",
+ ["lyci"]="lycian",
+ ["lydi"]="lydian",
+ ["mahj"]="mahajani",
+ ["maka"]="makasar",
+ ["mand"]="mandaic and mandaean",
+ ["mani"]="manichaean",
+ ["marc"]="marchen",
+ ["math"]="mathematical alphanumeric symbols",
+ ["medf"]="medefaidrin",
+ ["mend"]="mende kikakui",
+ ["merc"]="meroitic cursive",
+ ["mero"]="meroitic hieroglyphs",
+ ["mlm2"]="malayalam variant 2",
+ ["mlym"]="malayalam",
+ ["modi"]="modi",
+ ["mong"]="mongolian",
+ ["mroo"]="mro",
+ ["mtei"]="meitei Mayek",
+ ["mult"]="multani",
+ ["musc"]="musical symbols",
+ ["mym2"]="myanmar variant 2",
+ ["mymr"]="myanmar",
+ ["narb"]="old north arabian",
+ ["nbat"]="nabataean",
+ ["newa"]="newa",
+ ["nko" ]='n"ko',
+ ["nshu"]="nüshu",
+ ["ogam"]="ogham",
+ ["olck"]="ol chiki",
+ ["orkh"]="old turkic and orkhon runic",
+ ["ory2"]="odia variant 2",
+ ["orya"]="oriya",
+ ["osge"]="osage",
+ ["osma"]="osmanya",
+ ["palm"]="palmyrene",
+ ["pauc"]="pau cin hau",
+ ["perm"]="old permic",
+ ["phag"]="phags-pa",
+ ["phli"]="inscriptional pahlavi",
+ ["phlp"]="psalter pahlavi",
+ ["phnx"]="phoenician",
+ ["plrd"]="miao",
+ ["prti"]="inscriptional parthian",
+ ["rjng"]="rejang",
+ ["rohg"]="hanifi rohingya",
+ ["runr"]="runic",
+ ["samr"]="samaritan",
+ ["sarb"]="old south arabian",
+ ["saur"]="saurashtra",
+ ["sgnw"]="sign writing",
+ ["shaw"]="shavian",
+ ["shrd"]="sharada",
+ ["sidd"]="siddham",
+ ["sind"]="khudawadi",
+ ["sinh"]="sinhala",
+ ["sogd"]="sogdian",
+ ["sogo"]="old sogdian",
+ ["sora"]="sora sompeng",
+ ["soyo"]="soyombo",
+ ["sund"]="sundanese",
+ ["sylo"]="syloti nagri",
+ ["syrc"]="syriac",
+ ["tagb"]="tagbanwa",
+ ["takr"]="takri",
+ ["tale"]="tai le",
+ ["talu"]="tai lu",
+ ["taml"]="tamil",
+ ["tang"]="tangut",
+ ["tavt"]="tai viet",
+ ["tel2"]="telugu variant 2",
+ ["telu"]="telugu",
+ ["tfng"]="tifinagh",
+ ["tglg"]="tagalog",
+ ["thaa"]="thaana",
+ ["thai"]="thai",
+ ["tibt"]="tibetan",
+ ["tirh"]="tirhuta",
+ ["tml2"]="tamil variant 2",
+ ["ugar"]="ugaritic cuneiform",
+ ["vai" ]="vai",
+ ["wara"]="warang citi",
+ ["xpeo"]="old persian cuneiform",
+ ["xsux"]="sumero-akkadian cuneiform",
+ ["yi" ]="yi",
+ ["zanb"]="zanabazar square",
}
-local function sameformat(sequence,steps,first,nofsteps,kind)
- return true
-end
-local function mergesteps_1(lookup,strict)
- local steps=lookup.steps
- local nofsteps=lookup.nofsteps
- local first=steps[1]
- if strict then
- local f=first.format
- for i=2,nofsteps do
- if steps[i].format~=f then
- if trace_optimizations then
- report_optimizations("not merging %a steps of %a lookup %a, different formats",nofsteps,lookup.type,lookup.name)
- end
- return 0
- end
- end
- end
- if trace_optimizations then
- report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
- end
- local target=first.coverage
- for i=2,nofsteps do
- local c=steps[i].coverage
- if c then
- for k,v in next,c do
- if not target[k] then
- target[k]=v
- end
- end
- end
+local languages=allocate {
+ ["aba" ]="abaza",
+ ["abk" ]="abkhazian",
+ ["ach" ]="acholi",
+ ["acr" ]="achi",
+ ["ady" ]="adyghe",
+ ["afk" ]="afrikaans",
+ ["afr" ]="afar",
+ ["agw" ]="agaw",
+ ["aio" ]="aiton",
+ ["aka" ]="akan",
+ ["als" ]="alsatian",
+ ["alt" ]="altai",
+ ["amh" ]="amharic",
+ ["ang" ]="anglo-saxon",
+ ["apph"]="phonetic transcription—americanist conventions",
+ ["ara" ]="arabic",
+ ["arg" ]="aragonese",
+ ["ari" ]="aari",
+ ["ark" ]="rakhine",
+ ["asm" ]="assamese",
+ ["ast" ]="asturian",
+ ["ath" ]="athapaskan",
+ ["avr" ]="avar",
+ ["awa" ]="awadhi",
+ ["aym" ]="aymara",
+ ["azb" ]="torki",
+ ["aze" ]="azerbaijani",
+ ["bad" ]="badaga",
+ ["bad0"]="banda",
+ ["bag" ]="baghelkhandi",
+ ["bal" ]="balkar",
+ ["ban" ]="balinese",
+ ["bar" ]="bavarian",
+ ["bau" ]="baulé",
+ ["bbc" ]="batak toba",
+ ["bbr" ]="berber",
+ ["bch" ]="bench",
+ ["bcr" ]="bible cree",
+ ["bdy" ]="bandjalang",
+ ["bel" ]="belarussian",
+ ["bem" ]="bemba",
+ ["ben" ]="bengali",
+ ["bgc" ]="haryanvi",
+ ["bgq" ]="bagri",
+ ["bgr" ]="bulgarian",
+ ["bhi" ]="bhili",
+ ["bho" ]="bhojpuri",
+ ["bik" ]="bikol",
+ ["bil" ]="bilen",
+ ["bis" ]="bislama",
+ ["bjj" ]="kanauji",
+ ["bkf" ]="blackfoot",
+ ["bli" ]="baluchi",
+ ["blk" ]="pa'o karen",
+ ["bln" ]="balante",
+ ["blt" ]="balti",
+ ["bmb" ]="bambara (bamanankan)",
+ ["bml" ]="bamileke",
+ ["bos" ]="bosnian",
+ ["bpy" ]="bishnupriya manipuri",
+ ["bre" ]="breton",
+ ["brh" ]="brahui",
+ ["bri" ]="braj bhasha",
+ ["brm" ]="burmese",
+ ["brx" ]="bodo",
+ ["bsh" ]="bashkir",
+ ["bsk" ]="burushaski",
+ ["bti" ]="beti",
+ ["bts" ]="batak simalungun",
+ ["bug" ]="bugis",
+ ["byv" ]="medumba",
+ ["cak" ]="kaqchikel",
+ ["cat" ]="catalan",
+ ["cbk" ]="zamboanga chavacano",
+ ["cchn"]="chinantec",
+ ["ceb" ]="cebuano",
+ ["cgg" ]="chiga",
+ ["cha" ]="chamorro",
+ ["che" ]="chechen",
+ ["chg" ]="chaha gurage",
+ ["chh" ]="chattisgarhi",
+ ["chi" ]="chichewa (chewa, nyanja)",
+ ["chk" ]="chukchi",
+ ["chk0"]="chuukese",
+ ["cho" ]="choctaw",
+ ["chp" ]="chipewyan",
+ ["chr" ]="cherokee",
+ ["chu" ]="chuvash",
+ ["chy" ]="cheyenne",
+ ["cja" ]="western cham",
+ ["cjm" ]="eastern cham",
+ ["cmr" ]="comorian",
+ ["cop" ]="coptic",
+ ["cor" ]="cornish",
+ ["cos" ]="corsican",
+ ["cpp" ]="creoles",
+ ["cre" ]="cree",
+ ["crr" ]="carrier",
+ ["crt" ]="crimean tatar",
+ ["csb" ]="kashubian",
+ ["csl" ]="church slavonic",
+ ["csy" ]="czech",
+ ["ctg" ]="chittagonian",
+ ["cuk" ]="san blas kuna",
+ ["dan" ]="danish",
+ ["dar" ]="dargwa",
+ ["dax" ]="dayi",
+ ["dcr" ]="woods cree",
+ ["deu" ]="german",
+ ["dgo" ]="dogri",
+ ["dgr" ]="dogri",
+ ["dhg" ]="dhangu",
+ ["dhv" ]="divehi (dhivehi, maldivian)",
+ ["diq" ]="dimli",
+ ["div" ]="divehi (dhivehi, maldivian)",
+ ["djr" ]="zarma",
+ ["djr0"]="djambarrpuyngu",
+ ["dng" ]="dangme",
+ ["dnj" ]="dan",
+ ["dnk" ]="dinka",
+ ["dri" ]="dari",
+ ["duj" ]="dhuwal",
+ ["dun" ]="dungan",
+ ["dzn" ]="dzongkha",
+ ["ebi" ]="ebira",
+ ["ecr" ]="eastern cree",
+ ["edo" ]="edo",
+ ["efi" ]="efik",
+ ["ell" ]="greek",
+ ["emk" ]="eastern maninkakan",
+ ["eng" ]="english",
+ ["erz" ]="erzya",
+ ["esp" ]="spanish",
+ ["esu" ]="central yupik",
+ ["eti" ]="estonian",
+ ["euq" ]="basque",
+ ["evk" ]="evenki",
+ ["evn" ]="even",
+ ["ewe" ]="ewe",
+ ["fan" ]="french antillean",
+ ["fan0"]=" fang",
+ ["far" ]="persian",
+ ["fat" ]="fanti",
+ ["fin" ]="finnish",
+ ["fji" ]="fijian",
+ ["fle" ]="dutch (flemish)",
+ ["fmp" ]="fe’fe’",
+ ["fne" ]="forest nenets",
+ ["fon" ]="fon",
+ ["fos" ]="faroese",
+ ["fra" ]="french",
+ ["frc" ]="cajun french",
+ ["fri" ]="frisian",
+ ["frl" ]="friulian",
+ ["frp" ]="arpitan",
+ ["fta" ]="futa",
+ ["ful" ]="fulah",
+ ["fuv" ]="nigerian fulfulde",
+ ["gad" ]="ga",
+ ["gae" ]="scottish gaelic (gaelic)",
+ ["gag" ]="gagauz",
+ ["gal" ]="galician",
+ ["gar" ]="garshuni",
+ ["gaw" ]="garhwali",
+ ["gez" ]="ge'ez",
+ ["gih" ]="githabul",
+ ["gil" ]="gilyak",
+ ["gil0"]="kiribati (gilbertese)",
+ ["gkp" ]="kpelle (guinea)",
+ ["glk" ]="gilaki",
+ ["gmz" ]="gumuz",
+ ["gnn" ]="gumatj",
+ ["gog" ]="gogo",
+ ["gon" ]="gondi",
+ ["grn" ]="greenlandic",
+ ["gro" ]="garo",
+ ["gua" ]="guarani",
+ ["guc" ]="wayuu",
+ ["guf" ]="gupapuyngu",
+ ["guj" ]="gujarati",
+ ["guz" ]="gusii",
+ ["hai" ]="haitian (haitian creole)",
+ ["hal" ]="halam",
+ ["har" ]="harauti",
+ ["hau" ]="hausa",
+ ["haw" ]="hawaiian",
+ ["hay" ]="haya",
+ ["haz" ]="hazaragi",
+ ["hbn" ]="hammer-banna",
+ ["her" ]="herero",
+ ["hil" ]="hiligaynon",
+ ["hin" ]="hindi",
+ ["hma" ]="high mari",
+ ["hmn" ]="hmong",
+ ["hmo" ]="hiri motu",
+ ["hnd" ]="hindko",
+ ["ho" ]="ho",
+ ["hri" ]="harari",
+ ["hrv" ]="croatian",
+ ["hun" ]="hungarian",
+ ["hye" ]="armenian",
+ ["hye0"]="armenian east",
+ ["iba" ]="iban",
+ ["ibb" ]="ibibio",
+ ["ibo" ]="igbo",
+ ["ido" ]="ido",
+ ["ijo" ]="ijo languages",
+ ["ile" ]="interlingue",
+ ["ilo" ]="ilokano",
+ ["ina" ]="interlingua",
+ ["ind" ]="indonesian",
+ ["ing" ]="ingush",
+ ["inu" ]="inuktitut",
+ ["ipk" ]="inupiat",
+ ["ipph"]="phonetic transcription—ipa conventions",
+ ["iri" ]="irish",
+ ["irt" ]="irish traditional",
+ ["isl" ]="icelandic",
+ ["ism" ]="inari sami",
+ ["ita" ]="italian",
+ ["iwr" ]="hebrew",
+ ["jam" ]="jamaican creole",
+ ["jan" ]="japanese",
+ ["jav" ]="javanese",
+ ["jbo" ]="lojban",
+ ["jct" ]="krymchak",
+ ["jii" ]="yiddish",
+ ["jud" ]="ladino",
+ ["jul" ]="jula",
+ ["kab" ]="kabardian",
+ ["kab0"]="kabyle",
+ ["kac" ]="kachchi",
+ ["kal" ]="kalenjin",
+ ["kan" ]="kannada",
+ ["kar" ]="karachay",
+ ["kat" ]="georgian",
+ ["kaz" ]="kazakh",
+ ["kde" ]="makonde",
+ ["kea" ]="kabuverdianu (crioulo)",
+ ["keb" ]="kebena",
+ ["kek" ]="kekchi",
+ ["kge" ]="khutsuri georgian",
+ ["kha" ]="khakass",
+ ["khk" ]="khanty-kazim",
+ ["khm" ]="khmer",
+ ["khs" ]="khanty-shurishkar",
+ ["kht" ]="khamti shan",
+ ["khv" ]="khanty-vakhi",
+ ["khw" ]="khowar",
+ ["kik" ]="kikuyu (gikuyu)",
+ ["kir" ]="kirghiz (kyrgyz)",
+ ["kis" ]="kisii",
+ ["kiu" ]="kirmanjki",
+ ["kjd" ]="southern kiwai",
+ ["kjp" ]="eastern pwo karen",
+ ["kjz" ]="bumthangkha",
+ ["kkn" ]="kokni",
+ ["klm" ]="kalmyk",
+ ["kmb" ]="kamba",
+ ["kmn" ]="kumaoni",
+ ["kmo" ]="komo",
+ ["kms" ]="komso",
+ ["kmz" ]="khorasani turkic",
+ ["knr" ]="kanuri",
+ ["kod" ]="kodagu",
+ ["koh" ]="korean old hangul",
+ ["kok" ]="konkani",
+ ["kom" ]="komi",
+ ["kon" ]="kikongo",
+ ["kon0"]="kongo",
+ ["kop" ]="komi-permyak",
+ ["kor" ]="korean",
+ ["kos" ]="kosraean",
+ ["koz" ]="komi-zyrian",
+ ["kpl" ]="kpelle",
+ ["kri" ]="krio",
+ ["krk" ]="karakalpak",
+ ["krl" ]="karelian",
+ ["krm" ]="karaim",
+ ["krn" ]="karen",
+ ["krt" ]="koorete",
+ ["ksh" ]="kashmiri",
+ ["ksh0"]="ripuarian",
+ ["ksi" ]="khasi",
+ ["ksm" ]="kildin sami",
+ ["ksw" ]="s’gaw karen",
+ ["kua" ]="kuanyama",
+ ["kui" ]="kui",
+ ["kul" ]="kulvi",
+ ["kum" ]="kumyk",
+ ["kur" ]="kurdish",
+ ["kuu" ]="kurukh",
+ ["kuy" ]="kuy",
+ ["kyk" ]="koryak",
+ ["kyu" ]="western kayah",
+ ["lad" ]="ladin",
+ ["lah" ]="lahuli",
+ ["lak" ]="lak",
+ ["lam" ]="lambani",
+ ["lao" ]="lao",
+ ["lat" ]="latin",
+ ["laz" ]="laz",
+ ["lcr" ]="l-cree",
+ ["ldk" ]="ladakhi",
+ ["lez" ]="lezgi",
+ ["lij" ]="ligurian",
+ ["lim" ]="limburgish",
+ ["lin" ]="lingala",
+ ["lis" ]="lisu",
+ ["ljp" ]="lampung",
+ ["lki" ]="laki",
+ ["lma" ]="low mari",
+ ["lmb" ]="limbu",
+ ["lmo" ]="lombard",
+ ["lmw" ]="lomwe",
+ ["lom" ]="loma",
+ ["lrc" ]="luri",
+ ["lsb" ]="lower sorbian",
+ ["lsm" ]="lule sami",
+ ["lth" ]="lithuanian",
+ ["ltz" ]="luxembourgish",
+ ["lua" ]="luba-lulua",
+ ["lub" ]="luba-katanga",
+ ["lug" ]="ganda",
+ ["luh" ]="luyia",
+ ["luo" ]="luo",
+ ["lvi" ]="latvian",
+ ["mad" ]="madura",
+ ["mag" ]="magahi",
+ ["mah" ]="marshallese",
+ ["maj" ]="majang",
+ ["mak" ]="makhuwa",
+ ["mal" ]="malayalam reformed",
+ ["mam" ]="mam",
+ ["man" ]="mansi",
+ ["map" ]="mapudungun",
+ ["mar" ]="marathi",
+ ["maw" ]="marwari",
+ ["mbn" ]="mbundu",
+ ["mbo" ]="mbo",
+ ["mch" ]="manchu",
+ ["mcr" ]="moose cree",
+ ["mde" ]="mende",
+ ["mdr" ]="mandar",
+ ["men" ]="me'en",
+ ["mer" ]="meru",
+ ["mfa" ]="pattani malay",
+ ["mfe" ]="morisyen",
+ ["min" ]="minangkabau",
+ ["miz" ]="mizo",
+ ["mkd" ]="macedonian",
+ ["mkr" ]="makasar",
+ ["mkw" ]="kituba",
+ ["mle" ]="male",
+ ["mlg" ]="malagasy",
+ ["mln" ]="malinke",
+ ["mlr" ]="malayalam reformed",
+ ["mly" ]="malay",
+ ["mnd" ]="mandinka",
+ ["mng" ]="mongolian",
+ ["mni" ]="manipuri",
+ ["mnk" ]="maninka",
+ ["mnx" ]="manx",
+ ["moh" ]="mohawk",
+ ["mok" ]="moksha",
+ ["mol" ]="moldavian",
+ ["mon" ]="mon",
+ ["mor" ]="moroccan",
+ ["mos" ]="mossi",
+ ["mri" ]="maori",
+ ["mth" ]="maithili",
+ ["mts" ]="maltese",
+ ["mun" ]="mundari",
+ ["mus" ]="muscogee",
+ ["mwl" ]="mirandese",
+ ["mww" ]="hmong daw",
+ ["myn" ]="mayan",
+ ["mzn" ]="mazanderani",
+ ["nag" ]="naga-assamese",
+ ["nah" ]="nahuatl",
+ ["nan" ]="nanai",
+ ["nap" ]="neapolitan",
+ ["nas" ]="naskapi",
+ ["nau" ]="nauruan",
+ ["nav" ]="navajo",
+ ["ncr" ]="n-cree",
+ ["ndb" ]="ndebele",
+ ["ndc" ]="ndau",
+ ["ndg" ]="ndonga",
+ ["nds" ]="low saxon",
+ ["nep" ]="nepali",
+ ["new" ]="newari",
+ ["nga" ]="ngbaka",
+ ["ngr" ]="nagari",
+ ["nhc" ]="norway house cree",
+ ["nis" ]="nisi",
+ ["niu" ]="niuean",
+ ["nkl" ]="nyankole",
+ ["nko" ]="n'ko",
+ ["nld" ]="dutch",
+ ["noe" ]="nimadi",
+ ["nog" ]="nogai",
+ ["nor" ]="norwegian",
+ ["nov" ]="novial",
+ ["nsm" ]="northern sami",
+ ["nso" ]="sotho, northern",
+ ["nta" ]="northern tai",
+ ["nto" ]="esperanto",
+ ["nym" ]="nyamwezi",
+ ["nyn" ]="norwegian nynorsk",
+ ["nza" ]="mbembe tigon",
+ ["oci" ]="occitan",
+ ["ocr" ]="oji-cree",
+ ["ojb" ]="ojibway",
+ ["ori" ]="odia",
+ ["oro" ]="oromo",
+ ["oss" ]="ossetian",
+ ["paa" ]="palestinian aramaic",
+ ["pag" ]="pangasinan",
+ ["pal" ]="pali",
+ ["pam" ]="pampangan",
+ ["pan" ]="punjabi",
+ ["pap" ]="palpa",
+ ["pap0"]="papiamentu",
+ ["pas" ]="pashto",
+ ["pau" ]="palauan",
+ ["pcc" ]="bouyei",
+ ["pcd" ]="picard",
+ ["pdc" ]="pennsylvania german",
+ ["pgr" ]="polytonic greek",
+ ["phk" ]="phake",
+ ["pih" ]="norfolk",
+ ["pil" ]="filipino",
+ ["plg" ]="palaung",
+ ["plk" ]="polish",
+ ["pms" ]="piemontese",
+ ["pnb" ]="western panjabi",
+ ["poh" ]="pocomchi",
+ ["pon" ]="pohnpeian",
+ ["pro" ]="provencal",
+ ["ptg" ]="portuguese",
+ ["pwo" ]="western pwo karen",
+ ["qin" ]="chin",
+ ["quc" ]="k’iche’",
+ ["quh" ]="quechua (bolivia)",
+ ["quz" ]="quechua",
+ ["qvi" ]="quechua (ecuador)",
+ ["qwh" ]="quechua (peru)",
+ ["raj" ]="rajasthani",
+ ["rar" ]="rarotongan",
+ ["rbu" ]="russian buriat",
+ ["rcr" ]="r-cree",
+ ["rej" ]="rejang",
+ ["ria" ]="riang",
+ ["rif" ]="tarifit",
+ ["rit" ]="ritarungo",
+ ["rkw" ]="arakwal",
+ ["rms" ]="romansh",
+ ["rmy" ]="vlax romani",
+ ["rom" ]="romanian",
+ ["roy" ]="romany",
+ ["rsy" ]="rusyn",
+ ["rtm" ]="rotuman",
+ ["rua" ]="kinyarwanda",
+ ["run" ]="rundi",
+ ["rup" ]="aromanian",
+ ["rus" ]="russian",
+ ["sad" ]="sadri",
+ ["san" ]="sanskrit",
+ ["sas" ]="sasak",
+ ["sat" ]="santali",
+ ["say" ]="sayisi",
+ ["scn" ]="sicilian",
+ ["sco" ]="scots",
+ ["scs" ]="north slavey",
+ ["sek" ]="sekota",
+ ["sel" ]="selkup",
+ ["sga" ]="old irish",
+ ["sgo" ]="sango",
+ ["sgs" ]="samogitian",
+ ["shi" ]="tachelhit",
+ ["shn" ]="shan",
+ ["sib" ]="sibe",
+ ["sid" ]="sidamo",
+ ["sig" ]="silte gurage",
+ ["sks" ]="skolt sami",
+ ["sky" ]="slovak",
+ ["sla" ]="slavey",
+ ["slv" ]="slovenian",
+ ["sml" ]="somali",
+ ["smo" ]="samoan",
+ ["sna" ]="sena",
+ ["sna0"]="shona",
+ ["snd" ]="sindhi",
+ ["snh" ]="sinhala (sinhalese)",
+ ["snk" ]="soninke",
+ ["sog" ]="sodo gurage",
+ ["sop" ]="songe",
+ ["sot" ]="sotho, southern",
+ ["sqi" ]="albanian",
+ ["srb" ]="serbian",
+ ["srd" ]="sardinian",
+ ["srk" ]="saraiki",
+ ["srr" ]="serer",
+ ["ssl" ]="south slavey",
+ ["ssm" ]="southern sami",
+ ["stq" ]="saterland frisian",
+ ["suk" ]="sukuma",
+ ["sun" ]="sundanese",
+ ["sur" ]="suri",
+ ["sva" ]="svan",
+ ["sve" ]="swedish",
+ ["swa" ]="swadaya aramaic",
+ ["swk" ]="swahili",
+ ["swz" ]="swati",
+ ["sxt" ]="sutu",
+ ["sxu" ]="upper saxon",
+ ["syl" ]="sylheti",
+ ["syr" ]="syriac",
+ ["syre"]="estrangela syriac",
+ ["syrj"]="western syriac",
+ ["syrn"]="eastern syriac",
+ ["szl" ]="silesian",
+ ["tab" ]="tabasaran",
+ ["taj" ]="tajiki",
+ ["tam" ]="tamil",
+ ["tat" ]="tatar",
+ ["tcr" ]="th-cree",
+ ["tdd" ]="dehong dai",
+ ["tel" ]="telugu",
+ ["tet" ]="tetum",
+ ["tgl" ]="tagalog",
+ ["tgn" ]="tongan",
+ ["tgr" ]="tigre",
+ ["tgy" ]="tigrinya",
+ ["tha" ]="thai",
+ ["tht" ]="tahitian",
+ ["tib" ]="tibetan",
+ ["tiv" ]="tiv",
+ ["tkm" ]="turkmen",
+ ["tmh" ]="tamashek",
+ ["tmn" ]="temne",
+ ["tna" ]="tswana",
+ ["tne" ]="tundra nenets",
+ ["tng" ]="tonga",
+ ["tod" ]="todo",
+ ["tod0"]="toma",
+ ["tpi" ]="tok pisin",
+ ["trk" ]="turkish",
+ ["tsg" ]="tsonga",
+ ["tsj" ]="tshangla",
+ ["tua" ]="turoyo aramaic",
+ ["tul" ]="tulu",
+ ["tum" ]="tulu",
+ ["tuv" ]="tuvin",
+ ["tvl" ]="tuvalu",
+ ["twi" ]="twi",
+ ["tyz" ]="tày",
+ ["tzm" ]="tamazight",
+ ["tzo" ]="tzotzil",
+ ["udm" ]="udmurt",
+ ["ukr" ]="ukrainian",
+ ["umb" ]="umbundu",
+ ["urd" ]="urdu",
+ ["usb" ]="upper sorbian",
+ ["uyg" ]="uyghur",
+ ["uzb" ]="uzbek",
+ ["vec" ]="venetian",
+ ["ven" ]="venda",
+ ["vit" ]="vietnamese",
+ ["vol" ]="volapük",
+ ["vro" ]="võro",
+ ["wa" ]="wa",
+ ["wag" ]="wagdi",
+ ["war" ]="waray-waray",
+ ["wcr" ]="west-cree",
+ ["wel" ]="welsh",
+ ["wlf" ]="wolof",
+ ["wln" ]="walloon",
+ ["wtm" ]="mewati",
+ ["xbd" ]="lü",
+ ["xhs" ]="xhosa",
+ ["xjb" ]="minjangbal",
+ ["xkf" ]="khengkha",
+ ["xog" ]="soga",
+ ["xpe" ]="kpelle (liberia)",
+ ["yak" ]="sakha",
+ ["yao" ]="yao",
+ ["yap" ]="yapese",
+ ["yba" ]="yoruba",
+ ["ycr" ]="y-cree",
+ ["yic" ]="yi classic",
+ ["yim" ]="yi modern",
+ ["zea" ]="zealandic",
+ ["zgh" ]="standard morrocan tamazigh",
+ ["zha" ]="zhuang",
+ ["zhh" ]="chinese, hong kong sar",
+ ["zhp" ]="chinese phonetic",
+ ["zhs" ]="chinese simplified",
+ ["zht" ]="chinese traditional",
+ ["znd" ]="zande",
+ ["zul" ]="zulu",
+ ["zza" ]="zazaki",
+}
+local features=allocate {
+ ["aalt"]="access all alternates",
+ ["abvf"]="above-base forms",
+ ["abvm"]="above-base mark positioning",
+ ["abvs"]="above-base substitutions",
+ ["afrc"]="alternative fractions",
+ ["akhn"]="akhands",
+ ["blwf"]="below-base forms",
+ ["blwm"]="below-base mark positioning",
+ ["blws"]="below-base substitutions",
+ ["c2pc"]="petite capitals from capitals",
+ ["c2sc"]="small capitals from capitals",
+ ["calt"]="contextual alternates",
+ ["case"]="case-sensitive forms",
+ ["ccmp"]="glyph composition/decomposition",
+ ["cfar"]="conjunct form after ro",
+ ["cjct"]="conjunct forms",
+ ["clig"]="contextual ligatures",
+ ["cpct"]="centered cjk punctuation",
+ ["cpsp"]="capital spacing",
+ ["cswh"]="contextual swash",
+ ["curs"]="cursive positioning",
+ ["dflt"]="default processing",
+ ["dist"]="distances",
+ ["dlig"]="discretionary ligatures",
+ ["dnom"]="denominators",
+ ["dtls"]="dotless forms",
+ ["expt"]="expert forms",
+ ["falt"]="final glyph alternates",
+ ["fin2"]="terminal forms #2",
+ ["fin3"]="terminal forms #3",
+ ["fina"]="terminal forms",
+ ["flac"]="flattened accents over capitals",
+ ["frac"]="fractions",
+ ["fwid"]="full width",
+ ["half"]="half forms",
+ ["haln"]="halant forms",
+ ["halt"]="alternate half width",
+ ["hist"]="historical forms",
+ ["hkna"]="horizontal kana alternates",
+ ["hlig"]="historical ligatures",
+ ["hngl"]="hangul",
+ ["hojo"]="hojo kanji forms",
+ ["hwid"]="half width",
+ ["init"]="initial forms",
+ ["isol"]="isolated forms",
+ ["ital"]="italics",
+ ["jalt"]="justification alternatives",
+ ["jp04"]="jis2004 forms",
+ ["jp78"]="jis78 forms",
+ ["jp83"]="jis83 forms",
+ ["jp90"]="jis90 forms",
+ ["kern"]="kerning",
+ ["lfbd"]="left bounds",
+ ["liga"]="standard ligatures",
+ ["ljmo"]="leading jamo forms",
+ ["lnum"]="lining figures",
+ ["locl"]="localized forms",
+ ["ltra"]="left-to-right alternates",
+ ["ltrm"]="left-to-right mirrored forms",
+ ["mark"]="mark positioning",
+ ["med2"]="medial forms #2",
+ ["medi"]="medial forms",
+ ["mgrk"]="mathematical greek",
+ ["mkmk"]="mark to mark positioning",
+ ["mset"]="mark positioning via substitution",
+ ["nalt"]="alternate annotation forms",
+ ["nlck"]="nlc kanji forms",
+ ["nukt"]="nukta forms",
+ ["numr"]="numerators",
+ ["onum"]="old style figures",
+ ["opbd"]="optical bounds",
+ ["ordn"]="ordinals",
+ ["ornm"]="ornaments",
+ ["palt"]="proportional alternate width",
+ ["pcap"]="petite capitals",
+ ["pkna"]="proportional kana",
+ ["pnum"]="proportional figures",
+ ["pref"]="pre-base forms",
+ ["pres"]="pre-base substitutions",
+ ["pstf"]="post-base forms",
+ ["psts"]="post-base substitutions",
+ ["pwid"]="proportional widths",
+ ["qwid"]="quarter widths",
+ ["rand"]="randomize",
+ ["rclt"]="required contextual alternates",
+ ["rkrf"]="rakar forms",
+ ["rlig"]="required ligatures",
+ ["rphf"]="reph form",
+ ["rtbd"]="right bounds",
+ ["rtla"]="right-to-left alternates",
+ ["rtlm"]="right to left mirrored forms",
+ ["rvrn"]="required variation alternates",
+ ["ruby"]="ruby notation forms",
+ ["salt"]="stylistic alternates",
+ ["sinf"]="scientific inferiors",
+ ["size"]="optical size",
+ ["smcp"]="small capitals",
+ ["smpl"]="simplified forms",
+ ["ssty"]="script style",
+ ["stch"]="stretching glyph decomposition",
+ ["subs"]="subscript",
+ ["sups"]="superscript",
+ ["swsh"]="swash",
+ ["titl"]="titling",
+ ["tjmo"]="trailing jamo forms",
+ ["tnam"]="traditional name forms",
+ ["tnum"]="tabular figures",
+ ["trad"]="traditional forms",
+ ["twid"]="third widths",
+ ["unic"]="unicase",
+ ["valt"]="alternate vertical metrics",
+ ["vatu"]="vattu variants",
+ ["vert"]="vertical writing",
+ ["vhal"]="alternate vertical half metrics",
+ ["vjmo"]="vowel jamo forms",
+ ["vkna"]="vertical kana alternates",
+ ["vkrn"]="vertical kerning",
+ ["vpal"]="proportional alternate vertical metrics",
+ ["vrtr"]="vertical alternates for rotation",
+ ["vrt2"]="vertical rotation",
+ ["zero"]="slashed zero",
+ ["trep"]="traditional tex replacements",
+ ["tlig"]="traditional tex ligatures",
+ ["ss.."]="stylistic set ..",
+ ["cv.."]="character variant ..",
+ ["js.."]="justification ..",
+ ["dv.."]="devanagari ..",
+ ["ml.."]="malayalam ..",
+}
+local baselines=allocate {
+ ["hang"]="hanging baseline",
+ ["icfb"]="ideographic character face bottom edge baseline",
+ ["icft"]="ideographic character face tope edige baseline",
+ ["ideo"]="ideographic em-box bottom edge baseline",
+ ["idtp"]="ideographic em-box top edge baseline",
+ ["math"]="mathematical centered baseline",
+ ["romn"]="roman baseline"
+}
+tables.scripts=scripts
+tables.languages=languages
+tables.features=features
+tables.baselines=baselines
+local acceptscripts=true directives.register("otf.acceptscripts",function(v) acceptscripts=v end)
+local acceptlanguages=true directives.register("otf.acceptlanguages",function(v) acceptlanguages=v end)
+local report_checks=logs.reporter("fonts","checks")
+if otffeatures.features then
+ for k,v in next,otffeatures.features do
+ features[k]=v
end
- lookup.nofsteps=1
- lookup.merged=true
- lookup.steps={ first }
- return nofsteps-1
+ otffeatures.features=features
end
-local function mergesteps_2(lookup)
- local steps=lookup.steps
- local nofsteps=lookup.nofsteps
- local first=steps[1]
- if strict then
- local f=first.format
- for i=2,nofsteps do
- if steps[i].format~=f then
- if trace_optimizations then
- report_optimizations("not merging %a steps of %a lookup %a, different formats",nofsteps,lookup.type,lookup.name)
- end
- return 0
- end
- end
- end
- if trace_optimizations then
- report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
- end
- local target=first.coverage
- for i=2,nofsteps do
- local c=steps[i].coverage
- if c then
- for k,v in next,c do
- local tk=target[k]
- if tk then
- for kk,vv in next,v do
- if tk[kk]==nil then
- tk[kk]=vv
- end
- end
- else
- target[k]=v
- end
- end
- end
+local function swapped(h)
+ local r={}
+ for k,v in next,h do
+ r[gsub(v,"[^a-z0-9]","")]=k
end
- lookup.nofsteps=1
- lookup.merged=true
- lookup.steps={ first }
- return nofsteps-1
+ return r
end
-local function mergesteps_3(lookup,strict)
- local steps=lookup.steps
- local nofsteps=lookup.nofsteps
- if trace_optimizations then
- report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
- end
- local coverage={}
- for i=1,nofsteps do
- local c=steps[i].coverage
- if c then
- for k,v in next,c do
- local tk=coverage[k]
- if tk then
- if trace_optimizations then
- report_optimizations("quitting merge due to multiple checks")
- end
- return nofsteps
- else
- coverage[k]=v
- end
- end
- end
- end
- local first=steps[1]
- local baseclasses={}
- for i=1,nofsteps do
- local offset=i*10
- local step=steps[i]
- for k,v in sortedhash(step.baseclasses) do
- baseclasses[offset+k]=v
- end
- for k,v in next,step.coverage do
- v[1]=offset+v[1]
+local verbosescripts=allocate(swapped(scripts ))
+local verboselanguages=allocate(swapped(languages))
+local verbosefeatures=allocate(swapped(features ))
+local verbosebaselines=allocate(swapped(baselines))
+local function resolve(t,k)
+ if k then
+ k=gsub(lower(k),"[^a-z0-9]","")
+ local v=rawget(t,k)
+ if v then
+ return v
end
end
- first.baseclasses=baseclasses
- first.coverage=coverage
- lookup.nofsteps=1
- lookup.merged=true
- lookup.steps={ first }
- return nofsteps-1
end
-local function nested(old,new)
- for k,v in next,old do
- if k=="ligature" then
- if not new.ligature then
- new.ligature=v
- end
- else
- local n=new[k]
- if n then
- nested(v,n)
- else
- new[k]=v
- end
+setmetatableindex(verbosescripts,resolve)
+setmetatableindex(verboselanguages,resolve)
+setmetatableindex(verbosefeatures,resolve)
+setmetatableindex(verbosebaselines,resolve)
+setmetatableindex(scripts,function(t,k)
+ if k then
+ k=lower(k)
+ if k=="dflt" then
+ return k
end
- end
-end
-local function mergesteps_4(lookup)
- local steps=lookup.steps
- local nofsteps=lookup.nofsteps
- local first=steps[1]
- if trace_optimizations then
- report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
- end
- local target=first.coverage
- for i=2,nofsteps do
- local c=steps[i].coverage
- if c then
- for k,v in next,c do
- local tk=target[k]
- if tk then
- nested(v,tk)
- else
- target[k]=v
- end
- end
+ local v=rawget(t,k)
+ if v then
+ return v
end
- end
- lookup.nofsteps=1
- lookup.steps={ first }
- return nofsteps-1
-end
-local function mergesteps_5(lookup)
- local steps=lookup.steps
- local nofsteps=lookup.nofsteps
- local first=steps[1]
- if trace_optimizations then
- report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
- end
- local target=first.coverage
- local hash=nil
- for k,v in next,target do
- hash=v[1]
- break
- end
- for i=2,nofsteps do
- local c=steps[i].coverage
- if c then
- for k,v in next,c do
- local tk=target[k]
- if tk then
- if not tk[2] then
- tk[2]=v[2]
- end
- if not tk[3] then
- tk[3]=v[3]
- end
- else
- target[k]=v
- v[1]=hash
- end
- end
+ k=gsub(k," ","")
+ v=rawget(t,v)
+ if v then
+ return v
+ elseif acceptscripts then
+ report_checks("registering extra script %a",k)
+ rawset(t,k,k)
+ return k
end
end
- lookup.nofsteps=1
- lookup.merged=true
- lookup.steps={ first }
- return nofsteps-1
-end
-local function checkkerns(lookup)
- local steps=lookup.steps
- local nofsteps=lookup.nofsteps
- local kerned=0
- for i=1,nofsteps do
- local step=steps[i]
- if step.format=="pair" then
- local coverage=step.coverage
- local kerns=true
- for g1,d1 in next,coverage do
- if d1==true then
- elseif not d1 then
- elseif d1[1]~=0 or d1[2]~=0 or d1[4]~=0 then
- kerns=false
- break
- end
- end
- if kerns then
- if trace_optimizations then
- report_optimizations("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name)
- end
- local c={}
- for g1,d1 in next,coverage do
- if d1 and d1~=true then
- c[g1]=d1[3]
- end
- end
- step.coverage=c
- step.format="move"
- kerned=kerned+1
- end
+ return "dflt"
+end)
+setmetatableindex(languages,function(t,k)
+ if k then
+ k=lower(k)
+ if k=="dflt" then
+ return k
end
- end
- return kerned
-end
-local function checkpairs(lookup)
- local steps=lookup.steps
- local nofsteps=lookup.nofsteps
- local kerned=0
- local function onlykerns(step)
- local coverage=step.coverage
- for g1,d1 in next,coverage do
- for g2,d2 in next,d1 do
- if d2[2] then
- return false
- else
- local v=d2[1]
- if v==true then
- elseif v and (v[1]~=0 or v[2]~=0 or v[4]~=0) then
- return false
- end
- end
- end
+ local v=rawget(t,k)
+ if v then
+ return v
end
- return coverage
- end
- for i=1,nofsteps do
- local step=steps[i]
- if step.format=="pair" then
- local coverage=onlykerns(step)
- if coverage then
- if trace_optimizations then
- report_optimizations("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name)
- end
- for g1,d1 in next,coverage do
- local d={}
- for g2,d2 in next,d1 do
- local v=d2[1]
- if v==true then
- elseif v then
- d[g2]=v[3]
- end
- end
- coverage[g1]=d
- end
- step.format="move"
- kerned=kerned+1
- end
+ k=gsub(k," ","")
+ v=rawget(t,v)
+ if v then
+ return v
+ elseif acceptlanguages then
+ report_checks("registering extra language %a",k)
+ rawset(t,k,k)
+ return k
end
end
- return kerned
+ return "dflt"
+end)
+if setmetatablenewindex then
+ setmetatablenewindex(languages,"ignore")
+ setmetatablenewindex(scripts,"ignore")
+ setmetatablenewindex(baselines,"ignore")
end
-local compact_pairs=true
-local compact_singles=true
-local merge_pairs=true
-local merge_singles=true
-local merge_substitutions=true
-local merge_alternates=true
-local merge_multiples=true
-local merge_ligatures=true
-local merge_cursives=true
-local merge_marks=true
-directives.register("otf.compact.pairs",function(v) compact_pairs=v end)
-directives.register("otf.compact.singles",function(v) compact_singles=v end)
-directives.register("otf.merge.pairs",function(v) merge_pairs=v end)
-directives.register("otf.merge.singles",function(v) merge_singles=v end)
-directives.register("otf.merge.substitutions",function(v) merge_substitutions=v end)
-directives.register("otf.merge.alternates",function(v) merge_alternates=v end)
-directives.register("otf.merge.multiples",function(v) merge_multiples=v end)
-directives.register("otf.merge.ligatures",function(v) merge_ligatures=v end)
-directives.register("otf.merge.cursives",function(v) merge_cursives=v end)
-directives.register("otf.merge.marks",function(v) merge_marks=v end)
-function readers.compact(data)
- if not data or data.compacted then
- return
- else
- data.compacted=true
- end
- local resources=data.resources
- local merged=0
- local kerned=0
- local allsteps=0
- local function compact(what)
- local lookups=resources[what]
- if lookups then
- for i=1,#lookups do
- local lookup=lookups[i]
- local nofsteps=lookup.nofsteps
- local kind=lookup.type
- allsteps=allsteps+nofsteps
- if nofsteps>1 then
- local merg=merged
- if kind=="gsub_single" then
- if merge_substitutions then
- merged=merged+mergesteps_1(lookup)
- end
- elseif kind=="gsub_alternate" then
- if merge_alternates then
- merged=merged+mergesteps_1(lookup)
- end
- elseif kind=="gsub_multiple" then
- if merge_multiples then
- merged=merged+mergesteps_1(lookup)
- end
- elseif kind=="gsub_ligature" then
- if merge_ligatures then
- merged=merged+mergesteps_4(lookup)
- end
- elseif kind=="gpos_single" then
- if merge_singles then
- merged=merged+mergesteps_1(lookup,true)
- end
- if compact_singles then
- kerned=kerned+checkkerns(lookup)
- end
- elseif kind=="gpos_pair" then
- if merge_pairs then
- merged=merged+mergesteps_2(lookup)
- end
- if compact_pairs then
- kerned=kerned+checkpairs(lookup)
- end
- elseif kind=="gpos_cursive" then
- if merge_cursives then
- merged=merged+mergesteps_5(lookup)
- end
- elseif kind=="gpos_mark2mark" or kind=="gpos_mark2base" or kind=="gpos_mark2ligature" then
- if merge_marks then
- merged=merged+mergesteps_3(lookup)
- end
- end
- if merg~=merged then
- lookup.merged=true
- end
- elseif nofsteps==1 then
- local kern=kerned
- if kind=="gpos_single" then
- if compact_singles then
- kerned=kerned+checkkerns(lookup)
- end
- elseif kind=="gpos_pair" then
- if compact_pairs then
- kerned=kerned+checkpairs(lookup)
- end
- end
- if kern~=kerned then
- end
- end
- end
- elseif trace_optimizations then
- report_optimizations("no lookups in %a",what)
- end
- end
- compact("sequences")
- compact("sublookups")
- if trace_optimizations then
- if merged>0 then
- report_optimizations("%i steps of %i removed due to merging",merged,allsteps)
+local function resolve(t,k)
+ if k then
+ k=lower(k)
+ local v=rawget(t,k)
+ if v then
+ return v
end
- if kerned>0 then
- report_optimizations("%i steps of %i steps turned from pairs into kerns",kerned,allsteps)
+ k=gsub(k," ","")
+ local v=rawget(t,k)
+ if v then
+ return v
end
- end
-end
-local function mergesteps(t,k)
- if k=="merged" then
- local merged={}
- for i=1,#t do
- local step=t[i]
- local coverage=step.coverage
- for k in next,coverage do
- local m=merged[k]
- if m then
- m[2]=i
- else
- merged[k]={ i,i }
+ local tag,dd=match(k,"(..)(%d+)")
+ if tag and dd then
+ local v=rawget(t,tag)
+ if v then
+ return v
+ else
+ local v=rawget(t,tag.."..")
+ if v then
+ return (gsub(v,"%.%.",tonumber(dd)))
end
end
end
- t.merged=merged
- return merged
end
+ return k
end
-local function checkmerge(sequence)
- local steps=sequence.steps
- if steps then
- setmetatableindex(steps,mergesteps)
+setmetatableindex(features,resolve)
+local function assign(t,k,v)
+ if k and v then
+ v=lower(v)
+ rawset(t,k,v)
end
end
-local function checkflags(sequence,resources)
- if not sequence.skiphash then
- local flags=sequence.flags
- if flags then
- local skipmark=flags[1]
- local skipligature=flags[2]
- local skipbase=flags[3]
- local markclass=sequence.markclass
- local skipsome=skipmark or skipligature or skipbase or markclass or false
- if skipsome then
- sequence.skiphash=setmetatableindex(function(t,k)
- local c=resources.classes[k]
- local v=c==skipmark
- or (markclass and c=="mark" and not markclass[k])
- or c==skipligature
- or c==skipbase
- or false
- t[k]=v
- return v
- end)
- else
- sequence.skiphash=false
- end
- else
- sequence.skiphash=false
- end
- end
+if setmetatablenewindex then
+ setmetatablenewindex(features,assign)
end
-local function checksteps(sequence)
- local steps=sequence.steps
- if steps then
- for i=1,#steps do
- steps[i].index=i
- end
+local checkers={
+ rand=function(v)
+ return v==true and "random" or v
end
+}
+if not storage then
+ return
end
-if fonts.helpers then
- fonts.helpers.checkmerge=checkmerge
- fonts.helpers.checkflags=checkflags
- fonts.helpers.checksteps=checksteps
-end
-function readers.expand(data)
- if not data or data.expanded then
- return
- else
- data.expanded=true
- end
- local resources=data.resources
- local sublookups=resources.sublookups
- local sequences=resources.sequences
- local markclasses=resources.markclasses
- local descriptions=data.descriptions
- if descriptions then
- local defaultwidth=resources.defaultwidth or 0
- local defaultheight=resources.defaultheight or 0
- local defaultdepth=resources.defaultdepth or 0
- local basename=trace_markwidth and file.basename(resources.filename)
- for u,d in next,descriptions do
- local bb=d.boundingbox
- local wd=d.width
- if not wd then
- d.width=defaultwidth
- elseif trace_markwidth and wd~=0 and d.class=="mark" then
- report_markwidth("mark %a with width %b found in %a",d.name or "<noname>",wd,basename)
- end
- if bb then
- local ht=bb[4]
- local dp=-bb[2]
- if ht==0 or ht<0 then
- else
- d.height=ht
- end
- if dp==0 or dp<0 then
+local usedfeatures=statistics.usedfeatures or {}
+statistics.usedfeatures=usedfeatures
+table.setmetatableindex(usedfeatures,function(t,k) if k then local v={} t[k]=v return v end end)
+storage.register("fonts/otf/usedfeatures",usedfeatures,"fonts.handlers.otf.statistics.usedfeatures" )
+local normalizedaxis=otf.readers.helpers.normalizedaxis or function(s) return s end
+function otffeatures.normalize(features,wrap)
+ if features then
+ local h={}
+ for key,value in next,features do
+ local k=lower(key)
+ if k=="language" then
+ local v=gsub(lower(value),"[^a-z0-9]","")
+ h.language=rawget(verboselanguages,v) or (languages[v] and v) or "dflt"
+ elseif k=="script" then
+ local v=gsub(lower(value),"[^a-z0-9]","")
+ h.script=rawget(verbosescripts,v) or (scripts[v] and v) or "dflt"
+ elseif k=="axis" then
+ h[k]=normalizedaxis(value)
+ else
+ local uk=usedfeatures[key]
+ local uv=uk[value]
+ if uv then
else
- d.depth=dp
- end
- end
- end
- end
- local function expandlookups(sequences)
- if sequences then
- for i=1,#sequences do
- local sequence=sequences[i]
- local steps=sequence.steps
- if steps then
- local nofsteps=sequence.nofsteps
- local kind=sequence.type
- local markclass=sequence.markclass
- if markclass then
- if not markclasses then
- report_warning("missing markclasses")
- sequence.markclass=false
+ uv=tonumber(value)
+ if uv then
+ elseif type(value)=="string" then
+ local b=is_boolean(value)
+ if type(b)=="nil" then
+ if wrap and find(value,",") then
+ uv="{"..lower(value).."}"
+ else
+ uv=lower(value)
+ end
else
- sequence.markclass=markclasses[markclass]
+ uv=b
end
+ elseif type(value)=="table" then
+ uv=sequenced(t,",")
+ else
+ uv=value
end
- for i=1,nofsteps do
- local step=steps[i]
- local baseclasses=step.baseclasses
- if baseclasses then
- local coverage=step.coverage
- for k,v in next,coverage do
- v[1]=baseclasses[v[1]]
- end
- elseif kind=="gpos_cursive" then
- local coverage=step.coverage
- for k,v in next,coverage do
- v[1]=coverage
- end
- end
- local rules=step.rules
- if rules then
- local rulehash={ n=0 }
- local rulesize=0
- local coverage={}
- local lookuptype=sequence.type
- local nofrules=#rules
- step.coverage=coverage
- for currentrule=1,nofrules do
- local rule=rules[currentrule]
- local current=rule.current
- local before=rule.before
- local after=rule.after
- local replacements=rule.replacements or false
- local sequence={}
- local nofsequences=0
- if before then
- for n=1,#before do
- nofsequences=nofsequences+1
- sequence[nofsequences]=before[n]
- end
- end
- local start=nofsequences+1
- for n=1,#current do
- nofsequences=nofsequences+1
- sequence[nofsequences]=current[n]
- end
- local stop=nofsequences
- if after then
- for n=1,#after do
- nofsequences=nofsequences+1
- sequence[nofsequences]=after[n]
- end
- end
- local lookups=rule.lookups or false
- local subtype=nil
- if lookups then
- for i=1,#lookups do
- local lookups=lookups[i]
- if lookups then
- for k,v in next,lookups do
- local lookup=sublookups[v]
- if lookup then
- lookups[k]=lookup
- if not subtype then
- subtype=lookup.type
- end
- else
- end
- end
- end
- end
- end
- if sequence[1] then
- sequence.n=#sequence
- local ruledata={
- currentrule,
- lookuptype,
- sequence,
- start,
- stop,
- lookups,
- replacements,
- subtype,
- }
- rulesize=rulesize+1
- rulehash[rulesize]=ruledata
- rulehash.n=rulesize
- if true then
- for unic in next,sequence[start] do
- local cu=coverage[unic]
- if cu then
- local n=#cu+1
- cu[n]=ruledata
- cu.n=n
- else
- coverage[unic]={ ruledata,n=1 }
- end
- end
- else
- for unic in next,sequence[start] do
- local cu=coverage[unic]
- if cu then
- else
- coverage[unic]=rulehash
- end
- end
- end
- end
- end
- end
+ if not rawget(features,k) then
+ k=rawget(verbosefeatures,k) or k
end
- checkmerge(sequence)
- checkflags(sequence,resources)
- checksteps(sequence)
+ local c=checkers[k]
+ if c then
+ uv=c(uv) or vc
+ end
+ uk[value]=uv
end
+ h[k]=uv
end
end
+ return h
end
- expandlookups(sequences)
- expandlookups(sublookups)
end
end -- closure
@@ -24506,6 +21908,7 @@ do -- begin closure to overcome local limits and interference
if not modules then modules={} end modules ['font-otj']={
version=1.001,
+ optimize=true,
comment="companion to font-lib.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -25993,6 +23396,2649 @@ end -- closure
do -- begin closure to overcome local limits and interference
+if not modules then modules={} end modules ['font-oup']={
+ version=1.001,
+ comment="companion to font-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local next,type=next,type
+local P,R,S=lpeg.P,lpeg.R,lpeg.S
+local lpegmatch=lpeg.match
+local insert,remove,copy,unpack=table.insert,table.remove,table.copy,table.unpack
+local formatters=string.formatters
+local sortedkeys=table.sortedkeys
+local sortedhash=table.sortedhash
+local tohash=table.tohash
+local setmetatableindex=table.setmetatableindex
+local report_error=logs.reporter("otf reader","error")
+local report_markwidth=logs.reporter("otf reader","markwidth")
+local report_cleanup=logs.reporter("otf reader","cleanup")
+local report_optimizations=logs.reporter("otf reader","merges")
+local report_unicodes=logs.reporter("otf reader","unicodes")
+local trace_markwidth=false trackers.register("otf.markwidth",function(v) trace_markwidth=v end)
+local trace_cleanup=false trackers.register("otf.cleanups",function(v) trace_cleanups=v end)
+local trace_optimizations=false trackers.register("otf.optimizations",function(v) trace_optimizations=v end)
+local trace_unicodes=false trackers.register("otf.unicodes",function(v) trace_unicodes=v end)
+local readers=fonts.handlers.otf.readers
+local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000
+local f_private=formatters["P%05X"]
+local f_unicode=formatters["U%05X"]
+local f_index=formatters["I%05X"]
+local f_character_y=formatters["%C"]
+local f_character_n=formatters["[ %C ]"]
+local check_duplicates=true
+local check_soft_hyphen=true
+directives.register("otf.checksofthyphen",function(v)
+ check_soft_hyphen=v
+end)
+local function replaced(list,index,replacement)
+ if type(list)=="number" then
+ return replacement
+ elseif type(replacement)=="table" then
+ local t={}
+ local n=index-1
+ for i=1,n do
+ t[i]=list[i]
+ end
+ for i=1,#replacement do
+ n=n+1
+ t[n]=replacement[i]
+ end
+ for i=index+1,#list do
+ n=n+1
+ t[n]=list[i]
+ end
+ else
+ list[index]=replacement
+ return list
+ end
+end
+local function unifyresources(fontdata,indices)
+ local descriptions=fontdata.descriptions
+ local resources=fontdata.resources
+ if not descriptions or not resources then
+ return
+ end
+ local nofindices=#indices
+ local variants=fontdata.resources.variants
+ if variants then
+ for selector,unicodes in next,variants do
+ for unicode,index in next,unicodes do
+ unicodes[unicode]=indices[index]
+ end
+ end
+ end
+ local function remark(marks)
+ if marks then
+ local newmarks={}
+ for k,v in next,marks do
+ local u=indices[k]
+ if u then
+ newmarks[u]=v
+ elseif trace_optimizations then
+ report_optimizations("discarding mark %i",k)
+ end
+ end
+ return newmarks
+ end
+ end
+ local marks=resources.marks
+ if marks then
+ resources.marks=remark(marks)
+ end
+ local markclasses=resources.markclasses
+ if markclasses then
+ for class,marks in next,markclasses do
+ markclasses[class]=remark(marks)
+ end
+ end
+ local marksets=resources.marksets
+ if marksets then
+ for class,marks in next,marksets do
+ marksets[class]=remark(marks)
+ end
+ end
+ local done={}
+ local duplicates=check_duplicates and resources.duplicates
+ if duplicates and not next(duplicates) then
+ duplicates=false
+ end
+ local function recover(cover)
+ for i=1,#cover do
+ local c=cover[i]
+ if not done[c] then
+ local t={}
+ for k,v in next,c do
+ local ug=indices[k]
+ if ug then
+ t[ug]=v
+ else
+ report_error("case %i, bad index in unifying %s: %s of %s",1,"coverage",k,nofindices)
+ end
+ end
+ cover[i]=t
+ done[c]=d
+ end
+ end
+ end
+ local function recursed(c,kind)
+ local t={}
+ for g,d in next,c do
+ if type(d)=="table" then
+ local ug=indices[g]
+ if ug then
+ t[ug]=recursed(d,kind)
+ else
+ report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g,nofindices)
+ end
+ else
+ t[g]=indices[d]
+ end
+ end
+ return t
+ end
+ local function unifythem(sequences)
+ if not sequences then
+ return
+ end
+ for i=1,#sequences do
+ local sequence=sequences[i]
+ local kind=sequence.type
+ local steps=sequence.steps
+ local features=sequence.features
+ if steps then
+ for i=1,#steps do
+ local step=steps[i]
+ if kind=="gsub_single" then
+ local c=step.coverage
+ if c then
+ local t1=done[c]
+ if not t1 then
+ t1={}
+ if duplicates then
+ for g1,d1 in next,c do
+ local ug1=indices[g1]
+ if ug1 then
+ local ud1=indices[d1]
+ if ud1 then
+ t1[ug1]=ud1
+ local dg1=duplicates[ug1]
+ if dg1 then
+ for u in next,dg1 do
+ t1[u]=ud1
+ end
+ end
+ else
+ report_error("case %i, bad index in unifying %s: %s of %s",3,kind,d1,nofindices)
+ end
+ else
+ report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices)
+ end
+ end
+ else
+ for g1,d1 in next,c do
+ local ug1=indices[g1]
+ if ug1 then
+ t1[ug1]=indices[d1]
+ else
+ report_error("fuzzy case %i in unifying %s: %i",2,kind,g1)
+ end
+ end
+ end
+ done[c]=t1
+ end
+ step.coverage=t1
+ end
+ elseif kind=="gpos_pair" then
+ local c=step.coverage
+ if c then
+ local t1=done[c]
+ if not t1 then
+ t1={}
+ for g1,d1 in next,c do
+ local ug1=indices[g1]
+ if ug1 then
+ local t2=done[d1]
+ if not t2 then
+ t2={}
+ for g2,d2 in next,d1 do
+ local ug2=indices[g2]
+ if ug2 then
+ t2[ug2]=d2
+ else
+ report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g2,nofindices,nofindices)
+ end
+ end
+ done[d1]=t2
+ end
+ t1[ug1]=t2
+ else
+ report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices)
+ end
+ end
+ done[c]=t1
+ end
+ step.coverage=t1
+ end
+ elseif kind=="gsub_ligature" then
+ local c=step.coverage
+ if c then
+ step.coverage=recursed(c,kind)
+ end
+ elseif kind=="gsub_alternate" or kind=="gsub_multiple" then
+ local c=step.coverage
+ if c then
+ local t1=done[c]
+ if not t1 then
+ t1={}
+ if duplicates then
+ for g1,d1 in next,c do
+ for i=1,#d1 do
+ local d1i=d1[i]
+ local d1u=indices[d1i]
+ if d1u then
+ d1[i]=d1u
+ else
+ report_error("case %i, bad index in unifying %s: %s of %s",1,kind,i,d1i,nofindices)
+ end
+ end
+ local ug1=indices[g1]
+ if ug1 then
+ t1[ug1]=d1
+ local dg1=duplicates[ug1]
+ if dg1 then
+ for u in next,dg1 do
+ t1[u]=copy(d1)
+ end
+ end
+ else
+ report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices)
+ end
+ end
+ else
+ for g1,d1 in next,c do
+ for i=1,#d1 do
+ local d1i=d1[i]
+ local d1u=indices[d1i]
+ if d1u then
+ d1[i]=d1u
+ else
+ report_error("case %i, bad index in unifying %s: %s of %s",2,kind,d1i,nofindices)
+ end
+ end
+ t1[indices[g1]]=d1
+ end
+ end
+ done[c]=t1
+ end
+ step.coverage=t1
+ end
+ elseif kind=="gpos_single" then
+ local c=step.coverage
+ if c then
+ local t1=done[c]
+ if not t1 then
+ t1={}
+ if duplicates then
+ for g1,d1 in next,c do
+ local ug1=indices[g1]
+ if ug1 then
+ t1[ug1]=d1
+ local dg1=duplicates[ug1]
+ if dg1 then
+ for u in next,dg1 do
+ t1[u]=d1
+ end
+ end
+ else
+ report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices)
+ end
+ end
+ else
+ for g1,d1 in next,c do
+ local ug1=indices[g1]
+ if ug1 then
+ t1[ug1]=d1
+ else
+ report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices)
+ end
+ end
+ end
+ done[c]=t1
+ end
+ step.coverage=t1
+ end
+ elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" or kind=="gpos_mark2ligature" then
+ local c=step.coverage
+ if c then
+ local t1=done[c]
+ if not t1 then
+ t1={}
+ for g1,d1 in next,c do
+ local ug1=indices[g1]
+ if ug1 then
+ t1[ug1]=d1
+ else
+ report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices)
+ end
+ end
+ done[c]=t1
+ end
+ step.coverage=t1
+ end
+ local c=step.baseclasses
+ if c then
+ local t1=done[c]
+ if not t1 then
+ for g1,d1 in next,c do
+ local t2=done[d1]
+ if not t2 then
+ t2={}
+ for g2,d2 in next,d1 do
+ local ug2=indices[g2]
+ if ug2 then
+ t2[ug2]=d2
+ else
+ report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g2,nofindices)
+ end
+ end
+ done[d1]=t2
+ end
+ c[g1]=t2
+ end
+ done[c]=c
+ end
+ end
+ elseif kind=="gpos_cursive" then
+ local c=step.coverage
+ if c then
+ local t1=done[c]
+ if not t1 then
+ t1={}
+ if duplicates then
+ for g1,d1 in next,c do
+ local ug1=indices[g1]
+ if ug1 then
+ t1[ug1]=d1
+ local dg1=duplicates[ug1]
+ if dg1 then
+ for u in next,dg1 do
+ t1[u]=copy(d1)
+ end
+ end
+ else
+ report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices)
+ end
+ end
+ else
+ for g1,d1 in next,c do
+ local ug1=indices[g1]
+ if ug1 then
+ t1[ug1]=d1
+ else
+ report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices)
+ end
+ end
+ end
+ done[c]=t1
+ end
+ step.coverage=t1
+ end
+ end
+ local rules=step.rules
+ if rules then
+ for i=1,#rules do
+ local rule=rules[i]
+ local before=rule.before if before then recover(before) end
+ local after=rule.after if after then recover(after) end
+ local current=rule.current if current then recover(current) end
+ local replacements=rule.replacements
+ if replacements then
+ if not done[replacements] then
+ local r={}
+ for k,v in next,replacements do
+ r[indices[k]]=indices[v]
+ end
+ rule.replacements=r
+ done[replacements]=r
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ unifythem(resources.sequences)
+ unifythem(resources.sublookups)
+end
+local function copyduplicates(fontdata)
+ if check_duplicates then
+ local descriptions=fontdata.descriptions
+ local resources=fontdata.resources
+ local duplicates=resources.duplicates
+ if check_soft_hyphen then
+ local ds=descriptions[0xAD]
+ if not ds or ds.width==0 then
+ if ds then
+ descriptions[0xAD]=nil
+ if trace_unicodes then
+ report_unicodes("patching soft hyphen")
+ end
+ else
+ if trace_unicodes then
+ report_unicodes("adding soft hyphen")
+ end
+ end
+ if not duplicates then
+ duplicates={}
+ resources.duplicates=duplicates
+ end
+ local dh=duplicates[0x2D]
+ if dh then
+ dh[#dh+1]={ [0xAD]=true }
+ else
+ duplicates[0x2D]={ [0xAD]=true }
+ end
+ end
+ end
+ if duplicates then
+ for u,d in next,duplicates do
+ local du=descriptions[u]
+ if du then
+ local t={ f_character_y(u),"@",f_index(du.index),"->" }
+ local n=0
+ local m=25
+ for u in next,d do
+ if descriptions[u] then
+ if n<m then
+ t[n+4]=f_character_n(u)
+ end
+ else
+ local c=copy(du)
+ c.unicode=u
+ descriptions[u]=c
+ if n<m then
+ t[n+4]=f_character_y(u)
+ end
+ end
+ n=n+1
+ end
+ if trace_unicodes then
+ if n<=m then
+ report_unicodes("%i : % t",n,t)
+ else
+ report_unicodes("%i : % t ...",n,t)
+ end
+ end
+ else
+ end
+ end
+ end
+ end
+end
+local ignore={
+ ["notdef"]=true,
+ [".notdef"]=true,
+ ["null"]=true,
+ [".null"]=true,
+ ["nonmarkingreturn"]=true,
+}
+local function checklookups(fontdata,missing,nofmissing)
+ local descriptions=fontdata.descriptions
+ local resources=fontdata.resources
+ if missing and nofmissing and nofmissing<=0 then
+ return
+ end
+ local singles={}
+ local alternates={}
+ local ligatures={}
+ if not missing then
+ missing={}
+ nofmissing=0
+ for u,d in next,descriptions do
+ if not d.unicode then
+ nofmissing=nofmissing+1
+ missing[u]=true
+ end
+ end
+ end
+ local function collectthem(sequences)
+ if not sequences then
+ return
+ end
+ for i=1,#sequences do
+ local sequence=sequences[i]
+ local kind=sequence.type
+ local steps=sequence.steps
+ if steps then
+ for i=1,#steps do
+ local step=steps[i]
+ if kind=="gsub_single" then
+ local c=step.coverage
+ if c then
+ singles[#singles+1]=c
+ end
+ elseif kind=="gsub_alternate" then
+ local c=step.coverage
+ if c then
+ alternates[#alternates+1]=c
+ end
+ elseif kind=="gsub_ligature" then
+ local c=step.coverage
+ if c then
+ ligatures[#ligatures+1]=c
+ end
+ end
+ end
+ end
+ end
+ end
+ collectthem(resources.sequences)
+ collectthem(resources.sublookups)
+ local loops=0
+ while true do
+ loops=loops+1
+ local old=nofmissing
+ for i=1,#singles do
+ local c=singles[i]
+ for g1,g2 in next,c do
+ if missing[g1] then
+ local u2=descriptions[g2].unicode
+ if u2 then
+ missing[g1]=false
+ descriptions[g1].unicode=u2
+ nofmissing=nofmissing-1
+ end
+ end
+ if missing[g2] then
+ local u1=descriptions[g1].unicode
+ if u1 then
+ missing[g2]=false
+ descriptions[g2].unicode=u1
+ nofmissing=nofmissing-1
+ end
+ end
+ end
+ end
+ for i=1,#alternates do
+ local c=alternates[i]
+ for g1,d1 in next,c do
+ if missing[g1] then
+ for i=1,#d1 do
+ local g2=d1[i]
+ local u2=descriptions[g2].unicode
+ if u2 then
+ missing[g1]=false
+ descriptions[g1].unicode=u2
+ nofmissing=nofmissing-1
+ end
+ end
+ end
+ if not missing[g1] then
+ for i=1,#d1 do
+ local g2=d1[i]
+ if missing[g2] then
+ local u1=descriptions[g1].unicode
+ if u1 then
+ missing[g2]=false
+ descriptions[g2].unicode=u1
+ nofmissing=nofmissing-1
+ end
+ end
+ end
+ end
+ end
+ end
+ if nofmissing<=0 then
+ if trace_unicodes then
+ report_unicodes("all missings done in %s loops",loops)
+ end
+ return
+ elseif old==nofmissing then
+ break
+ end
+ end
+ local t,n
+ local function recursed(c)
+ for g,d in next,c do
+ if g~="ligature" then
+ local u=descriptions[g].unicode
+ if u then
+ n=n+1
+ t[n]=u
+ recursed(d)
+ n=n-1
+ end
+ elseif missing[d] then
+ local l={}
+ local m=0
+ for i=1,n do
+ local u=t[i]
+ if type(u)=="table" then
+ for i=1,#u do
+ m=m+1
+ l[m]=u[i]
+ end
+ else
+ m=m+1
+ l[m]=u
+ end
+ end
+ missing[d]=false
+ descriptions[d].unicode=l
+ nofmissing=nofmissing-1
+ end
+ end
+ end
+ if nofmissing>0 then
+ t={}
+ n=0
+ local loops=0
+ while true do
+ loops=loops+1
+ local old=nofmissing
+ for i=1,#ligatures do
+ recursed(ligatures[i])
+ end
+ if nofmissing<=0 then
+ if trace_unicodes then
+ report_unicodes("all missings done in %s loops",loops)
+ end
+ return
+ elseif old==nofmissing then
+ break
+ end
+ end
+ t=nil
+ n=0
+ end
+ if trace_unicodes and nofmissing>0 then
+ local done={}
+ for i,r in next,missing do
+ if r then
+ local data=descriptions[i]
+ local name=data and data.name or f_index(i)
+ if not ignore[name] then
+ done[name]=true
+ end
+ end
+ end
+ if next(done) then
+ report_unicodes("not unicoded: % t",sortedkeys(done))
+ end
+ end
+end
+local firstprivate=fonts.privateoffsets and fonts.privateoffsets.textbase or 0xF0000
+local puafirst=0xE000
+local pualast=0xF8FF
+local function unifymissing(fontdata)
+ if not fonts.mappings then
+ require("font-map")
+ require("font-agl")
+ end
+ local unicodes={}
+ local resources=fontdata.resources
+ resources.unicodes=unicodes
+ for unicode,d in next,fontdata.descriptions do
+ if unicode<privateoffset then
+ if unicode>=puafirst and unicode<=pualast then
+ else
+ local name=d.name
+ if name then
+ unicodes[name]=unicode
+ end
+ end
+ else
+ end
+ end
+ fonts.mappings.addtounicode(fontdata,fontdata.filename,checklookups)
+ resources.unicodes=nil
+end
+local function unifyglyphs(fontdata,usenames)
+ local private=fontdata.private or privateoffset
+ local glyphs=fontdata.glyphs
+ local indices={}
+ local descriptions={}
+ local names=usenames and {}
+ local resources=fontdata.resources
+ local zero=glyphs[0]
+ local zerocode=zero.unicode
+ if not zerocode then
+ zerocode=private
+ zero.unicode=zerocode
+ private=private+1
+ end
+ descriptions[zerocode]=zero
+ if names then
+ local name=glyphs[0].name or f_private(zerocode)
+ indices[0]=name
+ names[name]=zerocode
+ else
+ indices[0]=zerocode
+ end
+ if names then
+ for index=1,#glyphs do
+ local glyph=glyphs[index]
+ local unicode=glyph.unicode
+ if not unicode then
+ unicode=private
+ local name=glyph.name or f_private(unicode)
+ indices[index]=name
+ names[name]=unicode
+ private=private+1
+ elseif unicode>=firstprivate then
+ unicode=private
+ local name=glyph.name or f_private(unicode)
+ indices[index]=name
+ names[name]=unicode
+ private=private+1
+ elseif unicode>=puafirst and unicode<=pualast then
+ local name=glyph.name or f_private(unicode)
+ indices[index]=name
+ names[name]=unicode
+ elseif descriptions[unicode] then
+ unicode=private
+ local name=glyph.name or f_private(unicode)
+ indices[index]=name
+ names[name]=unicode
+ private=private+1
+ else
+ local name=glyph.name or f_unicode(unicode)
+ indices[index]=name
+ names[name]=unicode
+ end
+ descriptions[unicode]=glyph
+ end
+ elseif trace_unicodes then
+ for index=1,#glyphs do
+ local glyph=glyphs[index]
+ local unicode=glyph.unicode
+ if not unicode then
+ unicode=private
+ indices[index]=unicode
+ private=private+1
+ elseif unicode>=firstprivate then
+ local name=glyph.name
+ if name then
+ report_unicodes("moving glyph %a indexed %05X from private %U to %U ",name,index,unicode,private)
+ else
+ report_unicodes("moving glyph indexed %05X from private %U to %U ",index,unicode,private)
+ end
+ unicode=private
+ indices[index]=unicode
+ private=private+1
+ elseif unicode>=puafirst and unicode<=pualast then
+ local name=glyph.name
+ if name then
+ report_unicodes("keeping private unicode %U for glyph %a indexed %05X",unicode,name,index)
+ else
+ report_unicodes("keeping private unicode %U for glyph indexed %05X",unicode,index)
+ end
+ indices[index]=unicode
+ elseif descriptions[unicode] then
+ local name=glyph.name
+ if name then
+ report_unicodes("assigning duplicate unicode %U to %U for glyph %a indexed %05X ",unicode,private,name,index)
+ else
+ report_unicodes("assigning duplicate unicode %U to %U for glyph indexed %05X ",unicode,private,index)
+ end
+ unicode=private
+ indices[index]=unicode
+ private=private+1
+ else
+ indices[index]=unicode
+ end
+ descriptions[unicode]=glyph
+ end
+ else
+ for index=1,#glyphs do
+ local glyph=glyphs[index]
+ local unicode=glyph.unicode
+ if not unicode then
+ unicode=private
+ indices[index]=unicode
+ private=private+1
+ elseif unicode>=firstprivate then
+ local name=glyph.name
+ unicode=private
+ indices[index]=unicode
+ private=private+1
+ elseif unicode>=puafirst and unicode<=pualast then
+ local name=glyph.name
+ indices[index]=unicode
+ elseif descriptions[unicode] then
+ local name=glyph.name
+ unicode=private
+ indices[index]=unicode
+ private=private+1
+ else
+ indices[index]=unicode
+ end
+ descriptions[unicode]=glyph
+ end
+ end
+ for index=1,#glyphs do
+ local math=glyphs[index].math
+ if math then
+ local list=math.vparts
+ if list then
+ for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end
+ end
+ local list=math.hparts
+ if list then
+ for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end
+ end
+ local list=math.vvariants
+ if list then
+ for i=1,#list do list[i]=indices[list[i]] end
+ end
+ local list=math.hvariants
+ if list then
+ for i=1,#list do list[i]=indices[list[i]] end
+ end
+ end
+ end
+ local colorpalettes=resources.colorpalettes
+ if colorpalettes then
+ for index=1,#glyphs do
+ local colors=glyphs[index].colors
+ if colors then
+ for i=1,#colors do
+ local c=colors[i]
+ c.slot=indices[c.slot]
+ end
+ end
+ end
+ end
+ fontdata.private=private
+ fontdata.glyphs=nil
+ fontdata.names=names
+ fontdata.descriptions=descriptions
+ fontdata.hashmethod=hashmethod
+ return indices,names
+end
+local p_crappyname do
+ local p_hex=R("af","AF","09")
+ local p_digit=R("09")
+ local p_done=S("._-")^0+P(-1)
+ local p_alpha=R("az","AZ")
+ local p_ALPHA=R("AZ")
+ p_crappyname=(
+ lpeg.utfchartabletopattern({ "uni","u" },true)*S("Xx_")^0*p_hex^1
++lpeg.utfchartabletopattern({ "identity","glyph","jamo" },true)*p_hex^1
++lpeg.utfchartabletopattern({ "index","afii" },true)*p_digit^1
++p_digit*p_hex^3+p_alpha*p_digit^1
++P("aj")*p_digit^1+P("eh_")*(p_digit^1+p_ALPHA*p_digit^1)+(1-P("_"))^1*P("_uni")*p_hex^1+P("_")*P(1)^1
+ )*p_done
+end
+local forcekeep=false
+directives.register("otf.keepnames",function(v)
+ report_cleanup("keeping weird glyph names, expect larger files and more memory usage")
+ forcekeep=v
+end)
+local function stripredundant(fontdata)
+ local descriptions=fontdata.descriptions
+ if descriptions then
+ local n=0
+ local c=0
+ if (not context and fonts.privateoffsets.keepnames) or forcekeep then
+ for unicode,d in next,descriptions do
+ if d.class=="base" then
+ d.class=nil
+ c=c+1
+ end
+ end
+ else
+ for unicode,d in next,descriptions do
+ local name=d.name
+ if name and lpegmatch(p_crappyname,name) then
+ d.name=nil
+ n=n+1
+ end
+ if d.class=="base" then
+ d.class=nil
+ c=c+1
+ end
+ end
+ end
+ if trace_cleanup then
+ if n>0 then
+ report_cleanup("%s bogus names removed (verbose unicode)",n)
+ end
+ if c>0 then
+ report_cleanup("%s base class tags removed (default is base)",c)
+ end
+ end
+ end
+end
+readers.stripredundant=stripredundant
+function readers.getcomponents(fontdata)
+ local resources=fontdata.resources
+ if resources then
+ local sequences=resources.sequences
+ if sequences then
+ local collected={}
+ for i=1,#sequences do
+ local sequence=sequences[i]
+ if sequence.type=="gsub_ligature" then
+ local steps=sequence.steps
+ if steps then
+ local l={}
+ local function traverse(p,k,v)
+ if k=="ligature" then
+ collected[v]={ unpack(l) }
+ else
+ insert(l,k)
+ for k,vv in next,v do
+ traverse(p,k,vv)
+ end
+ remove(l)
+ end
+ end
+ for i=1,#steps do
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
+ traverse(k,k,v)
+ end
+ end
+ end
+ end
+ end
+ end
+ if next(collected) then
+ while true do
+ local done=false
+ for k,v in next,collected do
+ for i=1,#v do
+ local vi=v[i]
+ if vi==k then
+ collected[k]=nil
+ break
+ else
+ local c=collected[vi]
+ if c then
+ done=true
+ local t={}
+ local n=i-1
+ for j=1,n do
+ t[j]=v[j]
+ end
+ for j=1,#c do
+ n=n+1
+ t[n]=c[j]
+ end
+ for j=i+1,#v do
+ n=n+1
+ t[n]=v[j]
+ end
+ collected[k]=t
+ break
+ end
+ end
+ end
+ end
+ if not done then
+ break
+ end
+ end
+ return collected
+ end
+ end
+ end
+end
+readers.unifymissing=unifymissing
+function readers.rehash(fontdata,hashmethod)
+ if not (fontdata and fontdata.glyphs) then
+ return
+ end
+ if hashmethod=="indices" then
+ fontdata.hashmethod="indices"
+ elseif hashmethod=="names" then
+ fontdata.hashmethod="names"
+ local indices=unifyglyphs(fontdata,true)
+ unifyresources(fontdata,indices)
+ copyduplicates(fontdata)
+ unifymissing(fontdata)
+ else
+ fontdata.hashmethod="unicodes"
+ local indices=unifyglyphs(fontdata)
+ unifyresources(fontdata,indices)
+ copyduplicates(fontdata)
+ unifymissing(fontdata)
+ stripredundant(fontdata)
+ end
+end
+function readers.checkhash(fontdata)
+ local hashmethod=fontdata.hashmethod
+ if hashmethod=="unicodes" then
+ fontdata.names=nil
+ elseif hashmethod=="names" and fontdata.names then
+ unifyresources(fontdata,fontdata.names)
+ copyduplicates(fontdata)
+ fontdata.hashmethod="unicodes"
+ fontdata.names=nil
+ else
+ readers.rehash(fontdata,"unicodes")
+ end
+end
+function readers.addunicodetable(fontdata)
+ local resources=fontdata.resources
+ local unicodes=resources.unicodes
+ if not unicodes then
+ local descriptions=fontdata.descriptions
+ if descriptions then
+ unicodes={}
+ resources.unicodes=unicodes
+ for u,d in next,descriptions do
+ local n=d.name
+ if n then
+ unicodes[n]=u
+ end
+ end
+ end
+ end
+end
+local concat,sort=table.concat,table.sort
+local next,type,tostring=next,type,tostring
+local criterium=1
+local threshold=0
+local trace_packing=false trackers.register("otf.packing",function(v) trace_packing=v end)
+local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end)
+local report_otf=logs.reporter("fonts","otf loading")
+local function tabstr_normal(t)
+ local s={}
+ local n=0
+ for k,v in next,t do
+ n=n+1
+ if type(v)=="table" then
+ s[n]=k..">"..tabstr_normal(v)
+ elseif v==true then
+ s[n]=k.."+"
+ elseif v then
+ s[n]=k.."="..v
+ else
+ s[n]=k.."-"
+ end
+ end
+ if n==0 then
+ return ""
+ elseif n==1 then
+ return s[1]
+ else
+ sort(s)
+ return concat(s,",")
+ end
+end
+local function tabstr_flat(t)
+ local s={}
+ local n=0
+ for k,v in next,t do
+ n=n+1
+ s[n]=k.."="..v
+ end
+ if n==0 then
+ return ""
+ elseif n==1 then
+ return s[1]
+ else
+ sort(s)
+ return concat(s,",")
+ end
+end
+local function tabstr_mixed(t)
+ local s={}
+ local n=#t
+ if n==0 then
+ return ""
+ elseif n==1 then
+ local k=t[1]
+ if k==true then
+ return "++"
+ elseif k==false then
+ return "--"
+ else
+ return tostring(k)
+ end
+ else
+ for i=1,n do
+ local k=t[i]
+ if k==true then
+ s[i]="++"
+ elseif k==false then
+ s[i]="--"
+ else
+ s[i]=k
+ end
+ end
+ return concat(s,",")
+ end
+end
+local function tabstr_boolean(t)
+ local s={}
+ local n=0
+ for k,v in next,t do
+ n=n+1
+ if v then
+ s[n]=k.."+"
+ else
+ s[n]=k.."-"
+ end
+ end
+ if n==0 then
+ return ""
+ elseif n==1 then
+ return s[1]
+ else
+ sort(s)
+ return concat(s,",")
+ end
+end
+function readers.pack(data)
+ if data then
+ local h,t,c={},{},{}
+ local hh,tt,cc={},{},{}
+ local nt,ntt=0,0
+ local function pack_normal(v)
+ local tag=tabstr_normal(v)
+ local ht=h[tag]
+ if ht then
+ c[ht]=c[ht]+1
+ return ht
+ else
+ nt=nt+1
+ t[nt]=v
+ h[tag]=nt
+ c[nt]=1
+ return nt
+ end
+ end
+ local function pack_normal_cc(v)
+ local tag=tabstr_normal(v)
+ local ht=h[tag]
+ if ht then
+ c[ht]=c[ht]+1
+ return ht
+ else
+ v[1]=0
+ nt=nt+1
+ t[nt]=v
+ h[tag]=nt
+ c[nt]=1
+ return nt
+ end
+ end
+ local function pack_flat(v)
+ local tag=tabstr_flat(v)
+ local ht=h[tag]
+ if ht then
+ c[ht]=c[ht]+1
+ return ht
+ else
+ nt=nt+1
+ t[nt]=v
+ h[tag]=nt
+ c[nt]=1
+ return nt
+ end
+ end
+ local function pack_indexed(v)
+ local tag=concat(v," ")
+ local ht=h[tag]
+ if ht then
+ c[ht]=c[ht]+1
+ return ht
+ else
+ nt=nt+1
+ t[nt]=v
+ h[tag]=nt
+ c[nt]=1
+ return nt
+ end
+ end
+ local function pack_mixed(v)
+ local tag=tabstr_mixed(v)
+ local ht=h[tag]
+ if ht then
+ c[ht]=c[ht]+1
+ return ht
+ else
+ nt=nt+1
+ t[nt]=v
+ h[tag]=nt
+ c[nt]=1
+ return nt
+ end
+ end
+ local function pack_boolean(v)
+ local tag=tabstr_boolean(v)
+ local ht=h[tag]
+ if ht then
+ c[ht]=c[ht]+1
+ return ht
+ else
+ nt=nt+1
+ t[nt]=v
+ h[tag]=nt
+ c[nt]=1
+ return nt
+ end
+ end
+ local function pack_final(v)
+ if c[v]<=criterium then
+ return t[v]
+ else
+ local hv=hh[v]
+ if hv then
+ return hv
+ else
+ ntt=ntt+1
+ tt[ntt]=t[v]
+ hh[v]=ntt
+ cc[ntt]=c[v]
+ return ntt
+ end
+ end
+ end
+ local function pack_final_cc(v)
+ if c[v]<=criterium then
+ return t[v]
+ else
+ local hv=hh[v]
+ if hv then
+ return hv
+ else
+ ntt=ntt+1
+ tt[ntt]=t[v]
+ hh[v]=ntt
+ cc[ntt]=c[v]
+ return ntt
+ end
+ end
+ end
+ local function success(stage,pass)
+ if nt==0 then
+ if trace_loading or trace_packing then
+ report_otf("pack quality: nothing to pack")
+ end
+ return false
+ elseif nt>=threshold then
+ local one=0
+ local two=0
+ local rest=0
+ if pass==1 then
+ for k,v in next,c do
+ if v==1 then
+ one=one+1
+ elseif v==2 then
+ two=two+1
+ else
+ rest=rest+1
+ end
+ end
+ else
+ for k,v in next,cc do
+ if v>20 then
+ rest=rest+1
+ elseif v>10 then
+ two=two+1
+ else
+ one=one+1
+ end
+ end
+ data.tables=tt
+ end
+ if trace_loading or trace_packing then
+ report_otf("pack quality: stage %s, pass %s, %s packed, 1-10:%s, 11-20:%s, rest:%s (criterium: %s)",
+ stage,pass,one+two+rest,one,two,rest,criterium)
+ end
+ return true
+ else
+ if trace_loading or trace_packing then
+ report_otf("pack quality: stage %s, pass %s, %s packed, aborting pack (threshold: %s)",
+ stage,pass,nt,threshold)
+ end
+ return false
+ end
+ end
+ local function packers(pass)
+ if pass==1 then
+ return pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc
+ else
+ return pack_final,pack_final,pack_final,pack_final,pack_final,pack_final_cc
+ end
+ end
+ local resources=data.resources
+ local sequences=resources.sequences
+ local sublookups=resources.sublookups
+ local features=resources.features
+ local palettes=resources.colorpalettes
+ local variable=resources.variabledata
+ local chardata=characters and characters.data
+ local descriptions=data.descriptions or data.glyphs
+ if not descriptions then
+ return
+ end
+ for pass=1,2 do
+ if trace_packing then
+ report_otf("start packing: stage 1, pass %s",pass)
+ end
+ local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc=packers(pass)
+ for unicode,description in next,descriptions do
+ local boundingbox=description.boundingbox
+ if boundingbox then
+ description.boundingbox=pack_indexed(boundingbox)
+ end
+ local math=description.math
+ if math then
+ local kerns=math.kerns
+ if kerns then
+ for tag,kern in next,kerns do
+ kerns[tag]=pack_normal(kern)
+ end
+ end
+ end
+ end
+ local function packthem(sequences)
+ for i=1,#sequences do
+ local sequence=sequences[i]
+ local kind=sequence.type
+ local steps=sequence.steps
+ local order=sequence.order
+ local features=sequence.features
+ local flags=sequence.flags
+ if steps then
+ for i=1,#steps do
+ local step=steps[i]
+ if kind=="gpos_pair" then
+ local c=step.coverage
+ if c then
+ if step.format~="pair" then
+ for g1,d1 in next,c do
+ c[g1]=pack_normal(d1)
+ end
+ elseif step.shared then
+ local shared={}
+ for g1,d1 in next,c do
+ for g2,d2 in next,d1 do
+ if not shared[d2] then
+ local f=d2[1] if f and f~=true then d2[1]=pack_indexed(f) end
+ local s=d2[2] if s and s~=true then d2[2]=pack_indexed(s) end
+ shared[d2]=true
+ end
+ end
+ end
+ if pass==2 then
+ step.shared=nil
+ end
+ else
+ for g1,d1 in next,c do
+ for g2,d2 in next,d1 do
+ local f=d2[1] if f and f~=true then d2[1]=pack_indexed(f) end
+ local s=d2[2] if s and s~=true then d2[2]=pack_indexed(s) end
+ end
+ end
+ end
+ end
+ elseif kind=="gpos_single" then
+ local c=step.coverage
+ if c then
+ if step.format=="single" then
+ for g1,d1 in next,c do
+ if d1 and d1~=true then
+ c[g1]=pack_indexed(d1)
+ end
+ end
+ else
+ step.coverage=pack_normal(c)
+ end
+ end
+ elseif kind=="gpos_cursive" then
+ local c=step.coverage
+ if c then
+ for g1,d1 in next,c do
+ local f=d1[2] if f then d1[2]=pack_indexed(f) end
+ local s=d1[3] if s then d1[3]=pack_indexed(s) end
+ end
+ end
+ elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" then
+ local c=step.baseclasses
+ if c then
+ for g1,d1 in next,c do
+ for g2,d2 in next,d1 do
+ d1[g2]=pack_indexed(d2)
+ end
+ end
+ end
+ local c=step.coverage
+ if c then
+ for g1,d1 in next,c do
+ d1[2]=pack_indexed(d1[2])
+ end
+ end
+ elseif kind=="gpos_mark2ligature" then
+ local c=step.baseclasses
+ if c then
+ for g1,d1 in next,c do
+ for g2,d2 in next,d1 do
+ for g3,d3 in next,d2 do
+ d2[g3]=pack_indexed(d3)
+ end
+ end
+ end
+ end
+ local c=step.coverage
+ if c then
+ for g1,d1 in next,c do
+ d1[2]=pack_indexed(d1[2])
+ end
+ end
+ end
+ local rules=step.rules
+ if rules then
+ for i=1,#rules do
+ local rule=rules[i]
+ local r=rule.before if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
+ local r=rule.after if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
+ local r=rule.current if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
+ local r=rule.replacements if r then rule.replacements=pack_flat (r) end
+ end
+ end
+ end
+ end
+ if order then
+ sequence.order=pack_indexed(order)
+ end
+ if features then
+ for script,feature in next,features do
+ features[script]=pack_normal(feature)
+ end
+ end
+ if flags then
+ sequence.flags=pack_normal(flags)
+ end
+ end
+ end
+ if sequences then
+ packthem(sequences)
+ end
+ if sublookups then
+ packthem(sublookups)
+ end
+ if features then
+ for k,list in next,features do
+ for feature,spec in next,list do
+ list[feature]=pack_normal(spec)
+ end
+ end
+ end
+ if palettes then
+ for i=1,#palettes do
+ local p=palettes[i]
+ for j=1,#p do
+ p[j]=pack_indexed(p[j])
+ end
+ end
+ end
+ if variable then
+ local instances=variable.instances
+ if instances then
+ for i=1,#instances do
+ local v=instances[i].values
+ for j=1,#v do
+ v[j]=pack_normal(v[j])
+ end
+ end
+ end
+ local function packdeltas(main)
+ if main then
+ local deltas=main.deltas
+ if deltas then
+ for i=1,#deltas do
+ local di=deltas[i]
+ local d=di.deltas
+ for j=1,#d do
+ d[j]=pack_indexed(d[j])
+ end
+ di.regions=pack_indexed(di.regions)
+ end
+ end
+ local regions=main.regions
+ if regions then
+ for i=1,#regions do
+ local r=regions[i]
+ for j=1,#r do
+ r[j]=pack_normal(r[j])
+ end
+ end
+ end
+ end
+ end
+ packdeltas(variable.global)
+ packdeltas(variable.horizontal)
+ packdeltas(variable.vertical)
+ packdeltas(variable.metrics)
+ end
+ if not success(1,pass) then
+ return
+ end
+ end
+ if nt>0 then
+ for pass=1,2 do
+ if trace_packing then
+ report_otf("start packing: stage 2, pass %s",pass)
+ end
+ local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc=packers(pass)
+ for unicode,description in next,descriptions do
+ local math=description.math
+ if math then
+ local kerns=math.kerns
+ if kerns then
+ math.kerns=pack_normal(kerns)
+ end
+ end
+ end
+ local function packthem(sequences)
+ for i=1,#sequences do
+ local sequence=sequences[i]
+ local kind=sequence.type
+ local steps=sequence.steps
+ local features=sequence.features
+ if steps then
+ for i=1,#steps do
+ local step=steps[i]
+ if kind=="gpos_pair" then
+ local c=step.coverage
+ if c then
+ if step.format=="pair" then
+ for g1,d1 in next,c do
+ for g2,d2 in next,d1 do
+ d1[g2]=pack_normal(d2)
+ end
+ end
+ end
+ end
+ elseif kind=="gpos_mark2ligature" then
+ local c=step.baseclasses
+ if c then
+ for g1,d1 in next,c do
+ for g2,d2 in next,d1 do
+ d1[g2]=pack_normal(d2)
+ end
+ end
+ end
+ end
+ local rules=step.rules
+ if rules then
+ for i=1,#rules do
+ local rule=rules[i]
+ local r=rule.before if r then rule.before=pack_normal(r) end
+ local r=rule.after if r then rule.after=pack_normal(r) end
+ local r=rule.current if r then rule.current=pack_normal(r) end
+ end
+ end
+ end
+ end
+ if features then
+ sequence.features=pack_normal(features)
+ end
+ end
+ end
+ if sequences then
+ packthem(sequences)
+ end
+ if sublookups then
+ packthem(sublookups)
+ end
+ if variable then
+ local function unpackdeltas(main)
+ if main then
+ local regions=main.regions
+ if regions then
+ main.regions=pack_normal(regions)
+ end
+ end
+ end
+ unpackdeltas(variable.global)
+ unpackdeltas(variable.horizontal)
+ unpackdeltas(variable.vertical)
+ unpackdeltas(variable.metrics)
+ end
+ end
+ for pass=1,2 do
+ if trace_packing then
+ report_otf("start packing: stage 3, pass %s",pass)
+ end
+ local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc=packers(pass)
+ local function packthem(sequences)
+ for i=1,#sequences do
+ local sequence=sequences[i]
+ local kind=sequence.type
+ local steps=sequence.steps
+ local features=sequence.features
+ if steps then
+ for i=1,#steps do
+ local step=steps[i]
+ if kind=="gpos_pair" then
+ local c=step.coverage
+ if c then
+ if step.format=="pair" then
+ for g1,d1 in next,c do
+ c[g1]=pack_normal(d1)
+ end
+ end
+ end
+ elseif kind=="gpos_cursive" then
+ local c=step.coverage
+ if c then
+ for g1,d1 in next,c do
+ c[g1]=pack_normal_cc(d1)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ if sequences then
+ packthem(sequences)
+ end
+ if sublookups then
+ packthem(sublookups)
+ end
+ end
+ end
+ end
+end
+local unpacked_mt={
+ __index=function(t,k)
+ t[k]=false
+ return k
+ end
+}
+function readers.unpack(data)
+ if data then
+ local tables=data.tables
+ if tables then
+ local resources=data.resources
+ local descriptions=data.descriptions or data.glyphs
+ local sequences=resources.sequences
+ local sublookups=resources.sublookups
+ local features=resources.features
+ local palettes=resources.colorpalettes
+ local variable=resources.variabledata
+ local unpacked={}
+ setmetatable(unpacked,unpacked_mt)
+ for unicode,description in next,descriptions do
+ local tv=tables[description.boundingbox]
+ if tv then
+ description.boundingbox=tv
+ end
+ local math=description.math
+ if math then
+ local kerns=math.kerns
+ if kerns then
+ local tm=tables[kerns]
+ if tm then
+ math.kerns=tm
+ kerns=unpacked[tm]
+ end
+ if kerns then
+ for k,kern in next,kerns do
+ local tv=tables[kern]
+ if tv then
+ kerns[k]=tv
+ end
+ end
+ end
+ end
+ end
+ end
+ local function unpackthem(sequences)
+ for i=1,#sequences do
+ local sequence=sequences[i]
+ local kind=sequence.type
+ local steps=sequence.steps
+ local order=sequence.order
+ local features=sequence.features
+ local flags=sequence.flags
+ local markclass=sequence.markclass
+ if features then
+ local tv=tables[features]
+ if tv then
+ sequence.features=tv
+ features=tv
+ end
+ for script,feature in next,features do
+ local tv=tables[feature]
+ if tv then
+ features[script]=tv
+ end
+ end
+ end
+ if steps then
+ for i=1,#steps do
+ local step=steps[i]
+ if kind=="gpos_pair" then
+ local c=step.coverage
+ if c then
+ if step.format=="pair" then
+ for g1,d1 in next,c do
+ local tv=tables[d1]
+ if tv then
+ c[g1]=tv
+ d1=tv
+ end
+ for g2,d2 in next,d1 do
+ local tv=tables[d2]
+ if tv then
+ d1[g2]=tv
+ d2=tv
+ end
+ local f=tables[d2[1]] if f then d2[1]=f end
+ local s=tables[d2[2]] if s then d2[2]=s end
+ end
+ end
+ else
+ for g1,d1 in next,c do
+ local tv=tables[d1]
+ if tv then
+ c[g1]=tv
+ end
+ end
+ end
+ end
+ elseif kind=="gpos_single" then
+ local c=step.coverage
+ if c then
+ if step.format=="single" then
+ for g1,d1 in next,c do
+ local tv=tables[d1]
+ if tv then
+ c[g1]=tv
+ end
+ end
+ else
+ local tv=tables[c]
+ if tv then
+ step.coverage=tv
+ end
+ end
+ end
+ elseif kind=="gpos_cursive" then
+ local c=step.coverage
+ if c then
+ for g1,d1 in next,c do
+ local tv=tables[d1]
+ if tv then
+ d1=tv
+ c[g1]=d1
+ end
+ local f=tables[d1[2]] if f then d1[2]=f end
+ local s=tables[d1[3]] if s then d1[3]=s end
+ end
+ end
+ elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" then
+ local c=step.baseclasses
+ if c then
+ for g1,d1 in next,c do
+ for g2,d2 in next,d1 do
+ local tv=tables[d2]
+ if tv then
+ d1[g2]=tv
+ end
+ end
+ end
+ end
+ local c=step.coverage
+ if c then
+ for g1,d1 in next,c do
+ local tv=tables[d1[2]]
+ if tv then
+ d1[2]=tv
+ end
+ end
+ end
+ elseif kind=="gpos_mark2ligature" then
+ local c=step.baseclasses
+ if c then
+ for g1,d1 in next,c do
+ for g2,d2 in next,d1 do
+ local tv=tables[d2]
+ if tv then
+ d2=tv
+ d1[g2]=d2
+ end
+ for g3,d3 in next,d2 do
+ local tv=tables[d2[g3]]
+ if tv then
+ d2[g3]=tv
+ end
+ end
+ end
+ end
+ end
+ local c=step.coverage
+ if c then
+ for g1,d1 in next,c do
+ local tv=tables[d1[2]]
+ if tv then
+ d1[2]=tv
+ end
+ end
+ end
+ end
+ local rules=step.rules
+ if rules then
+ for i=1,#rules do
+ local rule=rules[i]
+ local before=rule.before
+ if before then
+ local tv=tables[before]
+ if tv then
+ rule.before=tv
+ before=tv
+ end
+ for i=1,#before do
+ local tv=tables[before[i]]
+ if tv then
+ before[i]=tv
+ end
+ end
+ end
+ local after=rule.after
+ if after then
+ local tv=tables[after]
+ if tv then
+ rule.after=tv
+ after=tv
+ end
+ for i=1,#after do
+ local tv=tables[after[i]]
+ if tv then
+ after[i]=tv
+ end
+ end
+ end
+ local current=rule.current
+ if current then
+ local tv=tables[current]
+ if tv then
+ rule.current=tv
+ current=tv
+ end
+ for i=1,#current do
+ local tv=tables[current[i]]
+ if tv then
+ current[i]=tv
+ end
+ end
+ end
+ local replacements=rule.replacements
+ if replacements then
+ local tv=tables[replacements]
+ if tv then
+ rule.replacements=tv
+ end
+ end
+ end
+ end
+ end
+ end
+ if order then
+ local tv=tables[order]
+ if tv then
+ sequence.order=tv
+ end
+ end
+ if flags then
+ local tv=tables[flags]
+ if tv then
+ sequence.flags=tv
+ end
+ end
+ end
+ end
+ if sequences then
+ unpackthem(sequences)
+ end
+ if sublookups then
+ unpackthem(sublookups)
+ end
+ if features then
+ for k,list in next,features do
+ for feature,spec in next,list do
+ local tv=tables[spec]
+ if tv then
+ list[feature]=tv
+ end
+ end
+ end
+ end
+ if palettes then
+ for i=1,#palettes do
+ local p=palettes[i]
+ for j=1,#p do
+ local tv=tables[p[j]]
+ if tv then
+ p[j]=tv
+ end
+ end
+ end
+ end
+ if variable then
+ local instances=variable.instances
+ if instances then
+ for i=1,#instances do
+ local v=instances[i].values
+ for j=1,#v do
+ local tv=tables[v[j]]
+ if tv then
+ v[j]=tv
+ end
+ end
+ end
+ end
+ local function unpackdeltas(main)
+ if main then
+ local deltas=main.deltas
+ if deltas then
+ for i=1,#deltas do
+ local di=deltas[i]
+ local d=di.deltas
+ local r=di.regions
+ for j=1,#d do
+ local tv=tables[d[j]]
+ if tv then
+ d[j]=tv
+ end
+ end
+ local tv=di.regions
+ if tv then
+ di.regions=tv
+ end
+ end
+ end
+ local regions=main.regions
+ if regions then
+ local tv=tables[regions]
+ if tv then
+ main.regions=tv
+ regions=tv
+ end
+ for i=1,#regions do
+ local r=regions[i]
+ for j=1,#r do
+ local tv=tables[r[j]]
+ if tv then
+ r[j]=tv
+ end
+ end
+ end
+ end
+ end
+ end
+ unpackdeltas(variable.global)
+ unpackdeltas(variable.horizontal)
+ unpackdeltas(variable.vertical)
+ unpackdeltas(variable.metrics)
+ end
+ data.tables=nil
+ end
+ end
+end
+local mt={
+ __index=function(t,k)
+ if k=="height" then
+ local ht=t.boundingbox[4]
+ return ht<0 and 0 or ht
+ elseif k=="depth" then
+ local dp=-t.boundingbox[2]
+ return dp<0 and 0 or dp
+ elseif k=="width" then
+ return 0
+ elseif k=="name" then
+ return forcenotdef and ".notdef"
+ end
+ end
+}
+local function sameformat(sequence,steps,first,nofsteps,kind)
+ return true
+end
+local function mergesteps_1(lookup,strict)
+ local steps=lookup.steps
+ local nofsteps=lookup.nofsteps
+ local first=steps[1]
+ if strict then
+ local f=first.format
+ for i=2,nofsteps do
+ if steps[i].format~=f then
+ if trace_optimizations then
+ report_optimizations("not merging %a steps of %a lookup %a, different formats",nofsteps,lookup.type,lookup.name)
+ end
+ return 0
+ end
+ end
+ end
+ if trace_optimizations then
+ report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
+ end
+ local target=first.coverage
+ for i=2,nofsteps do
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
+ if not target[k] then
+ target[k]=v
+ end
+ end
+ end
+ end
+ lookup.nofsteps=1
+ lookup.merged=true
+ lookup.steps={ first }
+ return nofsteps-1
+end
+local function mergesteps_2(lookup)
+ local steps=lookup.steps
+ local nofsteps=lookup.nofsteps
+ local first=steps[1]
+ if strict then
+ local f=first.format
+ for i=2,nofsteps do
+ if steps[i].format~=f then
+ if trace_optimizations then
+ report_optimizations("not merging %a steps of %a lookup %a, different formats",nofsteps,lookup.type,lookup.name)
+ end
+ return 0
+ end
+ end
+ end
+ if trace_optimizations then
+ report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
+ end
+ local target=first.coverage
+ for i=2,nofsteps do
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
+ local tk=target[k]
+ if tk then
+ for kk,vv in next,v do
+ if tk[kk]==nil then
+ tk[kk]=vv
+ end
+ end
+ else
+ target[k]=v
+ end
+ end
+ end
+ end
+ lookup.nofsteps=1
+ lookup.merged=true
+ lookup.steps={ first }
+ return nofsteps-1
+end
+local function mergesteps_3(lookup,strict)
+ local steps=lookup.steps
+ local nofsteps=lookup.nofsteps
+ if trace_optimizations then
+ report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
+ end
+ local coverage={}
+ for i=1,nofsteps do
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
+ local tk=coverage[k]
+ if tk then
+ if trace_optimizations then
+ report_optimizations("quitting merge due to multiple checks")
+ end
+ return nofsteps
+ else
+ coverage[k]=v
+ end
+ end
+ end
+ end
+ local first=steps[1]
+ local baseclasses={}
+ for i=1,nofsteps do
+ local offset=i*10
+ local step=steps[i]
+ for k,v in sortedhash(step.baseclasses) do
+ baseclasses[offset+k]=v
+ end
+ for k,v in next,step.coverage do
+ v[1]=offset+v[1]
+ end
+ end
+ first.baseclasses=baseclasses
+ first.coverage=coverage
+ lookup.nofsteps=1
+ lookup.merged=true
+ lookup.steps={ first }
+ return nofsteps-1
+end
+local function nested(old,new)
+ for k,v in next,old do
+ if k=="ligature" then
+ if not new.ligature then
+ new.ligature=v
+ end
+ else
+ local n=new[k]
+ if n then
+ nested(v,n)
+ else
+ new[k]=v
+ end
+ end
+ end
+end
+local function mergesteps_4(lookup)
+ local steps=lookup.steps
+ local nofsteps=lookup.nofsteps
+ local first=steps[1]
+ if trace_optimizations then
+ report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
+ end
+ local target=first.coverage
+ for i=2,nofsteps do
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
+ local tk=target[k]
+ if tk then
+ nested(v,tk)
+ else
+ target[k]=v
+ end
+ end
+ end
+ end
+ lookup.nofsteps=1
+ lookup.steps={ first }
+ return nofsteps-1
+end
+local function mergesteps_5(lookup)
+ local steps=lookup.steps
+ local nofsteps=lookup.nofsteps
+ local first=steps[1]
+ if trace_optimizations then
+ report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
+ end
+ local target=first.coverage
+ local hash=nil
+ for k,v in next,target do
+ hash=v[1]
+ break
+ end
+ for i=2,nofsteps do
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
+ local tk=target[k]
+ if tk then
+ if not tk[2] then
+ tk[2]=v[2]
+ end
+ if not tk[3] then
+ tk[3]=v[3]
+ end
+ else
+ target[k]=v
+ v[1]=hash
+ end
+ end
+ end
+ end
+ lookup.nofsteps=1
+ lookup.merged=true
+ lookup.steps={ first }
+ return nofsteps-1
+end
+local function checkkerns(lookup)
+ local steps=lookup.steps
+ local nofsteps=lookup.nofsteps
+ local kerned=0
+ for i=1,nofsteps do
+ local step=steps[i]
+ if step.format=="pair" then
+ local coverage=step.coverage
+ local kerns=true
+ for g1,d1 in next,coverage do
+ if d1==true then
+ elseif not d1 then
+ elseif d1[1]~=0 or d1[2]~=0 or d1[4]~=0 then
+ kerns=false
+ break
+ end
+ end
+ if kerns then
+ if trace_optimizations then
+ report_optimizations("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name)
+ end
+ local c={}
+ for g1,d1 in next,coverage do
+ if d1 and d1~=true then
+ c[g1]=d1[3]
+ end
+ end
+ step.coverage=c
+ step.format="move"
+ kerned=kerned+1
+ end
+ end
+ end
+ return kerned
+end
+local function checkpairs(lookup)
+ local steps=lookup.steps
+ local nofsteps=lookup.nofsteps
+ local kerned=0
+ local function onlykerns(step)
+ local coverage=step.coverage
+ for g1,d1 in next,coverage do
+ for g2,d2 in next,d1 do
+ if d2[2] then
+ return false
+ else
+ local v=d2[1]
+ if v==true then
+ elseif v and (v[1]~=0 or v[2]~=0 or v[4]~=0) then
+ return false
+ end
+ end
+ end
+ end
+ return coverage
+ end
+ for i=1,nofsteps do
+ local step=steps[i]
+ if step.format=="pair" then
+ local coverage=onlykerns(step)
+ if coverage then
+ if trace_optimizations then
+ report_optimizations("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name)
+ end
+ for g1,d1 in next,coverage do
+ local d={}
+ for g2,d2 in next,d1 do
+ local v=d2[1]
+ if v==true then
+ elseif v then
+ d[g2]=v[3]
+ end
+ end
+ coverage[g1]=d
+ end
+ step.format="move"
+ kerned=kerned+1
+ end
+ end
+ end
+ return kerned
+end
+local compact_pairs=true
+local compact_singles=true
+local merge_pairs=true
+local merge_singles=true
+local merge_substitutions=true
+local merge_alternates=true
+local merge_multiples=true
+local merge_ligatures=true
+local merge_cursives=true
+local merge_marks=true
+directives.register("otf.compact.pairs",function(v) compact_pairs=v end)
+directives.register("otf.compact.singles",function(v) compact_singles=v end)
+directives.register("otf.merge.pairs",function(v) merge_pairs=v end)
+directives.register("otf.merge.singles",function(v) merge_singles=v end)
+directives.register("otf.merge.substitutions",function(v) merge_substitutions=v end)
+directives.register("otf.merge.alternates",function(v) merge_alternates=v end)
+directives.register("otf.merge.multiples",function(v) merge_multiples=v end)
+directives.register("otf.merge.ligatures",function(v) merge_ligatures=v end)
+directives.register("otf.merge.cursives",function(v) merge_cursives=v end)
+directives.register("otf.merge.marks",function(v) merge_marks=v end)
+function readers.compact(data)
+ if not data or data.compacted then
+ return
+ else
+ data.compacted=true
+ end
+ local resources=data.resources
+ local merged=0
+ local kerned=0
+ local allsteps=0
+ local function compact(what)
+ local lookups=resources[what]
+ if lookups then
+ for i=1,#lookups do
+ local lookup=lookups[i]
+ local nofsteps=lookup.nofsteps
+ local kind=lookup.type
+ allsteps=allsteps+nofsteps
+ if nofsteps>1 then
+ local merg=merged
+ if kind=="gsub_single" then
+ if merge_substitutions then
+ merged=merged+mergesteps_1(lookup)
+ end
+ elseif kind=="gsub_alternate" then
+ if merge_alternates then
+ merged=merged+mergesteps_1(lookup)
+ end
+ elseif kind=="gsub_multiple" then
+ if merge_multiples then
+ merged=merged+mergesteps_1(lookup)
+ end
+ elseif kind=="gsub_ligature" then
+ if merge_ligatures then
+ merged=merged+mergesteps_4(lookup)
+ end
+ elseif kind=="gpos_single" then
+ if merge_singles then
+ merged=merged+mergesteps_1(lookup,true)
+ end
+ if compact_singles then
+ kerned=kerned+checkkerns(lookup)
+ end
+ elseif kind=="gpos_pair" then
+ if merge_pairs then
+ merged=merged+mergesteps_2(lookup)
+ end
+ if compact_pairs then
+ kerned=kerned+checkpairs(lookup)
+ end
+ elseif kind=="gpos_cursive" then
+ if merge_cursives then
+ merged=merged+mergesteps_5(lookup)
+ end
+ elseif kind=="gpos_mark2mark" or kind=="gpos_mark2base" or kind=="gpos_mark2ligature" then
+ if merge_marks then
+ merged=merged+mergesteps_3(lookup)
+ end
+ end
+ if merg~=merged then
+ lookup.merged=true
+ end
+ elseif nofsteps==1 then
+ local kern=kerned
+ if kind=="gpos_single" then
+ if compact_singles then
+ kerned=kerned+checkkerns(lookup)
+ end
+ elseif kind=="gpos_pair" then
+ if compact_pairs then
+ kerned=kerned+checkpairs(lookup)
+ end
+ end
+ if kern~=kerned then
+ end
+ end
+ end
+ elseif trace_optimizations then
+ report_optimizations("no lookups in %a",what)
+ end
+ end
+ compact("sequences")
+ compact("sublookups")
+ if trace_optimizations then
+ if merged>0 then
+ report_optimizations("%i steps of %i removed due to merging",merged,allsteps)
+ end
+ if kerned>0 then
+ report_optimizations("%i steps of %i steps turned from pairs into kerns",kerned,allsteps)
+ end
+ end
+end
+local function mergesteps(t,k)
+ if k=="merged" then
+ local merged={}
+ for i=1,#t do
+ local step=t[i]
+ local coverage=step.coverage
+ for k in next,coverage do
+ local m=merged[k]
+ if m then
+ m[2]=i
+ else
+ merged[k]={ i,i }
+ end
+ end
+ end
+ t.merged=merged
+ return merged
+ end
+end
+local function checkmerge(sequence)
+ local steps=sequence.steps
+ if steps then
+ setmetatableindex(steps,mergesteps)
+ end
+end
+local function checkflags(sequence,resources)
+ if not sequence.skiphash then
+ local flags=sequence.flags
+ if flags then
+ local skipmark=flags[1]
+ local skipligature=flags[2]
+ local skipbase=flags[3]
+ local markclass=sequence.markclass
+ local skipsome=skipmark or skipligature or skipbase or markclass or false
+ if skipsome then
+ sequence.skiphash=setmetatableindex(function(t,k)
+ local c=resources.classes[k]
+ local v=c==skipmark
+ or (markclass and c=="mark" and not markclass[k])
+ or c==skipligature
+ or c==skipbase
+ or false
+ t[k]=v
+ return v
+ end)
+ else
+ sequence.skiphash=false
+ end
+ else
+ sequence.skiphash=false
+ end
+ end
+end
+local function checksteps(sequence)
+ local steps=sequence.steps
+ if steps then
+ for i=1,#steps do
+ steps[i].index=i
+ end
+ end
+end
+if fonts.helpers then
+ fonts.helpers.checkmerge=checkmerge
+ fonts.helpers.checkflags=checkflags
+ fonts.helpers.checksteps=checksteps
+end
+function readers.expand(data)
+ if not data or data.expanded then
+ return
+ else
+ data.expanded=true
+ end
+ local resources=data.resources
+ local sublookups=resources.sublookups
+ local sequences=resources.sequences
+ local markclasses=resources.markclasses
+ local descriptions=data.descriptions
+ if descriptions then
+ local defaultwidth=resources.defaultwidth or 0
+ local defaultheight=resources.defaultheight or 0
+ local defaultdepth=resources.defaultdepth or 0
+ local basename=trace_markwidth and file.basename(resources.filename)
+ for u,d in next,descriptions do
+ local bb=d.boundingbox
+ local wd=d.width
+ if not wd then
+ d.width=defaultwidth
+ elseif trace_markwidth and wd~=0 and d.class=="mark" then
+ report_markwidth("mark %a with width %b found in %a",d.name or "<noname>",wd,basename)
+ end
+ if bb then
+ local ht=bb[4]
+ local dp=-bb[2]
+ if ht==0 or ht<0 then
+ else
+ d.height=ht
+ end
+ if dp==0 or dp<0 then
+ else
+ d.depth=dp
+ end
+ end
+ end
+ end
+ local function expandlookups(sequences)
+ if sequences then
+ for i=1,#sequences do
+ local sequence=sequences[i]
+ local steps=sequence.steps
+ if steps then
+ local nofsteps=sequence.nofsteps
+ local kind=sequence.type
+ local markclass=sequence.markclass
+ if markclass then
+ if not markclasses then
+ report_warning("missing markclasses")
+ sequence.markclass=false
+ else
+ sequence.markclass=markclasses[markclass]
+ end
+ end
+ for i=1,nofsteps do
+ local step=steps[i]
+ local baseclasses=step.baseclasses
+ if baseclasses then
+ local coverage=step.coverage
+ for k,v in next,coverage do
+ v[1]=baseclasses[v[1]]
+ end
+ elseif kind=="gpos_cursive" then
+ local coverage=step.coverage
+ for k,v in next,coverage do
+ v[1]=coverage
+ end
+ end
+ local rules=step.rules
+ if rules then
+ local rulehash={ n=0 }
+ local rulesize=0
+ local coverage={}
+ local lookuptype=sequence.type
+ local nofrules=#rules
+ step.coverage=coverage
+ for currentrule=1,nofrules do
+ local rule=rules[currentrule]
+ local current=rule.current
+ local before=rule.before
+ local after=rule.after
+ local replacements=rule.replacements or false
+ local sequence={}
+ local nofsequences=0
+ if before then
+ for n=1,#before do
+ nofsequences=nofsequences+1
+ sequence[nofsequences]=before[n]
+ end
+ end
+ local start=nofsequences+1
+ for n=1,#current do
+ nofsequences=nofsequences+1
+ sequence[nofsequences]=current[n]
+ end
+ local stop=nofsequences
+ if after then
+ for n=1,#after do
+ nofsequences=nofsequences+1
+ sequence[nofsequences]=after[n]
+ end
+ end
+ local lookups=rule.lookups or false
+ local subtype=nil
+ if lookups then
+ for i=1,#lookups do
+ local lookups=lookups[i]
+ if lookups then
+ for k,v in next,lookups do
+ local lookup=sublookups[v]
+ if lookup then
+ lookups[k]=lookup
+ if not subtype then
+ subtype=lookup.type
+ end
+ else
+ end
+ end
+ end
+ end
+ end
+ if sequence[1] then
+ sequence.n=#sequence
+ local ruledata={
+ currentrule,
+ lookuptype,
+ sequence,
+ start,
+ stop,
+ lookups,
+ replacements,
+ subtype,
+ }
+ rulesize=rulesize+1
+ rulehash[rulesize]=ruledata
+ rulehash.n=rulesize
+ if true then
+ for unic in next,sequence[start] do
+ local cu=coverage[unic]
+ if cu then
+ local n=#cu+1
+ cu[n]=ruledata
+ cu.n=n
+ else
+ coverage[unic]={ ruledata,n=1 }
+ end
+ end
+ else
+ for unic in next,sequence[start] do
+ local cu=coverage[unic]
+ if cu then
+ else
+ coverage[unic]=rulehash
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ checkmerge(sequence)
+ checkflags(sequence,resources)
+ checksteps(sequence)
+ end
+ end
+ end
+ end
+ expandlookups(sequences)
+ expandlookups(sublookups)
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
if not modules then modules={} end modules ['font-ota']={
version=1.001,
comment="companion to font-ini.mkiv",
@@ -26001,6 +26047,7 @@ if not modules then modules={} end modules ['font-ota']={
license="see context related readme files"
}
local type=type
+local setmetatableindex=table.setmetatableindex
if not trackers then trackers={ register=function() end } end
local fonts,nodes,node=fonts,nodes,node
local allocate=utilities.storage.allocate
@@ -26214,7 +26261,7 @@ if not classifiers then
local f_mandiac,l_mandiac=characters.blockrange("mandiac")
local f_nko,l_nko=characters.blockrange("nko")
local f_ext_a,l_ext_a=characters.blockrange("arabicextendeda")
- classifiers=table.setmetatableindex(function(t,k)
+ classifiers=setmetatableindex(function(t,k)
if type(k)=="number" then
local c=chardata[k]
local v=false
@@ -26380,6 +26427,106 @@ end
methods.syrc=methods.arab
methods.mand=methods.arab
methods.nko=methods.arab
+do
+ local joining=setmetatableindex(function(t,k)
+ if type(k)=="number" then
+ local c=chardata[k]
+ local v=false
+ if c then
+ local mongolian=c.mongolian
+ v=mongolian
+ end
+ t[k]=v
+ return v
+ end
+ end)
+ function methods.mong(head,font,attr)
+ local first,last
+ local current=head
+ local done=false
+ local prevjoin=nil
+ local prestate=nil
+ current=tonut(current)
+ local function wrapup()
+ if last then
+ if last~=first then
+ local s=getstate(last)
+ if s==s_medi then
+ setstate(last,s_fina)
+ elseif s==s_init then
+ setstate(last,s_isol)
+ end
+ end
+ last=nil
+ first=nil
+ prevjoin=nil
+ prestate=nil
+ end
+ end
+ while current do
+ local char,id=ischar(current,font)
+ if char and not getstate(current) then
+ local currjoin=joining[char]
+ done=true
+ if not last then
+ setstate(current,s_isol)
+ prevjoin=currjoin
+ first=current
+ last=current
+ prevstate=s_isol
+ elseif currjoin=="t" then
+ last=current
+ elseif prevjoin=="d" or prevjoin=="jc" or prevjoin=="l" then
+ if currjoin=="d" or prevjoin=="jc" or prevjoin=="r" then
+ local s=getstate(last)
+ if s==s_isol then
+ setstate(last,s_init)
+ elseif s==s_fina then
+ setstate(last,s_medi)
+ end
+ setstate(current,s_fina)
+ prevstate=s_fina
+ elseif prevjoin=="nj" or prevjoin=="l" then
+ local s=getstate(last)
+ if s==s_medi then
+ setstate(last,s_fina)
+ elseif s==s_init then
+ setstate(last,s_isol)
+ end
+ setstate(current,s_isol)
+ prevstate=s_isol
+ end
+ prevjoin=currjoin
+ last=current
+ elseif prevjoin=="nj" or prevjoin=="r" then
+ if s==s_medi then
+ setstate(last,s_fina)
+ elseif s==s_init then
+ setstate(last,s_isol)
+ end
+ setstate(current,s_isol)
+ prevjoin=currjoin
+ prevstate=s_isol
+ last=current
+ elseif last then
+ wrapup()
+ end
+ else
+ if last then
+ wrapup()
+ end
+ if id==math_code then
+ current=end_of_math(current)
+ end
+ end
+ current=getnext(current)
+ end
+ if last then
+ wrapup()
+ end
+ return head,done
+ end
+end
directives.register("otf.analyze.useunicodemarks",function(v)
analyzers.useunicodemarks=v
end)
@@ -26390,6 +26537,7 @@ do -- begin closure to overcome local limits and interference
if not modules then modules={} end modules ['font-ots']={
version=1.001,
+ optimize=true,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -26492,6 +26640,8 @@ local disc_code=nodecodes.disc
local math_code=nodecodes.math
local dir_code=nodecodes.dir
local localpar_code=nodecodes.localpar
+local lefttoright_code=nodes.dirvalues.lefttoright
+local righttoleft_code=nodes.dirvalues.righttoleft
local discretionarydisc_code=disccodes.discretionary
local ligatureglyph_code=glyphcodes.ligature
local a_noligature=attributes.private("noligature")
@@ -27995,6 +28145,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
local sweepnode=sweepnode
local sweeptype=sweeptype
local sweepoverflow=false
+ local checkdisc=getprev(head)
local keepdisc=not sweepnode
local lookaheaddisc=nil
local backtrackdisc=nil
@@ -28118,7 +28269,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
local current=prev
local i=f
local t=sweeptype=="pre" or sweeptype=="replace"
- if not current and t and current==checkdisk then
+ if not current and t and current==checkdisc then
current=getprev(sweepnode)
end
while current and i>1 do
@@ -28146,7 +28297,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
end
end
current=getprev(current)
- if t and current==checkdisk then
+ if t and current==checkdisc then
current=getprev(sweepnode)
end
end
@@ -28331,6 +28482,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
local l=ck[5]
local current=start
local last=start
+ if s==1 then
+ goto next
+ end
if l>f then
local discfound
local n=f+1
@@ -28396,6 +28550,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
break
end
end
+ if n<=l then
+ notmatchpre[last]=true
+ end
else
notmatchpre[last]=true
end
@@ -29341,8 +29498,6 @@ local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,datase
end
local txtdirstate,pardirstate do
local getdirection=nuts.getdirection
- local lefttoright=0
- local righttoleft=1
txtdirstate=function(start,stack,top,rlparmode)
local dir,pop=getdirection(start)
if pop then
@@ -29350,19 +29505,19 @@ local txtdirstate,pardirstate do
return 0,rlparmode
else
top=top-1
- if stack[top]==righttoleft then
+ if stack[top]==righttoleft_code then
return top,-1
else
return top,1
end
end
- elseif dir==lefttoright then
+ elseif dir==lefttoright_code then
top=top+1
- stack[top]=lefttoright
+ stack[top]=lefttoright_code
return top,1
- elseif dir==righttoleft then
+ elseif dir==righttoleft_code then
top=top+1
- stack[top]=righttoleft
+ stack[top]=righttoleft_code
return top,-1
else
return top,rlparmode
@@ -29370,13 +29525,9 @@ local txtdirstate,pardirstate do
end
pardirstate=function(start)
local dir=getdirection(start)
- if dir==lefttoright then
- return 1,1
- elseif dir==righttoleft then
- return -1,-1
- elseif dir=="TLT" then
+ if dir==lefttoright_code then
return 1,1
- elseif dir=="TRT" then
+ elseif dir==righttoleft_code then
return -1,-1
else
return 0,0
@@ -29431,7 +29582,7 @@ do
local initialrl=0
if getid(head)==localpar_code and start_of_par(head) then
initialrl=pardirstate(head)
- elseif direction==1 or direction=="TRT" then
+ elseif direction==righttoleft_code then
initialrl=-1
end
local datasets=otfdataset(tfmdata,font,attr)
@@ -29655,7 +29806,7 @@ do
local done=false
local dirstack={ nil }
local start=head
- local initialrl=(direction==1 or direction=="TRT") and -1 or 0
+ local initialrl=(direction==righttoleft_code) and -1 or 0
local rlmode=initialrl
local rlparmode=initialrl
local topstack=0
@@ -29980,6 +30131,765 @@ end -- closure
do -- begin closure to overcome local limits and interference
+if not modules then modules={} end modules ['font-otc']={
+ version=1.001,
+ comment="companion to font-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local insert,sortedkeys,sortedhash,tohash=table.insert,table.sortedkeys,table.sortedhash,table.tohash
+local type,next,tonumber=type,next,tonumber
+local lpegmatch=lpeg.match
+local utfbyte,utflen=utf.byte,utf.len
+local sortedhash=table.sortedhash
+local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end)
+local report_otf=logs.reporter("fonts","otf loading")
+local fonts=fonts
+local otf=fonts.handlers.otf
+local registerotffeature=otf.features.register
+local setmetatableindex=table.setmetatableindex
+local fonthelpers=fonts.helpers
+local checkmerge=fonthelpers.checkmerge
+local checkflags=fonthelpers.checkflags
+local checksteps=fonthelpers.checksteps
+local normalized={
+ substitution="substitution",
+ single="substitution",
+ ligature="ligature",
+ alternate="alternate",
+ multiple="multiple",
+ kern="kern",
+ pair="pair",
+ single="single",
+ chainsubstitution="chainsubstitution",
+ chainposition="chainposition",
+}
+local types={
+ substitution="gsub_single",
+ ligature="gsub_ligature",
+ alternate="gsub_alternate",
+ multiple="gsub_multiple",
+ kern="gpos_pair",
+ pair="gpos_pair",
+ single="gpos_single",
+ chainsubstitution="gsub_contextchain",
+ chainposition="gpos_contextchain",
+}
+local names={
+ gsub_single="gsub",
+ gsub_multiple="gsub",
+ gsub_alternate="gsub",
+ gsub_ligature="gsub",
+ gsub_context="gsub",
+ gsub_contextchain="gsub",
+ gsub_reversecontextchain="gsub",
+ gpos_single="gpos",
+ gpos_pair="gpos",
+ gpos_cursive="gpos",
+ gpos_mark2base="gpos",
+ gpos_mark2ligature="gpos",
+ gpos_mark2mark="gpos",
+ gpos_context="gpos",
+ gpos_contextchain="gpos",
+}
+setmetatableindex(types,function(t,k) t[k]=k return k end)
+local everywhere={ ["*"]={ ["*"]=true } }
+local noflags={ false,false,false,false }
+local function getrange(sequences,category)
+ local count=#sequences
+ local first=nil
+ local last=nil
+ for i=1,count do
+ local t=sequences[i].type
+ if t and names[t]==category then
+ if not first then
+ first=i
+ end
+ last=i
+ end
+ end
+ return first or 1,last or count
+end
+local function validspecification(specification,name)
+ local dataset=specification.dataset
+ if dataset then
+ elseif specification[1] then
+ dataset=specification
+ specification={ dataset=dataset }
+ else
+ dataset={ { data=specification.data } }
+ specification.data=nil
+ specification.dataset=dataset
+ end
+ local first=dataset[1]
+ if first then
+ first=first.data
+ end
+ if not first then
+ report_otf("invalid feature specification, no dataset")
+ return
+ end
+ if type(name)~="string" then
+ name=specification.name or first.name
+ end
+ if type(name)~="string" then
+ report_otf("invalid feature specification, no name")
+ return
+ end
+ local n=#dataset
+ if n>0 then
+ for i=1,n do
+ setmetatableindex(dataset[i],specification)
+ end
+ return specification,name
+ end
+end
+local function addfeature(data,feature,specifications)
+ if not specifications then
+ report_otf("missing specification")
+ return
+ end
+ local descriptions=data.descriptions
+ local resources=data.resources
+ local features=resources.features
+ local sequences=resources.sequences
+ if not features or not sequences then
+ report_otf("missing specification")
+ return
+ end
+ local alreadydone=resources.alreadydone
+ if not alreadydone then
+ alreadydone={}
+ resources.alreadydone=alreadydone
+ end
+ if alreadydone[specifications] then
+ return
+ else
+ alreadydone[specifications]=true
+ end
+ local fontfeatures=resources.features or everywhere
+ local unicodes=resources.unicodes
+ local splitter=lpeg.splitter(" ",unicodes)
+ local done=0
+ local skip=0
+ local aglunicodes=false
+ local privateslot=fonthelpers.privateslot
+ local specifications=validspecification(specifications,feature)
+ if not specifications then
+ return
+ end
+ local p=lpeg.P("P")*(lpeg.patterns.hexdigit^1/function(s) return tonumber(s,16) end)*lpeg.P(-1)
+ local function tounicode(code)
+ if not code then
+ return
+ end
+ if type(code)=="number" then
+ return code
+ end
+ local u=unicodes[code]
+ if u then
+ return u
+ end
+ if utflen(code)==1 then
+ u=utfbyte(code)
+ if u then
+ return u
+ end
+ end
+ if privateslot then
+ u=privateslot(code)
+ if u then
+ return u
+ end
+ end
+ local u=lpegmatch(p,code)
+ if u then
+ return u
+ end
+ if not aglunicodes then
+ aglunicodes=fonts.encodings.agl.unicodes
+ end
+ local u=aglunicodes[code]
+ if u then
+ return u
+ end
+ end
+ local coverup=otf.coverup
+ local coveractions=coverup.actions
+ local stepkey=coverup.stepkey
+ local register=coverup.register
+ local function prepare_substitution(list,featuretype,nocheck)
+ local coverage={}
+ local cover=coveractions[featuretype]
+ for code,replacement in next,list do
+ local unicode=tounicode(code)
+ local description=descriptions[unicode]
+ if not nocheck and not description then
+ skip=skip+1
+ else
+ if type(replacement)=="table" then
+ replacement=replacement[1]
+ end
+ replacement=tounicode(replacement)
+ if replacement and (nocheck or descriptions[replacement]) then
+ cover(coverage,unicode,replacement)
+ done=done+1
+ else
+ skip=skip+1
+ end
+ end
+ end
+ return coverage
+ end
+ local function prepare_alternate(list,featuretype,nocheck)
+ local coverage={}
+ local cover=coveractions[featuretype]
+ for code,replacement in next,list do
+ local unicode=tounicode(code)
+ local description=descriptions[unicode]
+ if not nocheck and not description then
+ skip=skip+1
+ elseif type(replacement)=="table" then
+ local r={}
+ for i=1,#replacement do
+ local u=tounicode(replacement[i])
+ r[i]=(nocheck or descriptions[u]) and u or unicode
+ end
+ cover(coverage,unicode,r)
+ done=done+1
+ else
+ local u=tounicode(replacement)
+ if u then
+ cover(coverage,unicode,{ u })
+ done=done+1
+ else
+ skip=skip+1
+ end
+ end
+ end
+ return coverage
+ end
+ local function prepare_multiple(list,featuretype,nocheck)
+ local coverage={}
+ local cover=coveractions[featuretype]
+ for code,replacement in next,list do
+ local unicode=tounicode(code)
+ local description=descriptions[unicode]
+ if not nocheck and not description then
+ skip=skip+1
+ elseif type(replacement)=="table" then
+ local r={}
+ local n=0
+ for i=1,#replacement do
+ local u=tounicode(replacement[i])
+ if nocheck or descriptions[u] then
+ n=n+1
+ r[n]=u
+ end
+ end
+ if n>0 then
+ cover(coverage,unicode,r)
+ done=done+1
+ else
+ skip=skip+1
+ end
+ else
+ local u=tounicode(replacement)
+ if u then
+ cover(coverage,unicode,{ u })
+ done=done+1
+ else
+ skip=skip+1
+ end
+ end
+ end
+ return coverage
+ end
+ local function prepare_ligature(list,featuretype,nocheck)
+ local coverage={}
+ local cover=coveractions[featuretype]
+ for code,ligature in next,list do
+ local unicode=tounicode(code)
+ local description=descriptions[unicode]
+ if not nocheck and not description then
+ skip=skip+1
+ else
+ if type(ligature)=="string" then
+ ligature={ lpegmatch(splitter,ligature) }
+ end
+ local present=true
+ for i=1,#ligature do
+ local l=ligature[i]
+ local u=tounicode(l)
+ if nocheck or descriptions[u] then
+ ligature[i]=u
+ else
+ present=false
+ break
+ end
+ end
+ if present then
+ cover(coverage,unicode,ligature)
+ done=done+1
+ else
+ skip=skip+1
+ end
+ end
+ end
+ return coverage
+ end
+ local function resetspacekerns()
+ data.properties.hasspacekerns=true
+ data.resources .spacekerns=nil
+ end
+ local function prepare_kern(list,featuretype)
+ local coverage={}
+ local cover=coveractions[featuretype]
+ local isspace=false
+ for code,replacement in next,list do
+ local unicode=tounicode(code)
+ local description=descriptions[unicode]
+ if description and type(replacement)=="table" then
+ local r={}
+ for k,v in next,replacement do
+ local u=tounicode(k)
+ if u then
+ r[u]=v
+ if u==32 then
+ isspace=true
+ end
+ end
+ end
+ if next(r) then
+ cover(coverage,unicode,r)
+ done=done+1
+ if unicode==32 then
+ isspace=true
+ end
+ else
+ skip=skip+1
+ end
+ else
+ skip=skip+1
+ end
+ end
+ if isspace then
+ resetspacekerns()
+ end
+ return coverage
+ end
+ local function prepare_pair(list,featuretype)
+ local coverage={}
+ local cover=coveractions[featuretype]
+ if cover then
+ for code,replacement in next,list do
+ local unicode=tounicode(code)
+ local description=descriptions[unicode]
+ if description and type(replacement)=="table" then
+ local r={}
+ for k,v in next,replacement do
+ local u=tounicode(k)
+ if u then
+ r[u]=v
+ if u==32 then
+ isspace=true
+ end
+ end
+ end
+ if next(r) then
+ cover(coverage,unicode,r)
+ done=done+1
+ if unicode==32 then
+ isspace=true
+ end
+ else
+ skip=skip+1
+ end
+ else
+ skip=skip+1
+ end
+ end
+ if isspace then
+ resetspacekerns()
+ end
+ else
+ report_otf("unknown cover type %a",featuretype)
+ end
+ return coverage
+ end
+ local prepare_single=prepare_pair
+ local function prepare_chain(list,featuretype,sublookups)
+ local rules=list.rules
+ local coverage={}
+ if rules then
+ local rulehash={}
+ local rulesize=0
+ local lookuptype=types[featuretype]
+ for nofrules=1,#rules do
+ local rule=rules[nofrules]
+ local current=rule.current
+ local before=rule.before
+ local after=rule.after
+ local replacements=rule.replacements or false
+ local sequence={}
+ local nofsequences=0
+ if before then
+ for n=1,#before do
+ nofsequences=nofsequences+1
+ sequence[nofsequences]=before[n]
+ end
+ end
+ local start=nofsequences+1
+ for n=1,#current do
+ nofsequences=nofsequences+1
+ sequence[nofsequences]=current[n]
+ end
+ local stop=nofsequences
+ if after then
+ for n=1,#after do
+ nofsequences=nofsequences+1
+ sequence[nofsequences]=after[n]
+ end
+ end
+ local lookups=rule.lookups or false
+ local subtype=nil
+ if lookups and sublookups then
+ for k,v in sortedhash(lookups) do
+ local t=type(v)
+ if t=="table" then
+ for i=1,#v do
+ local vi=v[i]
+ if type(vi)~="table" then
+ v[i]={ vi }
+ end
+ end
+ elseif t=="number" then
+ local lookup=sublookups[v]
+ if lookup then
+ lookups[k]={ lookup }
+ if not subtype then
+ subtype=lookup.type
+ end
+ elseif v==0 then
+ lookups[k]={ { type="gsub_remove" } }
+ else
+ lookups[k]=false
+ end
+ else
+ lookups[k]=false
+ end
+ end
+ end
+ if nofsequences>0 then
+ local hashed={}
+ for i=1,nofsequences do
+ local t={}
+ local s=sequence[i]
+ for i=1,#s do
+ local u=tounicode(s[i])
+ if u then
+ t[u]=true
+ end
+ end
+ hashed[i]=t
+ end
+ sequence=hashed
+ rulesize=rulesize+1
+ rulehash[rulesize]={
+ nofrules,
+ lookuptype,
+ sequence,
+ start,
+ stop,
+ lookups,
+ replacements,
+ subtype,
+ }
+ for unic in sortedhash(sequence[start]) do
+ local cu=coverage[unic]
+ if not cu then
+ coverage[unic]=rulehash
+ end
+ end
+ sequence.n=nofsequences
+ end
+ end
+ rulehash.n=rulesize
+ end
+ return coverage
+ end
+ local dataset=specifications.dataset
+ local function report(name,category,position,first,last,sequences)
+ report_otf("injecting name %a of category %a at position %i in [%i,%i] of [%i,%i]",
+ name,category,position,first,last,1,#sequences)
+ end
+ local function inject(specification,sequences,sequence,first,last,category,name)
+ local position=specification.position or false
+ if not position then
+ position=specification.prepend
+ if position==true then
+ if trace_loading then
+ report(name,category,first,first,last,sequences)
+ end
+ insert(sequences,first,sequence)
+ return
+ end
+ end
+ if not position then
+ position=specification.append
+ if position==true then
+ if trace_loading then
+ report(name,category,last+1,first,last,sequences)
+ end
+ insert(sequences,last+1,sequence)
+ return
+ end
+ end
+ local kind=type(position)
+ if kind=="string" then
+ local index=false
+ for i=first,last do
+ local s=sequences[i]
+ local f=s.features
+ if f then
+ for k in sortedhash(f) do
+ if k==position then
+ index=i
+ break
+ end
+ end
+ if index then
+ break
+ end
+ end
+ end
+ if index then
+ position=index
+ else
+ position=last+1
+ end
+ elseif kind=="number" then
+ if position<0 then
+ position=last-position+1
+ end
+ if position>last then
+ position=last+1
+ elseif position<first then
+ position=first
+ end
+ else
+ position=last+1
+ end
+ if trace_loading then
+ report(name,category,position,first,last,sequences)
+ end
+ insert(sequences,position,sequence)
+ end
+ for s=1,#dataset do
+ local specification=dataset[s]
+ local valid=specification.valid
+ local feature=specification.name or feature
+ if not feature or feature=="" then
+ report_otf("no valid name given for extra feature")
+ elseif not valid or valid(data,specification,feature) then
+ local initialize=specification.initialize
+ if initialize then
+ specification.initialize=initialize(specification,data) and initialize or nil
+ end
+ local askedfeatures=specification.features or everywhere
+ local askedsteps=specification.steps or specification.subtables or { specification.data } or {}
+ local featuretype=normalized[specification.type or "substitution"] or "substitution"
+ local featureflags=specification.flags or noflags
+ local nocheck=specification.nocheck
+ local featureorder=specification.order or { feature }
+ local featurechain=(featuretype=="chainsubstitution" or featuretype=="chainposition") and 1 or 0
+ local nofsteps=0
+ local steps={}
+ local sublookups=specification.lookups
+ local category=nil
+ checkflags(specification,resources)
+ if sublookups then
+ local s={}
+ for i=1,#sublookups do
+ local specification=sublookups[i]
+ local askedsteps=specification.steps or specification.subtables or { specification.data } or {}
+ local featuretype=normalized[specification.type or "substitution"] or "substitution"
+ local featureflags=specification.flags or noflags
+ local nofsteps=0
+ local steps={}
+ for i=1,#askedsteps do
+ local list=askedsteps[i]
+ local coverage=nil
+ local format=nil
+ if featuretype=="substitution" then
+ coverage=prepare_substitution(list,featuretype,nocheck)
+ elseif featuretype=="ligature" then
+ coverage=prepare_ligature(list,featuretype,nocheck)
+ elseif featuretype=="alternate" then
+ coverage=prepare_alternate(list,featuretype,nocheck)
+ elseif featuretype=="multiple" then
+ coverage=prepare_multiple(list,featuretype,nocheck)
+ elseif featuretype=="kern" or featuretype=="move" then
+ format=featuretype
+ coverage=prepare_kern(list,featuretype)
+ elseif featuretype=="pair" then
+ format="pair"
+ coverage=prepare_pair(list,featuretype)
+ elseif featuretype=="single" then
+ format="single"
+ coverage=prepare_single(list,featuretype)
+ end
+ if coverage and next(coverage) then
+ nofsteps=nofsteps+1
+ steps[nofsteps]=register(coverage,featuretype,format,feature,nofsteps,descriptions,resources)
+ end
+ end
+ checkmerge(specification)
+ checksteps(specification)
+ s[i]={
+ [stepkey]=steps,
+ nofsteps=nofsteps,
+ flags=featureflags,
+ type=types[featuretype],
+ }
+ end
+ sublookups=s
+ end
+ for i=1,#askedsteps do
+ local list=askedsteps[i]
+ local coverage=nil
+ local format=nil
+ if featuretype=="substitution" then
+ category="gsub"
+ coverage=prepare_substitution(list,featuretype,nocheck)
+ elseif featuretype=="ligature" then
+ category="gsub"
+ coverage=prepare_ligature(list,featuretype,nocheck)
+ elseif featuretype=="alternate" then
+ category="gsub"
+ coverage=prepare_alternate(list,featuretype,nocheck)
+ elseif featuretype=="multiple" then
+ category="gsub"
+ coverage=prepare_multiple(list,featuretype,nocheck)
+ elseif featuretype=="kern" or featuretype=="move" then
+ category="gpos"
+ format=featuretype
+ coverage=prepare_kern(list,featuretype)
+ elseif featuretype=="pair" then
+ category="gpos"
+ format="pair"
+ coverage=prepare_pair(list,featuretype)
+ elseif featuretype=="single" then
+ category="gpos"
+ format="single"
+ coverage=prepare_single(list,featuretype)
+ elseif featuretype=="chainsubstitution" then
+ category="gsub"
+ coverage=prepare_chain(list,featuretype,sublookups)
+ elseif featuretype=="chainposition" then
+ category="gpos"
+ coverage=prepare_chain(list,featuretype,sublookups)
+ else
+ report_otf("not registering feature %a, unknown category",feature)
+ return
+ end
+ if coverage and next(coverage) then
+ nofsteps=nofsteps+1
+ steps[nofsteps]=register(coverage,featuretype,format,feature,nofsteps,descriptions,resources)
+ end
+ end
+ if nofsteps>0 then
+ for k,v in next,askedfeatures do
+ if v[1] then
+ askedfeatures[k]=tohash(v)
+ end
+ end
+ if featureflags[1] then featureflags[1]="mark" end
+ if featureflags[2] then featureflags[2]="ligature" end
+ if featureflags[3] then featureflags[3]="base" end
+ local steptype=types[featuretype]
+ local sequence={
+ chain=featurechain,
+ features={ [feature]=askedfeatures },
+ flags=featureflags,
+ name=feature,
+ order=featureorder,
+ [stepkey]=steps,
+ nofsteps=nofsteps,
+ type=steptype,
+ }
+ checkflags(sequence,resources)
+ checkmerge(sequence)
+ checksteps(sequence)
+ local first,last=getrange(sequences,category)
+ inject(specification,sequences,sequence,first,last,category,feature)
+ local features=fontfeatures[category]
+ if not features then
+ features={}
+ fontfeatures[category]=features
+ end
+ local k=features[feature]
+ if not k then
+ k={}
+ features[feature]=k
+ end
+ for script,languages in next,askedfeatures do
+ local kk=k[script]
+ if not kk then
+ kk={}
+ k[script]=kk
+ end
+ for language,value in next,languages do
+ kk[language]=value
+ end
+ end
+ end
+ end
+ end
+ if trace_loading then
+ report_otf("registering feature %a, affected glyphs %a, skipped glyphs %a",feature,done,skip)
+ end
+end
+otf.enhancers.addfeature=addfeature
+local extrafeatures={}
+local knownfeatures={}
+function otf.addfeature(name,specification)
+ if type(name)=="table" then
+ specification=name
+ end
+ if type(specification)~="table" then
+ report_otf("invalid feature specification, no valid table")
+ return
+ end
+ specification,name=validspecification(specification,name)
+ if name and specification then
+ local slot=knownfeatures[name]
+ if not slot then
+ slot=#extrafeatures+1
+ knownfeatures[name]=slot
+ elseif specification.overload==false then
+ slot=#extrafeatures+1
+ knownfeatures[name]=slot
+ else
+ end
+ specification.name=name
+ extrafeatures[slot]=specification
+ end
+end
+local function enhance(data,filename,raw)
+ for slot=1,#extrafeatures do
+ local specification=extrafeatures[slot]
+ addfeature(data,specification.name,specification)
+ end
+end
+otf.enhancers.enhance=enhance
+otf.enhancers.register("check extra features",enhance)
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
if not modules then modules={} end modules ['font-osd']={
version=1.001,
comment="companion to font-ini.mkiv",
@@ -32417,9 +33327,6 @@ if not modules then modules={} end modules ['font-ocl']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-if CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 then
- return
-end
local tostring,tonumber,next=tostring,tonumber,next
local round,max=math.round,math.round
local gsub,find=string.gsub,string.find
@@ -32487,7 +33394,7 @@ local function convert(t,k)
t[k]=v
return v
end
-local start={ "pdf","mode","font" }
+local mode={ "pdf","mode","font" }
local push={ "pdf","page","q" }
local pop={ "pdf","page","Q" }
local function initializeoverlay(tfmdata,kind,value)
@@ -32532,7 +33439,7 @@ local function initializeoverlay(tfmdata,kind,value)
local s=#colorlist
local goback=w~=0 and leftcommand[w] or nil
local t={
- start,
+ mode,
not u and actualb or { "pdf","page",(getactualtext(tounicode(u))) },
push,
}
@@ -32656,20 +33563,15 @@ do
local loaddata=io.loaddata
local savedata=io.savedata
local remove=os.remove
- if context and xml.convert then
- local xmlconvert=xml.convert
- local xmlfirst=xml.first
- function otfsvg.filterglyph(entry,index)
- local svg=xmlconvert(entry.data)
- local root=svg and xmlfirst(svg,"/svg[@id='glyph"..index.."']")
- local data=root and tostring(root)
- return data
- end
- else
+if context then
+
+--removed
+
+else
function otfsvg.filterglyph(entry,index)
return entry.data
end
- end
+end
local runner=sandbox and sandbox.registerrunner {
name="otfsvg",
program="inkscape",
@@ -32682,6 +33584,14 @@ do
return io.popen("inkscape --export-area-drawing --shell > temp-otf-svg-shape.log","w")
end
end
+ local new=nil
+ local function inkscapeformat(suffix)
+ if new==nil then
+ new=os.resultof("inkscape --version") or ""
+ new=new=="" or not find(new,"Inkscape%s*0")
+ end
+ return new and "filename" or suffix
+ end
function otfsvg.topdf(svgshapes,tfmdata)
local pdfshapes={}
local inkscape=runner()
@@ -32690,7 +33600,7 @@ do
local nofshapes=#svgshapes
local f_svgfile=formatters["temp-otf-svg-shape-%i.svg"]
local f_pdffile=formatters["temp-otf-svg-shape-%i.pdf"]
- local f_convert=formatters["%s --export-pdf=%s\n"]
+ local f_convert=formatters["%s --export-%s=%s\n"]
local filterglyph=otfsvg.filterglyph
local nofdone=0
local processed={}
@@ -32704,7 +33614,7 @@ do
local svgfile=f_svgfile(index)
local pdffile=f_pdffile(index)
savedata(svgfile,data)
- inkscape:write(f_convert(svgfile,pdffile))
+ inkscape:write(f_convert(svgfile,inkscapeformat("pdf"),pdffile))
processed[index]=true
nofdone=nofdone+1
if nofdone%25==0 then
@@ -32893,767 +33803,9 @@ end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules={} end modules ['font-otc']={
- version=1.001,
- comment="companion to font-ini.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
-}
-local insert,sortedkeys,sortedhash,tohash=table.insert,table.sortedkeys,table.sortedhash,table.tohash
-local type,next,tonumber=type,next,tonumber
-local lpegmatch=lpeg.match
-local utfbyte,utflen=utf.byte,utf.len
-local sortedhash=table.sortedhash
-local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end)
-local report_otf=logs.reporter("fonts","otf loading")
-local fonts=fonts
-local otf=fonts.handlers.otf
-local registerotffeature=otf.features.register
-local setmetatableindex=table.setmetatableindex
-local fonthelpers=fonts.helpers
-local checkmerge=fonthelpers.checkmerge
-local checkflags=fonthelpers.checkflags
-local checksteps=fonthelpers.checksteps
-local normalized={
- substitution="substitution",
- single="substitution",
- ligature="ligature",
- alternate="alternate",
- multiple="multiple",
- kern="kern",
- pair="pair",
- single="single",
- chainsubstitution="chainsubstitution",
- chainposition="chainposition",
-}
-local types={
- substitution="gsub_single",
- ligature="gsub_ligature",
- alternate="gsub_alternate",
- multiple="gsub_multiple",
- kern="gpos_pair",
- pair="gpos_pair",
- single="gpos_single",
- chainsubstitution="gsub_contextchain",
- chainposition="gpos_contextchain",
-}
-local names={
- gsub_single="gsub",
- gsub_multiple="gsub",
- gsub_alternate="gsub",
- gsub_ligature="gsub",
- gsub_context="gsub",
- gsub_contextchain="gsub",
- gsub_reversecontextchain="gsub",
- gpos_single="gpos",
- gpos_pair="gpos",
- gpos_cursive="gpos",
- gpos_mark2base="gpos",
- gpos_mark2ligature="gpos",
- gpos_mark2mark="gpos",
- gpos_context="gpos",
- gpos_contextchain="gpos",
-}
-setmetatableindex(types,function(t,k) t[k]=k return k end)
-local everywhere={ ["*"]={ ["*"]=true } }
-local noflags={ false,false,false,false }
-local function getrange(sequences,category)
- local count=#sequences
- local first=nil
- local last=nil
- for i=1,count do
- local t=sequences[i].type
- if t and names[t]==category then
- if not first then
- first=i
- end
- last=i
- end
- end
- return first or 1,last or count
-end
-local function validspecification(specification,name)
- local dataset=specification.dataset
- if dataset then
- elseif specification[1] then
- dataset=specification
- specification={ dataset=dataset }
- else
- dataset={ { data=specification.data } }
- specification.data=nil
- specification.dataset=dataset
- end
- local first=dataset[1]
- if first then
- first=first.data
- end
- if not first then
- report_otf("invalid feature specification, no dataset")
- return
- end
- if type(name)~="string" then
- name=specification.name or first.name
- end
- if type(name)~="string" then
- report_otf("invalid feature specification, no name")
- return
- end
- local n=#dataset
- if n>0 then
- for i=1,n do
- setmetatableindex(dataset[i],specification)
- end
- return specification,name
- end
-end
-local function addfeature(data,feature,specifications)
- if not specifications then
- report_otf("missing specification")
- return
- end
- local descriptions=data.descriptions
- local resources=data.resources
- local features=resources.features
- local sequences=resources.sequences
- if not features or not sequences then
- report_otf("missing specification")
- return
- end
- local alreadydone=resources.alreadydone
- if not alreadydone then
- alreadydone={}
- resources.alreadydone=alreadydone
- end
- if alreadydone[specifications] then
- return
- else
- alreadydone[specifications]=true
- end
- local fontfeatures=resources.features or everywhere
- local unicodes=resources.unicodes
- local splitter=lpeg.splitter(" ",unicodes)
- local done=0
- local skip=0
- local aglunicodes=false
- local privateslot=fonthelpers.privateslot
- local specifications=validspecification(specifications,feature)
- if not specifications then
- return
- end
- local p=lpeg.P("P")*(lpeg.patterns.hexdigit^1/function(s) return tonumber(s,16) end)*lpeg.P(-1)
- local function tounicode(code)
- if not code then
- return
- end
- if type(code)=="number" then
- return code
- end
- local u=unicodes[code]
- if u then
- return u
- end
- if utflen(code)==1 then
- u=utfbyte(code)
- if u then
- return u
- end
- end
- if privateslot then
- u=privateslot(code)
- if u then
- return u
- end
- end
- local u=lpegmatch(p,code)
- if u then
- return u
- end
- if not aglunicodes then
- aglunicodes=fonts.encodings.agl.unicodes
- end
- local u=aglunicodes[code]
- if u then
- return u
- end
- end
- local coverup=otf.coverup
- local coveractions=coverup.actions
- local stepkey=coverup.stepkey
- local register=coverup.register
- local function prepare_substitution(list,featuretype,nocheck)
- local coverage={}
- local cover=coveractions[featuretype]
- for code,replacement in next,list do
- local unicode=tounicode(code)
- local description=descriptions[unicode]
- if not nocheck and not description then
- skip=skip+1
- else
- if type(replacement)=="table" then
- replacement=replacement[1]
- end
- replacement=tounicode(replacement)
- if replacement and (nocheck or descriptions[replacement]) then
- cover(coverage,unicode,replacement)
- done=done+1
- else
- skip=skip+1
- end
- end
- end
- return coverage
- end
- local function prepare_alternate(list,featuretype,nocheck)
- local coverage={}
- local cover=coveractions[featuretype]
- for code,replacement in next,list do
- local unicode=tounicode(code)
- local description=descriptions[unicode]
- if not nocheck and not description then
- skip=skip+1
- elseif type(replacement)=="table" then
- local r={}
- for i=1,#replacement do
- local u=tounicode(replacement[i])
- r[i]=(nocheck or descriptions[u]) and u or unicode
- end
- cover(coverage,unicode,r)
- done=done+1
- else
- local u=tounicode(replacement)
- if u then
- cover(coverage,unicode,{ u })
- done=done+1
- else
- skip=skip+1
- end
- end
- end
- return coverage
- end
- local function prepare_multiple(list,featuretype,nocheck)
- local coverage={}
- local cover=coveractions[featuretype]
- for code,replacement in next,list do
- local unicode=tounicode(code)
- local description=descriptions[unicode]
- if not nocheck and not description then
- skip=skip+1
- elseif type(replacement)=="table" then
- local r={}
- local n=0
- for i=1,#replacement do
- local u=tounicode(replacement[i])
- if nocheck or descriptions[u] then
- n=n+1
- r[n]=u
- end
- end
- if n>0 then
- cover(coverage,unicode,r)
- done=done+1
- else
- skip=skip+1
- end
- else
- local u=tounicode(replacement)
- if u then
- cover(coverage,unicode,{ u })
- done=done+1
- else
- skip=skip+1
- end
- end
- end
- return coverage
- end
- local function prepare_ligature(list,featuretype,nocheck)
- local coverage={}
- local cover=coveractions[featuretype]
- for code,ligature in next,list do
- local unicode=tounicode(code)
- local description=descriptions[unicode]
- if not nocheck and not description then
- skip=skip+1
- else
- if type(ligature)=="string" then
- ligature={ lpegmatch(splitter,ligature) }
- end
- local present=true
- for i=1,#ligature do
- local l=ligature[i]
- local u=tounicode(l)
- if nocheck or descriptions[u] then
- ligature[i]=u
- else
- present=false
- break
- end
- end
- if present then
- cover(coverage,unicode,ligature)
- done=done+1
- else
- skip=skip+1
- end
- end
- end
- return coverage
- end
- local function resetspacekerns()
- data.properties.hasspacekerns=true
- data.resources .spacekerns=nil
- end
- local function prepare_kern(list,featuretype)
- local coverage={}
- local cover=coveractions[featuretype]
- local isspace=false
- for code,replacement in next,list do
- local unicode=tounicode(code)
- local description=descriptions[unicode]
- if description and type(replacement)=="table" then
- local r={}
- for k,v in next,replacement do
- local u=tounicode(k)
- if u then
- r[u]=v
- if u==32 then
- isspace=true
- end
- end
- end
- if next(r) then
- cover(coverage,unicode,r)
- done=done+1
- if unicode==32 then
- isspace=true
- end
- else
- skip=skip+1
- end
- else
- skip=skip+1
- end
- end
- if isspace then
- resetspacekerns()
- end
- return coverage
- end
- local function prepare_pair(list,featuretype)
- local coverage={}
- local cover=coveractions[featuretype]
- if cover then
- for code,replacement in next,list do
- local unicode=tounicode(code)
- local description=descriptions[unicode]
- if description and type(replacement)=="table" then
- local r={}
- for k,v in next,replacement do
- local u=tounicode(k)
- if u then
- r[u]=v
- if u==32 then
- isspace=true
- end
- end
- end
- if next(r) then
- cover(coverage,unicode,r)
- done=done+1
- if unicode==32 then
- isspace=true
- end
- else
- skip=skip+1
- end
- else
- skip=skip+1
- end
- end
- if isspace then
- resetspacekerns()
- end
- else
- report_otf("unknown cover type %a",featuretype)
- end
- return coverage
- end
- local prepare_single=prepare_pair
- local function prepare_chain(list,featuretype,sublookups)
- local rules=list.rules
- local coverage={}
- if rules then
- local rulehash={}
- local rulesize=0
- local lookuptype=types[featuretype]
- for nofrules=1,#rules do
- local rule=rules[nofrules]
- local current=rule.current
- local before=rule.before
- local after=rule.after
- local replacements=rule.replacements or false
- local sequence={}
- local nofsequences=0
- if before then
- for n=1,#before do
- nofsequences=nofsequences+1
- sequence[nofsequences]=before[n]
- end
- end
- local start=nofsequences+1
- for n=1,#current do
- nofsequences=nofsequences+1
- sequence[nofsequences]=current[n]
- end
- local stop=nofsequences
- if after then
- for n=1,#after do
- nofsequences=nofsequences+1
- sequence[nofsequences]=after[n]
- end
- end
- local lookups=rule.lookups or false
- local subtype=nil
- if lookups and sublookups then
- for k,v in sortedhash(lookups) do
- local t=type(v)
- if t=="table" then
- for i=1,#v do
- local vi=v[i]
- if type(vi)~="table" then
- v[i]={ vi }
- end
- end
- elseif t=="number" then
- local lookup=sublookups[v]
- if lookup then
- lookups[k]={ lookup }
- if not subtype then
- subtype=lookup.type
- end
- elseif v==0 then
- lookups[k]={ { type="gsub_remove" } }
- else
- lookups[k]=false
- end
- else
- lookups[k]=false
- end
- end
- end
- if nofsequences>0 then
- local hashed={}
- for i=1,nofsequences do
- local t={}
- local s=sequence[i]
- for i=1,#s do
- local u=tounicode(s[i])
- if u then
- t[u]=true
- end
- end
- hashed[i]=t
- end
- sequence=hashed
- rulesize=rulesize+1
- rulehash[rulesize]={
- nofrules,
- lookuptype,
- sequence,
- start,
- stop,
- lookups,
- replacements,
- subtype,
- }
- for unic in sortedhash(sequence[start]) do
- local cu=coverage[unic]
- if not cu then
- coverage[unic]=rulehash
- end
- end
- sequence.n=nofsequences
- end
- end
- rulehash.n=rulesize
- end
- return coverage
- end
- local dataset=specifications.dataset
- local function report(name,category,position,first,last,sequences)
- report_otf("injecting name %a of category %a at position %i in [%i,%i] of [%i,%i]",
- name,category,position,first,last,1,#sequences)
- end
- local function inject(specification,sequences,sequence,first,last,category,name)
- local position=specification.position or false
- if not position then
- position=specification.prepend
- if position==true then
- if trace_loading then
- report(name,category,first,first,last,sequences)
- end
- insert(sequences,first,sequence)
- return
- end
- end
- if not position then
- position=specification.append
- if position==true then
- if trace_loading then
- report(name,category,last+1,first,last,sequences)
- end
- insert(sequences,last+1,sequence)
- return
- end
- end
- local kind=type(position)
- if kind=="string" then
- local index=false
- for i=first,last do
- local s=sequences[i]
- local f=s.features
- if f then
- for k in sortedhash(f) do
- if k==position then
- index=i
- break
- end
- end
- if index then
- break
- end
- end
- end
- if index then
- position=index
- else
- position=last+1
- end
- elseif kind=="number" then
- if position<0 then
- position=last-position+1
- end
- if position>last then
- position=last+1
- elseif position<first then
- position=first
- end
- else
- position=last+1
- end
- if trace_loading then
- report(name,category,position,first,last,sequences)
- end
- insert(sequences,position,sequence)
- end
- for s=1,#dataset do
- local specification=dataset[s]
- local valid=specification.valid
- local feature=specification.name or feature
- if not feature or feature=="" then
- report_otf("no valid name given for extra feature")
- elseif not valid or valid(data,specification,feature) then
- local initialize=specification.initialize
- if initialize then
- specification.initialize=initialize(specification,data) and initialize or nil
- end
- local askedfeatures=specification.features or everywhere
- local askedsteps=specification.steps or specification.subtables or { specification.data } or {}
- local featuretype=normalized[specification.type or "substitution"] or "substitution"
- local featureflags=specification.flags or noflags
- local nocheck=specification.nocheck
- local featureorder=specification.order or { feature }
- local featurechain=(featuretype=="chainsubstitution" or featuretype=="chainposition") and 1 or 0
- local nofsteps=0
- local steps={}
- local sublookups=specification.lookups
- local category=nil
- checkflags(specification,resources)
- if sublookups then
- local s={}
- for i=1,#sublookups do
- local specification=sublookups[i]
- local askedsteps=specification.steps or specification.subtables or { specification.data } or {}
- local featuretype=normalized[specification.type or "substitution"] or "substitution"
- local featureflags=specification.flags or noflags
- local nofsteps=0
- local steps={}
- for i=1,#askedsteps do
- local list=askedsteps[i]
- local coverage=nil
- local format=nil
- if featuretype=="substitution" then
- coverage=prepare_substitution(list,featuretype,nocheck)
- elseif featuretype=="ligature" then
- coverage=prepare_ligature(list,featuretype,nocheck)
- elseif featuretype=="alternate" then
- coverage=prepare_alternate(list,featuretype,nocheck)
- elseif featuretype=="multiple" then
- coverage=prepare_multiple(list,featuretype,nocheck)
- elseif featuretype=="kern" or featuretype=="move" then
- format=featuretype
- coverage=prepare_kern(list,featuretype)
- elseif featuretype=="pair" then
- format="pair"
- coverage=prepare_pair(list,featuretype)
- elseif featuretype=="single" then
- format="single"
- coverage=prepare_single(list,featuretype)
- end
- if coverage and next(coverage) then
- nofsteps=nofsteps+1
- steps[nofsteps]=register(coverage,featuretype,format,feature,nofsteps,descriptions,resources)
- end
- end
- checkmerge(specification)
- checksteps(specification)
- s[i]={
- [stepkey]=steps,
- nofsteps=nofsteps,
- flags=featureflags,
- type=types[featuretype],
- }
- end
- sublookups=s
- end
- for i=1,#askedsteps do
- local list=askedsteps[i]
- local coverage=nil
- local format=nil
- if featuretype=="substitution" then
- category="gsub"
- coverage=prepare_substitution(list,featuretype,nocheck)
- elseif featuretype=="ligature" then
- category="gsub"
- coverage=prepare_ligature(list,featuretype,nocheck)
- elseif featuretype=="alternate" then
- category="gsub"
- coverage=prepare_alternate(list,featuretype,nocheck)
- elseif featuretype=="multiple" then
- category="gsub"
- coverage=prepare_multiple(list,featuretype,nocheck)
- elseif featuretype=="kern" or featuretype=="move" then
- category="gpos"
- format=featuretype
- coverage=prepare_kern(list,featuretype)
- elseif featuretype=="pair" then
- category="gpos"
- format="pair"
- coverage=prepare_pair(list,featuretype)
- elseif featuretype=="single" then
- category="gpos"
- format="single"
- coverage=prepare_single(list,featuretype)
- elseif featuretype=="chainsubstitution" then
- category="gsub"
- coverage=prepare_chain(list,featuretype,sublookups)
- elseif featuretype=="chainposition" then
- category="gpos"
- coverage=prepare_chain(list,featuretype,sublookups)
- else
- report_otf("not registering feature %a, unknown category",feature)
- return
- end
- if coverage and next(coverage) then
- nofsteps=nofsteps+1
- steps[nofsteps]=register(coverage,featuretype,format,feature,nofsteps,descriptions,resources)
- end
- end
- if nofsteps>0 then
- for k,v in next,askedfeatures do
- if v[1] then
- askedfeatures[k]=tohash(v)
- end
- end
- if featureflags[1] then featureflags[1]="mark" end
- if featureflags[2] then featureflags[2]="ligature" end
- if featureflags[3] then featureflags[3]="base" end
- local steptype=types[featuretype]
- local sequence={
- chain=featurechain,
- features={ [feature]=askedfeatures },
- flags=featureflags,
- name=feature,
- order=featureorder,
- [stepkey]=steps,
- nofsteps=nofsteps,
- type=steptype,
- }
- checkflags(sequence,resources)
- checkmerge(sequence)
- checksteps(sequence)
- local first,last=getrange(sequences,category)
- inject(specification,sequences,sequence,first,last,category,feature)
- local features=fontfeatures[category]
- if not features then
- features={}
- fontfeatures[category]=features
- end
- local k=features[feature]
- if not k then
- k={}
- features[feature]=k
- end
- for script,languages in next,askedfeatures do
- local kk=k[script]
- if not kk then
- kk={}
- k[script]=kk
- end
- for language,value in next,languages do
- kk[language]=value
- end
- end
- end
- end
- end
- if trace_loading then
- report_otf("registering feature %a, affected glyphs %a, skipped glyphs %a",feature,done,skip)
- end
-end
-otf.enhancers.addfeature=addfeature
-local extrafeatures={}
-local knownfeatures={}
-function otf.addfeature(name,specification)
- if type(name)=="table" then
- specification=name
- end
- if type(specification)~="table" then
- report_otf("invalid feature specification, no valid table")
- return
- end
- specification,name=validspecification(specification,name)
- if name and specification then
- local slot=knownfeatures[name]
- if not slot then
- slot=#extrafeatures+1
- knownfeatures[name]=slot
- elseif specification.overload==false then
- slot=#extrafeatures+1
- knownfeatures[name]=slot
- else
- end
- specification.name=name
- extrafeatures[slot]=specification
- end
-end
-local function enhance(data,filename,raw)
- for slot=1,#extrafeatures do
- local specification=extrafeatures[slot]
- addfeature(data,specification.name,specification)
- end
-end
-otf.enhancers.enhance=enhance
-otf.enhancers.register("check extra features",enhance)
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
if not modules then modules={} end modules ['font-onr']={
version=1.001,
+ optimize=true,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -34028,6 +34180,7 @@ do -- begin closure to overcome local limits and interference
if not modules then modules={} end modules ['font-one']={
version=1.001,
+ optimize=true,
comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
@@ -35792,8 +35945,9 @@ function definers.read(specification,size,id)
report_defining("already hashed: %s",hash)
end
else
- tfmdata=definers.loadfont(specification)
+ tfmdata=definers.loadfont(specification)
if tfmdata then
+ tfmdata.original=specification.specification
if trace_defining then
report_defining("loaded and hashed: %s",hash)
end
@@ -35830,6 +35984,373 @@ end -- closure
do -- begin closure to overcome local limits and interference
+if not modules then modules={} end modules ['font-shp']={
+ version=1.001,
+ comment="companion to font-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local tonumber,next=tonumber,next
+local concat=table.concat
+local formatters=string.formatters
+local otf=fonts.handlers.otf
+local afm=fonts.handlers.afm
+local pfb=fonts.handlers.pfb
+local hashes=fonts.hashes
+local identifiers=hashes.identifiers
+local version=0.009
+local shapescache=containers.define("fonts","shapes",version,true)
+local streamscache=containers.define("fonts","streams",version,true)
+local compact_streams=false
+directives.register("fonts.streams.compact",function(v) compact_streams=v end)
+local function packoutlines(data,makesequence)
+ local subfonts=data.subfonts
+ if subfonts then
+ for i=1,#subfonts do
+ packoutlines(subfonts[i],makesequence)
+ end
+ return
+ end
+ local common=data.segments
+ if common then
+ return
+ end
+ local glyphs=data.glyphs
+ if not glyphs then
+ return
+ end
+ if makesequence then
+ for index=0,#glyphs do
+ local glyph=glyphs[index]
+ if glyph then
+ local segments=glyph.segments
+ if segments then
+ local sequence={}
+ local nofsequence=0
+ for i=1,#segments do
+ local segment=segments[i]
+ local nofsegment=#segment
+ nofsequence=nofsequence+1
+ sequence[nofsequence]=segment[nofsegment]
+ for i=1,nofsegment-1 do
+ nofsequence=nofsequence+1
+ sequence[nofsequence]=segment[i]
+ end
+ end
+ glyph.sequence=sequence
+ glyph.segments=nil
+ end
+ end
+ end
+ else
+ local hash={}
+ local common={}
+ local reverse={}
+ local last=0
+ for index=0,#glyphs do
+ local glyph=glyphs[index]
+ if glyph then
+ local segments=glyph.segments
+ if segments then
+ for i=1,#segments do
+ local h=concat(segments[i]," ")
+ hash[h]=(hash[h] or 0)+1
+ end
+ end
+ end
+ end
+ for index=0,#glyphs do
+ local glyph=glyphs[index]
+ if glyph then
+ local segments=glyph.segments
+ if segments then
+ for i=1,#segments do
+ local segment=segments[i]
+ local h=concat(segment," ")
+ if hash[h]>1 then
+ local idx=reverse[h]
+ if not idx then
+ last=last+1
+ reverse[h]=last
+ common[last]=segment
+ idx=last
+ end
+ segments[i]=idx
+ end
+ end
+ end
+ end
+ end
+ if last>0 then
+ data.segments=common
+ end
+ end
+end
+local function unpackoutlines(data)
+ local subfonts=data.subfonts
+ if subfonts then
+ for i=1,#subfonts do
+ unpackoutlines(subfonts[i])
+ end
+ return
+ end
+ local common=data.segments
+ if not common then
+ return
+ end
+ local glyphs=data.glyphs
+ if not glyphs then
+ return
+ end
+ for index=0,#glyphs do
+ local glyph=glyphs[index]
+ if glyph then
+ local segments=glyph.segments
+ if segments then
+ for i=1,#segments do
+ local c=common[segments[i]]
+ if c then
+ segments[i]=c
+ end
+ end
+ end
+ end
+ end
+ data.segments=nil
+end
+local readers=otf.readers
+local cleanname=otf.readers.helpers.cleanname
+local function makehash(filename,sub,instance)
+ local name=cleanname(file.basename(filename))
+ if instance then
+ return formatters["%s-%s-%s"](name,sub or 0,cleanname(instance))
+ else
+ return formatters["%s-%s"] (name,sub or 0)
+ end
+end
+local function loadoutlines(cache,filename,sub,instance)
+ local base=file.basename(filename)
+ local name=file.removesuffix(base)
+ local kind=file.suffix(filename)
+ local attr=lfs.attributes(filename)
+ local size=attr and attr.size or 0
+ local time=attr and attr.modification or 0
+ local sub=tonumber(sub)
+ if size>0 and (kind=="otf" or kind=="ttf" or kind=="tcc") then
+ local hash=makehash(filename,sub,instance)
+ data=containers.read(cache,hash)
+ if not data or data.time~=time or data.size~=size then
+ data=otf.readers.loadshapes(filename,sub,instance)
+ if data then
+ data.size=size
+ data.format=data.format or (kind=="otf" and "opentype") or "truetype"
+ data.time=time
+ packoutlines(data)
+ containers.write(cache,hash,data)
+ data=containers.read(cache,hash)
+ end
+ end
+ unpackoutlines(data)
+ elseif size>0 and (kind=="pfb") then
+ local hash=containers.cleanname(base)
+ data=containers.read(cache,hash)
+ if not data or data.time~=time or data.size~=size then
+ data=afm.readers.loadshapes(filename)
+ if data then
+ data.size=size
+ data.format="type1"
+ data.time=time
+ packoutlines(data)
+ containers.write(cache,hash,data)
+ data=containers.read(cache,hash)
+ end
+ end
+ unpackoutlines(data)
+ else
+ data={
+ filename=filename,
+ size=0,
+ time=time,
+ format="unknown",
+ units=1000,
+ glyphs={}
+ }
+ end
+ return data
+end
+local function cachethem(cache,hash,data)
+ containers.write(cache,hash,data,compact_streams)
+ return containers.read(cache,hash)
+end
+local function loadstreams(cache,filename,sub,instance)
+ local base=file.basename(filename)
+ local name=file.removesuffix(base)
+ local kind=file.suffix(filename)
+ local attr=lfs.attributes(filename)
+ local size=attr and attr.size or 0
+ local time=attr and attr.modification or 0
+ local sub=tonumber(sub)
+ if size>0 and (kind=="otf" or kind=="ttf" or kind=="ttc") then
+ local hash=makehash(filename,sub,instance)
+ data=containers.read(cache,hash)
+ if not data or data.time~=time or data.size~=size then
+ data=otf.readers.loadshapes(filename,sub,instance,true)
+ if data then
+ local glyphs=data.glyphs
+ local streams={}
+ if glyphs then
+ for i=0,#glyphs do
+ local glyph=glyphs[i]
+ if glyph then
+ streams[i]=glyph.stream or ""
+ else
+ streams[i]=""
+ end
+ end
+ end
+ data.streams=streams
+ data.glyphs=nil
+ data.size=size
+ data.format=data.format or (kind=="otf" and "opentype") or "truetype"
+ data.time=time
+ data=cachethem(cache,hash,data)
+ end
+ end
+ elseif size>0 and (kind=="pfb") then
+ local hash=makehash(filename,sub,instance)
+ data=containers.read(cache,hash)
+ if not data or data.time~=time or data.size~=size then
+ local names,encoding,streams,metadata=pfb.loadvector(filename,false,true)
+ if streams then
+ local fontbbox=metadata.fontbbox or { 0,0,0,0 }
+ for i=0,#streams do
+ streams[i]=streams[i].stream or "\14"
+ end
+ data={
+ filename=filename,
+ size=size,
+ time=time,
+ format="type1",
+ streams=streams,
+ fontheader={
+ fontversion=metadata.version,
+ units=1000,
+ xmin=fontbbox[1],
+ ymin=fontbbox[2],
+ xmax=fontbbox[3],
+ ymax=fontbbox[4],
+ },
+ horizontalheader={
+ ascender=0,
+ descender=0,
+ },
+ maximumprofile={
+ nofglyphs=#streams+1,
+ },
+ names={
+ copyright=metadata.copyright,
+ family=metadata.familyname,
+ fullname=metadata.fullname,
+ fontname=metadata.fontname,
+ subfamily=metadata.subfamilyname,
+ trademark=metadata.trademark,
+ notice=metadata.notice,
+ version=metadata.version,
+ },
+ cffinfo={
+ familyname=metadata.familyname,
+ fullname=metadata.fullname,
+ italicangle=metadata.italicangle,
+ monospaced=metadata.isfixedpitch and true or false,
+ underlineposition=metadata.underlineposition,
+ underlinethickness=metadata.underlinethickness,
+ weight=metadata.weight,
+ },
+ }
+ data=cachethem(cache,hash,data)
+ end
+ end
+ else
+ data={
+ filename=filename,
+ size=0,
+ time=time,
+ format="unknown",
+ streams={}
+ }
+ end
+ return data
+end
+local loadedshapes={}
+local loadedstreams={}
+local function loadoutlinedata(fontdata,streams)
+ local properties=fontdata.properties
+ local filename=properties.filename
+ local subindex=fontdata.subindex
+ local instance=properties.instance
+ local hash=makehash(filename,subindex,instance)
+ local loaded=loadedshapes[hash]
+ if not loaded then
+ loaded=loadoutlines(shapescache,filename,subindex,instance)
+ loadedshapes[hash]=loaded
+ end
+ return loaded
+end
+hashes.shapes=table.setmetatableindex(function(t,k)
+ local f=identifiers[k]
+ if f then
+ return loadoutlinedata(f)
+ end
+end)
+local function getstreamhash(fontid)
+ local fontdata=identifiers[fontid]
+ if fontdata then
+ local properties=fontdata.properties
+ return makehash(properties.filename,properties.subfont,properties.instance)
+ end
+end
+local function loadstreamdata(fontdata)
+ local properties=fontdata.properties
+ local shared=fontdata.shared
+ local rawdata=shared and shared.rawdata
+ local metadata=rawdata and rawdata.metadata
+ local filename=properties.filename
+ local subindex=metadata and metadata.subfontindex
+ local instance=properties.instance
+ local hash=makehash(filename,subindex,instance)
+ local loaded=loadedstreams[hash]
+ if not loaded then
+ loaded=loadstreams(streamscache,filename,subindex,instance)
+ loadedstreams[hash]=loaded
+ end
+ return loaded
+end
+hashes.streams=table.setmetatableindex(function(t,k)
+ local f=identifiers[k]
+ if f then
+ return loadstreamdata(f)
+ end
+end)
+otf.loadoutlinedata=loadoutlinedata
+otf.loadstreamdata=loadstreamdata
+otf.loadshapes=loadshapes
+otf.getstreamhash=getstreamhash
+local streams=fonts.hashes.streams
+callback.register("glyph_stream_provider",function(id,index,mode)
+ if id>0 then
+ local streams=streams[id].streams
+ if streams then
+ return streams[index] or ""
+ end
+ end
+ return ""
+end)
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
if not modules then modules={} end modules ['luatex-fonts-def']={
version=1.001,
comment="companion to luatex-*.tex",
@@ -36376,41 +36897,6 @@ if context then
--removed
end
-if context then
- local letter=characters.is_letter
- local always=true
- local function collapseitalics(tfmdata,key,value)
- local threshold=value==true and 100 or tonumber(value)
- if threshold and threshold>0 then
- if threshold>100 then
- threshold=100
- end
- for unicode,data in next,tfmdata.characters do
- if always or letter[unicode] or letter[data.unicode] then
- local italic=data.italic
- if italic and italic~=0 then
- local width=data.width
- if width and width~=0 then
- local delta=threshold*italic/100
- data.width=width+delta
- data.italic=italic-delta
- end
- end
- end
- end
- end
- end
- local dimensions_specification={
- name="collapseitalics",
- description="collapse italics",
- manipulators={
- base=collapseitalics,
- node=collapseitalics,
- }
- }
- registerotffeature(dimensions_specification)
- registerafmfeature(dimensions_specification)
-end
end -- closure
@@ -36647,6 +37133,7 @@ local function setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze
end
end
end
+local shiftmode=CONTEXTLMTXMODE>0
local function manipulateeffect(tfmdata)
local effect=tfmdata.properties.effect
if effect then
@@ -36668,38 +37155,45 @@ local function manipulateeffect(tfmdata)
local factor=(1+effect.factor)*factor
local hfactor=(1+effect.hfactor)*hfactor
local vfactor=(1+effect.vfactor)*vfactor
- local vshift=vshift~=0 and upcommand[vshift] or false
+ if shiftmode then
+ parameters.hshift=hshift
+ parameters.vshift=vshift
+ else
+ vshift=vshift~=0 and upcommand[vshift] or false
+ hshift=rightcommand[hshift]
+ end
for unicode,character in next,characters do
local oldwidth=character.width
local oldheight=character.height
local olddepth=character.depth
if oldwidth and oldwidth>0 then
character.width=oldwidth+wdelta
- local commands=character.commands
- local hshift=rightcommand[hshift]
- if vshift then
- if commands then
- prependcommands (commands,
- hshift,
- vshift
- )
- else
- character.commands={
- hshift,
- vshift,
- charcommand[unicode]
- }
- end
- else
- if commands then
- prependcommands (commands,
- hshift
- )
+ if not shiftmode then
+ local commands=character.commands
+ if vshift then
+ if commands then
+ prependcommands (commands,
+ hshift,
+ vshift
+ )
+ else
+ character.commands={
+ hshift,
+ vshift,
+ charcommand[unicode]
+ }
+ end
else
- character.commands={
- hshift,
- charcommand[unicode]
- }
+ if commands then
+ prependcommands (commands,
+ hshift
+ )
+ else
+ character.commands={
+ hshift,
+ charcommand[unicode]
+ }
+ end
end
end
end
diff --git a/macros/luatex/generic/luaotfload/fontloader-util-fil.lua b/macros/luatex/generic/luaotfload/fontloader-util-fil.lua
index 79af277437..183f7bea81 100644
--- a/macros/luatex/generic/luaotfload/fontloader-util-fil.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-util-fil.lua
@@ -1,5 +1,6 @@
if not modules then modules = { } end modules ['util-fil'] = {
version = 1.001,
+ optimize = true,
comment = "companion to luat-lib.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
diff --git a/macros/luatex/generic/luaotfload/fontloader-util-str.lua b/macros/luatex/generic/luaotfload/fontloader-util-str.lua
index aba7859c31..2d3f4d669f 100644
--- a/macros/luatex/generic/luaotfload/fontloader-util-str.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-util-str.lua
@@ -1057,76 +1057,44 @@ local format_rest = function(s)
return format("%q",s) -- catches " and \n and such
end
--- local format_extension = function(extensions,f,name)
--- local extension = extensions[name] or "tostring(%s)"
--- local f = tonumber(f) or 1
--- local w = find(extension,"%.%.%.")
--- if f == 0 then
--- if w then
--- extension = gsub(extension,"%.%.%.","")
--- end
--- return extension
--- elseif f == 1 then
--- if w then
--- extension = gsub(extension,"%.%.%.","%%s")
--- end
--- n = n + 1
--- local a = "a" .. n
--- return format(extension,a,a) -- maybe more times?
--- elseif f < 0 then
--- local a = "a" .. (n + f + 1)
--- return format(extension,a,a)
--- else
--- if w then
--- extension = gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s")
--- end
--- -- we could fill an array and then n = n + 1 unpack(t,n,n+f) but as we
--- -- cache we don't save much and there are hardly any extensions anyway
--- local t = { }
--- for i=1,f do
--- n = n + 1
--- -- t[#t+1] = "a" .. n
--- t[i] = "a" .. n
--- end
--- return format(extension,unpack(t))
--- end
--- end
-
local format_extension = function(extensions,f,name)
local extension = extensions[name] or "tostring(%s)"
local f = tonumber(f) or 1
local w = find(extension,"%.%.%.")
- if w then
- -- we have a wildcard
- if f == 0 then
+ if f == 0 then
+ if w then
extension = gsub(extension,"%.%.%.","")
- return extension
- elseif f == 1 then
+ end
+ return extension
+ elseif f == 1 then
+ if w then
extension = gsub(extension,"%.%.%.","%%s")
- n = n + 1
- local a = "a" .. n
- return format(extension,a,a) -- maybe more times?
- elseif f < 0 then
+ end
+ n = n + 1
+ local a = "a" .. n
+ return format(extension,a,a) -- maybe more times?
+ elseif f < 0 then
+ if w then
+ -- not supported
+ extension = gsub(extension,"%.%.%.","")
+ return extension
+ else
local a = "a" .. (n + f + 1)
return format(extension,a,a)
- else
- extension = gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s")
- -- we could fill an array and then n = n + 1 unpack(t,n,n+f) but as we
- -- cache we don't save much and there are hardly any extensions anyway
- local t = { }
- for i=1,f do
- n = n + 1
- -- t[#t+1] = "a" .. n
- t[i] = "a" .. n
- end
- return format(extension,unpack(t))
end
else
- extension = gsub(extension,"%%s",function()
+ if w then
+ extension = gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s")
+ end
+ -- we could fill an array and then n = n + 1 unpack(t,n,n+f) but as we
+ -- cache we don't save much and there are hardly any extensions anyway
+ local t = { }
+ for i=1,f do
n = n + 1
- return "a" .. n
- end)
- return extension
+ -- t[#t+1] = "a" .. n
+ t[i] = "a" .. n
+ end
+ return format(extension,unpack(t))
end
end
diff --git a/macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua b/macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua
index 62ef5d57a9..14a66da359 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua
@@ -6,8 +6,8 @@
local ProvidesLuaModule = {
name = "luaotfload-auxiliary",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / auxiliary functions",
license = "GPL v2.0"
}
diff --git a/macros/luatex/generic/luaotfload/luaotfload-colors.lua b/macros/luatex/generic/luaotfload/luaotfload-colors.lua
index 070fe868c7..e8a8e996a8 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-colors.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-colors.lua
@@ -5,8 +5,8 @@
local ProvidesLuaModule = {
name = "luaotfload-colors",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / color",
license = "GPL v2.0",
author = "Khaled Hosny, Elie Roux, Philipp Gesang, Dohyun Kim, David Carlisle",
diff --git a/macros/luatex/generic/luaotfload/luaotfload-conf.pdf b/macros/luatex/generic/luaotfload/luaotfload-conf.pdf
index c1efb7d479..85768faf2f 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-conf.pdf
+++ b/macros/luatex/generic/luaotfload/luaotfload-conf.pdf
Binary files differ
diff --git a/macros/luatex/generic/luaotfload/luaotfload-configuration.lua b/macros/luatex/generic/luaotfload/luaotfload-configuration.lua
index 36bb31dda1..8f04190a43 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-configuration.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-configuration.lua
@@ -7,8 +7,8 @@
local ProvidesLuaModule = {
name = "luaotfload-configuration",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / config file reader",
license = "GPL v2.0"
}
@@ -103,30 +103,31 @@ local valid_resolvers = tabletohash {
"tex", "path", "name", "file", "my"
}
+local base_features = tabletohash {
+ -- Adopt the generic default from HarfBuzz.
+ -- The first line is generally enabled there,
+ -- the second only for horizontal text.
+ -- The third line is luaotfload specific
+ "abvm", "blwm", "ccmp", "locl", "mark", "mkmk", "rlig",
+ "calt", "clig", "curs", "dist", "kern", "liga", "rclt",
+ "itlc",
+}
local feature_presets = {
- arab = tabletohash {
- "ccmp", "locl", "isol", "fina", "fin2",
- "fin3", "medi", "med2", "init", "rlig",
- "calt", "liga", "cswh", "mset", "curs",
- "kern", "mark", "mkmk",
- },
- deva = tabletohash {
- "ccmp", "locl", "init", "nukt", "akhn",
- "rphf", "blwf", "half", "pstf", "vatu",
- "pres", "blws", "abvs", "psts", "haln",
- "calt", "blwm", "abvm", "dist", "kern",
- "mark", "mkmk",
- },
- khmr = tabletohash {
- "ccmp", "locl", "pref", "blwf", "abvf",
- "pstf", "pres", "blws", "abvs", "psts",
- "clig", "calt", "blwm", "abvm", "dist",
- "kern", "mark", "mkmk",
- },
- thai = tabletohash {
- "ccmp", "locl", "liga", "kern", "mark",
- "mkmk",
- },
+ arab = table.merged( tabletohash {
+ "isol", "fina", "fin2", "fin3", "medi", "med2", "init",
+ "cswh", "mset",
+ }, base_features),
+ deva = table.merged( tabletohash {
+ "init", "nukt", "akhn", "rphf", "blwf", "half", "pstf",
+ "vatu", "pres", "blws", "abvs", "psts", "haln",
+ }, base_features),
+ khmr = table.merged( tabletohash {
+ "pref", "blwf", "abvf", "pstf", "pres", "blws", "abvs",
+ "psts",
+ }, base_features),
+ hang = table.merged( tabletohash {
+ "ccmp", "ljmo", "vjmo", "tjmo",
+ }, base_features),
}
--[[doc--
@@ -234,10 +235,7 @@ local default_config = {
},
default_features = {
global = { mode = "node" },
- dflt = tabletohash {
- "ccmp", "locl", "rlig", "liga", "clig",
- "kern", "mark", "mkmk", 'itlc',
- },
+ dflt = base_features,
arab = feature_presets.arab,
syrc = feature_presets.arab,
@@ -260,7 +258,7 @@ local default_config = {
thai = feature_presets.thai,
lao = feature_presets.thai,
- hang = tabletohash { "ccmp", "ljmo", "vjmo", "tjmo", },
+ hang = feature_presets.hang,
},
}
diff --git a/macros/luatex/generic/luaotfload/luaotfload-database.lua b/macros/luatex/generic/luaotfload/luaotfload-database.lua
index af123a0296..6d0bcff414 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-database.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-database.lua
@@ -5,8 +5,8 @@
do -- block to avoid to many local variables error
local ProvidesLuaModule = {
name = "luaotfload-database",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / database",
license = "GPL v2.0",
author = "Khaled Hosny, Elie Roux, Philipp Gesang, Marcel Krüger",
@@ -140,9 +140,11 @@ local tonumber = tonumber
local unpack = table.unpack
local fonts = fonts or { }
-local fontshandlers = fonts.handlers or { }
+do
+ local fontshandlers = fonts.handlers or { }
+ fonts.handlers = fontshandlers
+end
local otfhandler = fonts.handlers.otf or { }
-fonts.handlers = fontshandlers
local gzipload = gzip.load
local gzipsave = gzip.save
@@ -176,7 +178,6 @@ local utf8offset = utf8.offset
local context_environment = luaotfload.fontloader
local caches = context_environment.caches
local filebasename = file.basename
-local filecollapsepath = file.collapsepath or file.collapse_path
local filedirname = file.dirname
local fileextname = file.extname
local fileiswritable = file.iswritable
@@ -361,6 +362,7 @@ This is a sketch of the luaotfload db:
type dbobj = {
families : familytable;
+ fontnames : fontnametable;
files : filemap;
status : filestatus;
mappings : fontentry list;
@@ -381,6 +383,11 @@ This is a sketch of the luaotfload db:
default : int; // points into mappings or names
optical : (int, int) list; // design size -> index entry
}
+ and fontnametable = {
+ local : (format, index) hash;
+ texmf : (format, index) hash;
+ system : (format, index) hash;
+ }
and metadata = {
created : string // creation time
formats : string list; // { "otf", "ttf", "ttc" }
@@ -522,24 +529,13 @@ local function load_lua_file (path)
end
--- define locals in scope
-local access_font_index
-local find_closest
-local flush_lookup_cache
-local generate_filedata
local get_font_filter
-local group_modifiers
-local load_names
local lookup_font_name
-local getmetadata
-local order_design_sizes
-local ot_fullinfo
-local read_blacklist
local reload_db
local lookup_fullpath
local save_lookups
local save_names
local set_font_filter
-local t1_fullinfo
local update_names
--- state of the database
@@ -549,7 +545,7 @@ local fonts_reloaded = false
local fuzzy_limit = 1 --- display closest only
--- bool? -> -> bool? -> dbobj option
-load_names = function (dry_run, no_rebuild)
+local function load_names (dry_run, no_rebuild)
local starttime = osgettimeofday ()
local foundname, data = load_lua_file (config.luaotfload.paths.index_path_lua)
@@ -617,12 +613,12 @@ end
--doc]]--
-access_font_index = function ()
+local function access_font_index ()
if not name_index then name_index = load_names () end
return name_index
end
-getmetadata = function ()
+local function getmetadata ()
if not name_index then
name_index = load_names (false, true)
if name_index then return tablefastcopy (name_index.meta) end
@@ -728,9 +724,13 @@ do
local type1_metrics = { "tfm", "ofm", }
-- /MK
-lookup_font_file = function (filename)
+function lookup_font_file (filename)
local found = lookup_filename (filename)
+ if found and not lfsisfile(found) then
+ found = nil
+ end
+
if not found then
local type = file.suffix(filename)
if type ~= "" then
@@ -750,7 +750,7 @@ lookup_font_file = function (filename)
end
if not fonts_reloaded and config.luaotfload.db.update_live == true then
- return reload_db (stringformat ("File not found: %s.", filename),
+ return reload_db (stringformat ("File not found: %q.", filename),
lookup_font_file,
filename)
end
@@ -979,11 +979,8 @@ end
--- int * int * int * int list -> int -> int
local function choose_size (sizes, askedsize)
- local mappings = name_index.mappings
- local exact
local inrange = { } --- distance * index list
local norange = { } --- distance * index list
- local fontname, subfont
if askedsize ~= 0 then
--- firstly, look for an exactly matching design size or
--- matching range
@@ -1041,7 +1038,6 @@ end
--- spec -> string -> string -> int -> string * int * bool
local function lookup_familyname (specification, name, style, askedsize)
local families = name_index.families
- local mappings = name_index.mappings
local candidates = nil
local fallback = true
--- arrow code alert
@@ -1081,21 +1077,25 @@ local function lookup_familyname (specification, name, style, askedsize)
end
local function lookup_fontname (specification, name)
- local mappings = name_index.mappings
- local fallback = nil
- local lastresort = nil
- for i = 1, #mappings do
- local face = mappings [i]
- local typographicsubfamily = face.typographicsubfamily
- local subfamily = face.subfamily
- if face.fontname == name
- or face.fullname == name
- or face.psname == name
- then
- return face.fullpath, face.subfont
+ local fontnames = name_index.fontnames
+ --- arrow code alert
+ for i = 1, #location_precedence do
+ local location = location_precedence [i]
+ local locgroup = fontnames [location]
+ for j = 1, #format_precedence do
+ local format = format_precedence [j]
+ local fmtgroup = locgroup [format]
+ if fmtgroup then
+ local index = fmtgroup [name]
+ if index then
+ local success, resolved, subfont = get_font_file (index)
+ if success then
+ return resolved, subfont
+ end
+ end
+ end
end
end
- return nil, nil
end
local design_size_dimension --- scale asked size if not using bp
@@ -1204,7 +1204,7 @@ end
--doc]]--
--- table -> string * (int | bool)
-lookup_font_name = function (specification)
+function lookup_font_name (specification)
if not name_index then name_index = load_names () end
local name = sanitize_fontname (specification.name)
local style = sanitize_fontname (specification.style) or "r"
@@ -1238,7 +1238,7 @@ lookup_font_name = function (specification)
if not resolved then
if not fonts_reloaded and config.luaotfload.db.update_live == true then
- return reload_db (stringformat ("Font %s not found.",
+ return reload_db (stringformat ("Font %q not found.",
specification.name or "<?>"),
lookup_font_name,
specification)
@@ -1247,7 +1247,7 @@ lookup_font_name = function (specification)
return resolved, subfont
end
-lookup_fullpath = function (fontname, ext) --- getfilename()
+function lookup_fullpath (fontname, ext) --- getfilename()
if not name_index then name_index = load_names () end
local files = name_index.files
local basedata = files.base
@@ -1282,12 +1282,12 @@ end
--- and then re-run the caller with the arg list
--- string -> ('a -> 'a) -> 'a list -> 'a
-reload_db = function (why, caller, ...)
+function reload_db (why, caller, ...)
local namedata = name_index
local formats = tableconcat (namedata.meta.formats, ",")
logreport ("both", 0, "db",
- "Reload initiated (formats: %s); reason: %q.",
+ "Reload initiated (formats: %s); reason: %s",
formats, why)
set_font_filter (formats)
@@ -1350,7 +1350,7 @@ local function delete_dupes (lst)
end
--- string -> int -> bool
-find_closest = function (name, limit)
+local function find_closest (name, limit)
local name = sanitize_fontname (name)
limit = limit or fuzzy_limit
@@ -1671,7 +1671,7 @@ table as returned by the font file reader need to be relocated.
--- string -> int -> bool -> string -> fontentry
-ot_fullinfo = function (filename,
+local function ot_fullinfo (filename,
subfont,
location,
basename,
@@ -1717,7 +1717,7 @@ end
--- string -> int -> bool -> string -> fontentry
-t1_fullinfo = function (filename, _subfont, location, basename, format)
+local function t1_fullinfo (filename, _subfont, location, basename, format)
local sanitized
local metadata = load_font_file (filename)
local fontname = metadata.fontname
@@ -1954,8 +1954,7 @@ do
--- choose a normalization function in advance
--- instead of testing with every call
local os_type, os_name = os.type, os.name
- local filecollapsepath = filecollapsepath
- local lfsreadlink = lfs.readlink
+ local filecollapsepath = file.collapsepath or file.collapse_path
--- windows and dos
if os_type == "windows" or os_type == "msdos" then
@@ -1973,20 +1972,7 @@ do
--doc]]--
else -- posix
- function path_normalize (path)
- local dest = lfsreadlink(path)
- if dest then
- if kpsereadable_file(dest) then
- path = dest
- elseif kpsereadable_file(filejoin(filedirname(path), dest)) then
- path = filejoin(file.dirname(path), dest)
- else
- -- broken symlink?
- end
- end
- path = filecollapsepath(path)
- return path
- end
+ path_normalize = filecollapsepath
end
end
@@ -2056,7 +2042,7 @@ local function create_blacklist (blacklist, whitelist)
end
--- unit -> unit
-read_blacklist = function ()
+local function read_blacklist ()
local files = {
kpselookup ("luaotfload-blacklist.cnf",
{all=true, format="tex"})
@@ -2116,29 +2102,26 @@ do
local current_formats = { }
+ local splitcomma = luaotfload.parsers.splitcomma
function set_font_filter (formats)
if not formats or type (formats) ~= "string" then
return
end
- local splitcomma = luaotfload.parsers and luaotfload.parsers.splitcomma
-
if stringsub (formats, 1, 1) == "+" then -- add
formats = lpegmatch (splitcomma, stringsub (formats, 2))
if formats then
current_formats = tableappend (current_formats, formats)
end
- elseif stringsub (formats, 1, 1) == "-" then -- add
+ elseif stringsub (formats, 1, 1) == "-" then -- remove
formats = lpegmatch (splitcomma, stringsub (formats, 2))
if formats then
local newformats = { }
for i = 1, #current_formats do
local fmt = current_formats[i]
- local include = true
for j = 1, #formats do
if current_formats[i] == formats[j] then
- include = false
goto skip
end
end
@@ -2327,12 +2310,10 @@ local function collect_font_filenames_dir (dirname, location)
return files
end
+local stripslashes = luaotfload.parsers.stripslashes
--- string list -> string list
local function filter_out_pwd (dirs)
local result = { }
- if stripslashes == nil then
- stripslashes = luaotfload.parsers and luaotfload.parsers.stripslashes
- end
local pwd = path_normalize (lpegmatch (stripslashes,
lfscurrentdir ()))
for i = 1, #dirs do
@@ -2414,15 +2395,16 @@ local function get_os_dirs ()
elseif os.type == "windows" or os.type == "msdos" then
local windir = osgetenv("WINDIR")
local appdata = osgetenv("LOCALAPPDATA")
- return { filejoin(windir, 'Fonts'), filejoin(appdata, 'Microsoft/Windows/Fonts') }
+ if chgstrcp and kpse.var_value('command_line_encoding') ~= nil then
+ return { filejoin(windir, 'Fonts'), chgstrcp.syscptoutf8(filejoin(appdata, 'Microsoft/Windows/Fonts')) }
+ else
+ return { filejoin(windir, 'Fonts'), filejoin(appdata, 'Microsoft/Windows/Fonts') }
+ end
else
local fonts_conves = { --- plural, much?
"/usr/local/etc/fonts/fonts.conf",
"/etc/fonts/fonts.conf",
}
- if not luaotfload.parsers then
- logreport ("log", 0, "db", "Fatal: no fonts.conf parser.")
- end
local os_dirs = luaotfload.parsers.read_fonts_conf(fonts_conves, find_files)
return os_dirs
end
@@ -2529,7 +2511,7 @@ local function collect_font_filenames_system ()
end
--- unit -> bool
-flush_lookup_cache = function ()
+local function flush_lookup_cache ()
lookup_cache = { }
collectgarbage "collect"
return true
@@ -2565,7 +2547,7 @@ local function collect_font_filenames_local ()
end
--- fontentry list -> filemap
-generate_filedata = function (mappings)
+local function generate_filedata (mappings)
logreport ("both", 2, "db", "Creating filename map.")
@@ -2965,6 +2947,29 @@ local function collect_families (mappings)
return families
end
+local function collect_fontnames (mappings)
+
+ logreport ("info", 2, "db", "Collecting fontnames.")
+
+ local fontnames = {
+ ["local"] = { },
+ system = { },
+ texmf = { },
+ }
+
+ for i = 1, #mappings do
+ local entry = mappings [i]
+
+ local subtable = get_subtable (fontnames, entry)
+ if entry.fontname then subtable[entry.fontname] = i end
+ if entry.fullname then subtable[entry.fullname] = i end
+ if entry.psname then subtable[entry.psname] = i end
+ end
+
+ collectgarbage "collect"
+ return fontnames
+end
+
--[[doc--
group_modifiers -- For not-quite-bold faces, determine whether
@@ -2979,7 +2984,7 @@ end
local style_categories = { "r", "b", "i", "bi" }
local bold_categories = { "b", "bi" }
-group_modifiers = function (mappings, families)
+local function group_modifiers (mappings, families)
logreport ("info", 2, "db", "Analyzing shapes, weights, and styles.")
for location, location_data in next, families do
for format, format_data in next, location_data do
@@ -3082,7 +3087,7 @@ local function cmp_sizes (a, b)
return a [1] < b [1]
end
-order_design_sizes = function (families)
+local function order_design_sizes (families)
logreport ("info", 2, "db", "Ordering design sizes.")
@@ -3386,7 +3391,7 @@ end
--- dry_dun: don’t write to the db, just scan dirs
--- dbobj? -> bool? -> bool? -> dbobj
-update_names = function (currentnames, force, dry_run)
+function update_names (currentnames, force, dry_run)
local targetnames
local n_new = 0
local n_rem = 0
@@ -3472,15 +3477,17 @@ update_names = function (currentnames, force, dry_run)
targetnames.files = generate_filedata (targetnames.mappings)
--- pass 5: build family lookup table
- targetnames.families = collect_families (targetnames.mappings)
+ targetnames.families = collect_families (targetnames.mappings)
--- pass 6: arrange style and size info
targetnames.families = group_modifiers (targetnames.mappings,
targetnames.families)
-
--- pass 7: order design size tables
targetnames.families = order_design_sizes (targetnames.families)
+ --- pass 8: build family lookup table
+ targetnames.fontnames = collect_fontnames (targetnames.mappings)
+
logreport ("info", 3, "db",
"Rebuilt in %0.f ms.",
1000 * (osgettimeofday () - starttime))
@@ -3509,7 +3516,7 @@ update_names = function (currentnames, force, dry_run)
end
--- unit -> bool
-save_lookups = function ( )
+function save_lookups ( )
local paths = config.luaotfload.paths
local luaname, lucname = paths.lookup_path_lua, paths.lookup_path_luc
if fileiswritable (luaname) and fileiswritable (lucname) then
@@ -3536,7 +3543,7 @@ end
--- save_names() is usually called without the argument
--- dbobj? -> bool * string option
-save_names = function (currentnames)
+function save_names (currentnames)
if not currentnames then
currentnames = name_index
end
@@ -3825,7 +3832,7 @@ return function ()
names.blacklist = blacklist
-- MK Changed to rebuild with case insensitive fallback.
-- Negative version to indicate generation by modified code.
- names.version = -1 --- decrease monotonically
+ names.version = -2 --- decrease monotonically
-- /MK
names.data = nil --- contains the loaded database
names.lookups = nil --- contains the lookup cache
diff --git a/macros/luatex/generic/luaotfload/luaotfload-diagnostics.lua b/macros/luatex/generic/luaotfload/luaotfload-diagnostics.lua
index c90aa0f5be..be3183cf65 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-diagnostics.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-diagnostics.lua
@@ -7,8 +7,8 @@
local ProvidesLuaModule = {
name = "luaotfload-diagnostics",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload-tool submodule / diagnostics",
license = "GPL v2.0"
}
diff --git a/macros/luatex/generic/luaotfload/luaotfload-dvi.lua b/macros/luatex/generic/luaotfload/luaotfload-dvi.lua
new file mode 100644
index 0000000000..b57934fdb6
--- /dev/null
+++ b/macros/luatex/generic/luaotfload/luaotfload-dvi.lua
@@ -0,0 +1,131 @@
+-------------------------------------------------------------------------------
+-- FILE: luaotfload-dvi.lua
+-- DESCRIPTION: part of luaotfload / DVI
+-------------------------------------------------------------------------------
+
+
+local ProvidesLuaModule = {
+ name = "luaotfload-dvi",
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
+ description = "luaotfload submodule / DVI",
+ license = "GPL v2.0",
+ author = "Marcel Krüger",
+ copyright = "Luaotfload Development Team",
+}
+
+if luatexbase and luatexbase.provides_module then
+ luatexbase.provides_module (ProvidesLuaModule)
+end
+
+local getfont = font.getfont
+local setfont = node.direct.setfont
+local getdisc = node.direct.getdisc
+local traverse_glyph = node.direct.traverse_glyph
+local traverse_id = node.direct.traverse_id
+local uses_font = node.direct.uses_font
+local define_font = font.define
+local disc_t = node.id'disc'
+
+-- DVI output support
+--
+-- When writing DVI files, we can't assume that the DVI reader has access to our
+-- font dictionaries, so we need an independent representation for our glyphs. The
+-- approach we chose in coordination with the dvisvgm author is to create a DVI font
+-- name which indicates the font filename and some essential backend parameters
+-- (especially otential extend, shrink, embolden, etc. factors) and then use GIDs in
+-- the page stream.
+--
+-- Normally we could easily implement this using virtual fonts, but because we are
+-- dealing with DVI output, LuaTeX is not evaluating virtual fonts by itself.
+-- So instead, we process the shaped output and replace all glyph nodes with glyph
+-- nodes from special fonts which have the characteristics expected brom the DVI reader.
+
+-- mapped_fonts maps fontids from the user to fontids used in the DVI file
+local mapped_fonts = setmetatable({}, {__index = function(t, fid)
+ local font = getfont(fid)
+ local mapped = font.backend_font or false
+ t[fid] = mapped
+ return mapped
+end})
+
+local function process(head, font)
+ local mapping = mapped_fonts[font]
+ if not mapping then return head end
+ local mapped_font = mapping.font
+ for n, c, f in traverse_glyph(head) do if f == font then
+ local mapped = mapping[c]
+ if mapped then setfont(n, mapped_font, mapped) end
+ end end
+ for n in traverse_id(disc_t, head) do if uses_font(n, font) then
+ local pre, post, rep = getdisc(n)
+ for n, c, f in traverse_glyph(pre) do if f == font then
+ local mapped = mapping[c]
+ if mapped then setfont(n, mapped_font, mapped) end
+ end end
+ for n, c, f in traverse_glyph(post) do if f == font then
+ local mapped = mapping[c]
+ if mapped then setfont(n, mapped_font, mapped) end
+ end end
+ for n, c, f in traverse_glyph(rep) do if f == font then
+ local mapped = mapping[c]
+ if mapped then setfont(n, mapped_font, mapped) end
+ end end
+ end end
+end
+local function manipulate(tfmdata, _, dvi_kind)
+ if dvi_kind ~= 'dvisvgm' then
+ texio.write_nl(string.format('WARNING (luaotfload): Unsupported DVI backend %q, falling back to dvisvgm.', dvi_kind))
+ end
+ -- Legacy fonts can be written to the DVI file directly
+ if 2 ~= (tfmdata.encodingbytes or ((tfmdata.format == 'truetype' or tfmdata.format == 'opentype') and 2 or 1)) then
+ return
+ end
+ local newfont = {}
+ for k,v in pairs(tfmdata) do
+ newfont[k] = v
+ end
+ local newchars = {}
+ newfont.characters = newchars
+ local lookup = {}
+ for k,v in pairs(tfmdata.characters) do
+ local newchar = {
+ width = v.width, -- Only width should really be necessary
+ height = v.height,
+ depth = v.depth,
+ }
+ newchars[v.index or k] = newchar
+ lookup[k] = v.index or k
+ end
+ newfont.checksum = string.unpack('>I4', 'LuaF') -- Use a magic checksum such that the reader
+ -- can uniquely identify these fonts.
+ local name = '[' .. newfont.name .. ']:' -- TODO: Why .name? I would have expected .filename
+ if newfont.subfont and newfont.subfont ~= 1 then
+ name = name .. 'index=' .. tostring(math.tointeger(newfont.subfont-1)) .. ';'
+ end
+ if newfont.extend and newfont.extend ~= 1000 then
+ name = name .. 'extend=' .. tostring(math.tointeger(math.round(newfont.extend*65.536))) .. ';'
+ end
+ if newfont.slant and newfont.slant ~= 0 then
+ name = name .. 'slant=' .. tostring(math.tointeger(math.round(newfont.slant*65.536))) .. ';'
+ end
+ if newfont.mode == 2 and newfont.width and newfont.width ~= 0 then
+ name = name .. 'embolden=' .. tostring(math.tointeger(math.round(newfont.width*65.78176))) .. ';'
+ end
+ newfont.name = name:sub(1,-2) -- Stri th trailing : or ;
+ tfmdata.backend_font = lookup
+ lookup.font = define_font(newfont)
+end
+
+fonts.constructors.features.otf.register {
+ name = "dvifont",
+ default = "dvisvgm",
+ manipulators = {
+ node = manipulate,
+ base = manipulate,
+ },
+ processors = {
+ node = process,
+ base = process,
+ },
+}
diff --git a/macros/luatex/generic/luaotfload/luaotfload-embolden.lua b/macros/luatex/generic/luaotfload/luaotfload-embolden.lua
index 479c485d62..d1d4e478c8 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-embolden.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-embolden.lua
@@ -5,9 +5,9 @@
local ProvidesLuaModule = {
name = "luaotfload-embolden",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
- description = "luaotfload submodule / color",
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
+ description = "luaotfload submodule / embolden",
license = "GPL v2.0",
author = "Marcel Krüger"
}
diff --git a/macros/luatex/generic/luaotfload/luaotfload-fallback.lua b/macros/luatex/generic/luaotfload/luaotfload-fallback.lua
index 6218d9caeb..eee107c709 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-fallback.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-fallback.lua
@@ -5,8 +5,8 @@
local ProvidesLuaModule = {
name = "luaotfload-fallback",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / fallback",
license = "GPL v2.0",
author = "Marcel Krüger"
diff --git a/macros/luatex/generic/luaotfload/luaotfload-features.lua b/macros/luatex/generic/luaotfload/luaotfload-features.lua
index 59fe42da32..2d83df10ff 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-features.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-features.lua
@@ -5,8 +5,8 @@
local ProvidesLuaModule = {
name = "luaotfload-features",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / features",
license = "GPL v2.0",
author = "Hans Hagen, Khaled Hosny, Elie Roux, Philipp Gesang, Marcel Krüger",
@@ -429,6 +429,13 @@ local function handle_request (specification)
--- investigated it any further (luatex-fonts-ext), so it will
--- just stay here.
features.normal = normalize (request.features)
+ if features.normal.instance then
+ if features.normal.axis then
+ report("term and log", 0, "features", "instance and axis provided, instance will be ignored")
+ else
+ specification.instance = features.normal.instance
+ end
+ end
specification.sub = request.sub or specification.sub or false
local forced_mode = request.features and request.features.mode
@@ -451,6 +458,58 @@ if as_script == true then --- skip the remainder of the file
return
end
+do
+ local helpers = fonts.handlers.otf.readers.helpers
+ local axistofactors = helpers.axistofactors
+ local cleanname = helpers.cleanname
+ local getaxisscale = helpers.getaxisscale
+ local function search(table, term, key_field, value_field)
+ if not table then return end
+ for i=1, #table do
+ local entry = table[i]
+ if cleanname(entry[key_field]) == term then
+ return entry[value_field]
+ end
+ end
+ end
+ function helpers.getfactors(tfmdata, instance) -- `instance` might refer to an `axis` value here
+ assert(instance == true or type(instance) == "string", "Fontloader changed interface of helpers.getfactors. This is a bug, please notify the luaotfload maintainers.")
+ local variabledata = tfmdata.variabledata
+ if not variabledata or instance == "" then return end
+ local instances = variabledata.instances
+ local axis = variabledata.axis
+ local designaxis = variabledata.designaxis
+ local segments = variabledata.segments
+ if not axis then return end
+ local factors = {}
+ if instance == true then
+ for i=1, #axis do
+ local cur = axis[i]
+ local default = cur.default
+ factors[i] = getaxisscale(segments, cur.minimum, default, cur.maximum, default)
+ end
+ return factors
+ end
+ local values = search(instances, instance, "subfamily", "values")
+ if values then
+ for i=1, #axis do
+ local cur = axis[i]
+ factors[i] = getaxisscale(segments, cur.minimum, cur.default, cur.maximum, values[i].value)
+ end
+ return factors
+ end
+ values = axistofactors(instance)
+ for i=1, #axis do
+ local cur = axis[i]
+ local default = cur.default
+ local value = cur.name and values[cur.name] or values[cur.tag]
+ value = tonumber(value) or (value and search(search(designaxis, cur.tag, "tag", "variants"), cleanname(value), "name", "value")) or default
+ factors[i] = getaxisscale(segments, cur.minimum, default, cur.maximum, value)
+ end
+ return factors
+ end
+end
+
-- MK: Added
function fonts.definers.analyze (spec_string, size)
return handle_request {
@@ -602,6 +661,110 @@ do
}
end
+do
+ local function mathfontdimen(tfmdata, _, value)
+ if not next(tfmdata.mathparameters) then return end
+ local parameters = tfmdata.parameters
+ local mathparameters = tfmdata.mathparameters
+ if value == 'xetex' then
+ parameters[10] = mathparameters.ScriptPercentScaleDown
+ parameters[11] = mathparameters.ScriptScriptPercentScaleDown
+ parameters[12] = mathparameters.DelimitedSubFormulaMinHeight
+ parameters[13] = mathparameters.DisplayOperatorMinHeight
+ parameters[14] = mathparameters.MathLeading
+ parameters[15] = mathparameters.AxisHeight
+ parameters[16] = mathparameters.AccentBaseHeight
+ parameters[17] = mathparameters.FlattenedAccentBaseHeight
+ parameters[18] = mathparameters.SubscriptShiftDown
+ parameters[19] = mathparameters.SubscriptTopMax
+ parameters[20] = mathparameters.SubscriptBaselineDropMin
+ parameters[21] = mathparameters.SuperscriptShiftUp
+ parameters[22] = mathparameters.SuperscriptShiftUpCramped
+ parameters[23] = mathparameters.SuperscriptBottomMin
+ parameters[24] = mathparameters.SuperscriptBaselineDropMax
+ parameters[25] = mathparameters.SubSuperscriptGapMin
+ parameters[26] = mathparameters.SuperscriptBottomMaxWithSubscript
+ parameters[27] = mathparameters.SpaceAfterScript
+ parameters[28] = mathparameters.UpperLimitGapMin
+ parameters[29] = mathparameters.UpperLimitBaselineRiseMin
+ parameters[30] = mathparameters.LowerLimitGapMin
+ parameters[31] = mathparameters.LowerLimitBaselineDropMin
+ parameters[32] = mathparameters.StackTopShiftUp
+ parameters[33] = mathparameters.StackTopDisplayStyleShiftUp
+ parameters[34] = mathparameters.StackBottomShiftDown
+ parameters[35] = mathparameters.StackBottomDisplayStyleShiftDown
+ parameters[36] = mathparameters.StackGapMin
+ parameters[37] = mathparameters.StackDisplayStyleGapMin
+ parameters[38] = mathparameters.StretchStackTopShiftUp
+ parameters[39] = mathparameters.StretchStackBottomShiftDown
+ parameters[40] = mathparameters.StretchStackGapAboveMin
+ parameters[41] = mathparameters.StretchStackGapBelowMin
+ parameters[42] = mathparameters.FractionNumeratorShiftUp
+ parameters[43] = mathparameters.FractionNumeratorDisplayStyleShiftUp
+ parameters[44] = mathparameters.FractionDenominatorShiftDown
+ parameters[45] = mathparameters.FractionDenominatorDisplayStyleShiftDown
+ parameters[46] = mathparameters.FractionNumeratorGapMin
+ parameters[47] = mathparameters.FractionNumeratorDisplayStyleGapMin
+ parameters[48] = mathparameters.FractionRuleThickness
+ parameters[49] = mathparameters.FractionDenominatorGapMin
+ parameters[50] = mathparameters.FractionDenominatorDisplayStyleGapMin
+ parameters[51] = mathparameters.SkewedFractionHorizontalGap
+ parameters[52] = mathparameters.SkewedFractionVerticalGap
+ parameters[53] = mathparameters.OverbarVerticalGap
+ parameters[54] = mathparameters.OverbarRuleThickness
+ parameters[55] = mathparameters.OverbarExtraAscender
+ parameters[56] = mathparameters.UnderbarVerticalGap
+ parameters[57] = mathparameters.UnderbarRuleThickness
+ parameters[58] = mathparameters.UnderbarExtraDescender
+ parameters[59] = mathparameters.RadicalVerticalGap
+ parameters[60] = mathparameters.RadicalDisplayStyleVerticalGap
+ parameters[61] = mathparameters.RadicalRuleThickness
+ parameters[62] = mathparameters.RadicalExtraAscender
+ parameters[63] = mathparameters.RadicalKernBeforeDegree
+ parameters[64] = mathparameters.RadicalKernAfterDegree
+ parameters[65] = mathparameters.RadicalDegreeBottomRaisePercent
+ -- parameters[66] = mathparameters.MinConnectorOverlap
+ -- parameters[67] = mathparameters.SubscriptShiftDownWithSuperscript
+ -- parameters[68] = mathparameters.FractionDelimiterSize
+ -- parameters[69] = mathparameters.FractionDelimiterDisplayStyleSize
+ -- parameters[70] = mathparameters.NoLimitSubFactor
+ -- parameters[71] = mathparameters.NoLimitSupFactor
+ elseif value == 'tex2' then
+ parameters[8] = mathparameters.FractionNumeratorDisplayStyleShiftUp
+ parameters[9] = mathparameters.FractionNumeratorShiftUp
+ parameters[10] = mathparameters.StackTopShiftUp
+ parameters[11] = mathparameters.FractionDenominatorDisplayStyleShiftDown
+ parameters[12] = mathparameters.FractionDenominatorShiftDown
+ parameters[13] = mathparameters.SuperscriptShiftUp
+ parameters[14] = mathparameters.SuperscriptShiftUp
+ parameters[15] = mathparameters.SuperscriptShiftUpCramped
+ parameters[16] = mathparameters.SubscriptShiftDown
+ parameters[17] = mathparameters.SubscriptShiftDown
+ parameters[18] = mathparameters.SuperscriptBaselineDropMax
+ parameters[19] = mathparameters.SubscriptBaselineDropMin
+ parameters[20] = mathparameters.FractionDelimiterDisplayStyleSize
+ parameters[21] = mathparameters.FractionDelimiterSize
+ parameters[22] = mathparameters.AxisHeight
+ elseif value == 'tex3' then
+ parameters[8] = mathparameters.Defa
+ parameters[9] = mathparameters.UpperLimitGapMin
+ parameters[10] = mathparameters.LowerLimitGapMin
+ parameters[11] = mathparameters.UpperLimitBaselineRiseMin
+ parameters[12] = mathparameters.LowerLimitBaselineDropMin
+ parameters[13] = 0
+ end
+ end
+ fonts.constructors.features.otf.register {
+ name = 'mathfontdimen',
+ description = 'Set fontdimen values for compatibility with other engines',
+ manipulators = {
+ base = mathfontdimen,
+ -- node = mathfontdimen,
+ -- plug = mathfontdimen,
+ },
+ }
+end
+
return function ()
if not fonts and fonts.handlers then
report ("log", 0, "features",
diff --git a/macros/luatex/generic/luaotfload/luaotfload-filelist.lua b/macros/luatex/generic/luaotfload/luaotfload-filelist.lua
index 1e3a4fff38..b8ab343402 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-filelist.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-filelist.lua
@@ -6,8 +6,8 @@
local ProvidesLuaModule = {
name = "luaotfload-filelist",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / filelist",
license = "GPL v2.0"
}
@@ -188,26 +188,27 @@ luaotfload.filelist.data =
{ name = "fonts-syn" , ours = nil , ext = ".lua", kind = kind_ignored , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirgen, ctxtype = "ctxgene" , ctxpref = "luatex-" },
{ name = "font-vfc" , ours = "font-vfc" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "font-otr" , ours = "font-otr" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
- { name = "font-oti" , ours = "font-oti" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
- { name = "font-ott" , ours = "font-ott" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "font-cff" , ours = "font-cff" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "font-ttf" , ours = "font-ttf" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "font-dsp" , ours = "font-dsp" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
- { name = "font-oup" , ours = "font-oup" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-oti" , ours = "font-oti" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-ott" , ours = "font-ott" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "font-otl" , ours = "font-otl" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "font-oto" , ours = "font-oto" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "font-otj" , ours = "font-otj" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-oup" , ours = "font-oup" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "font-ota" , ours = "font-ota" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "font-ots" , ours = "font-ots" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-otc" , ours = "font-otc" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "font-osd" , ours = "font-osd" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "font-ocl" , ours = "font-ocl" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
- { name = "font-otc" , ours = "font-otc" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "font-onr" , ours = "font-onr" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "font-one" , ours = "font-one" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "font-afk" , ours = "font-afk" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "fonts-tfm" , ours = nil , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxgene" , ctxpref = "luatex-" },
{ name = "font-lua" , ours = "font-lua" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "font-def" , ours = "font-def" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-shp" , ours = "font-shp" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
{ name = "fonts-def" , ours = nil , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirgen, ctxtype = "ctxgene" , ctxpref = "luatex-" },
{ name = "fonts-ext" , ours = nil , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirgen, ctxtype = "ctxgene" , ctxpref = "luatex-" },
{ name = "font-imp-tex" , ours = "font-imp-tex" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
@@ -259,6 +260,7 @@ luaotfload.filelist.data =
{ name = "resolvers" ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
{ name = "unicode" ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
{ name = "tounicode" ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+ { name = "dvi" ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
{ name = "characters" ,kind = kind_generated, ext =".lua", gitdir=gitdirgen, texdir=texdirtex, gitpref = "luaotfload-", script="mkcharacter" },
{ name = "glyphlist" ,kind = kind_generated, ext =".lua", gitdir=gitdirgen, texdir=texdirtex, gitpref = "luaotfload-", script="mkglyphlist" },
diff --git a/macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua b/macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua
index 6c19570ab7..19f5c2082b 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua
@@ -1,7 +1,7 @@
local ProvidesLuaModule = {
name = "luaotfload-glyphlist",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / autogenerated glyphlist",
copyright = "derived from https://raw.githubusercontent.com/adobe-type-tools/agl-aglfn/master/glyphlist.txt",
original = "Adobe Glyph List, version 2.0, September 20, 2002",
diff --git a/macros/luatex/generic/luaotfload/luaotfload-harf-define.lua b/macros/luatex/generic/luaotfload/luaotfload-harf-define.lua
index 31a92e4aa0..37ada59d00 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-harf-define.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-harf-define.lua
@@ -5,9 +5,9 @@
do -- block to avoid to many local variables error
local ProvidesLuaModule = {
name = "luaotfload-harf-define",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
- description = "luaotfload submodule / database",
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
+ description = "luaotfload submodule / HarfBuzz font loading",
license = "GPL v2.0",
author = "Khaled Hosny, Marcel Krüger",
copyright = "Luaotfload Development Team",
diff --git a/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua b/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua
index 8e1883e23f..6759747fbf 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua
@@ -5,9 +5,9 @@
do -- block to avoid to many local variables error
local ProvidesLuaModule = {
name = "luaotfload-harf-plug",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
- description = "luaotfload submodule / database",
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
+ description = "luaotfload submodule / HarfBuzz shaping",
license = "GPL v2.0",
author = "Khaled Hosny, Marcel Krüger",
copyright = "Luaotfload Development Team",
@@ -18,7 +18,8 @@ do -- block to avoid to many local variables error
end
end
-local hb = luaotfload.harfbuzz
+local hb = luaotfload.harfbuzz
+local logreport = luaotfload.log.report
local assert = assert
local next = next
@@ -50,8 +51,7 @@ local getattrs = direct.getattributelist
local setattrs = direct.setattributelist
local getchar = direct.getchar
local setchar = direct.setchar
-local getdir = direct.getdir
-local setdir = direct.setdir
+local getdirection = direct.getdirection
local getdisc = direct.getdisc
local setdisc = direct.setdisc
local getfont = direct.getfont
@@ -59,6 +59,8 @@ local getdata = direct.getdata
local setdata = direct.setdata
local getfont = direct.getfont
local setfont = direct.setfont
+local getwhatsitfield = direct.getwhatsitfield or direct.getfield
+local setwhatsitfield = direct.setwhatsitfield or direct.setfield
local getfield = direct.getfield
local setfield = direct.setfield
local getid = direct.getid
@@ -174,7 +176,7 @@ local function itemize(head, fontid, direction)
local runs, codes = {}, {}
local dirstack = {}
- local currdir = direction or "TLT"
+ local currdir = direction or 0
local lastskip, lastdir = true
local lastrun = {}
@@ -203,18 +205,19 @@ local function itemize(head, fontid, direction)
skip = true
end
elseif id == dir_t then
- local dir = getdir(n)
- if dir:sub(1, 1) == "+" then
- -- Push the current direction to the stack.
- tableinsert(dirstack, currdir)
- currdir = dir:sub(2)
- else
- assert(currdir == dir:sub(2))
+ local dir, cancel = getdirection(n)
+ local direction, kind = getdirection(n)
+ if cancel then
+ assert(currdir == dir)
-- Pop the last direction from the stack.
currdir = tableremove(dirstack)
+ else
+ -- Push the current direction to the stack.
+ tableinsert(dirstack, currdir)
+ currdir = dir
end
elseif id == localpar_t then
- currdir = getdir(n)
+ currdir = getdirection(n)
end
codes[#codes + 1] = code
@@ -225,7 +228,7 @@ local function itemize(head, fontid, direction)
start = #codes,
len = 1,
font = fontid,
- dir = currdir == "TRT" and dir_rtl or dir_ltr,
+ dir = currdir == 1 and dir_rtl or dir_ltr,
skip = skip,
codes = codes,
}
@@ -265,6 +268,7 @@ local function makesub(run, codes, nodelist)
nodelist = nil
end
nodelist, nodelist, glyphs = shape(nodelist, nodelist, subrun)
+ assert(glyphs, [[Shaping discretionary list failed. This shouldn't happen.]])
return { glyphs = glyphs, run = subrun, head = nodelist }
end
@@ -428,7 +432,8 @@ function shape(head, firstnode, run)
while startglyph > 1
and codes[glyphs[startglyph - 1].cluster + 1] ~= 0x20
and codes[glyphs[startglyph - 1].cluster + 1] ~= 0xFFFC
- and unsafetobreak(glyphs[startglyph]) do
+ and (unsafetobreak(glyphs[startglyph])
+ or glyphs[startglyph].cluster == glyphs[startglyph-1].cluster) do
startglyph = startglyph - 1
end
-- Get the corresponding character index.
@@ -550,9 +555,23 @@ function shape(head, firstnode, run)
end
end
return head, firstnode, glyphs, run.len - len
+ else
+ if not fontdata.shaper_warning then
+ local shaper = shapers[1]
+ if shaper then
+ tex.error("luaotfload | harf : Shaper failed", {
+ string.format("You asked me to use shaper %q to shape", shaper),
+ string.format("the font %q", fontdata.name),
+ "but the shaper failed. This probably means that either the shaper is not",
+ "available or the font is not compatible.",
+ "Maybe you should try the default shaper instead?"
+ })
+ else
+ tex.error(string.format("luaotfload | harf : All shapers failed for font %q.", fontdata.name))
+ end
+ fontdata.shaper_warning = true -- Only warn once for every font
+ end
end
-
- return head, firstnode, {}, 0
end
local function color_to_rgba(color)
@@ -687,6 +706,7 @@ local function tonodes(head, node, run, glyphs)
if layers then
local cmds = {} -- Every layer will add 5 cmds
local prev_color = nil
+ local k = 1 -- k == j except that k does only get increased if the layer isn't dropped
for j = 1, #layers do
local layer = layers[j]
local layerchar = characters[gid_offset + layer.glyph]
@@ -700,13 +720,16 @@ local function tonodes(head, node, run, glyphs)
-- color, we don’t check for it here explicitly since we will
-- get nil anyway.
local color = palette[layer.color_index]
- cmds[5*j - 4] = (color and not prev_color) and save_cmd or nop_cmd
- cmds[5*j - 3] = prev_color == color and nop_cmd or (color and {"pdf", "page", color_to_rgba(color)} or restore_cmd)
- cmds[5*j - 2] = push_cmd
- cmds[5*j - 1] = {"char", layer.glyph + gid_offset}
- cmds[5*j] = pop_cmd
- fontglyphs[layer.glyph].used = true
- prev_color = color
+ if not color or color.alpha ~= 0 then
+ cmds[5*k - 4] = (color and not prev_color) and save_cmd or nop_cmd
+ cmds[5*k - 3] = prev_color == color and nop_cmd or (color and {"pdf", "page", color_to_rgba(color)} or restore_cmd)
+ cmds[5*k - 2] = push_cmd
+ cmds[5*k - 1] = {"char", layer.glyph + gid_offset}
+ cmds[5*k] = pop_cmd
+ fontglyphs[layer.glyph].used = true
+ prev_color = color
+ k = k+1
+ end
end
cmds[#cmds + 1] = prev_color and restore_cmd
if not character.colored then
@@ -888,10 +911,11 @@ local function shape_run(head, current, run)
-- shaping.
local glyphs, offset
head, current, glyphs, offset = shape(head, current, run)
- return offset, tonodes(head, current, run, glyphs)
- else
- return 0, head, run.after
+ if glyphs then
+ return offset, tonodes(head, current, run, glyphs)
+ end
end
+ return 0, head, run.after
end
function process(head, font, _attr, direction)
@@ -912,8 +936,8 @@ end
local function pageliteral(data)
local n = newnode(whatsit_t, pdfliteral_t)
- setfield(n, "mode", 1) -- page
- setdata(n, data)
+ setwhatsitfield(n, "mode", 1) -- page
+ setwhatsitfield(n, "data", data) -- page
return n
end
@@ -994,7 +1018,16 @@ local utfchar = utf8.char
local function get_glyph_info(n)
n = todirect(n)
local props = properties[n]
- return props and props.glyph_info or utfchar(getchar(n)):gsub('\0', '^^@')
+ local info = props and props.glyph_info
+ if info then return info end
+ local c = getchar(n)
+ if c == 0 then
+ return '^^@'
+ elseif c < 0x110000 then
+ return utfchar(c)
+ else
+ return string.format("^^^^^^%06X", c)
+ end
end
fonts.handlers.otf.registerplugin('harf', process)
diff --git a/macros/luatex/generic/luaotfload/luaotfload-init.lua b/macros/luatex/generic/luaotfload/luaotfload-init.lua
index e86945b033..cfbcb68eab 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-init.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-init.lua
@@ -5,17 +5,17 @@
-- AUTHOR: Philipp Gesang (Phg), <phg@phi-gamma.net>, Marcel Krüger
-----------------------------------------------------------------------
-local ProvidesLuaModule = {
+local ProvidesLuaModule = {
name = "luaotfload-init",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / initialization",
license = "GPL v2.0"
}
if luatexbase and luatexbase.provides_module then
luatexbase.provides_module (ProvidesLuaModule)
-end
+end
-----------------------------------------------------------------------
@@ -79,68 +79,73 @@ local logreport --- filled in after loading the log module
--doc]]--
--- below paths are relative to the texmf-context
-local ltx = "tex/generic/context/luatex"
-local ctx = { "tex/context/base/mkiv", "tex/context/base" }
+
+local ignore, ltx, ctx = 0, 1, 2
+
+local context_module_paths = { -- [ltx] =
+ "tex/generic/context/luatex", -- [ctx] =
+ {"tex/context/base/mkiv", "tex/context/base" },
+}
local context_modules = {
--- Since 2.6 those are directly provided by the Lualibs package.
- { false, "l-lua" },
- { false, "l-lpeg" },
- { false, "l-function" },
- { false, "l-string" },
- { false, "l-table" },
- { false, "l-io" },
- { false, "l-file" },
- { false, "l-boolean" },
- { false, "l-math" },
- { false, "l-unicode" }, -- NEW UF 19.09.2018
- { false, "util-str" },
- { false, "util-fil" },
+ { ignore, "l-lua" },
+ { ignore, "l-lpeg" },
+ { ignore, "l-function" },
+ { ignore, "l-string" },
+ { ignore, "l-table" },
+ { ignore, "l-io" },
+ { ignore, "l-file" },
+ { ignore, "l-boolean" },
+ { ignore, "l-math" },
+ { ignore, "l-unicode" }, -- NEW UF 19.09.2018
+ { ignore, "util-str" },
+ { ignore, "util-fil" },
--- These constitute the fontloader proper.
- { ltx, "luatex-basics-gen" },
+ { ltx, "basics-gen" },
{ ctx, "data-con" },
- { ltx, "luatex-basics-nod" },
- { ltx, "luatex-basics-chr" }, -- NEW UF 14.12.2018
+ { ltx, "basics-nod" },
+ { ltx, "basics-chr" }, -- NEW UF 14.12.2018
{ ctx, "font-ini" },
- { ltx, "luatex-fonts-mis" }, -- NEW UF 19.09.2018
+ { ltx, "fonts-mis" }, -- NEW UF 19.09.2018
{ ctx, "font-con" },
- { ltx, "luatex-fonts-enc" },
+ { ltx, "fonts-enc" },
{ ctx, "font-cid" },
{ ctx, "font-map" },
--- { ltx, "luatex-fonts-syn" }, -- ignore??
+-- { ltx, "fonts-syn" }, -- ignore??
{ ctx, "font-vfc" }, -- NEW UF 19.09.2018
- { ctx, "font-oti" },
{ ctx, "font-otr" },
- { ctx, "font-ott" },
{ ctx, "font-cff" },
{ ctx, "font-ttf" },
{ ctx, "font-dsp" },
- { ctx, "font-oup" },
+ { ctx, "font-oti" },
+ { ctx, "font-ott" },
{ ctx, "font-otl" },
{ ctx, "font-oto" },
{ ctx, "font-otj" },
+ { ctx, "font-oup" },
{ ctx, "font-ota" },
{ ctx, "font-ots" },
+ { ctx, "font-otc" },
{ ctx, "font-osd" },
{ ctx, "font-ocl" },
- { ctx, "font-otc" },
{ ctx, "font-onr" },
{ ctx, "font-one" },
{ ctx, "font-afk" },
- { ctx, "luatex-fonts-tfm" },
+ { ltx, "fonts-tfm" },
{ ctx, "font-lua" },
{ ctx, "font-def" },
- { ltx, "luatex-fonts-def" },
- { ltx, "luatex-fonts-ext" },
+ { ctx, "font-shp" },
+ { ltx, "fonts-def" },
+ { ltx, "fonts-ext" },
{ ctx, "font-imp-tex" },
{ ctx, "font-imp-ligatures"},
{ ctx, "font-imp-italics" },
{ ctx, "font-imp-effects" },
- { ltx, "luatex-fonts-lig" },
- { ltx, "luatex-fonts-gbn" },
-
+ { ltx, "fonts-lig" },
+ { ltx, "fonts-gbn" },
} --[[context_modules]]
@@ -151,12 +156,15 @@ local function load_context_modules (pth)
logreport ("both", 2, "init",
"Loading fontloader components from context.")
- local n = #context_modules
- for i = 1, n do
- local sub, spec = unpack (context_modules [i])
- if sub == false then
+ for i = 1, #context_modules do
+ local kind, spec = unpack (context_modules [i])
+ if kind == ignore then
ignore_module (spec)
else
+ if kind == ltx then
+ spec = 'luatex-' .. spec
+ end
+ local sub = context_module_paths[kind]
local tsub = type (sub)
if not pth then
load_module (spec)
@@ -193,10 +201,10 @@ local function load_context_modules (pth)
end
local function verify_context_dir (pth)
- if lfsisdir(file.join(pth, ltx)) then
+ if lfsisdir(file.join(pth, context_module_paths[ltx])) then
return true
end
- for _, d in ipairs(ctx) do
+ for _, d in ipairs(context_module_paths[ctx]) do
if lfsisdir(file.join(pth, d)) then
return true
end
@@ -265,6 +273,7 @@ local function init_main(early_hook)
local the_attributes = luatexbase.attributes
local context_environment = luaotfload.fontloader
+ context_environment.CONTEXTLMTXMODE = 0
context_environment.attributes = {
private = function (name)
local attr = "luaotfload@" .. name --- used to be: “otfl@”
@@ -285,7 +294,21 @@ local function init_main(early_hook)
local load_fontloader_module = luaotfload.loaders.fontloader
local ignore_module = luaotfload.loaders.ignore
- load_fontloader_module "basics-gen"
+ do
+ local saved_reporter = texio.reporter
+ local saved_exit = os.exit
+ local errmsg
+ function texio.reporter(msg, ...)
+ print(...)
+ errmsg = msg
+ end
+ function os.exit()
+ error(errmsg)
+ end
+ load_fontloader_module "basics-gen"
+ texio.reporter = saved_reporter
+ os.exit = saved_exit
+ end
if early_hook then early_hook() end
@@ -324,66 +347,13 @@ local function init_main(early_hook)
load_fontloader_module (luaotfload.fontloader_package)
elseif fontloader == "unpackaged" then
+
logreport ("log", 0, "init",
"Loading fontloader components individually.")
- --- The loading sequence is known to change, so this might have to be
- --- updated with future updates. Do not modify it though unless there is
- --- a change to the upstream package!
-
- --- Since 2.6 those are directly provided by the Lualibs package.
- ignore_module "l-lua"
- ignore_module "l-lpeg"
- ignore_module "l-function"
- ignore_module "l-string"
- ignore_module "l-table"
- ignore_module "l-io"
- ignore_module "l-file"
- ignore_module "l-boolean"
- ignore_module "l-math"
- ignore_module "util-str"
- ignore_module "util-fil"
- ignore_module "luatex-basics-gen"
-
- load_fontloader_module "data-con"
- load_fontloader_module "basics-nod"
- load_fontloader_module "basics-chr"
- load_fontloader_module "font-ini"
- load_fontloader_module "fonts-mis"
- load_fontloader_module "font-con"
- load_fontloader_module "fonts-enc"
- load_fontloader_module "font-cid"
- load_fontloader_module "font-map"
--- load_fontloader_module "fonts-syn" -- ignore?
- load_fontloader_module "font-vfc"
- load_fontloader_module "font-otr"
- load_fontloader_module "font-oti"
- load_fontloader_module "font-ott"
- load_fontloader_module "font-cff"
- load_fontloader_module "font-ttf"
- load_fontloader_module "font-dsp"
- load_fontloader_module "font-oup"
- load_fontloader_module "font-otl"
- load_fontloader_module "font-oto"
- load_fontloader_module "font-otj"
- load_fontloader_module "font-ota"
- load_fontloader_module "font-ots"
- load_fontloader_module "font-osd"
- load_fontloader_module "font-ocl"
- load_fontloader_module "font-otc"
- load_fontloader_module "font-onr"
- load_fontloader_module "font-one"
- load_fontloader_module "font-afk"
- load_fontloader_module "fonts-tfm"
- load_fontloader_module "font-lua"
- load_fontloader_module "font-def"
- load_fontloader_module "fonts-def"
- load_fontloader_module "fonts-ext"
- load_fontloader_module "font-imp-tex"
- load_fontloader_module "font-imp-ligatures"
- load_fontloader_module "font-imp-italics"
- load_fontloader_module "font-imp-effects"
- load_fontloader_module "fonts-lig"
- load_fontloader_module "fonts-gbn"
+ for i = 1, #context_modules do
+ local mod = context_modules[i];
+ (mod[1] == ignore and ignore_module or load_fontloader_module)(mod[2])
+ end
elseif fontloader == "context" then
logreport ("log", 0, "init",
@@ -457,7 +427,9 @@ local init_post_install_callbacks = function ()
local handler = luaotfload.fontloader.nodes.simple_font_handler
local callback = function(head, groupcode, _, _, direction)
if not direction then
- direction = tex.get'textdir'
+ direction = tex.get'textdirection'
+ else
+ direction = direction == "TRT" and 1 or 0
end
multiscript(head, nil, nil, nil, direction)
fallback(head, nil, nil, nil, direction)
@@ -472,6 +444,14 @@ local init_post_install_callbacks = function ()
"luaotfload.node_processor",
1)
-- /MK
+
+ local streams = fonts.hashes.streams
+ luatexbase.add_to_callback("glyph_stream_provider",function(id,index,mode)
+ if id <= 0 then return "" end
+ local stream = streams[id].streams
+ if not stream then return "" end
+ return stream[index] or ""
+ end, "luaotfload.glyph_stream")
end
local function init_post_load_agl ()
diff --git a/macros/luatex/generic/luaotfload/luaotfload-latex.pdf b/macros/luatex/generic/luaotfload/luaotfload-latex.pdf
index fbdcad78c9..df1a8e0e86 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-latex.pdf
+++ b/macros/luatex/generic/luaotfload/luaotfload-latex.pdf
Binary files differ
diff --git a/macros/luatex/generic/luaotfload/luaotfload-letterspace.lua b/macros/luatex/generic/luaotfload/luaotfload-letterspace.lua
index 927fa68771..f9c24a1335 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-letterspace.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-letterspace.lua
@@ -5,9 +5,9 @@
local ProvidesLuaModule = {
name = "luaotfload-letterspace",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
- description = "luaotfload submodule / color",
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
+ description = "luaotfload submodule / letterspacing",
license = "GPL v2.0",
copyright = "PRAGMA ADE / ConTeXt Development Team",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL; adapted by Philipp Gesang, Ulrike Fischer, Marcel Krüger"
diff --git a/macros/luatex/generic/luaotfload/luaotfload-loaders.lua b/macros/luatex/generic/luaotfload/luaotfload-loaders.lua
index 02dd8359e6..a63506237a 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-loaders.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-loaders.lua
@@ -8,8 +8,8 @@
local ProvidesLuaModule = {
name = "luaotfload-loaders",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / callback handling",
license = "GPL v2.0"
}
diff --git a/macros/luatex/generic/luaotfload/luaotfload-log.lua b/macros/luatex/generic/luaotfload/luaotfload-log.lua
index 801310981d..b102da65bf 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-log.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-log.lua
@@ -6,8 +6,8 @@
local ProvidesLuaModule = {
name = "luaotfload-log",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / logging",
license = "GPL v2.0",
author = "Khaled Hosny, Elie Roux, Philipp Gesang",
diff --git a/macros/luatex/generic/luaotfload/luaotfload-main.lua b/macros/luatex/generic/luaotfload/luaotfload-main.lua
index 0c8a909c1b..5fa8c54ad3 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-main.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-main.lua
@@ -20,8 +20,8 @@ local authors = "\z
-- version number is used below!
local ProvidesLuaModule = {
name = "luaotfload-main",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload entry point",
author = authors,
copyright = authors,
@@ -40,7 +40,6 @@ luaotfload.log = luaotfload.log or { }
local logreport
luaotfload.version = ProvidesLuaModule.version
luaotfload.loaders = { }
-luaotfload.min_luatex_version = { 0, 95, 0 }
luaotfload.fontloader_package = "reference" --- default: from current Context
if not tex or not tex.luatexversion then
@@ -48,21 +47,14 @@ if not tex or not tex.luatexversion then
end
--- version check
-local major = tex.luatexversion / 100
-local minor = tex.luatexversion % 100
-local revision = tex.luatexrevision --[[ : string ]]
-local revno = tonumber (revision)
-local minimum = luaotfload.min_luatex_version
-local actual = { major, minor, revno or 0 }
-if actual [1] < minimum [1]
- or actual == minimum and actual [2] < minimum [2]
- or actual == minimum and actual [2] == minimum [2] and actual [3] < minimum [3]
-then
+local revno = tonumber(tex.luatexrevision)
+local minimum = { 110, 0 }
+if tex.luatexversion < minimum[1] or tex.luatexversion == minimum[1] and revno < minimum[2] then
texio.write_nl ("term and log",
string.format ("\tFATAL ERROR\n\z
\tLuaotfload requires a Luatex version >= %d.%d.%d.\n\z
\tPlease update your TeX distribution!\n\n",
- (unpack or table.unpack) (minimum)))
+ math.floor(minimum[1] / 100), minimum[1] % 100, minimum[2]))
error "version check failed"
end
@@ -234,13 +226,13 @@ local function context_loader (name, path)
local t_end = osgettimeofday ()
timing_info.t_load [name] = t_end - t_0
- if ret ~= true then
+ if ret ~= nil then
--- require () returns “true” upon success unless the loaded file
--- yields a non-zero exit code. This isn’t per se indicating that
--- something isn’t right, but against HH’s coding practices. We’ll
--- silently ignore this ever happening on lower log levels.
luaotfload.log.report ("log", 4, "load",
- "Module %q returned %q.", ret)
+ "Module %q returned %q.", modname, ret)
end
return ret
end
@@ -334,6 +326,9 @@ luaotfload.main = function ()
loadmodule "szss" --- missing glyph handling
initialize "auxiliary" --- additional high-level functionality
loadmodule "tounicode"
+ if tex.outputmode == 0 then
+ loadmodule "dvi" --- allow writing fonts to DVI files
+ end
luaotfload.aux.start_rewrite_fontname () --- to be migrated to fontspec
diff --git a/macros/luatex/generic/luaotfload/luaotfload-main.tex b/macros/luatex/generic/luaotfload/luaotfload-main.tex
index 69502b5b12..a1f79b7da4 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-main.tex
+++ b/macros/luatex/generic/luaotfload/luaotfload-main.tex
@@ -32,7 +32,7 @@
\beginfrontmatter
\setdocumenttitle {The \identifier{luaotfload} package}
- \setdocumentdate {2020-05-06 v3.14}
+ \setdocumentdate {2020-09-02 v3.15}
\setdocumentauthor {LaTeX3 Project\\
Elie Roux · Khaled Hosny · Philipp Gesang · Ulrike Fischer · Marcel Krüger\\
Home: \hyperlink {https://github.com/latex3/luaotfload}}
@@ -62,6 +62,27 @@ Supported is the \identifier{luatex} versions of a current TeXLive 2019 (and a c
\endsection
\beginsection{Changes}
+\beginsubsection {New in version 3.15 (by Ulrike Fischer/Marcel Krüger)}
+\begin{itemize}
+ \item The font database is updated more reliably if fonts get deleted.
+ \item In multiple error cases, error messages are shown instead of silently
+ generating bad output.
+ \item Write glyph ids instead of internal identifiers to DVI files. This
+ allows using OpenType fonts when working with \identifier{dvilualatex}.
+ (This requires additional support from the DVI reader)
+ \item The\marginpar{\mbox{}\hfill \textbf{Change!}} set of font features which
+ are enabled by default has been changed to be more similar to HarfBuzz.
+ Especially \enquote{Above-base mark Positioning} (abvm),
+ \enquote{Below-base mark Positioning} (blwm), \enquote{Contextual
+ Alternates} (calt), \enquote{Cursive Positioning} (curs),
+ \enquote{Distances} (dist), and \enquote{Required Contextual Alternates}
+ (rclt) are now enabled by default for all scripts.
+ \item Added a \identifier{mathfontdimen} font feature which allows emulating
+ fontdimen values from xetex or traditional \TeX\ math fonts.
+ \item Initial support for variable fonts in \identifier{node} mode.
+\end{itemize}
+\endsubsection
+
\beginsubsection {New in version 3.14 (by Ulrike Fischer/Marcel Krüger)}
\begin{itemize}
\item a bug in luaotfload-tool has been corrected (reported on the texlive list)
@@ -217,7 +238,7 @@ On the other side there is a lot new:
\beginaltitem {Lualibs} The update of the fontloader files also required an update of the \identifier{Lualibs} package. This \identifier{Luaotfload} version needs version 2.6 of \identifier{Lualibs}.
\endaltitem
- \beginaltitem {Maintenance} As the current maintainer wasn't available and it was urgent to get a \identifier{Luaotfload} compatible with \LUATEX 1.08/1.09 maintenance has been transfered to Ulrike Fischer and Marcel Krüger. The package was maintained and developed at \hyperlink{https://github.com/u-fischer/luaotfload}. Issues should be reported there.
+ \beginaltitem {Maintenance} As the current maintainer wasn't available and it was urgent to get a \identifier{Luaotfload} compatible with \LUATEX 1.08/1.09 maintenance has been transfered to Ulrike Fischer and Marcel Krüger. The package was maintained and developed at \hyperlink{https://github.com/u-fischer/luaotfload}.
\endaltitem
\beginaltitem {Documentation}
@@ -915,6 +936,52 @@ obviously, \inlinecode{random}.
\endaltitem
+ \beginaltitem {axis\&instance}
+ Experimental!\marginpar{\mbox{}\hfill NEW in v3.15!} Support for OpenType variable fonts. \emph{Varible fonts are only
+ supported in \texttt{base} and \texttt{node} mode, not in \texttt{harf}
+ mode.}
+
+ To specify the parameters of a variable font, you can either specify a
+ predefined instance of the font by passing the associated
+ \enquote{subfamily} name to \texttt{instance} or parameters for individual
+ axis can be provided using the \texttt{axis} feature. You can \emph{not}
+ use \texttt{instance} and \texttt{axis} together.
+
+ For example (needs the variable Fraunces font installed)
+
+ \beginlisting
+ \def\fraunces#1#2{%
+ \font\varfont = "Fraunces/B:mode=node;#1;" at #2pt\varfont
+ }
+ \fraunces{axis={wght=Regular}}{10}Regular font\par
+ \fraunces{axis={wght=Black}}{10}Black variant (aka. very bold)\par
+ \fraunces{axis={wght=Black,opsz=10}}{10}Black again, but with
+ correct optical size\par
+ \fraunces{axis={weight=100,opsz=10}}{10}Let's try giving axis values
+ numerically\par
+ \fraunces{instance=semibold}{10}A semi-bold one given as
+ a instance
+ (Corresponding to
+ \verb|axis={opsz=144,wght=600,SOFT=100,WONG=1}|)\par
+ \endlisting
+
+ {\def\fraunces#1#2{%
+ \font\varfont = "Fraunces/B:mode=node;#1;" at #2pt\varfont
+ }
+ \fraunces{axis={wght=Regular}}{10}Regular font\par
+ \fraunces{axis={wght=Black}}{10}Black variant (aka. very bold)\par
+ \fraunces{axis={wght=Black,opsz=10}}{10}Black again, but with
+ correct optical size\par
+ \fraunces{axis={weight=100,opsz=10}}{10}Let's try giving axis values
+ numerically\par
+ \fraunces{instance=semibold}{10}A semi-bold one given as a
+ instance\\
+ (Corresponding to
+ \verb|axis={opsz=144,wght=600,SOFT=100,WONG=1}|)\par
+ }
+
+ \endaltitem
+
\beginaltitem {embolden}
A factor, defined as a decimal number.
diff --git a/macros/luatex/generic/luaotfload/luaotfload-multiscript.lua b/macros/luatex/generic/luaotfload/luaotfload-multiscript.lua
index fe6cf17985..aae924c9de 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-multiscript.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-multiscript.lua
@@ -5,8 +5,8 @@
local ProvidesLuaModule = {
name = "luaotfload-multiscript",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / multiscript",
license = "GPL v2.0",
author = "Marcel Krüger"
diff --git a/macros/luatex/generic/luaotfload/luaotfload-notdef.lua b/macros/luatex/generic/luaotfload/luaotfload-notdef.lua
index e027d20666..f2043a7ad7 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-notdef.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-notdef.lua
@@ -5,9 +5,9 @@
local ProvidesLuaModule = {
name = "luaotfload-notdef",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
- description = "luaotfload submodule / color",
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
+ description = "luaotfload submodule / notdef",
license = "GPL v2.0",
author = "Marcel Krüger"
}
@@ -34,6 +34,8 @@ local setfont = node.direct.setfont
local traverse_char = node.direct.traverse_char
local traverse_id = node.direct.traverse_id
local setchar = node.direct.setchar
+local setdisc = node.direct.setdisc
+local getdisc = node.direct.getdisc
local getwidth = node.direct.getwidth
local setkern = node.direct.setkern
local setattributelist = node.direct.setattributelist
@@ -197,7 +199,7 @@ local push, pop do
head = node.direct.remove(head, n)
l[#l+1] = n
elseif id == disc_id then
- local pre, post, replace = node.direct.getdisc(n)
+ local pre, post, replace = getdisc(n)
for nn in node.direct.traverse(pre) do
if checkprop(nn) then
local after
@@ -217,7 +219,7 @@ local push, pop do
l[#l+1] = {nn, n, 'replace'}
end
end
- node.direct.setdisc(n, pre, post, replace)
+ setdisc(n, pre, post, replace)
end
end
return head
@@ -302,8 +304,6 @@ otfregister {
},
}
-ignorable_replacement = {}
-
local delayed_remove do
local delayed
function delayed_remove(n)
@@ -335,7 +335,7 @@ local function ignorablehandler(head, fid, ...) -- FIXME: The arguments are prob
end
end end
delayed_remove()
- for n in traverse_id(head, disc_id) do
+ for n in traverse_id(disc_id, head) do
local a, b, c = getdisc(n)
setdisc(ignorablehandler(a, fid), ignorablehandler(b, fid), ignorablehandler(c, fid))
end
diff --git a/macros/luatex/generic/luaotfload/luaotfload-parsers.lua b/macros/luatex/generic/luaotfload/luaotfload-parsers.lua
index c69cb86f56..f321e9733f 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-parsers.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-parsers.lua
@@ -7,9 +7,9 @@
local ProvidesLuaModule = {
name = "luaotfload-parsers",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
- description = "luaotfload submodule / filelist",
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
+ description = "luaotfload submodule / parsers",
license = "GPL v2.0"
}
@@ -779,19 +779,20 @@ local parse_config = Ct (ini_sections)
--doc]=]--
+luaotfload.parsers = {
+ --- parameters
+ traversal_maxdepth = traversal_maxdepth,
+ --- main parsers
+ read_fonts_conf = read_fonts_conf,
+ font_request = font_request,
+ config = parse_config,
+ --- common patterns
+ stripslashes = stripslashes,
+ splitcomma = splitcomma,
+}
+
return function ()
logreport = luaotfload.log.report
- luaotfload.parsers = {
- --- parameters
- traversal_maxdepth = traversal_maxdepth,
- --- main parsers
- read_fonts_conf = read_fonts_conf,
- font_request = font_request,
- config = parse_config,
- --- common patterns
- stripslashes = stripslashes,
- splitcomma = splitcomma,
- }
return true
end
diff --git a/macros/luatex/generic/luaotfload/luaotfload-resolvers.lua b/macros/luatex/generic/luaotfload/luaotfload-resolvers.lua
index 14a503bb14..b7ca21ec87 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-resolvers.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-resolvers.lua
@@ -11,8 +11,8 @@
local ProvidesLuaModule = {
name = "luaotfload-resolvers",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / resolvers",
license = "GPL v2.0"
}
@@ -233,7 +233,7 @@ local function resolve_kpse (specification)
local name = specification.name
local suffix = stringlower (filesuffix (name))
if suffix and fonts.formats[suffix] then
- local resolved = resolvers.findfile(name, suffix)
+ local resolved = resolvers_findfile(name, suffix)
if resolved then return resolved end
end
for t, format in next, fonts.formats do --- brute force
@@ -292,7 +292,7 @@ return function()
end
logreport ("log", 5, "resolvers", "installing font resolvers", name)
local request_resolvers = fonts.definers.resolvers
- for k, _ in pairs(resolvers) do
+ for k, _ in pairs(request_resolvers) do
request_resolvers[k] = nil
end
setmetatable(request_resolvers, {__index = function(t, n)
diff --git a/macros/luatex/generic/luaotfload/luaotfload-scripts.lua b/macros/luatex/generic/luaotfload/luaotfload-scripts.lua
index fb842c5532..6ac19f14d5 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-scripts.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-scripts.lua
@@ -5,8 +5,8 @@
local ProvidesLuaModule = {
name = "luaotfload-script",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / Script helpers",
license = "CC0 1.0 Universal",
author = "Marcel Krüger"
diff --git a/macros/luatex/generic/luaotfload/luaotfload-status.lua b/macros/luatex/generic/luaotfload/luaotfload-status.lua
index 69fa2f6ab5..dd38631cc8 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-status.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-status.lua
@@ -1,97 +1,97 @@
return {
["hashes"]={
- { "fontloader-2020-05-06.lua", "cb465e20137d75429cb876688189ff36" },
- { "fontloader-util-fil.lua", "4bb3e4dc72e308d8ed67cd7a80027fa7" },
- { "fontloader-util-str.lua", "2c1a12d8248d3719c0b5fc93184242bf" },
- { "fontloader-l-unicode.lua", "9bc311ce08ce498f9caacb6164ea1d9f" },
- { "fontloader-l-math.lua", "a373be3ed2db0d5f98588fa81abca48f" },
- { "fontloader-l-boolean.lua", "18ed6c4b2c40dd87224ea33229548d20" },
- { "fontloader-l-file.lua", "60ddd3948d9de7bde8b4a0f5c51ff9f5" },
- { "fontloader-l-io.lua", "a4042e9d6bce71c61fdd94e6e17f2bf4" },
- { "fontloader-l-table.lua", "20c03ae1b81e902217f3f76995b9d294" },
- { "fontloader-l-string.lua", "e1347bef0eeeff9f098df83b30b32df9" },
- { "fontloader-l-function.lua", "f771cc91839ebcdfc094083434fbe00f" },
- { "fontloader-l-lpeg.lua", "efe630e3a9a1d269120e59cfd8fba4ba" },
- { "fontloader-l-lua.lua", "4185c43dd58d217094ef91c0310d8772" },
- { "fontloader-fonts-gbn.lua", "d25472d54c4841db43a745764a63533e" },
- { "fontloader-fonts-lig.lua", "b9dbe77ce747d4c35bb2a20ffbe5aa51" },
- { "fontloader-fonts-ext.lua", "01015ab3758cdc2af29394e6d502a91a" },
- { "fontloader-fonts-def.lua", "5ad79120ebc5e60f4d322fb3ee13bffe" },
- { "fontloader-fonts-tfm.lua", "3bbba3214fd0b8c6f35ad85592fc2917" },
- { "fontloader-fonts-enc.lua", "3e71a54297e8f85a1ac438bb0f20dd79" },
- { "fontloader-fonts-mis.lua", "bc9eb43c27f63ce9d0fff67e104fe1c6" },
- { "fontloader-basics-chr.lua", "58b7ef0c486e06090b362971b9f85e27" },
- { "fontloader-basics-nod.lua", "68226d7dadd241bca55171af9ce1f243" },
- { "fontloader-font-imp-effects.lua", "73a660359a0ec71e44cc2b7225a715ac" },
- { "fontloader-font-imp-italics.lua", "fe1ca80fb5ea4a2f8d2d5c484e7ba913" },
- { "fontloader-font-imp-ligatures.lua", "043daa4fcccf2560868da359d71d3a4a" },
- { "fontloader-font-imp-tex.lua", "77c374b0ef00c2fb12188ec42beb4257" },
- { "fontloader-font-def.lua", "c525b9f55da1c736a1f6939c0a6f8f00" },
- { "fontloader-font-lua.lua", "55b281fb98f7bd848fc19928f376f647" },
- { "fontloader-font-afk.lua", "54d554530e75c57c56ee76234724e26d" },
- { "fontloader-font-one.lua", "987c5c5ed3754ad2feab80985067d59e" },
- { "fontloader-font-onr.lua", "22572ec0f86f53631e14b6d1ed43ee51" },
- { "fontloader-font-otc.lua", "1204a2fdc436e644127c0aa38ab69607" },
- { "fontloader-font-ocl.lua", "ee310c8d0ac411d5ba6b50d338548013" },
- { "fontloader-font-osd.lua", "61f05fcf91add1aa5dac9bc8b235adc9" },
- { "fontloader-font-ots.lua", "113b7ad0c40d4786bb026706e479c3f3" },
- { "fontloader-font-ota.lua", "dd5f1c8ba28abaf4505fd960d04a3a98" },
- { "fontloader-font-otj.lua", "c9ded1d935bfa43020657e1f408fb820" },
- { "fontloader-font-oto.lua", "24238a7c600d090a8ee88312321dd9b3" },
- { "fontloader-font-otl.lua", "f111f9ac18d24049fadeb8883e4e8da5" },
- { "fontloader-font-oup.lua", "1700a2dac4f8b105c187d4e5b84cecdf" },
- { "fontloader-font-dsp.lua", "618e5e760ec5dceb0c898a83816dbe61" },
- { "fontloader-font-ttf.lua", "44e61cef50dab9b1aaf48130f9367c34" },
- { "fontloader-font-cff.lua", "155821e11e84021437869ff973e75d93" },
- { "fontloader-font-ott.lua", "aba6d8335a5f38a5a62d3631492f3392" },
- { "fontloader-font-oti.lua", "dbae7722baae24d917a17176553825cf" },
- { "fontloader-font-otr.lua", "d96724dcb40c673ac294df7044a39925" },
- { "fontloader-font-vfc.lua", "94937140f2c909e9c831ba021f1ab303" },
- { "fontloader-font-map.lua", "51d0362c19d2d0f621e5cb750410a809" },
- { "fontloader-font-cid.lua", "4d87988efa86020a14708ee03c23415f" },
- { "fontloader-font-con.lua", "40e3a857b2f31be1959dc6d445aaa9c4" },
- { "fontloader-font-ini.lua", "4dee96e1e1474d324dd126bd5d375df8" },
- { "fontloader-data-con.lua", "de6ae0997b0e70a23bcc9afff5d8b072" },
- { "fontloader-reference.lua", "2479b532aa53f60c4a83041c4f0e6632" },
- { "fontloader-basics-gen.lua", "b88f9848c3247e4222b7bb63b0ee3f35" },
- { "mktests", "c7cff7025962922944376acc1ffa9c47" },
- { "mkstatus", "8f230b751f58ec989604884a58cb5cfa" },
- { "mkcharacters", "92c24bb582fc84c0365634f29eb89863" },
- { "mkglyphlist", "95bbf91338214d40b2102114285ccd3f" },
- { "mkimport", "60e0b11a1a68719033e86a3e0f4d5e86" },
- { "luaotfload-glyphlist.lua", "f14bb296a5a4eb9a6cb130f6a703d160" },
- { "luaotfload-characters.lua", "6a46f4749368e4f56a863da9c61b7bd6" },
- { "luaotfload-tounicode.lua", "610d27c11ea928a7a299ada038db3a6d" },
- { "luaotfload-unicode.lua", "737a96fb0cd50197bb2ceb6e28fec021" },
- { "luaotfload-resolvers.lua", "8349bdce20fa37470f985f1aabc7946f" },
- { "luaotfload-parsers.lua", "f61808c1b01a3a40385b3e74f8171c3e" },
- { "luaotfload-fallback.lua", "5d613223f8153767305bd8d3d4387de7" },
- { "luaotfload-szss.lua", "58a838170ea2d61affee0a83cbf602c2" },
- { "luaotfload-scripts.lua", "702a128883d033ab9f3726ba2e21fc8d" },
- { "luaotfload-multiscript.lua", "7089c788fa75d8074e73919532fefa92" },
- { "luaotfload-loaders.lua", "53d26bba499abf18cf823675c77e36de" },
- { "luaotfload-harf-plug.lua", "840abb8a4965dd32532cc73e670f5906" },
- { "luaotfload-harf-define.lua", "ba5861271933078de634b9e00172f69a" },
- { "luaotfload-notdef.lua", "af12a1afe613f42b0d8d1033776eefaf" },
- { "luaotfload-embolden.lua", "9f2cda5502e5a0ceb6402f6dd075732f" },
- { "luaotfload-letterspace.lua", "06639c9e935da07c4694da6579a36781" },
- { "luaotfload-features.lua", "0bd3943f65c0688738407ff1a186900f" },
- { "luaotfload-database.lua", "8e9e26a9acd048ec1217fad9fa80cd0d" },
- { "luaotfload-configuration.lua", "827b91b6f6881a69ea48885093f10c71" },
- { "luaotfload-colors.lua", "23cfde48b9609e33e9b809a3ebd1a670" },
- { "luaotfload-auxiliary.lua", "50a56ccd209e59b66514c483fd8af85d" },
- { "luaotfload-filelist.lua", "e3139b052bc5789b9135c1eb20753d3e" },
- { "luaotfload-tool.lua", "89fc62620ef6f534ea1f6a3f6253886b" },
- { "luaotfload-diagnostics.lua", "a4635cd5da922b6cb3ef27e74a3cf6d8" },
- { "luaotfload-log.lua", "b37a69c07eecaecc17d2d069e088b133" },
- { "luaotfload-init.lua", "8c9b852cdf019fa43c938618773ecd5e" },
- { "luaotfload-main.lua", "5ccffdfbe87102c13d6d1910873935d3" },
+ { "fontloader-2020-08-31.lua", "70a72561e3869bcaa8554921083b3872" },
+ { "fontloader-util-fil.lua", "aae2a2add764144bb58dd8216fd59260" },
+ { "fontloader-util-str.lua", "c975ff7bbd178163cf47d9e9296c8b4b" },
+ { "fontloader-l-unicode.lua", "f368874f11f3c525de5864fd413e4b24" },
+ { "fontloader-l-math.lua", "082add08e0bb79f39191ae9534a79849" },
+ { "fontloader-l-boolean.lua", "abe28515dd33e8f6c416c09bca351cf8" },
+ { "fontloader-l-file.lua", "352b42b8360ada02ceb26a41f0bd2a76" },
+ { "fontloader-l-io.lua", "bbcc4824d0ded30b415d7d2d5763028a" },
+ { "fontloader-l-table.lua", "0330da8b3a08d39876def70df8d9c0e5" },
+ { "fontloader-l-string.lua", "9457f2af85723e0e6c46d0b5122e9000" },
+ { "fontloader-l-function.lua", "a7e68a9703c35238729da41a474e951b" },
+ { "fontloader-l-lpeg.lua", "10bdaef44175902917691835010ae5f5" },
+ { "fontloader-l-lua.lua", "420bc442e6d81f4624728a6c56fcd175" },
+ { "fontloader-fonts-gbn.lua", "10ecdf01e7c926e5128ad8a9dff4d677" },
+ { "fontloader-fonts-lig.lua", "fbd251eea3810a43a8d5542319361d68" },
+ { "fontloader-fonts-ext.lua", "32013cbc5d5d336be8b1d1e5879d86c4" },
+ { "fontloader-fonts-def.lua", "f435e0875f203f343157baeff876ec9c" },
+ { "fontloader-fonts-tfm.lua", "f0eb5e2a8068b17ad401bb7efdba1630" },
+ { "fontloader-fonts-enc.lua", "5ff4ca50493d7c4ecea0e15c203099f0" },
+ { "fontloader-fonts-mis.lua", "17e967c9ec4d001deefd43ddf25e98f7" },
+ { "fontloader-basics-chr.lua", "64fafe4eaf55d64aead6513c1e74a024" },
+ { "fontloader-basics-nod.lua", "335e61ffb6dec00f88f737854a2d9ab4" },
+ { "fontloader-font-imp-effects.lua", "d9b935e9b73f250a175ddd71a226b8e9" },
+ { "fontloader-font-imp-italics.lua", "ae563638fa29a4ff3e8e4d1e81fd35ae" },
+ { "fontloader-font-imp-ligatures.lua", "26ffcf089391445f7af59536c8814364" },
+ { "fontloader-font-imp-tex.lua", "ceb087ef6fa2f89aed7179f60ddf8f35" },
+ { "fontloader-font-def.lua", "b9d908c2338b7dc443ce9d1e9fcb7139" },
+ { "fontloader-font-lua.lua", "1fbfdf7b689b2bdfd0e3bb9bf74ce136" },
+ { "fontloader-font-afk.lua", "9da14e0fb22129c053acc599d1312544" },
+ { "fontloader-font-one.lua", "5a2f244c88c8178e997c16a9b628bb6f" },
+ { "fontloader-font-onr.lua", "6d161533f3437435e12a0ad64866df44" },
+ { "fontloader-font-otc.lua", "0f12230ea07b5151f75d52726977e91f" },
+ { "fontloader-font-ocl.lua", "797b5c71bf819c5f4fb314a4d646e9a7" },
+ { "fontloader-font-osd.lua", "73c9531c79df5ada320cb20777f7ed49" },
+ { "fontloader-font-ots.lua", "f018ae1f355a8ef5c8d403cc5489e3d3" },
+ { "fontloader-font-ota.lua", "ad1d5de06400f88829509e1f3ff2b473" },
+ { "fontloader-font-otj.lua", "8de59cb9b043e5f73c6b9f7cc8f6978e" },
+ { "fontloader-font-oto.lua", "2b1d6bc63b2ebf8f2655a15e1cda6541" },
+ { "fontloader-font-otl.lua", "b168cf69300873d6668203bc7afe1f56" },
+ { "fontloader-font-oup.lua", "6f46aa00ae1c20c43f8ffaf329dc8695" },
+ { "fontloader-font-dsp.lua", "5d6528c0673b7651600ca6b763b51df5" },
+ { "fontloader-font-ttf.lua", "786a535ba0385446b7015260388bc415" },
+ { "fontloader-font-cff.lua", "802a10ad12ac32329f540881f940e3f2" },
+ { "fontloader-font-ott.lua", "673ed11e1d159997f535bfec5fa73808" },
+ { "fontloader-font-oti.lua", "309a75f9c14b77d87e94eba827dc4e71" },
+ { "fontloader-font-otr.lua", "64dcbbc7107538723990e1119a80a9f8" },
+ { "fontloader-font-vfc.lua", "a81c29eda98cd62cbebdb6c93544b50d" },
+ { "fontloader-font-map.lua", "c4a39db5ad822b348aa61bca5f4a599a" },
+ { "fontloader-font-cid.lua", "22b0367742fb253deef84ef7ccf5e8de" },
+ { "fontloader-font-con.lua", "a3eb543fa5946fa1faf0e1e50d5b3b91" },
+ { "fontloader-font-ini.lua", "5343de60613adb24cdd7a8d2ee1d153c" },
+ { "fontloader-data-con.lua", "23a0f5386d46a1c157ae82a373e35fa0" },
+ { "fontloader-reference.lua", "c10086745bc0b8b2303572fdea86d61c" },
+ { "fontloader-basics-gen.lua", "4bc43036e9796fccb0b8869f4b05bf2e" },
+ { "mktests", "918cb50be9ee8bd645ac1a27dc501e8c" },
+ { "mkstatus", "49692433db8a578cf3a03fbedfb2ea9c" },
+ { "mkcharacters", "bfca0e96e1e351afe7077502f9595af9" },
+ { "mkglyphlist", "7a8a8fdc0eac7fac2f13ec8f4e8e7aa9" },
+ { "mkimport", "7d62f1042e548f8b9368f26b9ba4be5c" },
+ { "luaotfload-glyphlist.lua", "af60521c7ea3f5828c83ed1d1fa23b45" },
+ { "luaotfload-characters.lua", "76415ca3ede312cad6e09038323489ae" },
+ { "luaotfload-tounicode.lua", "24601f0255c35508eddbb427a6e18873" },
+ { "luaotfload-unicode.lua", "c7d3f282db7a0f9588cc57d8f079a3cb" },
+ { "luaotfload-resolvers.lua", "ac9e134e0614ab7ab69122ec0fd99e54" },
+ { "luaotfload-parsers.lua", "10afafb81544840cb0fd0ecaac3c3344" },
+ { "luaotfload-fallback.lua", "9d70a346c2584834f40d83be25d53a6a" },
+ { "luaotfload-szss.lua", "0e29a05f35bbd05388e5af674059c242" },
+ { "luaotfload-scripts.lua", "9a1e50e55ddef481ca3863004f33703e" },
+ { "luaotfload-multiscript.lua", "8a828bf429dc73742ea78ad73332d219" },
+ { "luaotfload-loaders.lua", "f13bafee1dca48db5073fe4390dc8ec4" },
+ { "luaotfload-harf-plug.lua", "f43e0d894cf9ca3f31ff405d1684a5ff" },
+ { "luaotfload-harf-define.lua", "0aecef4ea82a6edc305be2eed7b8e9c9" },
+ { "luaotfload-notdef.lua", "73762a6d7662aa090f8f950a34d55835" },
+ { "luaotfload-embolden.lua", "3444350537a12803b8e255f56b33b50d" },
+ { "luaotfload-letterspace.lua", "6ac6c8d6f54107984ad338a94f0acd86" },
+ { "luaotfload-features.lua", "b42fbc57c4fb1306dc23bf4e3bf6cd98" },
+ { "luaotfload-database.lua", "8e11e69cf6a83bc1723c95e4788cdc70" },
+ { "luaotfload-configuration.lua", "d1f4d64caa58bfc5feb524ea7cd365f6" },
+ { "luaotfload-colors.lua", "5d1e7e10b5a8dda7ccf3742ae90f002e" },
+ { "luaotfload-auxiliary.lua", "6d4e31212b8852e5f1425dc0ea49e016" },
+ { "luaotfload-filelist.lua", "5e4c15ea6e5aafc19a533289b6ac2709" },
+ { "luaotfload-tool.lua", "9caf618c38bf58cf9a29f2b2d4449346" },
+ { "luaotfload-diagnostics.lua", "797176921da30591e6112831ed7459a7" },
+ { "luaotfload-log.lua", "932117045a6abfe303314a295c24d338" },
+ { "luaotfload-init.lua", "eb1bfca3833688aba31521032ed38883" },
+ { "luaotfload-main.lua", "133ee97a73e07f3116d0417c9373398b" },
},
["notes"]={
["committer"]="Marcel Fabian Krüger <tex@2krueger.de>",
- ["description"]="v3.14/2020-05-06",
- ["loader"]="fontloader-2020-05-06.lua",
- ["revision"]="79077b0311ec65e8eb3c60bfc306500d72fd270e",
- ["timestamp"]="2020-05-06 20:58:39 +0200",
+ ["description"]="v3.15/2020-09-02",
+ ["loader"]="fontloader-2020-08-31.lua",
+ ["revision"]="77eede02640bef0cb596d24aa79661328a68b448",
+ ["timestamp"]="2020-09-02 21:02:40 +0200",
},
} \ No newline at end of file
diff --git a/macros/luatex/generic/luaotfload/luaotfload-suppress.lua b/macros/luatex/generic/luaotfload/luaotfload-suppress.lua
index 50a0037c43..768cf81402 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-suppress.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-suppress.lua
@@ -5,8 +5,8 @@
local ProvidesLuaModule = {
name = "luaotfload-suppress",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / suppress",
license = "GPL v2.0",
author = "Marcel Krüger"
diff --git a/macros/luatex/generic/luaotfload/luaotfload-szss.lua b/macros/luatex/generic/luaotfload/luaotfload-szss.lua
index de3b47230c..751964cdd1 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-szss.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-szss.lua
@@ -5,9 +5,9 @@
local ProvidesLuaModule = {
name = "luaotfload-szss",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
- description = "luaotfload submodule / color",
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
+ description = "luaotfload submodule / Special feature handling",
license = "GPL v2.0",
author = "Marcel Krüger"
}
diff --git a/macros/luatex/generic/luaotfload/luaotfload-tool.1 b/macros/luatex/generic/luaotfload/luaotfload-tool.1
index 98d1a0abc5..ea2d12e9eb 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-tool.1
+++ b/macros/luatex/generic/luaotfload/luaotfload-tool.1
@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
-.TH LUAOTFLOAD-TOOL 1 "2020-05-06" "3.14" "text processing"
+.TH LUAOTFLOAD-TOOL 1 "2020-09-02" "3.15" "text processing"
.SH NAME
luaotfload-tool \- generate and query the Luaotfload font names database
.
diff --git a/macros/luatex/generic/luaotfload/luaotfload-tool.lua b/macros/luatex/generic/luaotfload/luaotfload-tool.lua
index eabd8e4434..18334d5ab3 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-tool.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-tool.lua
@@ -9,8 +9,8 @@
local ProvidesLuaModule = {
name = "luaotfload-tool",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload-tool / database functionality",
license = "GPL v2.0"
}
@@ -23,7 +23,6 @@ end
luaotfload = luaotfload or { }
local version = ProvidesLuaModule.version
luaotfload.version = ProvidesLuaModule.version
-luaotfload.min_luatex_version = { 0, 95, 0 }
luaotfload.self = "luaotfload-tool"
luaotfload.fontloader = _G -- We don't isolate the fontloader here
@@ -65,32 +64,21 @@ local tonumber = tonumber
local type = type
do
- local runtime = _G.jit and { "jit" , jit.version }
- or { "stock", _VERSION }
- local stats = status and status.list ()
- local minimum = luaotfload.min_luatex_version
- local actual = { 0, 0, 0 }
- if stats then
- local major = stats.luatex_version // 100
- local minor = stats.luatex_version % 100
- local revision = stats.luatex_revision --[[ : string ]]
- local revno = tonumber (revision)
- actual = { major, minor, revno or 0 }
- end
-
- if actual [1] < minimum [1]
- or actual == minimum and actual [2] < minimum [2]
- or actual == minimum and actual [2] == minimum [2] and actual [3] < minimum [3]
- then
+ local runtime = _G.jit and { "jit" , jit.version }
+ or { "stock", _VERSION }
+ local minimum = {110, 0}
+ local revn = tonumber (status.luatex_revision) or 0 --[[ : string ]]
+
+ if status.luatex_version < minimum[1]
+ or status.luatex_version == minimum[1] and status.luatex_revision < minimum[2] then
texio.write_nl ("term and log",
string.format ("\tFATAL ERROR\n\z
\tLuaotfload requires a Luatex version >= %d.%d.%d.\n\z
\tPlease update your TeX distribution!\n\n",
- (unpack or table.unpack) (minimum)))
+ math.floor(minimum[1] / 100), minimum[1] % 100, minimum[2]))
error "version check failed"
end
luaotfload.runtime = runtime
- luaotfload.luatex_version = actual
end
local C, Ct, P, S = lpeg.C, lpeg.Ct, lpeg.P, lpeg.S
@@ -349,8 +337,7 @@ local function version_msg ( )
local meta = fonts.names.getmetadata ()
local runtime = luaotfload.runtime
- local actual = luaotfload.luatex_version
- local status = config.luaotfload.status
+ local notes = config.luaotfload.status
local notes = status and status.notes or { }
out (about, luaotfload.self)
@@ -361,7 +348,7 @@ local function version_msg ( )
out ("Revision: %q", notes.revision)
out ("Lua interpreter: %s; version %q", runtime[1], runtime[2])
--[[out ("Luatex SVN revision: %d", info.luatex_svn)]] --> SVN r5624
- out ("Luatex version: %d.%d", actual [1], actual [2])
+ out ("Luatex version: %d.%d", math.floor(status.luatex_version / 100), status.luatex_version % 100)
out ("Platform: type=%s name=%s", os.type, os.name)
local uname_vars = tablesortedkeys (uname)
diff --git a/macros/luatex/generic/luaotfload/luaotfload-tool.pdf b/macros/luatex/generic/luaotfload/luaotfload-tool.pdf
index 142a65e486..6697476a0e 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-tool.pdf
+++ b/macros/luatex/generic/luaotfload/luaotfload-tool.pdf
Binary files differ
diff --git a/macros/luatex/generic/luaotfload/luaotfload-tool.rst b/macros/luatex/generic/luaotfload/luaotfload-tool.rst
index 20ab6b253e..c030ab81f2 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-tool.rst
+++ b/macros/luatex/generic/luaotfload/luaotfload-tool.rst
@@ -6,9 +6,9 @@
generate and query the Luaotfload font names database
-----------------------------------------------------------------------
-:Date: 2020-05-06
+:Date: 2020-09-02
:Copyright: GPL v2.0
-:Version: 3.14
+:Version: 3.15
:Manual section: 1
:Manual group: text processing
diff --git a/macros/luatex/generic/luaotfload/luaotfload-tounicode.lua b/macros/luatex/generic/luaotfload/luaotfload-tounicode.lua
index 73bab11709..028aef9d12 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-tounicode.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-tounicode.lua
@@ -5,8 +5,8 @@
local ProvidesLuaModule = {
name = "luaotfload-tounicode",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / tounicode",
license = "GPL v2.0",
author = "Hans Hagen, Khaled Hosny, Elie Roux, Philipp Gesang, Marcel Krüger",
diff --git a/macros/luatex/generic/luaotfload/luaotfload-unicode.lua b/macros/luatex/generic/luaotfload/luaotfload-unicode.lua
index 0fd71ec27a..2e9b28cf79 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-unicode.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-unicode.lua
@@ -5,8 +5,8 @@
local ProvidesLuaModule = {
name = "luaotfload-unicode",
- version = "3.14", --TAGVERSION
- date = "2020-05-06", --TAGDATE
+ version = "3.15", --TAGVERSION
+ date = "2020-09-02", --TAGDATE
description = "luaotfload submodule / Unicode helpers",
license = "CC0 1.0 Universal",
author = "Marcel Krüger"
diff --git a/macros/luatex/generic/luaotfload/luaotfload.conf.5 b/macros/luatex/generic/luaotfload/luaotfload.conf.5
index 54a845709f..0035ce834f 100644
--- a/macros/luatex/generic/luaotfload/luaotfload.conf.5
+++ b/macros/luatex/generic/luaotfload/luaotfload.conf.5
@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
-.TH LUAOTFLOAD.CONF 5 "2020-05-06" "3.14" "text processing"
+.TH LUAOTFLOAD.CONF 5 "2020-09-02" "3.15" "text processing"
.SH NAME
luaotfload.conf \- Luaotfload configuration file
.
diff --git a/macros/luatex/generic/luaotfload/luaotfload.conf.rst b/macros/luatex/generic/luaotfload/luaotfload.conf.rst
index 589fcd9825..d40cb3a967 100644
--- a/macros/luatex/generic/luaotfload/luaotfload.conf.rst
+++ b/macros/luatex/generic/luaotfload/luaotfload.conf.rst
@@ -6,9 +6,9 @@
Luaotfload configuration file
-----------------------------------------------------------------------
-:Date: 2020-05-06
+:Date: 2020-09-02
:Copyright: GPL v2.0
-:Version: 3.14
+:Version: 3.15
:Manual section: 5
:Manual group: text processing
diff --git a/macros/luatex/generic/luaotfload/luaotfload.sty b/macros/luatex/generic/luaotfload/luaotfload.sty
index 590a0b27ab..33e15ba7c3 100644
--- a/macros/luatex/generic/luaotfload/luaotfload.sty
+++ b/macros/luatex/generic/luaotfload/luaotfload.sty
@@ -1,4 +1,4 @@
-%% Copyright (C) 2009-2018
+%% Copyright (C) 2009-2020
%%
%% by Elie Roux <elie.roux@telecom-bretagne.eu>
%% and Khaled Hosny <khaledhosny@eglug.org>
@@ -8,9 +8,8 @@
%%
%% This file is part of Luaotfload.
%%
-%% Home: https://github.com/lualatex/luaotfload
-%%Current home: https://github.com/u-fischer/luaotfload
-%% Support: <lualatex-dev@tug.org>.
+%% Home: https://github.com/latex3/luaotfload
+%% Support: https://github.com/latex3/luaotfload/issues, <lualatex-dev@tug.org>.
%%
%% Luaotfload is under the GPL v2.0 (exactly) license.
%%
@@ -40,7 +39,7 @@
\fi
\ifdefined\ProvidesPackage
\ProvidesPackage{luaotfload}%
- [2020/05/06 v3.14 OpenType layout system]
+ [2020/09/02 v3.15 OpenType layout system]
\fi
\directlua{
if xpcall(function ()%
diff --git a/macros/luatex/generic/luaotfload/scripts-demo.pdf b/macros/luatex/generic/luaotfload/scripts-demo.pdf
index 319824cb1e..60b7e524de 100644
--- a/macros/luatex/generic/luaotfload/scripts-demo.pdf
+++ b/macros/luatex/generic/luaotfload/scripts-demo.pdf
Binary files differ
diff --git a/macros/luatex/generic/luaotfload/shaper-demo-graphite.pdf b/macros/luatex/generic/luaotfload/shaper-demo-graphite.pdf
index 602f3ce86f..8eb287e081 100644
--- a/macros/luatex/generic/luaotfload/shaper-demo-graphite.pdf
+++ b/macros/luatex/generic/luaotfload/shaper-demo-graphite.pdf
Binary files differ
diff --git a/macros/luatex/generic/luaotfload/shaper-demo.pdf b/macros/luatex/generic/luaotfload/shaper-demo.pdf
index 8861d5067a..77a7463630 100644
--- a/macros/luatex/generic/luaotfload/shaper-demo.pdf
+++ b/macros/luatex/generic/luaotfload/shaper-demo.pdf
Binary files differ