summaryrefslogtreecommitdiff
path: root/macros/luatex/generic
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2022-02-26 03:00:34 +0000
committerNorbert Preining <norbert@preining.info>2022-02-26 03:00:34 +0000
commit740a11f29a3551babe3d7edbb57ac3baa2280a3f (patch)
tree5d6d449e762f5ab95042e3517d03c5ac3ddaf7c3 /macros/luatex/generic
parent157cc9e776520d0b7d488317a69a10d4ae4d493b (diff)
CTAN sync 202202260300
Diffstat (limited to 'macros/luatex/generic')
-rw-r--r--macros/luatex/generic/luaotfload/NEWS15
-rw-r--r--macros/luatex/generic/luaotfload/README.md4
-rw-r--r--macros/luatex/generic/luaotfload/filegraph.pdfbin40024 -> 40019 bytes
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-2022-02-24.lua (renamed from macros/luatex/generic/luaotfload/fontloader-2021-05-20.lua)1955
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-basics-chr.lua234
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-basics-gen.lua2
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-basics-nod.lua2
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-cff.lua29
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-dsp.lua2
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-osd.lua636
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-otc.lua353
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-otl.lua32
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-oto.lua77
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-otr.lua73
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-ots.lua121
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-oup.lua193
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-shp.lua4
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-font-ttf.lua276
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-fonts-enc.lua10
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-l-file.lua2
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-l-io.lua10
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-l-lpeg.lua12
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-l-math.lua2
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-reference.lua1836
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-util-fil.lua18
-rw-r--r--macros/luatex/generic/luaotfload/fontloader-util-str.lua59
-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.pdfbin77497 -> 77690 bytes
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-configuration.lua8
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-database.lua579
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-diagnostics.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-dvi.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-embolden.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-fallback.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-features.lua101
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-filelist.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-harf-define.lua164
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua51
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-harf-var-cff2.lua442
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-harf-var-t2-writer.lua120
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-harf-var-ttf.lua564
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-init.lua10
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-latex.pdfbin494977 -> 494376 bytes
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-letterspace.lua26
-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.tex24
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-multiscript.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-notdef.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-parsers.lua6
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-resolvers.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-scripts.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-status.lua108
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-suppress.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-szss.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-t3.lua142
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-tool.12
-rw-r--r--[-rwxr-xr-x]macros/luatex/generic/luaotfload/luaotfload-tool.lua4
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-tool.pdfbin77067 -> 76959 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.514
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload.conf.rst10
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload.lua13
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload.sty2
-rw-r--r--macros/luatex/generic/luaotfload/scripts-demo.pdfbin21837 -> 22075 bytes
-rw-r--r--macros/luatex/generic/luaotfload/shaper-demo-graphite.pdfbin8559 -> 8560 bytes
-rw-r--r--macros/luatex/generic/luaotfload/shaper-demo.pdfbin8479 -> 8481 bytes
71 files changed, 6158 insertions, 2265 deletions
diff --git a/macros/luatex/generic/luaotfload/NEWS b/macros/luatex/generic/luaotfload/NEWS
index f6e4e0fcb7..44b749c352 100644
--- a/macros/luatex/generic/luaotfload/NEWS
+++ b/macros/luatex/generic/luaotfload/NEWS
@@ -1,5 +1,20 @@
Change History
--------------
+2022-02-24 luaotfload v3.19
+
+ * When used with LuaTeX 1.15.0 or newer, variable fonts are supported
+ when using the harf shaper too.
+ * A new algorithm for selecting fonts based on font family names allows
+ to more reliably load fonts based on their family name.
+ * The compiled font database gets compressed to reduce disk space and
+ improve performance on newer systems.
+ * Text automatically gets normalized to Unicode's NFC before shaping.
+ This improves rendering for text written in decomposed forms for many
+ fonts. This can be turned off by passing the -normalize font feature.
+ * The fontloader has been synced with the context code from 2022-02-24.
+ This fixes some broken rendering of TrueType based variable fonts.
+ * A number of small bugfixes.
+
2021-05-21 luaotfload v3.18
* Allow using variable fonts without explicitly specifying any axis values
diff --git a/macros/luatex/generic/luaotfload/README.md b/macros/luatex/generic/luaotfload/README.md
index a58b1c99fb..565733e6c5 100644
--- a/macros/luatex/generic/luaotfload/README.md
+++ b/macros/luatex/generic/luaotfload/README.md
@@ -1,8 +1,8 @@
# The Luaotfload Package
-VERSION: 3.18
+VERSION: 3.19
-DATE: 2021-05-21
+DATE: 2022-02-24
## Description
diff --git a/macros/luatex/generic/luaotfload/filegraph.pdf b/macros/luatex/generic/luaotfload/filegraph.pdf
index 0704762fd1..b455173c6b 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/fontloader-2021-05-20.lua b/macros/luatex/generic/luaotfload/fontloader-2022-02-24.lua
index f541668099..aee123be03 100644
--- a/macros/luatex/generic/luaotfload/fontloader-2021-05-20.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-2022-02-24.lua
@@ -1,9 +1,9 @@
--[[info-----------------------------------------------------------------------
Luaotfload fontloader package
- build 2021-05-20 19:43:52
+ build 2022-02-24 08:04:22
-------------------------------------------------------------------------------
- © 2021 PRAGMA ADE / ConTeXt Development Team
+ © 2022 PRAGMA ADE / ConTeXt Development Team
The code in this file is provided under the GPL v2.0 license. See the
file COPYING in the Luaotfload repository for details.
@@ -63,7 +63,7 @@
--info]]-----------------------------------------------------------------------
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “data-con” 23a0f5386d46a1c157ae82a373e35fa0] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “data-con” 23a0f5386d46a1c157ae82a373e35fa0] ---
if not modules then modules={} end modules ['data-con']={
version=1.100,
@@ -184,10 +184,10 @@ function containers.cleanname(name)
return (gsub(lower(name),"[^%w\128-\255]+","-"))
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “data-con”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “data-con”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “basics-nod” b2e0a0e5e1e27349aed464fa738b8db1] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “basics-nod” 1750af43148def9e7a75c6900a96f9dc] ---
if not modules then modules={} end modules ['luatex-fonts-nod']={
version=1.001,
@@ -276,7 +276,7 @@ nuts.setcomponents=direct.setcomponents
nuts.setdirection=direct.setdirection
nuts.setdisc=direct.setdisc
nuts.setreplace=direct.setreplace
-nuts.setfield=setfield
+nuts.setfield=direct.setfield
nuts.setkern=direct.setkern
nuts.setlink=direct.setlink
nuts.setlist=direct.setlist
@@ -454,10 +454,10 @@ do
end
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “basics-nod”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “basics-nod”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “basics-chr” 64fafe4eaf55d64aead6513c1e74a024] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “basics-chr” 1bb1ea05b5ca1bb5a9848b9eb66322bf] ---
characters=characters or {}
@@ -660,6 +660,7 @@ characters.classifiers={
[1562]=5,
[1563]=6,
[1564]=6,
+ [1565]=6,
[1566]=6,
[1567]=6,
[1568]=2,
@@ -1126,9 +1127,9 @@ characters.classifiers={
[2131]=2,
[2132]=3,
[2133]=2,
- [2134]=4,
- [2135]=4,
- [2136]=4,
+ [2134]=3,
+ [2135]=3,
+ [2136]=3,
[2137]=5,
[2138]=5,
[2139]=5,
@@ -1143,6 +1144,47 @@ characters.classifiers={
[2152]=2,
[2153]=3,
[2154]=3,
+ [2160]=3,
+ [2161]=3,
+ [2162]=3,
+ [2163]=3,
+ [2164]=3,
+ [2165]=3,
+ [2166]=3,
+ [2167]=3,
+ [2168]=3,
+ [2169]=3,
+ [2170]=3,
+ [2171]=3,
+ [2172]=3,
+ [2173]=3,
+ [2174]=3,
+ [2175]=3,
+ [2176]=3,
+ [2177]=3,
+ [2178]=3,
+ [2179]=2,
+ [2180]=2,
+ [2181]=2,
+ [2182]=2,
+ [2183]=4,
+ [2184]=4,
+ [2185]=2,
+ [2186]=2,
+ [2187]=2,
+ [2188]=2,
+ [2189]=2,
+ [2190]=3,
+ [2192]=4,
+ [2193]=4,
+ [2200]=5,
+ [2201]=5,
+ [2202]=5,
+ [2203]=5,
+ [2204]=5,
+ [2205]=5,
+ [2206]=5,
+ [2207]=5,
[2208]=2,
[2209]=2,
[2210]=2,
@@ -1164,6 +1206,7 @@ characters.classifiers={
[2226]=3,
[2227]=2,
[2228]=2,
+ [2229]=2,
[2230]=2,
[2231]=2,
[2232]=2,
@@ -1172,6 +1215,26 @@ characters.classifiers={
[2235]=2,
[2236]=2,
[2237]=2,
+ [2238]=2,
+ [2239]=2,
+ [2240]=2,
+ [2241]=2,
+ [2242]=2,
+ [2243]=2,
+ [2244]=2,
+ [2245]=2,
+ [2246]=2,
+ [2247]=2,
+ [2248]=2,
+ [2250]=5,
+ [2251]=5,
+ [2252]=5,
+ [2253]=5,
+ [2254]=5,
+ [2255]=5,
+ [2256]=5,
+ [2257]=5,
+ [2258]=5,
[2259]=5,
[2260]=5,
[2261]=5,
@@ -1291,6 +1354,7 @@ characters.classifiers={
[2883]=5,
[2884]=5,
[2893]=5,
+ [2901]=5,
[2902]=5,
[2914]=5,
[2915]=5,
@@ -1299,6 +1363,7 @@ characters.classifiers={
[3021]=5,
[3072]=5,
[3076]=5,
+ [3132]=5,
[3134]=5,
[3135]=5,
[3136]=5,
@@ -1332,6 +1397,7 @@ characters.classifiers={
[3405]=5,
[3426]=5,
[3427]=5,
+ [3457]=5,
[3530]=5,
[3538]=5,
[3539]=5,
@@ -1511,6 +1577,7 @@ characters.classifiers={
[6156]=5,
[6157]=5,
[6158]=4,
+ [6159]=5,
[6176]=2,
[6177]=2,
[6178]=2,
@@ -1695,6 +1762,22 @@ characters.classifiers={
[6843]=5,
[6844]=5,
[6845]=5,
+ [6847]=5,
+ [6848]=5,
+ [6849]=5,
+ [6850]=5,
+ [6851]=5,
+ [6852]=5,
+ [6853]=5,
+ [6854]=5,
+ [6855]=5,
+ [6856]=5,
+ [6857]=5,
+ [6858]=5,
+ [6859]=5,
+ [6860]=5,
+ [6861]=5,
+ [6862]=5,
[6912]=5,
[6913]=5,
[6914]=5,
@@ -1827,6 +1910,7 @@ characters.classifiers={
[7671]=5,
[7672]=5,
[7673]=5,
+ [7674]=5,
[7675]=5,
[7676]=5,
[7677]=5,
@@ -1928,6 +2012,7 @@ characters.classifiers={
[43019]=5,
[43045]=5,
[43046]=5,
+ [43052]=5,
[43072]=2,
[43073]=2,
[43074]=2,
@@ -2204,6 +2289,8 @@ characters.classifiers={
[68901]=5,
[68902]=5,
[68903]=5,
+ [69291]=5,
+ [69292]=5,
[69424]=2,
[69425]=2,
[69426]=2,
@@ -2241,6 +2328,56 @@ characters.classifiers={
[69458]=2,
[69459]=2,
[69460]=3,
+ [69488]=2,
+ [69489]=2,
+ [69490]=2,
+ [69491]=2,
+ [69492]=3,
+ [69493]=3,
+ [69494]=2,
+ [69495]=2,
+ [69496]=2,
+ [69497]=2,
+ [69498]=2,
+ [69499]=2,
+ [69500]=2,
+ [69501]=2,
+ [69502]=2,
+ [69503]=2,
+ [69504]=2,
+ [69505]=2,
+ [69506]=5,
+ [69507]=5,
+ [69508]=5,
+ [69509]=5,
+ [69552]=2,
+ [69553]=4,
+ [69554]=2,
+ [69555]=2,
+ [69556]=3,
+ [69557]=3,
+ [69558]=3,
+ [69559]=4,
+ [69560]=2,
+ [69561]=3,
+ [69562]=3,
+ [69563]=2,
+ [69564]=2,
+ [69565]=3,
+ [69566]=2,
+ [69567]=2,
+ [69568]=4,
+ [69569]=2,
+ [69570]=3,
+ [69571]=3,
+ [69572]=2,
+ [69573]=4,
+ [69574]=4,
+ [69575]=4,
+ [69576]=4,
+ [69577]=3,
+ [69578]=2,
+ [69579]=1,
[69633]=5,
[69688]=5,
[69689]=5,
@@ -2257,6 +2394,9 @@ characters.classifiers={
[69700]=5,
[69701]=5,
[69702]=5,
+ [69744]=5,
+ [69747]=5,
+ [69748]=5,
[69759]=5,
[69760]=5,
[69761]=5,
@@ -2267,6 +2407,7 @@ characters.classifiers={
[69817]=5,
[69818]=5,
[69821]=4,
+ [69826]=5,
[69837]=4,
[69888]=5,
[69889]=5,
@@ -2299,6 +2440,7 @@ characters.classifiers={
[70090]=5,
[70091]=5,
[70092]=5,
+ [70095]=5,
[70191]=5,
[70192]=5,
[70193]=5,
@@ -2409,6 +2551,10 @@ characters.classifiers={
[71735]=5,
[71737]=5,
[71738]=5,
+ [71995]=5,
+ [71996]=5,
+ [71998]=5,
+ [72003]=5,
[72148]=5,
[72149]=5,
[72150]=5,
@@ -2546,8 +2692,78 @@ characters.classifiers={
[94096]=5,
[94097]=5,
[94098]=5,
+ [94180]=5,
[113821]=5,
[113822]=5,
+ [118528]=5,
+ [118529]=5,
+ [118530]=5,
+ [118531]=5,
+ [118532]=5,
+ [118533]=5,
+ [118534]=5,
+ [118535]=5,
+ [118536]=5,
+ [118537]=5,
+ [118538]=5,
+ [118539]=5,
+ [118540]=5,
+ [118541]=5,
+ [118542]=5,
+ [118543]=5,
+ [118544]=5,
+ [118545]=5,
+ [118546]=5,
+ [118547]=5,
+ [118548]=5,
+ [118549]=5,
+ [118550]=5,
+ [118551]=5,
+ [118552]=5,
+ [118553]=5,
+ [118554]=5,
+ [118555]=5,
+ [118556]=5,
+ [118557]=5,
+ [118558]=5,
+ [118559]=5,
+ [118560]=5,
+ [118561]=5,
+ [118562]=5,
+ [118563]=5,
+ [118564]=5,
+ [118565]=5,
+ [118566]=5,
+ [118567]=5,
+ [118568]=5,
+ [118569]=5,
+ [118570]=5,
+ [118571]=5,
+ [118572]=5,
+ [118573]=5,
+ [118576]=5,
+ [118577]=5,
+ [118578]=5,
+ [118579]=5,
+ [118580]=5,
+ [118581]=5,
+ [118582]=5,
+ [118583]=5,
+ [118584]=5,
+ [118585]=5,
+ [118586]=5,
+ [118587]=5,
+ [118588]=5,
+ [118589]=5,
+ [118590]=5,
+ [118591]=5,
+ [118592]=5,
+ [118593]=5,
+ [118594]=5,
+ [118595]=5,
+ [118596]=5,
+ [118597]=5,
+ [118598]=5,
[119143]=5,
[119144]=5,
[119145]=5,
@@ -2745,6 +2961,7 @@ characters.classifiers={
[123188]=5,
[123189]=5,
[123190]=5,
+ [123566]=5,
[123628]=5,
[123629]=5,
[123630]=5,
@@ -2912,6 +3129,7 @@ characters.indicgroups={
[2879]=true,
[2902]=true,
[3376]=true,
+ [5901]=true,
},
["after_postscript"]={
[2433]=true,
@@ -3087,6 +3305,7 @@ characters.indicgroups={
[2915]=true,
[3009]=true,
[3010]=true,
+ [3132]=true,
[3170]=true,
[3171]=true,
[3260]=true,
@@ -3505,6 +3724,7 @@ characters.indicgroups={
[4225]=true,
[4226]=true,
[4238]=true,
+ [5901]=true,
[43488]=true,
[43489]=true,
[43490]=true,
@@ -3829,6 +4049,7 @@ characters.indicgroups={
[3090]=true,
[3091]=true,
[3092]=true,
+ [3165]=true,
[3168]=true,
[3169]=true,
[3205]=true,
@@ -3845,6 +4066,7 @@ characters.indicgroups={
[3218]=true,
[3219]=true,
[3220]=true,
+ [3293]=true,
[3296]=true,
[3297]=true,
[3333]=true,
@@ -3885,6 +4107,7 @@ characters.indicgroups={
[2620]=true,
[2748]=true,
[2876]=true,
+ [3132]=true,
[3260]=true,
},
["post_mark"]={
@@ -3988,6 +4211,7 @@ characters.indicgroups={
[3120]=true,
[3248]=true,
[3376]=true,
+ [5901]=true,
},
["stress_tone_mark"]={
[2385]=true,
@@ -4067,10 +4291,10 @@ characters.indicgroups={
},
}
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “basics-chr”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “basics-chr”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-ini” 5343de60613adb24cdd7a8d2ee1d153c] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-ini” 5343de60613adb24cdd7a8d2ee1d153c] ---
if not modules then modules={} end modules ['font-ini']={
version=1.001,
@@ -4111,10 +4335,10 @@ if node and not tex.getfontoffamily then
tex.getfontoffamily=node.family_font
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-ini”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-ini”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “fonts-mis” 17e967c9ec4d001deefd43ddf25e98f7] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “fonts-mis” 17e967c9ec4d001deefd43ddf25e98f7] ---
if not modules then modules={} end modules ['luatex-font-mis']={
version=1.001,
@@ -4146,10 +4370,10 @@ function font.each()
return table.sortedhash(fonts.hashes.identifiers)
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “fonts-mis”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “fonts-mis”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-con” 724e5dd14aec2d4d189f8619898004cf] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-con” 724e5dd14aec2d4d189f8619898004cf] ---
if not modules then modules={} end modules ['font-con']={
version=1.001,
@@ -5517,10 +5741,10 @@ function constructors.addcoreunicodes(unicodes)
return unicodes
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-con”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-con”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “fonts-enc” 5ff4ca50493d7c4ecea0e15c203099f0] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “fonts-enc” c24fd6b4f34f87b9c4ff5e6193ce2656] ---
if not modules then modules={} end modules ['luatex-font-enc']={
version=1.001,
@@ -5537,10 +5761,16 @@ local encodings={}
fonts.encodings=encodings
encodings.agl={}
encodings.known={}
+encodings.glyphlistfilename="font-age.lua"
setmetatable(encodings.agl,{ __index=function(t,k)
if k=="unicodes" then
logs.report("fonts","loading (extended) adobe glyph list")
- local unicodes=dofile(resolvers.findfile("font-age.lua"))
+ local foundname=resolvers.findfile(encodings.glyphlistfilename) or ""
+ local unicodes=foundname~="" and dofile(foundname)
+ if type(unicodes)~="table" then
+ logs.report("fonts","missing or invalid (extended) adobe glyph list")
+ unicodes={}
+ end
encodings.agl={ unicodes=unicodes }
return unicodes
else
@@ -5589,10 +5819,10 @@ function encodings.load(filename)
return containers.write(encodings.cache,name,data)
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “fonts-enc”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “fonts-enc”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-cid” 22b0367742fb253deef84ef7ccf5e8de] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-cid” 22b0367742fb253deef84ef7ccf5e8de] ---
if not modules then modules={} end modules ['font-cid']={
version=1.001,
@@ -5743,10 +5973,10 @@ function cid.getmap(specification)
return found
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-cid”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-cid”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-map” c4a39db5ad822b348aa61bca5f4a599a] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-map” c4a39db5ad822b348aa61bca5f4a599a] ---
if not modules then modules={} end modules ['font-map']={
version=1.001,
@@ -6154,10 +6384,10 @@ function mappings.addtounicode(data,filename,checklookups,forceligatures)
end
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-map”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-map”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-vfc” a81c29eda98cd62cbebdb6c93544b50d] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-vfc” a81c29eda98cd62cbebdb6c93544b50d] ---
if not modules then modules={} end modules ['font-vfc']={
version=1.001,
@@ -6254,10 +6484,10 @@ helpers.commands=utilities.storage.allocate {
dummy=dummy,
}
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-vfc”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-vfc”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-otr” ad238624c9ebd488d4bbe9af3b620189] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-otr” 91f70c1216e60227e1437b6c8dcd8647] ---
if not modules then modules={} end modules ['font-otr']={
version=1.001,
@@ -6499,15 +6729,15 @@ local weights={
[900]="black",
}
local widths={
- [1]="ultracondensed",
- [2]="extracondensed",
- [3]="condensed",
- [4]="semicondensed",
- [5]="normal",
- [6]="semiexpanded",
- [7]="expanded",
- [8]="extraexpanded",
- [9]="ultraexpanded",
+ "ultracondensed",
+ "extracondensed",
+ "condensed",
+ "semicondensed",
+ "normal",
+ "semiexpanded",
+ "expanded",
+ "extraexpanded",
+ "ultraexpanded",
}
setmetatableindex(weights,function(t,k)
local r=floor((k+50)/100)*100
@@ -6517,30 +6747,28 @@ end)
setmetatableindex(widths,function(t,k)
return "normal"
end)
-local panoseweights={
- [ 0]="normal",
- [ 1]="normal",
- [ 2]="verylight",
- [ 3]="light",
- [ 4]="thin",
- [ 5]="book",
- [ 6]="medium",
- [ 7]="demi",
- [ 8]="bold",
- [ 9]="heavy",
- [10]="black",
+local panoseweights={ [0]="normal",
+ "normal",
+ "verylight",
+ "light",
+ "thin",
+ "book",
+ "medium",
+ "demi",
+ "bold",
+ "heavy",
+ "black",
}
-local panosewidths={
- [ 0]="normal",
- [ 1]="normal",
- [ 2]="normal",
- [ 3]="normal",
- [ 4]="normal",
- [ 5]="expanded",
- [ 6]="condensed",
- [ 7]="veryexpanded",
- [ 8]="verycondensed",
- [ 9]="monospaced",
+local panosewidths={ [0]="normal",
+ "normal",
+ "normal",
+ "normal",
+ "normal",
+ "expanded",
+ "condensed",
+ "veryexpanded",
+ "verycondensed",
+ "monospaced",
}
local helpers={}
readers.helpers=helpers
@@ -6974,7 +7202,7 @@ readers.post=function(f,fontdata,specification)
local version=readulong(f)
fontdata.postscript={
version=version,
- italicangle=round(1000*readfixed(f))/1000,
+ italicangle=readfixed(f),
underlineposition=readfword(f),
underlinethickness=readfword(f),
monospaced=readulong(f),
@@ -7591,6 +7819,7 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo,inst
pfmwidth=metrics.widthclass or 5,
panosewidth=metrics.panosewidth,
panoseweight=metrics.panoseweight,
+ fstype=metrics.fstype or 0,
italicangle=postscript.italicangle or 0,
units=fontheader.units or 0,
designsize=fontdata.designsize,
@@ -8084,6 +8313,9 @@ end
function readers.compact(fontdata)
report("the %a helper is not yet implemented","compact")
end
+function readers.condense(fontdata)
+ report("the %a helper is not yet implemented","condense")
+end
local extenders={}
function readers.registerextender(extender)
extenders[#extenders+1]=extender
@@ -8099,10 +8331,10 @@ function readers.extend(fontdata)
end
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-otr”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-otr”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-oti” 309a75f9c14b77d87e94eba827dc4e71] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-oti” 309a75f9c14b77d87e94eba827dc4e71] ---
if not modules then modules={} end modules ['font-oti']={
version=1.001,
@@ -8245,10 +8477,10 @@ function otffeatures.checkeddefaultlanguage(featuretype,autolanguage,languages)
end
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-oti”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-oti”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-ott” 3f67b1b1d40bbc222681d8db4aff0f42] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-ott” 3f67b1b1d40bbc222681d8db4aff0f42] ---
if not modules then modules={} end modules ["font-ott"]={
version=1.001,
@@ -9364,10 +9596,10 @@ function otffeatures.normalize(features,wrap)
end
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-ott”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-ott”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-cff” 01e7c6fbc8961a566f4e4f8cbedb7004] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-cff” e38c1a40e1d1d577cdf7920fa50d0654] ---
if not modules then modules={} end modules ['font-cff']={
version=1.001,
@@ -9817,7 +10049,8 @@ do
top=0
end
local p_dictionary=(
- p_byte+p_positive+p_negative+p_short+p_long+p_nibbles+p_single+p_double+p_unsupported
+ p_byte+p_positive+p_negative+p_short+p_long+p_nibbles+p_single+p_double
++p_unsupported
)^1
parsedictionaries=function(data,dictionaries,version)
stack={}
@@ -9889,6 +10122,7 @@ do
local y=0
local width=false
local lsb=0
+local result={}
local r=0
local stems=0
local globalbias=0
@@ -10843,12 +11077,12 @@ do
stack[top]=-t*256+64148-tab[i+1]
i=i+2
else
- local n=0x100*tab[i+1]+tab[i+2]
- if n>=0x8000 then
- stack[top]=n-0x10000+(0x100*tab[i+3]+tab[i+4])/0xFFFF
- else
- stack[top]=n+(0x100*tab[i+3]+tab[i+4])/0xFFFF
+ local n1=0x100*tab[i+1]+tab[i+2]
+ local n2=0x100*tab[i+3]+tab[i+4]
+ if n1>=0x8000 then
+ n1=n1-0x10000
end
+ stack[top]=n1+n2/0xFFFF
i=i+5
end
elseif t==28 then
@@ -10936,7 +11170,7 @@ do
i=i+s+1
elseif t==1 or t==3 or t==18 or operation==23 then
p_getstem()
- if true then
+ if version=="cff" then
if top>0 then
for i=1,top do
r=r+1;result[r]=encode[stack[i]]
@@ -10949,7 +11183,7 @@ do
end
i=i+1
elseif t==19 or t==20 then
- local s=p_getmask() or 0
+ local s=p_getmask() or 0
if true then
if top>0 then
for i=1,top do
@@ -10972,7 +11206,7 @@ do
i=i+1
elseif t==13 then
hsbw()
- if version=="cff" then
+ if true then
r=r+1;result[r]=encode[lsb]
r=r+1;result[r]=chars[22]
else
@@ -11099,6 +11333,7 @@ do
r=r+1
result[r]=c_endchar
local stream=concat(result)
+result=nil
if glyph then
glyph.stream=stream
else
@@ -11120,6 +11355,7 @@ do
width=width,
name=charset and charset[index] or nil,
}
+result=nil
else
glyphs[index]={
boundingbox=boundingbox,
@@ -11592,10 +11828,10 @@ function readers.cffcheck(filename)
end
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-cff”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-cff”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-ttf” ffffc827e1bcddc33a2b615340ecff7f] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-ttf” feba1fdc80160343b24f89ef978e53cb] ---
if not modules then modules={} end modules ['font-ttf']={
version=1.001,
@@ -11607,7 +11843,7 @@ if not modules then modules={} end modules ['font-ttf']={
}
local next,type,unpack=next,type,unpack
local band,rshift=bit32.band,bit32.rshift
-local sqrt,round=math.sqrt,math.round
+local sqrt,round,abs,min,max=math.sqrt,math.round,math.abs,math.min,math.max
local char,rep=string.char,string.rep
local concat=table.concat
local idiv=number.idiv
@@ -11741,69 +11977,164 @@ local function curveto(m_x,m_y,l_x,l_y,r_x,r_y)
r_x+2/3*(m_x-r_x),r_y+2/3*(m_y-r_y),
r_x,r_y,"c"
end
+local xv={}
+local yv={}
local function applyaxis(glyph,shape,deltas,dowidth)
local points=shape.points
if points then
local nofpoints=#points
- local h=nofpoints+2
- local l=nofpoints+1
local dw=0
local dl=0
for i=1,#deltas do
local deltaset=deltas[i]
local xvalues=deltaset.xvalues
local yvalues=deltaset.yvalues
- local dpoints=deltaset.points
- local factor=deltaset.factor
- if dpoints then
- local nofdpoints=#dpoints
- for i=1,nofdpoints do
- local d=dpoints[i]
- local p=points[d]
- if p then
- if xvalues then
- local x=xvalues[i]
- if x and x~=0 then
- p[1]=p[1]+factor*x
+ if xvalues and yvalues then
+ local dpoints=deltaset.points
+ local factor=deltaset.factor
+ if dpoints then
+ local cnt=#dpoints
+ if dowidth then
+ cnt=cnt-4
+ end
+ if cnt==1 then
+ local d=dpoints[1]
+ local x=xvalues[d]*factor
+ local y=yvalues[d]*factor
+ for i=1,nofpoints do
+ local p=points[i]
+ if x~=0 then
+ p[1]=p[1]+x
+ end
+ if y~=0 then
+ p[2]=p[2]+y
end
end
- if yvalues then
- local y=yvalues[i]
- if y and y~=0 then
- p[2]=p[2]+factor*y
+ elseif cnt>0 then
+ local function find(i)
+ local prv=cnt
+ for j=1,cnt do
+ local nxt=dpoints[j]
+ if nxt==i then
+ return false,j,false
+ elseif nxt>i then
+ return prv,false,j
+ end
+ prv=j
+ end
+ return prv,false,1
+ end
+ for i=1,nofpoints do
+ local d1,d2,d3=find(i)
+ local p2=points[i]
+ if d2 then
+ xv[i]=xvalues[d2]
+ yv[i]=yvalues[d2]
+ else
+ local n1=dpoints[d1]
+ local n3=dpoints[d3]
+ if n1>nofpoints then
+ n1=nofpoints
+ end
+ if n3>nofpoints then
+ n3=nofpoints
+ end
+ local p1=points[n1]
+ local p3=points[n3]
+ local p1x=p1[1]
+ local p2x=p2[1]
+ local p3x=p3[1]
+ local p1y=p1[2]
+ local p2y=p2[2]
+ local p3y=p3[2]
+ local x1=xvalues[d1]
+ local y1=yvalues[d1]
+ local x3=xvalues[d3]
+ local y3=yvalues[d3]
+ local fx
+ local fy
+ if p1x==p3x then
+ if x1==x3 then
+ fx=x1
+ else
+ fx=0
+ end
+ elseif p2x<=min(p1x,p3x) then
+ if p1x<p3x then
+ fx=x1
+ else
+ fx=x3
+ end
+ elseif p2x>=max(p1x,p3x) then
+ if p1x>p3x then
+ fx=x1
+ else
+ fx=x3
+ end
+ else
+ fx=(p2x-p1x)/(p3x-p1x)
+ fx=(1-fx)*x1+fx*x3
+ end
+ if p1y==p3y then
+ if y1==y3 then
+ fy=y1
+ else
+ fy=0
+ end
+ elseif p2y<=min(p1y,p3y) then
+ if p1y<p3y then
+ fy=y1
+ else
+ fy=y3
+ end
+ elseif p2y>=max(p1y,p3y) then
+ if p1y>p3y then
+ fy=y1
+ else
+ fy=y3
+ end
+ else
+ fy=(p2y-p1y)/(p3y-p1y)
+ fy=(1-fy)*y1+fy*y3
+ end
+ xv[i]=fx
+ yv[i]=fy
end
end
- elseif dowidth then
- if d==h then
- local x=xvalues[i]
- if x then
- dw=dw+factor*x
+ for i=1,nofpoints do
+ local pi=points[i]
+ local fx=xv[i]
+ local fy=yv[i]
+ if fx~=0 then
+ pi[1]=pi[1]+factor*fx
end
- elseif d==l then
- local x=xvalues[i]
- if x then
- dl=dl+factor*x
+ if fy~=0 then
+ pi[2]=pi[2]+factor*fy
end
end
+ else
+ report("bad deltapoint data, maybe a missing hvar table")
end
- end
- else
- for i=1,nofpoints do
- local p=points[i]
- if xvalues then
+ else
+ for i=1,nofpoints do
+ local p=points[i]
local x=xvalues[i]
- if x and x~=0 then
- p[1]=p[1]+factor*x
- end
- end
- if yvalues then
- local y=yvalues[i]
- if y and y~=0 then
- p[2]=p[2]+factor*y
+ if x then
+ local y=yvalues[i]
+ if x~=0 then
+ p[1]=p[1]+factor*x
+ end
+ if y~=0 then
+ p[2]=p[2]+factor*y
+ end
+ else
+ break
end
end
end
if dowidth then
+ local h=nofpoints+2
+ local l=nofpoints+1
local x=xvalues[h]
if x then
dw=dw+factor*x
@@ -12382,13 +12713,13 @@ local function readcomposite(f)
yoffset=yoffset*yscale
end
elseif band(flags,0x0080)~=0 then
- xscale=read2dot14(f)
- xrotate=read2dot14(f)
- yrotate=read2dot14(f)
- yscale=read2dot14(f)
+ xscale=read2dot14(f)
+ xrotate=read2dot14(f)
+ yrotate=read2dot14(f)
+ yscale=read2dot14(f)
if f_xyarg and f_offset then
- xoffset=xoffset*sqrt(xscale^2+xrotate^2)
- yoffset=yoffset*sqrt(yrotate^2+yscale^2)
+ xoffset=xoffset*sqrt(xscale^2+yrotate^2)
+ yoffset=yoffset*sqrt(xrotate^2+yscale^2)
end
end
nofcomponents=nofcomponents+1
@@ -12546,40 +12877,6 @@ end
local function readdeltas(f,nofpoints)
local deltas={}
local p=0
- local z=0
- while nofpoints>0 do
- local control=readbyte(f)
-if not control then
- break
-end
- local allzero=band(control,0x80)~=0
- local runlength=band(control,0x3F)+1
- if allzero then
- z=z+runlength
- else
- local runreader=band(control,0x40)~=0 and readshort or readinteger
- if z>0 then
- for i=1,z do
- p=p+1
- deltas[p]=0
- end
- z=0
- end
- for i=1,runlength do
- p=p+1
- deltas[p]=runreader(f)
- end
- end
- nofpoints=nofpoints-runlength
- end
- if p>0 then
- return deltas
- else
- end
-end
-local function readdeltas(f,nofpoints)
- local deltas={}
- local p=0
while nofpoints>0 do
local control=readbyte(f)
if control then
@@ -12766,10 +13063,10 @@ function readers.gvar(f,fontdata,specification,glyphdata,shapedata)
end
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-ttf”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-ttf”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-dsp” 174ce11f3ba0bddf270f48d8d2addd56] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-dsp” 7616dae672693fd8ec0f1892358019a2] ---
if not modules then modules={} end modules ['font-dsp']={
version=1.001,
@@ -15938,6 +16235,7 @@ function readers.hvar(f,fontdata,specification)
end
local tableoffset=gotodatatable(f,fontdata,"hvar",specification.variable)
if not tableoffset then
+ report("no hvar table, expect problems due to messy widths")
return
end
local version=readulong(f)
@@ -16045,10 +16343,10 @@ function readers.mvar(f,fontdata,specification)
end
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-dsp”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-dsp”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-oup” 4eb2f26e51835239e26a8df2ecf04366] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-oup” e6e2cc0a202aec2c787d5524e64d340a] ---
if not modules then modules={} end modules ['font-oup']={
version=1.001,
@@ -16083,9 +16381,9 @@ 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
+local check_soft_hyphen=context
directives.register("otf.checksofthyphen",function(v)
- check_soft_hyphen=v
+ check_soft_hyphen=v
end)
local function replaced(list,index,replacement)
if type(list)=="number" then
@@ -16474,27 +16772,30 @@ local function copyduplicates(fontdata)
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
+ local dh=descriptions[0x2D]
+ if dh then
+ local ds=descriptions[0xAD]
+ if not ds or ds.width~=dh.width then
descriptions[0xAD]=nil
- if trace_unicodes then
- report_unicodes("patching soft hyphen")
+ if ds then
+ if trace_unicodes then
+ report_unicodes("patching soft hyphen")
+ end
+ else
+ if trace_unicodes then
+ report_unicodes("adding soft hyphen")
+ end
end
- else
- if trace_unicodes then
- report_unicodes("adding soft hyphen")
+ if not duplicates then
+ duplicates={}
+ resources.duplicates=duplicates
+ end
+ local d=duplicates[0x2D]
+ if d then
+ d[0xAD]=true
+ else
+ duplicates[0x2D]={ [0xAD]=true }
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
@@ -16760,6 +17061,7 @@ local function unifyglyphs(fontdata,usenames)
local resources=fontdata.resources
local zero=glyphs[0]
local zerocode=zero.unicode
+ local nofglyphs=#glyphs
if not zerocode then
zerocode=private
zero.unicode=zerocode
@@ -16774,7 +17076,7 @@ local function unifyglyphs(fontdata,usenames)
indices[0]=zerocode
end
if names then
- for index=1,#glyphs do
+ for index=1,nofglyphs do
local glyph=glyphs[index]
local unicode=glyph.unicode
if not unicode then
@@ -16807,7 +17109,7 @@ local function unifyglyphs(fontdata,usenames)
descriptions[unicode]=glyph
end
elseif trace_unicodes then
- for index=1,#glyphs do
+ for index=1,nofglyphs do
local glyph=glyphs[index]
local unicode=glyph.unicode
if not unicode then
@@ -16848,7 +17150,7 @@ local function unifyglyphs(fontdata,usenames)
descriptions[unicode]=glyph
end
else
- for index=1,#glyphs do
+ for index=1,nofglyphs do
local glyph=glyphs[index]
local unicode=glyph.unicode
if not unicode then
@@ -16874,7 +17176,7 @@ local function unifyglyphs(fontdata,usenames)
descriptions[unicode]=glyph
end
end
- for index=1,#glyphs do
+ for index=1,nofglyphs do
local math=glyphs[index].math
if math then
local list=math.vparts
@@ -16897,7 +17199,7 @@ local function unifyglyphs(fontdata,usenames)
end
local colorpalettes=resources.colorpalettes
if colorpalettes then
- for index=1,#glyphs do
+ for index=1,nofglyphs do
local colors=glyphs[index].colors
if colors then
for i=1,#colors do
@@ -16912,6 +17214,7 @@ local function unifyglyphs(fontdata,usenames)
fontdata.names=names
fontdata.descriptions=descriptions
fontdata.hashmethod=hashmethod
+ fontdata.nofglyphs=nofglyphs
return indices,names
end
local p_crappyname do
@@ -16984,6 +17287,10 @@ function readers.getcomponents(fontdata)
local function traverse(p,k,v)
if k=="ligature" then
collected[v]={ unpack(l) }
+ elseif tonumber(v) then
+ insert(l,k)
+ collected[v]={ unpack(l) }
+ remove(l)
else
insert(l,k)
for k,vv in next,v do
@@ -17144,7 +17451,6 @@ local function tabstr_flat(t)
end
end
local function tabstr_mixed(t)
- local s={}
local n=#t
if n==0 then
return ""
@@ -17158,6 +17464,7 @@ local function tabstr_mixed(t)
return tostring(k)
end
else
+ local s={}
for i=1,n do
local k=t[i]
if k==true then
@@ -18481,6 +18788,85 @@ function readers.compact(data)
end
end
end
+if CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 then
+ local done=0
+ local function condense_1(k,v,t)
+ if type(v)=="table" then
+ local u=false
+ local l=false
+ for k,v in next,v do
+ if k=="ligature" then
+ l=v
+ if u then
+ break
+ end
+ elseif u then
+ break
+ else
+ u=true
+ end
+ end
+ if l and not u then
+ t[k]=l
+ done=done+1
+ end
+ if u then
+ for k,vv in next,v do
+ if k~="ligature" then
+ condense_1(k,vv,v)
+ end
+ end
+ end
+ end
+ end
+ local function condensesteps_1(lookup)
+ done=0
+ if lookup.type=="gsub_ligature" then
+ local steps=lookup.steps
+ if steps then
+ for i=1,#steps do
+ local step=steps[i]
+ local coverage=step.coverage
+ if coverage then
+ for k,v in next,coverage do
+ if condense_1(k,v,coverage) then
+ coverage[k]=v.ligature
+ done=done+1
+ end
+ end
+ end
+ end
+ end
+ end
+ return done
+ end
+ function readers.condense(data)
+ if not data or data.condensed then
+ return
+ else
+ data.condensed=true
+ end
+ local resources=data.resources
+ local condensed=0
+ local function condense(what)
+ local lookups=resources[what]
+ if lookups then
+ for i=1,#lookups do
+ condensed=condensed+condensesteps_1(lookups[i])
+ end
+ elseif trace_optimizations then
+ report_optimizations("no lookups in %a",what)
+ end
+ end
+ condense("sequences")
+ condense("sublookups")
+ if trace_optimizations then
+ if condensed>0 then
+ report_optimizations("%i ligatures condensed",condensed)
+ end
+ end
+ end
+end
local function mergesteps(t,k)
if k=="merged" then
local merged={}
@@ -18585,7 +18971,7 @@ function readers.expand(data)
end
end
end
- local function expandlookups(sequences)
+ local function expandlookups(sequences,whatever)
if sequences then
for i=1,#sequences do
local sequence=sequences[i]
@@ -18658,6 +19044,9 @@ function readers.expand(data)
if lookups then
for k,v in next,lookups do
local lookup=sublookups[v]
+if not lookup and whatever then
+ lookup=whatever[v]
+end
if lookup then
lookups[k]=lookup
if not subtype then
@@ -18716,13 +19105,13 @@ function readers.expand(data)
end
end
expandlookups(sequences)
- expandlookups(sublookups)
+ expandlookups(sublookups,sequences)
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-oup”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-oup”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-otl” 6f701653de713e8aa80d82c7cdf32d75] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-otl” 67078f58bc1a612e4646523538a4e3eb] ---
if not modules then modules={} end modules ['font-otl']={
version=1.001,
@@ -18734,7 +19123,7 @@ if not modules then modules={} end modules ['font-otl']={
local lower=string.lower
local type,next,tonumber,tostring,unpack=type,next,tonumber,tostring,unpack
local abs=math.abs
-local derivetable=table.derive
+local derivetable,sortedhash=table.derive,table.sortedhash
local formatters=string.formatters
local setmetatableindex=table.setmetatableindex
local allocate=utilities.storage.allocate
@@ -18750,7 +19139,7 @@ local trace_defining=false registertracker("fonts.defining",function(v) trace_d
local report_otf=logs.reporter("fonts","otf loading")
local fonts=fonts
local otf=fonts.handlers.otf
-otf.version=3.116
+otf.version=3.119
otf.cache=containers.define("fonts","otl",otf.version,true)
otf.svgcache=containers.define("fonts","svg",otf.version,true)
otf.pngcache=containers.define("fonts","png",otf.version,true)
@@ -18885,6 +19274,9 @@ function otf.load(filename,sub,instance)
if cleanup==0 then
checkmemory(used,threshold,tracememory)
end
+ if context then
+ otfreaders.condense(data)
+ end
otfreaders.pack(data)
report_otf("loading done")
report_otf("saving %a in cache",filename)
@@ -18955,7 +19347,7 @@ local function copytotfm(data,cache_id)
local properties=derivetable(data.properties)
local descriptions=derivetable(data.descriptions)
local goodies=derivetable(data.goodies)
- local characters={}
+ local characters={}
local parameters={}
local mathparameters={}
local resources=data.resources
@@ -19123,7 +19515,25 @@ local function copytotfm(data,cache_id)
properties.name=filename or fullname
properties.subfont=subfont
if not CONTEXTLMTXMODE or CONTEXTLMTXMODE==0 then
- properties.encodingbytes=2
+ properties.encodingbytes=2
+elseif CONTEXTLMTXMODE then
+ local duplicates=resources and resources.duplicates
+ if duplicates then
+ local maxindex=data.nofglyphs or metadata.nofglyphs
+ if maxindex then
+ for u,d in sortedhash(duplicates) do
+ local du=descriptions[u]
+ if du then
+ for uu in sortedhash(d) do
+ maxindex=maxindex+1
+ descriptions[uu].dupindex=du.index
+ descriptions[uu].index=maxindex
+ end
+ else
+ end
+ end
+ end
+ end
end
properties.private=properties.private or data.private or privateoffset
return {
@@ -19429,10 +19839,10 @@ otf.coverup={
end
}
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-otl”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-otl”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-oto” 2b1d6bc63b2ebf8f2655a15e1cda6541] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-oto” 9febc4d75d17a543cd73fb17918f7307] ---
if not modules then modules={} end modules ['font-oto']={
version=1.001,
@@ -19492,7 +19902,7 @@ local function gref(descriptions,n)
end
end
local function cref(feature,sequence)
- return formatters["feature %a, type %a, chain lookup %a"](feature,sequence.type,sequence.name)
+ return formatters["feature %a, type %a, (chain) lookup %a"](feature,sequence.type,sequence.name)
end
local function report_substitution(feature,sequence,descriptions,unicode,substitution)
if unicode==substitution then
@@ -19553,49 +19963,60 @@ end
local function makefake(tfmdata,name,present)
local private=getprivate(tfmdata)
local character={ intermediate=true,ligatures={} }
- resources.unicodes[name]=private
+ tfmdata.resources.unicodes[name]=private
tfmdata.characters[private]=character
tfmdata.descriptions[private]={ name=name }
present[name]=private
return character
end
local function make_1(present,tree,name)
- for k,v in next,tree do
- if k=="ligature" then
- present[name]=v
+ if tonumber(tree) then
+ present[name]=v
+ else
+ for k,v in next,tree do
+ if k=="ligature" then
+ present[name]=v
+ else
+ make_1(present,v,name.."_"..k)
+ end
+ end
+ end
+end
+local function make_3(present,tfmdata,characters,tree,name,preceding,unicode,done,v)
+ local character=characters[preceding]
+ if not character then
+ if trace_baseinit then
+ report_prepare("weird ligature in lookup %a, current %C, preceding %C",sequence.name,v,preceding)
+ end
+ character=makefake(tfmdata,name,present)
+ end
+ local ligatures=character.ligatures
+ if ligatures then
+ ligatures[unicode]={ char=v }
+ else
+ character.ligatures={ [unicode]={ char=v } }
+ end
+ if done then
+ local d=done[name]
+ if not d then
+ done[name]={ "dummy",v }
else
- make_1(present,v,name.."_"..k)
+ d[#d+1]=v
end
end
end
local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done)
- for k,v in next,tree do
- if k=="ligature" then
- local character=characters[preceding]
- if not character then
- if trace_baseinit then
- report_prepare("weird ligature in lookup %a, current %C, preceding %C",sequence.name,v,preceding)
- end
- character=makefake(tfmdata,name,present)
- end
- local ligatures=character.ligatures
- if ligatures then
- ligatures[unicode]={ char=v }
+ if tonumber(tree) then
+ make_3(present,tfmdata,characters,tree,name,preceding,unicode,done,tree)
+ else
+ for k,v in next,tree do
+ if k=="ligature" then
+ make_3(present,tfmdata,characters,tree,name,preceding,unicode,done,v)
else
- character.ligatures={ [unicode]={ char=v } }
- end
- if done then
- local d=done[name]
- if not d then
- done[name]={ "dummy",v }
- else
- d[#d+1]=v
- end
+ local code=present[name] or unicode
+ local name=name.."_"..k
+ make_2(present,tfmdata,characters,v,name,code,k,done)
end
- else
- local code=present[name] or unicode
- local name=name.."_"..k
- make_2(present,tfmdata,characters,v,name,code,k,done)
end
end
end
@@ -19890,10 +20311,10 @@ registerotffeature {
}
otf.basemodeinitializer=featuresinitializer
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-oto”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-oto”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-otj” b2c165bd6771a57633f992d07384b739] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-otj” b2c165bd6771a57633f992d07384b739] ---
if not modules then modules={} end modules ['font-otj']={
version=1.001,
@@ -21386,10 +21807,10 @@ function injections.handler(head,where)
end
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-otj”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-otj”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-ota” 2bb12d708e35bc05443eba791e2554e7] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-ota” 2bb12d708e35bc05443eba791e2554e7] ---
if not modules then modules={} end modules ['font-ota']={
version=1.001,
@@ -21883,10 +22304,10 @@ directives.register("otf.analyze.useunicodemarks",function(v)
analyzers.useunicodemarks=v
end)
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-ota”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-ota”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-ots” cb106ae882e8548051f00aac8b7fa862] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-ots” 55316a605d11a1d07d38795224c90a63] ---
if not modules then modules={} end modules ['font-ots']={
version=1.001,
@@ -21928,6 +22349,7 @@ local trace_compruns=false registertracker("otf.compruns",function(v) trace_com
local trace_testruns=false registertracker("otf.testruns",function(v) trace_testruns=v end)
local forcediscretionaries=false
local forcepairadvance=false
+local repeatablemultiples=context or false
directives.register("otf.forcediscretionaries",function(v)
forcediscretionaries=v
end)
@@ -22306,15 +22728,47 @@ local function multiple_glyphs(head,start,multiple,skiphash,what,stop)
insertnodeafter(head,start,n)
start=n
end
- if what==true then
- elseif what>1 then
- local m=multiple[nofmultiples]
- for i=2,what do
- local n=copy_node(start)
- resetinjection(n)
- setchar(n,m)
- insertnodeafter(head,start,n)
- start=n
+ if what~=true and repeatablemultiples then
+ local kind=type(what)
+ local m,f,l
+ if kind=="string" then
+ local what,n=string.match(what,"^repeat(.-)[:=](%d+)$")
+ if what=="middle" then
+ m=tonumber(n)
+ elseif what=="first" then
+ f=tonumber(n)
+ elseif what=="last" then
+ l=tonumber(n)
+ end
+ elseif kind=="table" then
+ m=what.middle
+ f=what.first
+ l=what.last
+ end
+ if f or m or l then
+ if m and m>1 and nofmultiples==3 then
+ local middle=getnext(first)
+ for i=2,m do
+ local n=copynode(middle)
+ resetinjection(n)
+ insertnodeafter(head,first,n)
+ end
+ end
+ if f and f>1 then
+ for i=2,f do
+ local n=copynode(first)
+ resetinjection(n)
+ insertnodeafter(head,first,n)
+ end
+ end
+ if l and l>1 then
+ for i=2,l do
+ local n=copynode(start)
+ resetinjection(n)
+ insertnodeafter(head,start,n)
+ start=n
+ end
+ end
end
end
end
@@ -22402,7 +22856,7 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
while current do
local char=ischar(current,currentfont)
if char then
- local lg=ligature[char]
+ local lg=not tonumber(ligature) and ligature[char]
if lg then
stop=current
ligature=lg
@@ -22415,14 +22869,14 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
end
end
if stop then
- local lig=ligature.ligature
- if lig then
+ local ligature=tonumber(ligature) or ligature.ligature
+ if ligature then
if trace_ligatures then
local stopchar=getchar(stop)
- head,start=markstoligature(head,start,stop,lig)
+ head,start=markstoligature(head,start,stop,ligature)
logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(getchar(start)))
else
- head,start=markstoligature(head,start,stop,lig)
+ head,start=markstoligature(head,start,stop,ligature)
end
return head,start,true,false
else
@@ -22437,7 +22891,7 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
if skiphash and skiphash[char] then
current=getnext(current)
else
- local lg=ligature[char]
+ local lg=not tonumber(ligature) and ligature[char]
if lg then
if marks[char] then
hasmarks=true
@@ -22463,20 +22917,20 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
local match
if replace then
local char=ischar(replace,currentfont)
- if char and ligature[char] then
+ if char and (not tonumber(ligature) and ligature[char]) then
match=true
end
end
if not match and pre then
local char=ischar(pre,currentfont)
- if char and ligature[char] then
+ if char and (not tonumber(ligature) and ligature[char]) then
match=true
end
end
if not match and not pre or not replace then
local n=getnext(discfound)
local char=ischar(n,currentfont)
- if char and ligature[char] then
+ if char and (not tonumber(ligature) and ligature[char]) then
match=true
end
end
@@ -22519,21 +22973,21 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
return head,start,true,true
end
end
- local lig=ligature.ligature
- if lig then
+ local ligature=tonumber(ligature) or ligature.ligature
+ if ligature then
if stop then
if trace_ligatures then
local stopchar=getchar(stop)
- head,start=toligature(head,start,stop,lig,dataset,sequence,skiphash,false,hasmarks)
- logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(lig))
+ head,start=toligature(head,start,stop,ligature,dataset,sequence,skiphash,false,hasmarks)
+ logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(ligature))
else
- head,start=toligature(head,start,stop,lig,dataset,sequence,skiphash,false,hasmarks)
+ head,start=toligature(head,start,stop,ligature,dataset,sequence,skiphash,false,hasmarks)
end
else
resetinjection(start)
- setchar(start,lig)
+ setchar(start,ligature)
if trace_ligatures then
- logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(dataset,sequence),gref(startchar),gref(lig))
+ logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(dataset,sequence),gref(startchar),gref(ligature))
end
end
return head,start,true,false
@@ -22728,7 +23182,7 @@ function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlm
end
end
elseif trace_bugs then
- onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
+ onetimemessage(currentfont,basechar,"no base anchors")
end
elseif trace_bugs then
logwarning("%s: prev node is no char, case %i",pref(dataset,sequence),1)
@@ -23007,7 +23461,7 @@ function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup
if skiphash and skiphash[schar] then
current=getnext(current)
else
- local lg=ligatures[schar]
+ local lg=not tonumber(ligatures) and ligatures[schar]
if lg then
ligatures=lg
last=current
@@ -23026,7 +23480,7 @@ function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup
end
end
end
- local ligature=ligatures.ligature
+ local ligature=tonumber(ligatures) or ligatures.ligature
if ligature then
if chainindex then
stop=last
@@ -23368,7 +23822,7 @@ function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup,
end
end
elseif trace_bugs then
- onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
+ onetimemessage(currentfont,startchar,"no entry anchors")
end
break
end
@@ -23438,7 +23892,7 @@ local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck)
local chainproc=chainprocs[chainkind]
if chainproc then
local ok
- head,start,ok=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash)
+ head,start,ok=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,1)
if ok then
done=true
end
@@ -23855,6 +24309,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
local ck=contexts[k]
local seq=ck[3]
local f=ck[4]
+local last=start
if not startchar or not seq[f][startchar] then
goto next
end
@@ -23863,7 +24318,6 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
else
local l=ck[5]
local current=start
- local last=start
if l>f then
local discfound
local n=f+1
@@ -24647,7 +25101,7 @@ local function t_run_single(start,stop,font,attr,lookupcache)
while s do
local char=ischar(s,font)
if char then
- local lg=lookupmatch[char]
+ local lg=not tonumber(lookupmatch) and lookupmatch[char]
if lg then
if sstop then
d=1
@@ -24677,7 +25131,7 @@ local function t_run_single(start,stop,font,attr,lookupcache)
break
end
end
- if l and l.ligature then
+ if l and (tonumber(l) or l.ligature) then
lastd=d
end
else
@@ -24802,7 +25256,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
while s do
local char=ischar(s)
if char then
- local lg=lookupmatch[char]
+ local lg=not tonumber(lookupmatch) and lookupmatch[char]
if lg then
if sstop then
d=1
@@ -24832,7 +25286,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
break
end
end
- if l and l.ligature then
+ if l and (tonumber(l) or l.ligature) then
lastd=d
end
end
@@ -25513,10 +25967,10 @@ registerotffeature {
},
}
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-ots”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-ots”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-osd” 0e051ca0d3b1a8e0604ced27e753fde8] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-osd” a67b6fb465e7a8b9ecf7c6bbf8dfda03] ---
if not modules then modules={} end modules ['font-osd']={
version=1.001,
@@ -25525,8 +25979,10 @@ if not modules then modules={} end modules ['font-osd']={
copyright="TAT Zetwerk / PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local insert,imerge,copy,tohash=table.insert,table.imerge,table.copy,table.tohash
-local next,type=next,type
+local insert,remove,imerge,copy,tohash=table.insert,table.remove,table.imerge,table.copy,table.tohash
+local next,type,rawget=next,type,rawget
+local formatters=string.formatters
+local settings_to_hash=utilities.parsers.settings_to_hash
local report=logs.reporter("otf","devanagari")
fonts=fonts or {}
fonts.analyzers=fonts.analyzers or {}
@@ -25536,6 +25992,7 @@ local handlers=otf.handlers
local methods=fonts.analyzers.methods
local otffeatures=fonts.constructors.features.otf
local registerotffeature=otffeatures.register
+local trace_steps=false
local nuts=nodes.nuts
local getnext=nuts.getnext
local getprev=nuts.getprev
@@ -25561,7 +26018,8 @@ local flushnode=nuts.flushnode
local copyinjection=nodes.injections.copy
local unsetvalue=attributes.unsetvalue
local fontdata=fonts.hashes.identifiers
-local a_syllabe=attributes.private('syllabe')
+local a_syllabe="syllable"
+local a_reordered="reordered"
local dotted_circle=0x25CC
local c_nbsp=0x00A0
local c_zwnj=0x200C
@@ -25581,8 +26039,11 @@ replace_all_nbsp=function(head)
return replace_all_nbsp(head)
end
local processcharacters=nil
+local logprocess=nil
if context then
local fontprocesses=fonts.hashes.processes
+ local tracers=nodes.tracers
+ local registermessage=(tracers and tracers.steppers.message) or function() end
function processcharacters(head,font)
local processors=fontprocesses[font]
for i=1,#processors do
@@ -25590,6 +26051,16 @@ if context then
end
return head
end
+ trackers.register("otf.steps",function(v) trace_steps=v end)
+ logprocess=function(str)
+ if trace_steps then
+ registermessage("devanagari %s",str)
+ if trace_steps=="silent" then
+ return
+ end
+ end
+ report(str)
+ end
else
function processcharacters(head,font)
local processors=fontdata[font].shared.processes
@@ -25598,6 +26069,8 @@ else
end
return head
end
+ logprocess=function(str)
+ end
end
local indicgroups=characters and characters.indicgroups
if not indicgroups and characters then
@@ -25707,7 +26180,7 @@ local before_subscript=indicgroups.before_subscript
local after_subscript=indicgroups.after_subscript
local before_main=indicgroups.before_main
local after_main=indicgroups.after_main
-local mark_four=table.merged (
+local mark_pre_above_below_post=table.merged (
pre_mark,
above_mark,
below_mark,
@@ -25718,6 +26191,11 @@ local mark_above_below_post=table.merged (
below_mark,
post_mark
)
+local devanagarihash=table.setmetatableindex(function(t,k)
+ local v=fontdata[k].resources.devanagari or false
+ t[k]=v
+ return v
+end)
local zw_char={
[c_zwnj]=true,
[c_zwj ]=true,
@@ -25838,7 +26316,7 @@ local function initializedevanagi(tfmdata)
local resources=tfmdata.resources
local devanagari=resources.devanagari
if not devanagari then
- report("adding devanagari features to font")
+ report("adding features to font")
local gsubfeatures=resources.features.gsub
local sequences=resources.sequences
local sharedfeatures=tfmdata.shared.features
@@ -25865,7 +26343,7 @@ local function initializedevanagi(tfmdata)
for k,v in next,pre_mark do
local locl=coverage[k]
if locl then
- if #locl>0 then
+ if #locl>0 then
for j=1,#locl do
local ck=locl[j]
local f=ck[4]
@@ -25886,6 +26364,7 @@ local function initializedevanagi(tfmdata)
end
end
end
+ else
end
if locl then
reorder_matras.steps[1].coverage[locl]=true
@@ -25898,7 +26377,7 @@ local function initializedevanagi(tfmdata)
if basic_shaping_forms[k] then
lastmatch=lastmatch+1
if s~=lastmatch then
- table.insert(sequences,lastmatch,table.remove(sequences,s))
+ insert(sequences,lastmatch,remove(sequences,s))
end
end
end
@@ -25916,9 +26395,7 @@ local function initializedevanagi(tfmdata)
local vatucache={}
local pstfcache={}
local seqsubset={}
- local rephstep={
- coverage={}
- }
+ local rephstep={ coverage={} }
local devanagari={
reph=false,
vattu=false,
@@ -25943,7 +26420,7 @@ local function initializedevanagi(tfmdata)
local has_pstf=features.pstf
if has_rphf and has_rphf[script] then
devanagari.reph=true
- elseif (has_blwf and has_blwf[script] ) or (has_vatu and has_vatu[script] ) then
+ elseif (has_blwf and has_blwf[script]) or (has_vatu and has_vatu[script]) then
devanagari.vattu=true
for i=1,nofsteps do
local step=steps[i]
@@ -25951,10 +26428,8 @@ local function initializedevanagi(tfmdata)
if coverage then
for k,v in next,coverage do
for h,w in next,halant do
- if v[h] then
- if not blwfcache[k] then
- blwfcache[k]=v
- end
+ if v[h] and not blwfcache[k] then
+ blwfcache[k]=v
end
if has_vatu and has_vatu[script] and not vatucache[k] then
vatucache[k]=v
@@ -25977,33 +26452,37 @@ local function initializedevanagi(tfmdata)
local r=coverage[k]
if r then
local found=false
- if #r>0 then
+ if #r>0 then
for j=1,#r do
local ck=r[j]
local f=ck[4]
local chainlookups=ck[6]
- if chainlookups and chainlookups[f] then
+ if chainlookups then
local chainlookup=chainlookups[f]
- for j=1,#chainlookup do
- local chainstep=chainlookup[j]
- local steps=chainstep.steps
- local nofsteps=chainstep.nofsteps
- for i=1,nofsteps do
- local step=steps[i]
- local coverage=step.coverage
- if coverage then
- local h=coverage[k]
- if h then
- for k,v in next,h do
- found=v and v.ligature
+ if chainlookup then
+ for j=1,#chainlookup do
+ local chainstep=chainlookup[j]
+ local steps=chainstep.steps
+ local nofsteps=chainstep.nofsteps
+ for i=1,nofsteps do
+ local step=steps[i]
+ local coverage=step.coverage
+ if coverage then
+ local h=coverage[k]
+ if h then
+ for k,v in next,h do
+ if v then
+ found=tonumber(v) or v.ligature
+ if found then
+ pre_base_reordering_consonants[found]=true
+ break
+ end
+ end
+ end
if found then
- pre_base_reordering_consonants[found]=true
break
end
end
- if found then
- break
- end
end
end
end
@@ -26012,10 +26491,12 @@ local function initializedevanagi(tfmdata)
end
else
for k,v in next,r do
- found=v and v.ligature
- if found then
- pre_base_reordering_consonants[found]=true
- break
+ if v then
+ found=tonumber(v) or v.ligature
+ if found then
+ pre_base_reordering_consonants[found]=true
+ break
+ end
end
end
end
@@ -26033,14 +26514,15 @@ local function initializedevanagi(tfmdata)
local step=steps[i]
local coverage=step.coverage
if coverage then
- local reph,rephbase=false,false
+ local reph=false
+ local base=false
if kind=="rphf" then
for k,v in next,ra do
local r=coverage[k]
if r then
- rephbase=k
+ base=k
local h=false
- if #r>0 then
+ if #r>0 then
for j=1,#r do
local ck=r[j]
local f=ck[4]
@@ -26060,7 +26542,7 @@ local function initializedevanagi(tfmdata)
for k,v in next,halant do
local h=r[k]
if h then
- reph=h.ligature or false
+ reph=tonumber(h) or h.ligature or false
break
end
end
@@ -26077,7 +26559,7 @@ local function initializedevanagi(tfmdata)
for k,v in next,halant do
local h=r[k]
if h then
- reph=h.ligature or false
+ reph=tonumber(h) or h.ligature or false
break
end
end
@@ -26088,7 +26570,7 @@ local function initializedevanagi(tfmdata)
end
end
end
- seqsubset[#seqsubset+1]={ kind,coverage,reph,rephbase }
+ seqsubset[#seqsubset+1]={ kind,coverage,reph,base }
end
end
end
@@ -26103,7 +26585,7 @@ local function initializedevanagi(tfmdata)
local h=coverage[k]
if h then
local found=false
- if #h>0 then
+ if #h>0 then
for j=1,#h do
local ck=h[j]
local f=ck[4]
@@ -26121,10 +26603,12 @@ local function initializedevanagi(tfmdata)
local h=coverage[k]
if h then
for k,v in next,h do
- found=v and v.ligature
- if found then
- pre_base_reordering_consonants[found]=true
- break
+ if v then
+ found=tonumber(v) or v.ligature
+ if found then
+ pre_base_reordering_consonants[found]=true
+ break
+ end
end
end
if found then
@@ -26138,7 +26622,7 @@ local function initializedevanagi(tfmdata)
end
else
for k,v in next,h do
- found=v and v.ligature
+ found=v and (tonumber(v) or v.ligature)
if found then
pre_base_reordering_consonants[found]=true
break
@@ -26164,9 +26648,6 @@ local function initializedevanagi(tfmdata)
sharedfeatures["dv03"]=true
sharedfeatures["dv04"]=true
end
- if script=="mlym" or script=="taml" then
- devanagari.left_matra_before_base=true
- end
end
end
end
@@ -26178,6 +26659,44 @@ registerotffeature {
node=initializedevanagi,
},
}
+local function initializeconjuncts(tfmdata,value)
+ if value then
+ local resources=tfmdata.resources
+ local devanagari=resources.devanagari
+ if devanagari then
+ local conjuncts="auto"
+ local movematra="auto"
+ if type(value)=="string" and value~="auto" then
+ value=settings_to_hash(value)
+ conjuncts=rawget(value,"conjuncts") or conjuncts
+ movematra=rawget(value,"movematra") or movematra
+ end
+ if conjuncts=="auto" then
+ conjuncts="mixed"
+ end
+ if movematra=="auto" and
+ script=="mlym" or
+ script=="taml" then
+ movematra="leftbeforebase"
+ else
+ movematra="default"
+ end
+ devanagari.conjuncts=conjuncts
+ devanagari.movematra=movematra
+ if trace_steps then
+ report("conjuncts %a, movematra %a",conjuncts,movematra)
+ end
+ end
+ end
+end
+registerotffeature {
+ name="indic",
+ description="control indic",
+ default="auto",
+ initializers={
+ node=initializeconjuncts,
+ },
+}
local show_syntax_errors=false
local function inject_syntax_error(head,current,char)
local signal=copy_node(current)
@@ -26223,36 +26742,40 @@ local function initialize_one(font,attr)
end
local function contextchain(contexts,n)
local char=getchar(n)
- for k=1,#contexts do
- local ck=contexts[k]
- local seq=ck[3]
- local f=ck[4]
- local l=ck[5]
- if (l-f)==1 and seq[f+1][char] then
- local ok=true
- local c=n
- for i=l+1,#seq do
- c=getnext(c)
- if not c or not seq[i][ischar(c)] then
- ok=false
- break
- end
- end
- if ok then
- c=getprev(n)
- for i=1,f-1 do
- c=getprev(c)
- if not c or not seq[f-i][ischar(c)] then
+ if not contexts.n then
+ return contexts[char]
+ else
+ for k=1,#contexts do
+ local ck=contexts[k]
+ local seq=ck[3]
+ local f=ck[4]
+ local l=ck[5]
+ if (l-f)==1 and seq[f+1][char] then
+ local ok=true
+ local c=n
+ for i=l+1,#seq do
+ c=getnext(c)
+ if not c or not seq[i][ischar(c)] then
ok=false
+ break
end
end
- end
- if ok then
- return true
+ if ok then
+ c=getprev(n)
+ for i=1,f-1 do
+ c=getprev(c)
+ if not c or not seq[f-i][ischar(c)] then
+ ok=false
+ end
+ end
+ end
+ if ok then
+ return true
+ end
end
end
+ return false
end
- return false
end
local function order_matras(c)
local cn=getnext(c)
@@ -26281,9 +26804,9 @@ local function order_matras(c)
char=getchar(cn)
end
end
+local swapped=table.swapped(states)
local function reorder_one(head,start,stop,font,attr,nbspaces)
- local reph,vattu,blwfcache,vatucache,pstfcache=initialize_one(font,attr)
- local devanagari=fontdata[font].resources.devanagari
+ local reph,vattu,blwfcache,vatucache,pstfcache=initialize_one(font,attr)
local current=start
local n=getnext(start)
local base=nil
@@ -26306,6 +26829,9 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
stop=getprev(stop)
head=remove_node(head,current)
flushnode(current)
+ if trace_steps then
+ logprocess("reorder one, remove nbsp")
+ end
return head,stop,nbspaces
else
nbspaces=nbspaces+1
@@ -26349,6 +26875,9 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
stop=current
end
end
+ if trace_steps then
+ logprocess("reorder one, handle nbsp")
+ end
end
end
end
@@ -26403,6 +26932,9 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
if lastcons==stop then
stop=n
end
+ if trace_steps then
+ logprocess("reorder one, handle halant")
+ end
end
end
n=getnext(start)
@@ -26427,6 +26959,9 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
if matra==stop then
stop=n
end
+ if trace_steps then
+ logprocess("reorder one, handle matra")
+ end
end
local current=start
while current~=stop do
@@ -26465,14 +27000,19 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
ch=getchar(n)
end
local tpm=twopart_mark[ch]
- while tpm do
- local extra=copy_node(n)
- copyinjection(extra,n)
- ch=tpm[1]
- setchar(n,ch)
- setchar(extra,tpm[2])
- head=insertnodeafter(head,current,extra)
- tpm=twopart_mark[ch]
+ if tpm then
+ while tpm do
+ local extra=copy_node(n)
+ copyinjection(extra,n)
+ ch=tpm[1]
+ setchar(n,ch)
+ setchar(extra,tpm[2])
+ head=insertnodeafter(head,current,extra)
+ tpm=twopart_mark[ch]
+ end
+ if trace_steps then
+ logprocess("reorder one, handle mark")
+ end
end
while c~=stop and dependent_vowel[ch] do
c=n
@@ -26495,9 +27035,10 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
local bp=getprev(firstcons)
local cn=getnext(current)
local last=getnext(c)
+ local done=false
while cn~=last do
if pre_mark[getchar(cn)] then
- if devanagari.left_matra_before_base then
+ if devanagarihash[font].movematra=="leftbeforebase" then
local prev,next=getboth(cn)
setlink(prev,next)
if cn==stop then
@@ -26534,6 +27075,7 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
end
cn=next
end
+ done=true
elseif current~=base and dependent_vowel[getchar(cn)] then
local prev,next=getboth(cn)
if next then
@@ -26546,6 +27088,7 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
setlink(b,cn,getnext(b))
order_matras(cn)
cn=next
+ done=true
elseif current==base and dependent_vowel[getchar(cn)] then
local cnn=getnext(cn)
order_matras(cn)
@@ -26559,9 +27102,14 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
end
allreordered=c==stop
current=getnext(c)
+ if done and trace_steps then
+ logprocess("reorder one, matra")
+ end
end
if reph or vattu then
- local current,cns=start,nil
+ local current=start
+ local cns=nil
+ local done=false
while current~=stop do
local c=current
local n=getnext(current)
@@ -26592,6 +27140,7 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
local next=getnext(b)
setlink(c,next)
setlink(b,current)
+ done=true
end
elseif cns and getnext(cns)~=current then
local cp=getprev(current)
@@ -26599,6 +27148,7 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
setlink(cp,n)
setlink(cns,current)
setlink(c,cnsn)
+ done=true
if c==stop then
stop=cp
break
@@ -26638,11 +27188,14 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
end
current=getnext(current)
end
+ if done and trace_steps then
+ logprocess("reorder one, handle reph and vata")
+ end
end
if getchar(base)==c_nbsp then
nbspaces=nbspaces-1
if base==stop then
- stop=getprev(stop)
+ stop=getprev(stop)
end
head=remove_node(head,base)
flushnode(base)
@@ -26670,6 +27223,9 @@ function handlers.devanagari_reorder_matras(head,start)
setlink(start,next)
setlink(current,start)
start=startnext
+ if trace_steps then
+ logprocess("reorder matra")
+ end
break
end
else
@@ -26698,6 +27254,9 @@ function handlers.devanagari_reorder_reph(head,start)
local char=ischar(current,startfont)
if char and getprop(current,a_syllabe)==startattr then
if halant[char] then
+ if trace_steps then
+ logprocess("reorder reph, handling halant")
+ end
local next=getnext(current)
if next then
local nextchar=ischar(next,startfont)
@@ -26728,6 +27287,9 @@ function handlers.devanagari_reorder_reph(head,start)
local char=ischar(current,startfont)
if char and getprop(current,a_syllabe)==startattr then
if consonant[char] and not getstate(current,s_pref) then
+ if trace_steps then
+ logprocess("reorder reph, handling consonant")
+ end
startnext=getnext(start)
head=remove_node(head,start)
setlink(current,start)
@@ -26752,6 +27314,9 @@ function handlers.devanagari_reorder_reph(head,start)
local char=ischar(current,startfont)
if char and getprop(current,a_syllabe)==startattr then
if getstate(current,s_pstf) then
+ if trace_steps then
+ logprocess("reorder reph, before postscript, post base")
+ end
startnext=getnext(start)
head=remove_node(head,start)
setlink(getprev(current),start)
@@ -26759,12 +27324,15 @@ function handlers.devanagari_reorder_reph(head,start)
start=startnext
startattr=getprop(start,a_syllabe)
break
- elseif not c and (vowel_modifier[char] or stress_tone_mark[char] ) then
+ elseif not c and (vowel_modifier[char] or stress_tone_mark[char]) then
c=current
end
current=getnext(current)
else
if c then
+ if trace_steps then
+ logprocess("reorder reph, before postscript")
+ end
startnext=getnext(start)
head=remove_node(head,start)
setlink(getprev(c),start)
@@ -26787,7 +27355,13 @@ function handlers.devanagari_reorder_reph(head,start)
local state=getstate(current)
if before_subscript[rephbase] and (state==s_blwf or state==s_pstf) then
c=current
+ if trace_steps then
+ logprocess("reorder reph, before subscript")
+ end
elseif after_subscript[rephbase] and (state==s_pstf) then
+ if trace_steps then
+ logprocess("reorder reph, after subscript")
+ end
c=current
end
current=getnext(current)
@@ -26818,6 +27392,9 @@ function handlers.devanagari_reorder_reph(head,start)
end
end
if start~=current then
+ if trace_steps then
+ logprocess("reorder reph, to end")
+ end
startnext=getnext(start)
head=remove_node(head,start)
setlink(start,getnext(current))
@@ -26827,9 +27404,8 @@ function handlers.devanagari_reorder_reph(head,start)
end
return head,start,true
end
-local reordered_pre_base_reordering_consonants={}
function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
- if reordered_pre_base_reordering_consonants[start] then
+ if getprop(start,a_reordered) then
return head,start,true
end
local current=start
@@ -26840,6 +27416,9 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
local next=getnext(current)
if char and getprop(current,a_syllabe)==startattr then
if halant[char] then
+ if trace_steps then
+ logprocess("reorder pre base consonants, handle halant")
+ end
if next then
local char=ischar(next,startfont)
if char and zw_char[char] and getprop(next,a_syllabe)==startattr then
@@ -26851,7 +27430,7 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
head=remove_node(head,start)
setlink(start,next)
setlink(current,start)
- reordered_pre_base_reordering_consonants[start]=true
+ setprop(start,"reordered",true)
start=startnext
return head,start,true
end
@@ -26865,6 +27444,9 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
while current and getprop(current,a_syllabe)==startattr do
local char=ischar(current)
if (not dependent_vowel[char] and (not getstate(current) or getstate(current,s_init))) then
+ if trace_steps then
+ logprocess("reorder pre base consonants, handle vowel or initial")
+ end
startnext=getnext(start)
head=remove_node(head,start)
if current==head then
@@ -26874,7 +27456,7 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
setlink(getprev(current),start)
setlink(start,current)
end
- reordered_pre_base_reordering_consonants[start]=true
+ setprop(start,"reordered",true)
start=startnext
break
end
@@ -26906,6 +27488,9 @@ function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replaceme
head=stop
end
flushlist(start)
+ if trace_steps then
+ logprocess("remove joiners")
+ end
return head,stop,true
end
local function initialize_two(font,attr)
@@ -26922,15 +27507,17 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
local basepos=nil
local subpos=nil
local postpos=nil
- reorderreph.coverage={}
- rephbase[font]={}
+ reorderreph.coverage={}
+ rephbase[font]={}
for i=1,#seqsubset do
local subset=seqsubset[i]
local kind=subset[1]
local lookupcache=subset[2]
if kind=="rphf" then
- reorderreph.coverage[subset[3]]=true
- rephbase[font][subset[3]]=subset[4]
+ local reph=subset[3]
+ local base=subset[4]
+ reorderreph.coverage[reph]=true
+ rephbase[font][reph]=base
local current=start
local last=getnext(stop)
while current~=last do
@@ -26939,15 +27526,15 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
local found=lookupcache[c]
if found then
local next=getnext(current)
- if found[getchar(next)] or contextchain(found,next) then
+ if contextchain(found,next) then
local afternext=next~=stop and getnext(next)
if afternext and zw_char[getchar(afternext)] then
current=afternext
elseif current==start then
setstate(current,s_rphf)
- current=next
+ current=next
else
- current=next
+ current=next
end
end
end
@@ -26963,8 +27550,8 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
local found=lookupcache[c]
if found then
local next=getnext(current)
- if found[getchar(next)] or contextchain(found,next) then
- if (not getstate(current) and not getstate(next)) then
+ if contextchain(found,next) then
+ if not getstate(current) and not getstate(next) then
setstate(current,s_pref)
setstate(next,s_pref)
current=next
@@ -26983,10 +27570,10 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
local found=lookupcache[c]
if found then
local next=getnext(current)
- if found[getchar(next)] or contextchain(found,next) then
+ if contextchain(found,next) then
if next~=stop and getchar(getnext(next))==c_zwnj then
current=next
- elseif (not getstate(current)) then
+ elseif not getstate(current) then
setstate(current,s_half)
if not halfpos then
halfpos=current
@@ -27007,8 +27594,8 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
local found=lookupcache[c]
if found then
local next=getnext(current)
- if found[getchar(next)] or contextchain(found,next) then
- if (not getstate(current) and not getstate(next)) then
+ if contextchain(found,next) then
+ if not getstate(current) and not getstate(next) then
setstate(current,s_blwf)
setstate(next,s_blwf)
current=next
@@ -27028,8 +27615,8 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
local found=lookupcache[c]
if found then
local next=getnext(current)
- if found[getchar(next)] or contextchain(found,next) then
- if (not getstate(current) and not getstate(next)) then
+ if contextchain(found,next) then
+ if not getstate(current) and not getstate(next) then
setstate(current,s_pstf)
setstate(next,s_pstf)
current=next
@@ -27051,6 +27638,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
stop=getprev(stop)
head=remove_node(head,current)
flushnode(current)
+ if trace_steps then
+ logprocess("reorder two, remove nbsp")
+ end
return head,stop,nbspaces
else
nbspaces=nbspaces+1
@@ -27091,6 +27681,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
end
end
end
+ if trace_steps then
+ logprocess("reorder two, handle nbsp")
+ end
end
else
local last=getnext(stop)
@@ -27120,7 +27713,7 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
return head,stop,nbspaces
else
if getstate(base) then
- setstate(base,unsetvalue)
+ setstate(base,unsetvalue)
end
basepos=base
end
@@ -27141,14 +27734,19 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
local target=nil
local cn=getnext(current)
local tpm=twopart_mark[char]
- while tpm do
- local extra=copy_node(current)
- copyinjection(extra,current)
- char=tpm[1]
- setchar(current,char)
- setchar(extra,tpm[2])
- head=insertnodeafter(head,current,extra)
- tpm=twopart_mark[char]
+ if tpm then
+ while tpm do
+ local extra=copy_node(current)
+ copyinjection(extra,current)
+ char=tpm[1]
+ setchar(current,char)
+ setchar(extra,tpm[2])
+ head=insertnodeafter(head,current,extra)
+ tpm=twopart_mark[char]
+ end
+ if tpm and trace_steps then
+ logprocess("reorder two, handle matra")
+ end
end
if not moved[current] and dependent_vowel[char] then
if pre_mark[char] then
@@ -27189,6 +27787,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
end
setlink(getprev(pos),current)
setlink(current,pos)
+ if trace_steps then
+ logprocess("reorder two, handle pre mark")
+ end
elseif above_mark[char] then
target=basepos
if subpos==basepos then
@@ -27228,6 +27829,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
end
setlink(current,getnext(target))
setlink(target,current)
+ if trace_steps then
+ logprocess("reorder two, handle mark")
+ end
end
end
end
@@ -27255,6 +27859,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
stop=prev
end
cn=next
+ if trace_steps then
+ logprocess("reorder two, handle halant and ra")
+ end
end
end
end
@@ -27287,6 +27894,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
setprev(nextnextnext,current)
end
setlink(nextnext,c)
+ if trace_steps then
+ logprocess("reorder two, handle nukta")
+ end
end
if stop==current then break end
current=getnext(current)
@@ -27298,6 +27908,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
nbspaces=nbspaces-1
head=remove_node(head,base)
flushnode(base)
+ if trace_steps then
+ logprocess("reorder two, handle nbsp")
+ end
end
return head,stop,nbspaces
end
@@ -27385,21 +27998,42 @@ local function analyze_next_chars_one(c,font,variant)
local already_below_mark
local already_post_mark
while dependent_vowel[v] do
- local vowels=twopart_mark[v] or { v }
- for k,v in next,vowels do
- if pre_mark[v] and not already_pre_mark then
- already_pre_mark=true
- elseif above_mark[v] and not already_above_mark then
- already_above_mark=true
- elseif below_mark[v] and not already_below_mark then
- already_below_mark=true
- elseif post_mark[v] and not already_post_mark then
- already_post_mark=true
- else
- return c
- end
- end
- c=getnext(c)
+ local vowels=twopart_mark[v]
+ if vowels then
+ for k=1,#vowels do
+ local v=vowels[k]
+ if pre_mark[v] and not already_pre_mark then
+ already_pre_mark=true
+ elseif above_mark[v] and not already_above_mark then
+ already_above_mark=true
+ elseif below_mark[v] and not already_below_mark then
+ already_below_mark=true
+ elseif post_mark[v] and not already_post_mark then
+ already_post_mark=true
+ elseif devanagarihash[font].conjuncts=="continue" then
+ else
+ return c
+ end
+ end
+ else
+ if pre_mark[v] and not already_pre_mark then
+ already_pre_mark=true
+ elseif post_mark[v] and not already_post_mark then
+ if devanagarihash[font].conjuncts=="mixed" then
+ return c
+ else
+ already_post_mark=true
+ end
+ elseif below_mark[v] and not already_below_mark then
+ already_below_mark=true
+ elseif above_mark[v] and not already_above_mark then
+ already_above_mark=true
+ elseif devanagarihash[font].conjuncts=="continue" then
+ else
+ return c
+ end
+ end
+ c=n
n=getnext(c)
if not n then
return c
@@ -27410,7 +28044,7 @@ local function analyze_next_chars_one(c,font,variant)
end
end
if nukta[v] then
- c=getnext(c)
+ c=n
n=getnext(c)
if not n then
return c
@@ -27421,7 +28055,7 @@ local function analyze_next_chars_one(c,font,variant)
end
end
if halant[v] then
- c=getnext(c)
+ c=n
n=getnext(c)
if not n then
return c
@@ -27432,7 +28066,7 @@ local function analyze_next_chars_one(c,font,variant)
end
end
if vowel_modifier[v] then
- c=getnext(c)
+ c=n
n=getnext(c)
if not n then
return c
@@ -27443,7 +28077,7 @@ local function analyze_next_chars_one(c,font,variant)
end
end
if stress_tone_mark[v] then
- c=getnext(c)
+ c=n
n=getnext(c)
if not n then
return c
@@ -27460,11 +28094,12 @@ local function analyze_next_chars_one(c,font,variant)
end
end
local function analyze_next_chars_two(c,font)
- local n=getnext(c)
+ local n,v
+ n=getnext(c)
if not n then
return c
end
- local v=ischar(n,font)
+ v=ischar(n,font)
if v and nukta[v] then
c=n
end
@@ -27523,11 +28158,11 @@ local function analyze_next_chars_two(c,font)
if not c then
return
end
- local n=getnext(c)
+ n=getnext(c)
if not n then
return c
end
- local v=ischar(n,font)
+ v=ischar(n,font)
if not v then
return c
end
@@ -27567,22 +28202,43 @@ local function analyze_next_chars_two(c,font)
local already_pre_mark
local already_above_mark
local already_below_mark
- local already_post_mark
- while dependent_vowel[v] do
- local vowels=twopart_mark[v] or { v }
- for k,v in next,vowels do
- if pre_mark[v] and not already_pre_mark then
- already_pre_mark=true
- elseif above_mark[v] and not already_above_mark then
- already_above_mark=true
- elseif below_mark[v] and not already_below_mark then
- already_below_mark=true
- elseif post_mark[v] and not already_post_mark then
- already_post_mark=true
- else
- return c
- end
- end
+ local already_post_mark
+ while dependent_vowel[v] do
+ local vowels=twopart_mark[v]
+ if vowels then
+ for k=1,#vowels do
+ local v=vowels[k]
+ if pre_mark[v] and not already_pre_mark then
+ already_pre_mark=true
+ elseif above_mark[v] and not already_above_mark then
+ already_above_mark=true
+ elseif below_mark[v] and not already_below_mark then
+ already_below_mark=true
+ elseif post_mark[v] and not already_post_mark then
+ already_post_mark=true
+ elseif devanagarihash[font].conjuncts=="continue" then
+ else
+ return c
+ end
+ end
+ else
+ if pre_mark[v] and not already_pre_mark then
+ already_pre_mark=true
+ elseif post_mark[v] and not already_post_mark then
+ if devanagarihash[font].conjuncts=="mixed" then
+ return c
+ else
+ already_post_mark=true
+ end
+ elseif below_mark[v] and not already_below_mark then
+ already_below_mark=true
+ elseif above_mark[v] and not already_above_mark then
+ already_above_mark=true
+ elseif devanagarihash[font].conjuncts=="continue" then
+ else
+ return c
+ end
+ end
c=n
n=getnext(c)
if not n then
@@ -27817,7 +28473,7 @@ local function method_one(head,font,attr)
end
else
if show_syntax_errors then
- local mark=mark_four[char]
+ local mark=mark_pre_above_below_post[char]
if mark then
head,current=inject_syntax_error(head,current,char)
end
@@ -27838,15 +28494,15 @@ local function method_one(head,font,attr)
while current do
local char=ischar(current,font)
if char then
- if n==0 and not getstate(current) then
- setstate(current,s_init)
- end
- n=n+1
- else
- n=0
- end
- current=getnext(current)
- end
+ if n==0 and not getstate(current) then
+ setstate(current,s_init)
+ end
+ n=n+1
+ else
+ n=0
+ end
+ current=getnext(current)
+ end
return head,done
end
local function method_two(head,font,attr)
@@ -27916,7 +28572,7 @@ local function method_two(head,font,attr)
if not syllableend and show_syntax_errors then
local char=ischar(current,font)
if char and not getstate(current) then
- local mark=mark_four[char]
+ local mark=mark_pre_above_below_post[char]
if mark then
head,current=inject_syntax_error(head,current,char)
end
@@ -27933,15 +28589,15 @@ local function method_two(head,font,attr)
while current do
local char=ischar(current,font)
if char then
- if n==0 and not getstate(current) then
- setstate(current,s_init)
- end
- n=n+1
- else
- n=0
- end
- current=getnext(current)
- end
+ if n==0 and not getstate(current) then
+ setstate(current,s_init)
+ end
+ n=n+1
+ else
+ n=0
+ end
+ current=getnext(current)
+ end
return head,done
end
for i=1,nofscripts do
@@ -27949,10 +28605,10 @@ for i=1,nofscripts do
methods[scripts_two[i]]=method_two
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-osd”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-osd”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-ocl” 2a377351ae23c339764ec8ce2e8e9164] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-ocl” 2a377351ae23c339764ec8ce2e8e9164] ---
if not modules then modules={} end modules ['font-ocl']={
version=1.001,
@@ -28500,10 +29156,10 @@ if context then
}
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-ocl”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-ocl”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-otc” 0f12230ea07b5151f75d52726977e91f] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-otc” 582295d3d1e44cd4a31e8bbc1156f7c1] ---
if not modules then modules={} end modules ['font-otc']={
version=1.001,
@@ -28594,6 +29250,7 @@ local function validspecification(specification,name)
else
dataset={ { data=specification.data } }
specification.data=nil
+ specification.coverage=dataset
specification.dataset=dataset
end
local first=dataset[1]
@@ -28893,7 +29550,28 @@ local function addfeature(data,feature,specifications)
return coverage
end
local prepare_single=prepare_pair
- local function prepare_chain(list,featuretype,sublookups)
+ local function hassteps(lookups)
+ if lookups then
+ for i=1,#lookups do
+ local l=lookups[i]
+ if l then
+ for j=1,#l do
+ local l=l[j]
+ if l then
+ local n=l.nofsteps
+ if not n then
+ return true
+ elseif n>0 then
+ return true
+ end
+ end
+ end
+ end
+ end
+ end
+ return false
+ end
+ local function prepare_chain(list,featuretype,sublookups,nocheck)
local rules=list.rules
local coverage={}
if rules then
@@ -28929,6 +29607,7 @@ local function addfeature(data,feature,specifications)
local lookups=rule.lookups or false
local subtype=nil
if lookups and sublookups then
+ local l={}
for k,v in sortedhash(lookups) do
local t=type(v)
if t=="table" then
@@ -28938,55 +29617,63 @@ local function addfeature(data,feature,specifications)
v[i]={ vi }
end
end
+ l[k]=v
elseif t=="number" then
local lookup=sublookups[v]
if lookup then
- lookups[k]={ lookup }
+ l[k]={ lookup }
if not subtype then
subtype=lookup.type
end
elseif v==0 then
- lookups[k]={ { type="gsub_remove" } }
+ l[k]={ { type="gsub_remove",nosteps=true } }
else
- lookups[k]=false
+ l[k]=false
end
else
- lookups[k]=false
+ l[k]=false
end
end
+ if nocheck then
+ rule.lookups=l
+ end
+ lookups=l
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
+ if hassteps(lookups) 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
- 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
+ sequence.n=nofsequences
+ else
end
- sequence.n=nofsequences
end
end
rulehash.n=rulesize
@@ -29073,126 +29760,148 @@ local function addfeature(data,feature,specifications)
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 featuretype=specification.type or "substitution"
+ local featureaction=false
local featureflags=specification.flags or noflags
local nocheck=specification.nocheck
+ local mapping=specification.mapping
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
+ local steptype=nil
+ local sequence=nil
+ if fonts.handlers.otf.handlers[featuretype] then
+ featureaction=true
+ else
+ featuretype=normalized[specification.type or "substitution"] or "substitution"
+ end
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)
+ 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
+ if featureaction then
+ category="gsub"
+ sequence={
+ features={ [feature]=askedfeatures },
+ flags=featureflags,
+ name=feature,
+ order=featureorder,
+ type=featuretype,
+ nofsteps=0,
+ }
+ else
+ 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=(mapping and list) or 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,nocheck)
+ elseif featuretype=="chainposition" then
+ category="gpos"
+ coverage=prepare_chain(list,featuretype,sublookups,nocheck)
+ 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
- checkmerge(specification)
- checksteps(specification)
- s[i]={
+ end
+ if nofsteps>0 then
+ sequence={
+ chain=featurechain,
+ features={ [feature]=askedfeatures },
+ flags=featureflags,
+ name=feature,
+ order=featureorder,
[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,
- }
+ if sequence then
checkflags(sequence,resources)
checkmerge(sequence)
checksteps(sequence)
@@ -29260,10 +29969,10 @@ end
otf.enhancers.enhance=enhance
otf.enhancers.register("check extra features",enhance)
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-otc”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-otc”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-onr” 6d161533f3437435e12a0ad64866df44] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-onr” 6d161533f3437435e12a0ad64866df44] ---
if not modules then modules={} end modules ['font-onr']={
version=1.001,
@@ -29636,10 +30345,10 @@ function readers.getinfo(filename)
end
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-onr”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-onr”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-one” bd39d42055a44ca2002f8ddbbbbf27c3] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-one” bd39d42055a44ca2002f8ddbbbbf27c3] ---
if not modules then modules={} end modules ['font-one']={
version=1.001,
@@ -30354,10 +31063,10 @@ registerafmenhancer("normalize features",enhance_normalize_features)
registerafmenhancer("check extra features",otfenhancers.enhance)
registerafmenhancer("fix names",enhance_fix_names)
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-one”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-one”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-afk” 9da14e0fb22129c053acc599d1312544] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-afk” 9da14e0fb22129c053acc599d1312544] ---
if not modules then modules={} end modules ['font-afk']={
version=1.001,
@@ -30524,10 +31233,10 @@ fonts.handlers.afm.helpdata={
}
}
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-afk”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-afk”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “fonts-tfm” f0eb5e2a8068b17ad401bb7efdba1630] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “fonts-tfm” f0eb5e2a8068b17ad401bb7efdba1630] ---
if not modules then modules={} end modules ['luatex-fonts-tfm']={
version=1.001,
@@ -31042,10 +31751,10 @@ registertfmfeature {
}
}
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “fonts-tfm”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “fonts-tfm”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-lua” 1fbfdf7b689b2bdfd0e3bb9bf74ce136] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-lua” 1fbfdf7b689b2bdfd0e3bb9bf74ce136] ---
if not modules then modules={} end modules ['font-lua']={
version=1.001,
@@ -31085,10 +31794,10 @@ function readers.lua(specification)
return check_lua(specification,fullname)
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-lua”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-lua”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-def” b9d908c2338b7dc443ce9d1e9fcb7139] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-def” b9d908c2338b7dc443ce9d1e9fcb7139] ---
if not modules then modules={} end modules ['font-def']={
version=1.001,
@@ -31488,10 +32197,10 @@ if not context then
callbacks.register('define_font',definers.read,"definition of fonts (tfmdata preparation)")
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-def”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-def”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-shp” 2bb36adb4b264a895a2c4d97e1ac1d1e] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-shp” a40862fe382d26c1f3753431254bcfdd] ---
if not modules then modules={} end modules ['font-shp']={
version=1.001,
@@ -31508,7 +32217,7 @@ local afm=fonts.handlers.afm
local pfb=fonts.handlers.pfb
local hashes=fonts.hashes
local identifiers=hashes.identifiers
-local version=0.010
+local version=otf.version or 0.011
local shapescache=containers.define("fonts","shapes",version,true)
local streamscache=containers.define("fonts","streams",version,true)
local compact_streams=false
@@ -31816,7 +32525,7 @@ local function getstreamhash(fontid)
local fontdata=identifiers[fontid]
if fontdata then
local properties=fontdata.properties
- return makehash(properties.filename,properties.subfont,properties.instance)
+ return makehash(properties.filename,properties.subfont,properties.instance),fontdata
end
end
local function loadstreamdata(fontdata)
@@ -31856,10 +32565,10 @@ callback.register("glyph_stream_provider",function(id,index,mode)
return ""
end)
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-shp”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-shp”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “fonts-def” f435e0875f203f343157baeff876ec9c] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “fonts-def” f435e0875f203f343157baeff876ec9c] ---
if not modules then modules={} end modules ['luatex-fonts-def']={
version=1.001,
@@ -31940,10 +32649,10 @@ function fonts.definers.applypostprocessors(tfmdata)
return tfmdata
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “fonts-def”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “fonts-def”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “fonts-ext” 32013cbc5d5d336be8b1d1e5879d86c4] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “fonts-ext” 32013cbc5d5d336be8b1d1e5879d86c4] ---
if not modules then modules={} end modules ['luatex-fonts-ext']={
version=1.001,
@@ -32129,10 +32838,10 @@ registerotffeature {
}
}
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “fonts-ext”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “fonts-ext”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-imp-tex” ceb087ef6fa2f89aed7179f60ddf8f35] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-imp-tex” ceb087ef6fa2f89aed7179f60ddf8f35] ---
if not modules then modules={} end modules ['font-imp-tex']={
version=1.001,
@@ -32231,10 +32940,10 @@ registerotffeature {
description="arabic digits",
}
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-imp-tex”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-imp-tex”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-imp-ligatures” 26ffcf089391445f7af59536c8814364] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-imp-ligatures” 26ffcf089391445f7af59536c8814364] ---
if not modules then modules={} end modules ['font-imp-ligatures']={
version=1.001,
@@ -32348,10 +33057,10 @@ if context then
}
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-imp-ligatures”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-imp-ligatures”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-imp-italics” defcb415bc1e0a0999b27773902adc18] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-imp-italics” defcb415bc1e0a0999b27773902adc18] ---
if not modules then modules={} end modules ['font-imp-italics']={
version=1.001,
@@ -32455,10 +33164,10 @@ if context then
registerafmfeature(dimensions_specification)
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-imp-italics”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-imp-italics”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “font-imp-effects” d05997c1826355548ec9aec1346f9f23] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “font-imp-effects” d05997c1826355548ec9aec1346f9f23] ---
if not modules then modules={} end modules ['font-imp-effects']={
version=1.001,
@@ -32815,10 +33524,10 @@ local specification={
registerotffeature(specification)
registerafmfeature(specification)
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “font-imp-effects”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “font-imp-effects”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “fonts-lig” fbd251eea3810a43a8d5542319361d68] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “fonts-lig” fbd251eea3810a43a8d5542319361d68] ---
fonts.handlers.otf.addfeature {
@@ -34887,10 +35596,10 @@ fonts.handlers.otf.addfeature {
["type"]="ligature",
}
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “fonts-lig”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “fonts-lig”] ---
-do --- [luaotfload, fontloader-2021-05-20.lua scope for “fonts-gbn” 34e4543a02f6fbc8c2ade896cb6dc7df] ---
+do --- [luaotfload, fontloader-2022-02-24.lua scope for “fonts-gbn” 34e4543a02f6fbc8c2ade896cb6dc7df] ---
if not modules then modules={} end modules ['luatex-fonts-gbn']={
version=1.001,
@@ -35155,7 +35864,7 @@ function nodes.simple_font_handler(head,groupcode,size,packtype,direction)
return head
end
-end --- [luaotfload, fontloader-2021-05-20.lua scope for “fonts-gbn”] ---
+end --- [luaotfload, fontloader-2022-02-24.lua scope for “fonts-gbn”] ---
--- vim:ft=lua:sw=2:ts=8:et:tw=79
diff --git a/macros/luatex/generic/luaotfload/fontloader-basics-chr.lua b/macros/luatex/generic/luaotfload/fontloader-basics-chr.lua
index 0ac0eab14e..3bbb693ab3 100644
--- a/macros/luatex/generic/luaotfload/fontloader-basics-chr.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-basics-chr.lua
@@ -206,6 +206,7 @@ characters.classifiers={
[1562]=5,
[1563]=6,
[1564]=6,
+ [1565]=6,
[1566]=6,
[1567]=6,
[1568]=2,
@@ -672,9 +673,9 @@ characters.classifiers={
[2131]=2,
[2132]=3,
[2133]=2,
- [2134]=4,
- [2135]=4,
- [2136]=4,
+ [2134]=3,
+ [2135]=3,
+ [2136]=3,
[2137]=5,
[2138]=5,
[2139]=5,
@@ -689,6 +690,47 @@ characters.classifiers={
[2152]=2,
[2153]=3,
[2154]=3,
+ [2160]=3,
+ [2161]=3,
+ [2162]=3,
+ [2163]=3,
+ [2164]=3,
+ [2165]=3,
+ [2166]=3,
+ [2167]=3,
+ [2168]=3,
+ [2169]=3,
+ [2170]=3,
+ [2171]=3,
+ [2172]=3,
+ [2173]=3,
+ [2174]=3,
+ [2175]=3,
+ [2176]=3,
+ [2177]=3,
+ [2178]=3,
+ [2179]=2,
+ [2180]=2,
+ [2181]=2,
+ [2182]=2,
+ [2183]=4,
+ [2184]=4,
+ [2185]=2,
+ [2186]=2,
+ [2187]=2,
+ [2188]=2,
+ [2189]=2,
+ [2190]=3,
+ [2192]=4,
+ [2193]=4,
+ [2200]=5,
+ [2201]=5,
+ [2202]=5,
+ [2203]=5,
+ [2204]=5,
+ [2205]=5,
+ [2206]=5,
+ [2207]=5,
[2208]=2,
[2209]=2,
[2210]=2,
@@ -710,6 +752,7 @@ characters.classifiers={
[2226]=3,
[2227]=2,
[2228]=2,
+ [2229]=2,
[2230]=2,
[2231]=2,
[2232]=2,
@@ -718,6 +761,26 @@ characters.classifiers={
[2235]=2,
[2236]=2,
[2237]=2,
+ [2238]=2,
+ [2239]=2,
+ [2240]=2,
+ [2241]=2,
+ [2242]=2,
+ [2243]=2,
+ [2244]=2,
+ [2245]=2,
+ [2246]=2,
+ [2247]=2,
+ [2248]=2,
+ [2250]=5,
+ [2251]=5,
+ [2252]=5,
+ [2253]=5,
+ [2254]=5,
+ [2255]=5,
+ [2256]=5,
+ [2257]=5,
+ [2258]=5,
[2259]=5,
[2260]=5,
[2261]=5,
@@ -837,6 +900,7 @@ characters.classifiers={
[2883]=5,
[2884]=5,
[2893]=5,
+ [2901]=5,
[2902]=5,
[2914]=5,
[2915]=5,
@@ -845,6 +909,7 @@ characters.classifiers={
[3021]=5,
[3072]=5,
[3076]=5,
+ [3132]=5,
[3134]=5,
[3135]=5,
[3136]=5,
@@ -878,6 +943,7 @@ characters.classifiers={
[3405]=5,
[3426]=5,
[3427]=5,
+ [3457]=5,
[3530]=5,
[3538]=5,
[3539]=5,
@@ -1057,6 +1123,7 @@ characters.classifiers={
[6156]=5,
[6157]=5,
[6158]=4,
+ [6159]=5,
[6176]=2,
[6177]=2,
[6178]=2,
@@ -1241,6 +1308,22 @@ characters.classifiers={
[6843]=5,
[6844]=5,
[6845]=5,
+ [6847]=5,
+ [6848]=5,
+ [6849]=5,
+ [6850]=5,
+ [6851]=5,
+ [6852]=5,
+ [6853]=5,
+ [6854]=5,
+ [6855]=5,
+ [6856]=5,
+ [6857]=5,
+ [6858]=5,
+ [6859]=5,
+ [6860]=5,
+ [6861]=5,
+ [6862]=5,
[6912]=5,
[6913]=5,
[6914]=5,
@@ -1373,6 +1456,7 @@ characters.classifiers={
[7671]=5,
[7672]=5,
[7673]=5,
+ [7674]=5,
[7675]=5,
[7676]=5,
[7677]=5,
@@ -1474,6 +1558,7 @@ characters.classifiers={
[43019]=5,
[43045]=5,
[43046]=5,
+ [43052]=5,
[43072]=2,
[43073]=2,
[43074]=2,
@@ -1750,6 +1835,8 @@ characters.classifiers={
[68901]=5,
[68902]=5,
[68903]=5,
+ [69291]=5,
+ [69292]=5,
[69424]=2,
[69425]=2,
[69426]=2,
@@ -1787,6 +1874,56 @@ characters.classifiers={
[69458]=2,
[69459]=2,
[69460]=3,
+ [69488]=2,
+ [69489]=2,
+ [69490]=2,
+ [69491]=2,
+ [69492]=3,
+ [69493]=3,
+ [69494]=2,
+ [69495]=2,
+ [69496]=2,
+ [69497]=2,
+ [69498]=2,
+ [69499]=2,
+ [69500]=2,
+ [69501]=2,
+ [69502]=2,
+ [69503]=2,
+ [69504]=2,
+ [69505]=2,
+ [69506]=5,
+ [69507]=5,
+ [69508]=5,
+ [69509]=5,
+ [69552]=2,
+ [69553]=4,
+ [69554]=2,
+ [69555]=2,
+ [69556]=3,
+ [69557]=3,
+ [69558]=3,
+ [69559]=4,
+ [69560]=2,
+ [69561]=3,
+ [69562]=3,
+ [69563]=2,
+ [69564]=2,
+ [69565]=3,
+ [69566]=2,
+ [69567]=2,
+ [69568]=4,
+ [69569]=2,
+ [69570]=3,
+ [69571]=3,
+ [69572]=2,
+ [69573]=4,
+ [69574]=4,
+ [69575]=4,
+ [69576]=4,
+ [69577]=3,
+ [69578]=2,
+ [69579]=1,
[69633]=5,
[69688]=5,
[69689]=5,
@@ -1803,6 +1940,9 @@ characters.classifiers={
[69700]=5,
[69701]=5,
[69702]=5,
+ [69744]=5,
+ [69747]=5,
+ [69748]=5,
[69759]=5,
[69760]=5,
[69761]=5,
@@ -1813,6 +1953,7 @@ characters.classifiers={
[69817]=5,
[69818]=5,
[69821]=4,
+ [69826]=5,
[69837]=4,
[69888]=5,
[69889]=5,
@@ -1845,6 +1986,7 @@ characters.classifiers={
[70090]=5,
[70091]=5,
[70092]=5,
+ [70095]=5,
[70191]=5,
[70192]=5,
[70193]=5,
@@ -1955,6 +2097,10 @@ characters.classifiers={
[71735]=5,
[71737]=5,
[71738]=5,
+ [71995]=5,
+ [71996]=5,
+ [71998]=5,
+ [72003]=5,
[72148]=5,
[72149]=5,
[72150]=5,
@@ -2092,8 +2238,78 @@ characters.classifiers={
[94096]=5,
[94097]=5,
[94098]=5,
+ [94180]=5,
[113821]=5,
[113822]=5,
+ [118528]=5,
+ [118529]=5,
+ [118530]=5,
+ [118531]=5,
+ [118532]=5,
+ [118533]=5,
+ [118534]=5,
+ [118535]=5,
+ [118536]=5,
+ [118537]=5,
+ [118538]=5,
+ [118539]=5,
+ [118540]=5,
+ [118541]=5,
+ [118542]=5,
+ [118543]=5,
+ [118544]=5,
+ [118545]=5,
+ [118546]=5,
+ [118547]=5,
+ [118548]=5,
+ [118549]=5,
+ [118550]=5,
+ [118551]=5,
+ [118552]=5,
+ [118553]=5,
+ [118554]=5,
+ [118555]=5,
+ [118556]=5,
+ [118557]=5,
+ [118558]=5,
+ [118559]=5,
+ [118560]=5,
+ [118561]=5,
+ [118562]=5,
+ [118563]=5,
+ [118564]=5,
+ [118565]=5,
+ [118566]=5,
+ [118567]=5,
+ [118568]=5,
+ [118569]=5,
+ [118570]=5,
+ [118571]=5,
+ [118572]=5,
+ [118573]=5,
+ [118576]=5,
+ [118577]=5,
+ [118578]=5,
+ [118579]=5,
+ [118580]=5,
+ [118581]=5,
+ [118582]=5,
+ [118583]=5,
+ [118584]=5,
+ [118585]=5,
+ [118586]=5,
+ [118587]=5,
+ [118588]=5,
+ [118589]=5,
+ [118590]=5,
+ [118591]=5,
+ [118592]=5,
+ [118593]=5,
+ [118594]=5,
+ [118595]=5,
+ [118596]=5,
+ [118597]=5,
+ [118598]=5,
[119143]=5,
[119144]=5,
[119145]=5,
@@ -2291,6 +2507,7 @@ characters.classifiers={
[123188]=5,
[123189]=5,
[123190]=5,
+ [123566]=5,
[123628]=5,
[123629]=5,
[123630]=5,
@@ -2459,6 +2676,7 @@ characters.indicgroups={
[2879]=true,
[2902]=true,
[3376]=true,
+ [5901]=true,
},
["after_postscript"]={
[2433]=true,
@@ -2634,6 +2852,7 @@ characters.indicgroups={
[2915]=true,
[3009]=true,
[3010]=true,
+ [3132]=true,
[3170]=true,
[3171]=true,
[3260]=true,
@@ -3052,6 +3271,7 @@ characters.indicgroups={
[4225]=true,
[4226]=true,
[4238]=true,
+ [5901]=true,
[43488]=true,
[43489]=true,
[43490]=true,
@@ -3376,6 +3596,7 @@ characters.indicgroups={
[3090]=true,
[3091]=true,
[3092]=true,
+ [3165]=true,
[3168]=true,
[3169]=true,
[3205]=true,
@@ -3392,6 +3613,7 @@ characters.indicgroups={
[3218]=true,
[3219]=true,
[3220]=true,
+ [3293]=true,
[3296]=true,
[3297]=true,
[3333]=true,
@@ -3432,6 +3654,7 @@ characters.indicgroups={
[2620]=true,
[2748]=true,
[2876]=true,
+ [3132]=true,
[3260]=true,
},
["post_mark"]={
@@ -3535,6 +3758,7 @@ characters.indicgroups={
[3120]=true,
[3248]=true,
[3376]=true,
+ [5901]=true,
},
["stress_tone_mark"]={
[2385]=true,
@@ -3614,6 +3838,4 @@ characters.indicgroups={
},
}
--- done, uncomment for testing:
-
--- return characters.indicgroups
+-- done
diff --git a/macros/luatex/generic/luaotfload/fontloader-basics-gen.lua b/macros/luatex/generic/luaotfload/fontloader-basics-gen.lua
index 5a6e90ceee..1cc8537168 100644
--- a/macros/luatex/generic/luaotfload/fontloader-basics-gen.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-basics-gen.lua
@@ -189,7 +189,7 @@ local readables = { }
local usingjit = jit
if not caches.namespace or caches.namespace == "" or caches.namespace == "context" then
- caches.namespace = 'generic'
+ caches.namespace = 'generic-dev'
end
do
diff --git a/macros/luatex/generic/luaotfload/fontloader-basics-nod.lua b/macros/luatex/generic/luaotfload/fontloader-basics-nod.lua
index 76e36f2aab..61587d5ded 100644
--- a/macros/luatex/generic/luaotfload/fontloader-basics-nod.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-basics-nod.lua
@@ -118,7 +118,7 @@ nuts.setcomponents = direct.setcomponents
nuts.setdirection = direct.setdirection
nuts.setdisc = direct.setdisc
nuts.setreplace = direct.setreplace
-nuts.setfield = setfield
+nuts.setfield = direct.setfield
nuts.setkern = direct.setkern
nuts.setlink = direct.setlink
nuts.setlist = direct.setlist
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-cff.lua b/macros/luatex/generic/luaotfload/fontloader-font-cff.lua
index ff87292baf..4258991c67 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-cff.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-cff.lua
@@ -572,6 +572,11 @@ do
stack[top] = -(byte(b0)-251)*256 - byte(b1) - 108
end
+ -- local p_float = P("\255") * C(1) * C(1) * C(1) * C(1) / function(b0,b1,b2,b3)
+ -- top = top + 1
+ -- stack[top] = 0
+ -- end
+
local p_short = P("\28") * C(1) * C(1) / function(b1,b2)
-- -32768 .. +32767 : b1<<8 | b2
top = top + 1
@@ -607,6 +612,7 @@ do
+ p_nibbles
+ p_single
+ p_double
+ -- + p_float
+ p_unsupported
)^1
@@ -701,6 +707,7 @@ do
local y = 0
local width = false
local lsb = 0
+local result = { }
local r = 0
local stems = 0
local globalbias = 0
@@ -1825,13 +1832,13 @@ do
stack[top] = -t*256 + 64148 - tab[i+1]
i = i + 2
else
- -- a 16.16 float
- local n = 0x100 * tab[i+1] + tab[i+2]
- if n >= 0x8000 then
- stack[top] = n - 0x10000 + (0x100 * tab[i+3] + tab[i+4])/0xFFFF
- else
- stack[top] = n + (0x100 * tab[i+3] + tab[i+4])/0xFFFF
+ -- a 16.16 float (used for italic but pretty unreliable)
+ local n1 = 0x100 * tab[i+1] + tab[i+2]
+ local n2 = 0x100 * tab[i+3] + tab[i+4]
+ if n1 >= 0x8000 then
+ n1 = n1 - 0x10000
end
+ stack[top] = n1 + n2/0xFFFF
i = i + 5
end
elseif t == 28 then
@@ -1924,7 +1931,8 @@ do
-- cff 1: (when cff2 strip them)
elseif t == 1 or t == 3 or t == 18 or operation == 23 then
p_getstem() -- at the start
- if true then
+ if version == "cff" then
+-- if true then
if top > 0 then
for i=1,top do
r = r + 1 ; result[r] = encode[stack[i]]
@@ -1939,6 +1947,7 @@ do
-- cff 1: (when cff2 strip them)
elseif t == 19 or t == 20 then
local s = p_getmask() or 0 -- after the stems
+-- if version == "cff" then
if true then
if top > 0 then
for i=1,top do
@@ -1962,7 +1971,8 @@ do
i = i + 1
elseif t == 13 then
hsbw()
- if version == "cff" then
+-- if version == "cff" then
+ if true then
-- we do a moveto over lsb
r = r + 1 ; result[r] = encode[lsb]
r = r + 1 ; result[r] = chars[22]
@@ -2122,7 +2132,6 @@ do
end
process(tab)
-
if hack then
return x, y
end
@@ -2145,6 +2154,7 @@ do
r = r + 1
result[r] = c_endchar
local stream = concat(result)
+result = nil
-- if trace_charstrings then
-- report("vdata: %s",stream)
-- end
@@ -2171,6 +2181,7 @@ do
name = charset and charset[index] or nil,
-- sidebearing = 0,
}
+result = nil
else
glyphs[index] = {
boundingbox = boundingbox,
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-dsp.lua b/macros/luatex/generic/luaotfload/fontloader-font-dsp.lua
index 8d7c3d359d..7028f7c087 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-dsp.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-dsp.lua
@@ -3806,6 +3806,7 @@ function readers.hvar(f,fontdata,specification)
end
local tableoffset = gotodatatable(f,fontdata,"hvar",specification.variable)
if not tableoffset then
+ report("no hvar table, expect problems due to messy widths")
return
end
@@ -3823,7 +3824,6 @@ function readers.hvar(f,fontdata,specification)
if variationoffset > 0 then
regions, deltas = readvariationdata(f,variationoffset,factors)
end
-
if not regions then
-- for now .. what to do ?
return
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-osd.lua b/macros/luatex/generic/luaotfload/fontloader-font-osd.lua
index 2d0e685c19..34c0472903 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-osd.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-osd.lua
@@ -6,7 +6,6 @@ if not modules then modules = { } end modules ['font-osd'] = { -- script devanag
license = "see context related readme files"
}
-
-- we need to check nbsphash (context only)
-- A few remarks:
@@ -56,6 +55,11 @@ if not modules then modules = { } end modules ['font-osd'] = { -- script devanag
-- By now we have yet another incremental improved version. In the end I might
-- rewrite the code.
--
+-- At the start of 2022 Kauśika spent a lot of time testing combinations of fonts
+-- and scripts and in the process some more tracing was added as well as a mixed
+-- conjuncts options that can deal with fuzzy fonts. The machinery does what it has
+-- to do but some fonts expect more magic to be applied.
+--
-- Hans Hagen, PRAGMA-ADE, Hasselt NL
-- Todo:
@@ -81,8 +85,10 @@ if not modules then modules = { } end modules ['font-osd'] = { -- script devanag
-- malayalam, oriya, tamil and tolugu but not all are checked. Also, some of the
-- code below might need to be adapted to the extra scripts.
-local insert, imerge, copy, tohash = table.insert, table.imerge, table.copy, table.tohash
-local next, type = next, type
+local insert, remove, imerge, copy, tohash = table.insert, table.remove, table.imerge, table.copy, table.tohash
+local next, type, rawget = next, type, rawget
+local formatters = string.formatters
+local settings_to_hash = utilities.parsers.settings_to_hash
local report = logs.reporter("otf","devanagari")
@@ -98,6 +104,8 @@ local methods = fonts.analyzers.methods
local otffeatures = fonts.constructors.features.otf
local registerotffeature = otffeatures.register
+local trace_steps = false
+
local nuts = nodes.nuts
local getnext = nuts.getnext
@@ -118,7 +126,7 @@ local setstate = nuts.setstate
local ischar = nuts.ischar
-local insertnodeafter = nuts.insertafter
+local insertnodeafter = nuts.insertafter
local copy_node = nuts.copy
local remove_node = nuts.remove
local flushlist = nuts.flushlist
@@ -130,7 +138,8 @@ local unsetvalue = attributes.unsetvalue
local fontdata = fonts.hashes.identifiers
-local a_syllabe = attributes.private('syllabe')
+local a_syllabe = "syllable" -- attributes.private('syllabe') -- can be just a property key
+local a_reordered = "reordered" -- attributes.private('reordered') -- can be just a property key
local dotted_circle = 0x25CC
local c_nbsp = 0x00A0
@@ -156,9 +165,14 @@ replace_all_nbsp = function(head) -- delayed definition
end
local processcharacters = nil
+local logprocess = nil
if context then
- local fontprocesses = fonts.hashes.processes
+
+ local fontprocesses = fonts.hashes.processes
+ local tracers = nodes.tracers
+ local registermessage = (tracers and tracers.steppers.message) or function() end
+
function processcharacters(head,font)
local processors = fontprocesses[font]
for i=1,#processors do
@@ -166,7 +180,24 @@ if context then
end
return head
end
+
+ -- When we'retrying to fix something it can be handy to have some more
+ -- details available.
+
+ trackers.register("otf.steps", function(v) trace_steps = v end)
+
+ logprocess = function(str)
+ if trace_steps then
+ registermessage("devanagari %s",str)
+ if trace_steps == "silent" then
+ return
+ end
+ end
+ report(str)
+ end
+
else
+
function processcharacters(head,font)
local processors = fontdata[font].shared.processes
for i=1,#processors do
@@ -174,6 +205,11 @@ else
end
return head
end
+
+ logprocess = function(str)
+ -- do nothing
+ end
+
end
-- We can assume that script are not mixed in the source but if that is the case
@@ -302,7 +338,7 @@ local after_subscript = indicgroups.after_subscript
local before_main = indicgroups.before_main
local after_main = indicgroups.after_main
-local mark_four = table.merged (
+local mark_pre_above_below_post = table.merged (
pre_mark,
above_mark,
below_mark,
@@ -315,6 +351,14 @@ local mark_above_below_post = table.merged (
post_mark
)
+-- Handy
+
+local devanagarihash = table.setmetatableindex(function(t,k)
+ local v = fontdata[k].resources.devanagari or false
+ t[k] = v
+ return v
+end)
+
-- We use some pseudo features as we need to manipulate the nodelist based
-- on information in the font as well as already applied features. We can
-- probably replace some of the code below by injecting 'real' features
@@ -460,7 +504,7 @@ local function initializedevanagi(tfmdata)
local devanagari = resources.devanagari
if not devanagari then
--
- report("adding devanagari features to font")
+ report("adding features to font")
--
local gsubfeatures = resources.features.gsub
local sequences = resources.sequences
@@ -491,7 +535,9 @@ local function initializedevanagi(tfmdata)
for k, v in next, pre_mark do
local locl = coverage[k]
if locl then
- if #locl > 0 then --contextchain; KE: is this right?
+ -- if #locl > 0 then we have a list otherwise a hash; we actually should
+ -- test properly for gsub_...
+ if #locl > 0 then
for j=1,#locl do
local ck = locl[j]
local f = ck[4]
@@ -512,6 +558,8 @@ local function initializedevanagi(tfmdata)
end
end
end
+ else
+ -- useless next if, because locl is a table
end
if locl then
reorder_matras.steps[1].coverage[locl] = true
@@ -524,7 +572,7 @@ local function initializedevanagi(tfmdata)
if basic_shaping_forms[k] then
lastmatch = lastmatch + 1
if s ~= lastmatch then
- table.insert(sequences, lastmatch, table.remove(sequences, s))
+ insert(sequences,lastmatch,remove(sequences,s))
end
end
end
@@ -545,9 +593,7 @@ local function initializedevanagi(tfmdata)
local vatucache = { }
local pstfcache = { }
local seqsubset = { }
- local rephstep = {
- coverage = { } -- will be adapted each work
- }
+ local rephstep = { coverage = { } } -- will be adapted each work
local devanagari = {
reph = false,
vattu = false,
@@ -577,7 +623,7 @@ local function initializedevanagi(tfmdata)
local has_pstf = features.pstf
if has_rphf and has_rphf[script] then
devanagari.reph = true
- elseif (has_blwf and has_blwf[script] ) or (has_vatu and has_vatu[script] ) then
+ elseif (has_blwf and has_blwf[script]) or (has_vatu and has_vatu[script]) then
devanagari.vattu = true
for i=1,nofsteps do
local step = steps[i]
@@ -585,10 +631,8 @@ local function initializedevanagi(tfmdata)
if coverage then
for k, v in next, coverage do
for h, w in next, halant do
- if v[h] then
- if not blwfcache[k] then
- blwfcache[k] = v
- end
+ if v[h] and not blwfcache[k] then
+ blwfcache[k] = v
end
if has_vatu and has_vatu[script] and not vatucache[k] then
vatucache[k] = v
@@ -610,34 +654,40 @@ local function initializedevanagi(tfmdata)
for k, v in next, ra do
local r = coverage[k]
if r then
+ -- if #r > 0 then we have a list otherwise a hash; we actually should
+ -- test properly for gsub_...
local found = false
- if #r > 0 then -- contextchain; KE: is this right?
+ if #r > 0 then
for j=1,#r do
- local ck = r[j]
- local f = ck[4]
+ local ck = r[j]
+ local f = ck[4]
local chainlookups = ck[6]
- if chainlookups and chainlookups[f] then --KE: why is check for chainlookups[f] necessacy???
+ if chainlookups then
local chainlookup = chainlookups[f]
- for j=1,#chainlookup do
- local chainstep = chainlookup[j]
- local steps = chainstep.steps
- local nofsteps = chainstep.nofsteps
- for i=1,nofsteps do
- local step = steps[i]
- local coverage = step.coverage
- if coverage then
- local h = coverage[k]
- if h then
- for k, v in next, h do
- found = v and v.ligature
+ if chainlookup then
+ for j=1,#chainlookup do
+ local chainstep = chainlookup[j]
+ local steps = chainstep.steps
+ local nofsteps = chainstep.nofsteps
+ for i=1,nofsteps do
+ local step = steps[i]
+ local coverage = step.coverage
+ if coverage then
+ local h = coverage[k]
+ if h then
+ for k, v in next, h do
+ if v then
+ found = tonumber(v) or v.ligature
+ if found then
+ pre_base_reordering_consonants[found] = true
+ break
+ end
+ end
+ end
if found then
- pre_base_reordering_consonants[found] = true
break
end
end
- if found then
- break
- end
end
end
end
@@ -646,10 +696,12 @@ local function initializedevanagi(tfmdata)
end
else
for k, v in next, r do
- found = v and v.ligature
- if found then
- pre_base_reordering_consonants[found] = true
- break
+ if v then
+ found = tonumber(v) or v.ligature
+ if found then
+ pre_base_reordering_consonants[found] = true
+ break
+ end
end
end
end
@@ -667,18 +719,21 @@ local function initializedevanagi(tfmdata)
local step = steps[i]
local coverage = step.coverage
if coverage then
- local reph, rephbase = false, false
+ local reph = false
+ local base = false
if kind == "rphf" then
-- rphf acts on consonant + halant
for k, v in next, ra do
local r = coverage[k]
if r then
- rephbase = k
+ -- if #r > 0 then we have a list otherwise a hash; we actually should
+ -- test properly for gsub_...
+ base = k
local h = false
- if #r > 0 then --contextchain; KE: is this right?
+ if #r > 0 then
for j=1,#r do
- local ck = r[j]
- local f = ck[4]
+ local ck = r[j]
+ local f = ck[4]
local chainlookups = ck[6]
if chainlookups then
local chainlookup = chainlookups[f]
@@ -695,7 +750,7 @@ local function initializedevanagi(tfmdata)
for k, v in next, halant do
local h = r[k]
if h then
- reph = h.ligature or false
+ reph = tonumber(h) or h.ligature or false
break
end
end
@@ -712,7 +767,7 @@ local function initializedevanagi(tfmdata)
for k, v in next, halant do
local h = r[k]
if h then
- reph = h.ligature or false
+ reph = tonumber(h) or h.ligature or false
break
end
end
@@ -723,7 +778,9 @@ local function initializedevanagi(tfmdata)
end
end
end
- seqsubset[#seqsubset+1] = { kind, coverage, reph, rephbase }
+-- if reph then
+ seqsubset[#seqsubset+1] = { kind, coverage, reph, base }
+-- end
end
end
end
@@ -737,18 +794,20 @@ local function initializedevanagi(tfmdata)
for k, v in next, halant do
local h = coverage[k]
if h then
+ -- if #h > 0 then we have a list otherwise a hash; we actually should
+ -- test properly for gsub_...
local found = false
- if #h > 0 then -- contextchain; KE: is this right?
+ if #h > 0 then
for j=1,#h do
- local ck = h[j]
- local f = ck[4]
+ local ck = h[j]
+ local f = ck[4]
local chainlookups = ck[6]
if chainlookups then
local chainlookup = chainlookups[f]
for j=1,#chainlookup do
local chainstep = chainlookup[j]
- local steps = chainstep.steps
- local nofsteps = chainstep.nofsteps
+ local steps = chainstep.steps
+ local nofsteps = chainstep.nofsteps
for i=1,nofsteps do
local step = steps[i]
local coverage = step.coverage
@@ -756,10 +815,12 @@ local function initializedevanagi(tfmdata)
local h = coverage[k]
if h then
for k, v in next, h do
- found = v and v.ligature
- if found then
- pre_base_reordering_consonants[found] = true
- break
+ if v then
+ found = tonumber(v) or v.ligature
+ if found then
+ pre_base_reordering_consonants[found] = true
+ break
+ end
end
end
if found then
@@ -773,7 +834,7 @@ local function initializedevanagi(tfmdata)
end
else
for k, v in next, h do
- found = v and v.ligature
+ found = v and (tonumber(v) or v.ligature)
if found then
pre_base_reordering_consonants[found] = true
break
@@ -800,9 +861,9 @@ local function initializedevanagi(tfmdata)
sharedfeatures["dv03"] = true -- dv03_reorder_pre_base_reordering_consonants
sharedfeatures["dv04"] = true -- dv04_remove_joiners
end
- if script == "mlym" or script == "taml" then
- devanagari.left_matra_before_base = true
- end
+ -- if script == "mlym" or script == "taml" then
+ -- devanagari.movematra = "leftbeforebase"
+ -- end
end
end
end
@@ -816,6 +877,49 @@ registerotffeature {
},
}
+local function initializeconjuncts(tfmdata,value)
+ if value then
+ local resources = tfmdata.resources
+ local devanagari = resources.devanagari
+ if devanagari then
+ -- quit was the old situation
+ local conjuncts = "auto" -- mixed|continue|quit|auto
+ local movematra = "auto" -- default|leftbeforebase|auto
+ if type(value) == "string" and value ~= "auto" then
+ value = settings_to_hash(value)
+ conjuncts = rawget(value,"conjuncts") or conjuncts
+ movematra = rawget(value,"movematra") or movematra
+ end
+ if conjuncts == "auto" then
+ conjuncts = "mixed" -- for all scripts ?
+ end
+ if movematra == "auto" and
+ script == "mlym" or
+ script == "taml" then
+ movematra = "leftbeforebase"
+ else
+ movematra = "default"
+ end
+ devanagari.conjuncts = conjuncts
+ devanagari.movematra = movematra
+ --
+ if trace_steps then
+ report("conjuncts %a, movematra %a",conjuncts,movematra)
+ end
+ --
+ end
+ end
+end
+
+registerotffeature {
+ name = "indic",
+ description = "control indic",
+ default = "auto",
+ initializers = {
+ node = initializeconjuncts,
+ },
+}
+
local show_syntax_errors = false
local function inject_syntax_error(head,current,char)
@@ -874,38 +978,44 @@ local function initialize_one(font,attr) -- we need a proper hook into the datas
end
-local function contextchain(contexts, n)
+-- HH: somehow we can get a non context here so for now we check for .n
+
+local function contextchain(contexts,n)
local char = getchar(n)
- for k=1,#contexts do
- local ck = contexts[k]
- local seq = ck[3]
- local f = ck[4]
- local l = ck[5]
- if (l - f) == 1 and seq[f+1][char] then
- local ok = true
- local c = n
- for i=l+1,#seq do
- c = getnext(c)
- if not c or not seq[i][ischar(c)] then
- ok = false
- break
- end
- end
- if ok then
- c = getprev(n)
- for i=1,f-1 do
- c = getprev(c)
- if not c or not seq[f-i][ischar(c)] then
+ if not contexts.n then
+ return contexts[char]
+ else
+ for k=1,#contexts do
+ local ck = contexts[k]
+ local seq = ck[3]
+ local f = ck[4]
+ local l = ck[5]
+ if (l - f) == 1 and seq[f+1][char] then
+ local ok = true
+ local c = n
+ for i=l+1,#seq do
+ c = getnext(c)
+ if not c or not seq[i][ischar(c)] then
ok = false
+ break
end
end
- end
- if ok then
- return true
+ if ok then
+ c = getprev(n)
+ for i=1,f-1 do
+ c = getprev(c)
+ if not c or not seq[f-i][ischar(c)] then
+ ok = false
+ end
+ end
+ end
+ if ok then
+ return true
+ end
end
end
+ return false
end
- return false
end
local function order_matras(c)
@@ -937,11 +1047,13 @@ local function order_matras(c)
end
end
+local swapped = table.swapped(states)
+
local function reorder_one(head,start,stop,font,attr,nbspaces)
local reph, vattu, blwfcache, vatucache, pstfcache = initialize_one(font,attr) -- todo: a hash[font]
- local devanagari = fontdata[font].resources.devanagari
+ -- local devanagari = devanagarihash[font]
local current = start
local n = getnext(start)
local base = nil
@@ -969,6 +1081,9 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
stop = getprev(stop)
head = remove_node(head,current)
flushnode(current)
+ if trace_steps then
+ logprocess("reorder one, remove nbsp")
+ end
return head, stop, nbspaces
else
nbspaces = nbspaces + 1
@@ -1012,6 +1127,9 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
stop = current
end
end
+ if trace_steps then
+ logprocess("reorder one, handle nbsp")
+ end
end
end
end
@@ -1073,6 +1191,9 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
if lastcons == stop then
stop = n
end
+ if trace_steps then
+ logprocess("reorder one, handle halant")
+ end
end
end
@@ -1102,6 +1223,9 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
if matra == stop then
stop = n
end
+ if trace_steps then
+ logprocess("reorder one, handle matra")
+ end
end
local current = start
@@ -1148,14 +1272,19 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
end
local tpm = twopart_mark[ch]
- while tpm do
- local extra = copy_node(n)
- copyinjection(extra,n)
- ch = tpm[1]
- setchar(n,ch)
- setchar(extra,tpm[2])
- head = insertnodeafter(head,current,extra)
- tpm = twopart_mark[ch]
+ if tpm then
+ while tpm do
+ local extra = copy_node(n)
+ copyinjection(extra,n)
+ ch = tpm[1]
+ setchar(n,ch)
+ setchar(extra,tpm[2])
+ head = insertnodeafter(head,current,extra)
+ tpm = twopart_mark[ch]
+ end
+ if trace_steps then
+ logprocess("reorder one, handle mark")
+ end
end
while c ~= stop and dependent_vowel[ch] do
c = n
@@ -1178,10 +1307,11 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
local bp = getprev(firstcons)
local cn = getnext(current)
local last = getnext(c)
+ local done = false
while cn ~= last do
-- move pre-base matras...
if pre_mark[getchar(cn)] then
- if devanagari.left_matra_before_base then
+ if devanagarihash[font].movematra == "leftbeforebase" then
local prev, next = getboth(cn)
setlink(prev,next)
if cn == stop then
@@ -1219,6 +1349,7 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
end
cn = next
end
+ done = true
elseif current ~= base and dependent_vowel[getchar(cn)] then
local prev, next = getboth(cn)
if next then
@@ -1231,6 +1362,7 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
setlink(b,cn,getnext(b))
order_matras(cn)
cn = next
+ done = true
elseif current == base and dependent_vowel[getchar(cn)] then
local cnn = getnext(cn)
order_matras(cn)
@@ -1244,10 +1376,15 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
end
allreordered = c == stop
current = getnext(c)
+ if done and trace_steps then
+ logprocess("reorder one, matra")
+ end
end
if reph or vattu then
- local current, cns = start, nil
+ local current = start
+ local cns = nil
+ local done = false
while current ~= stop do
local c = current
local n = getnext(current)
@@ -1280,6 +1417,7 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
local next = getnext(b)
setlink(c,next)
setlink(b,current)
+ done = true
end
elseif cns and getnext(cns) ~= current then -- todo: optimize next
-- position below-base Ra (vattu) following the consonants on which it is placed (either the base consonant or one of the pre-base consonants)
@@ -1288,6 +1426,7 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
setlink(cp,n)
setlink(cns,current) -- cns ?
setlink(c,cnsn)
+ done = true
if c == stop then
stop = cp
break
@@ -1327,12 +1466,15 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
end
current = getnext(current)
end
+ if done and trace_steps then
+ logprocess("reorder one, handle reph and vata") -- todo: boolean
+ end
end
if getchar(base) == c_nbsp then
nbspaces = nbspaces - 1
if base == stop then
- stop = getprev(stop)
+ stop = getprev(stop)
end
head = remove_node(head,base)
flushnode(base)
@@ -1373,6 +1515,9 @@ function handlers.devanagari_reorder_matras(head,start) -- no leak
setlink(current,start)
-- setlink(current,start,next) -- maybe
start = startnext
+ if trace_steps then
+ logprocess("reorder matra")
+ end
break
-- elseif consonant[char] and (not getstate(current) or getstate(current,s_init) then
-- startnext = getnext(start)
@@ -1438,6 +1583,9 @@ function handlers.devanagari_reorder_reph(head,start)
local char = ischar(current,startfont)
if char and getprop(current,a_syllabe) == startattr then
if halant[char] then
+ if trace_steps then
+ logprocess("reorder reph, handling halant")
+ end
local next = getnext(current)
if next then
local nextchar = ischar(next,startfont)
@@ -1475,6 +1623,9 @@ function handlers.devanagari_reorder_reph(head,start)
local char = ischar(current,startfont)
if char and getprop(current,a_syllabe) == startattr then
if consonant[char] and not getstate(current,s_pref) then
+ if trace_steps then
+ logprocess("reorder reph, handling consonant")
+ end
startnext = getnext(start)
head = remove_node(head,start)
setlink(current,start)
@@ -1506,6 +1657,9 @@ function handlers.devanagari_reorder_reph(head,start)
local char = ischar(current,startfont)
if char and getprop(current,a_syllabe) == startattr then
if getstate(current,s_pstf) then -- post-base
+ if trace_steps then
+ logprocess("reorder reph, before postscript, post base")
+ end
startnext = getnext(start)
head = remove_node(head,start)
setlink(getprev(current),start)
@@ -1514,12 +1668,15 @@ function handlers.devanagari_reorder_reph(head,start)
start = startnext
startattr = getprop(start,a_syllabe)
break
- elseif not c and ( vowel_modifier[char] or stress_tone_mark[char] ) then
+ elseif not c and (vowel_modifier[char] or stress_tone_mark[char]) then
c = current
end
current = getnext(current)
else
if c then
+ if trace_steps then
+ logprocess("reorder reph, before postscript")
+ end
startnext = getnext(start)
head = remove_node(head,start)
setlink(getprev(c),start)
@@ -1551,7 +1708,13 @@ function handlers.devanagari_reorder_reph(head,start)
local state = getstate(current)
if before_subscript[rephbase] and (state == s_blwf or state == s_pstf) then
c = current
+ if trace_steps then
+ logprocess("reorder reph, before subscript")
+ end
elseif after_subscript[rephbase] and (state == s_pstf) then
+ if trace_steps then
+ logprocess("reorder reph, after subscript")
+ end
c = current
end
current = getnext(current)
@@ -1589,6 +1752,9 @@ function handlers.devanagari_reorder_reph(head,start)
end
end
if start ~= current then
+ if trace_steps then
+ logprocess("reorder reph, to end")
+ end
startnext = getnext(start)
head = remove_node(head,start)
setlink(start,getnext(current))
@@ -1616,10 +1782,10 @@ end
-- return head, start, done
-- end
-local reordered_pre_base_reordering_consonants = { } -- shared ? not reset ?
+-- todo: nodes -> table -> nodes
function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
- if reordered_pre_base_reordering_consonants[start] then
+ if getprop(start,a_reordered) then
return head, start, true
end
local current = start -- we could cache attributes here
@@ -1630,6 +1796,9 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
local next = getnext(current)
if char and getprop(current,a_syllabe) == startattr then
if halant[char] then -- state can also be init
+ if trace_steps then
+ logprocess("reorder pre base consonants, handle halant")
+ end
if next then
local char = ischar(next,startfont)
if char and zw_char[char] and getprop(next,a_syllabe) == startattr then
@@ -1643,7 +1812,7 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
setlink(start,next)
setlink(current,start)
-- setlink(current,start,next) -- maybe
- reordered_pre_base_reordering_consonants[start] = true
+ setprop(start,"reordered",true)
start = startnext
return head, start, true
-- elseif consonant[char] and (not getstate(current) or getstate(current,s_init)) then
@@ -1670,6 +1839,9 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
while current and getprop(current,a_syllabe) == startattr do
local char = ischar(current)
if (not dependent_vowel[char] and (not getstate(current) or getstate(current,s_init))) then
+ if trace_steps then
+ logprocess("reorder pre base consonants, handle vowel or initial")
+ end
startnext = getnext(start)
head = remove_node(head,start)
if current == head then
@@ -1679,7 +1851,7 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
setlink(getprev(current),start)
setlink(start,current)
end
- reordered_pre_base_reordering_consonants[start] = true
+ setprop(start,"reordered",true)
start = startnext
break
end
@@ -1713,6 +1885,9 @@ function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replaceme
head = stop
end
flushlist(start)
+ if trace_steps then
+ logprocess("remove joiners")
+ end
return head, stop, true
end
@@ -1739,8 +1914,8 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
local subpos = nil
local postpos = nil
- reorderreph.coverage = { }
- rephbase[font] = { }
+ reorderreph.coverage = { } -- use local
+ rephbase[font] = { } -- use local
for i=1,#seqsubset do
@@ -1750,8 +1925,12 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
local kind = subset[1]
local lookupcache = subset[2]
if kind == "rphf" then
- reorderreph.coverage[subset[3]] = true -- neat
- rephbase[font][subset[3]] = subset[4]
+ --
+ local reph = subset[3]
+ local base = subset[4]
+ reorderreph.coverage[reph] = true -- neat -- use local
+ rephbase[font][reph] = base -- use local
+ --
local current = start
local last = getnext(stop)
while current ~= last do
@@ -1760,15 +1939,15 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
local found = lookupcache[c]
if found then
local next = getnext(current)
- if found[getchar(next)] or contextchain(found, next) then --above-base: rphf Consonant + Halant
+ if contextchain(found, next) then -- above-base: rphf Consonant + Halant
local afternext = next ~= stop and getnext(next)
if afternext and zw_char[getchar(afternext)] then -- ZWJ and ZWNJ prevent creation of reph
current = afternext -- getnext(next)
elseif current == start then
setstate(current,s_rphf)
- current = next
+ current = next -- later again next
else
- current = next
+ current = next -- later again next
end
end
end
@@ -1784,8 +1963,8 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
local found = lookupcache[c]
if found then -- pre-base: pref Halant + Consonant
local next = getnext(current)
- if found[getchar(next)] or contextchain(found, next) then
- if (not getstate(current) and not getstate(next)) then --KE: state can also be init...
+ if contextchain(found, next) then
+ if not getstate(current) and not getstate(next) then --KE: state can also be init...
setstate(current,s_pref)
setstate(next,s_pref)
current = next
@@ -1804,10 +1983,10 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
local found = lookupcache[c]
if found then
local next = getnext(current)
- if found[getchar(next)] or contextchain(found, next) then
+ if contextchain(found, next) then
if next ~= stop and getchar(getnext(next)) == c_zwnj then -- zwnj prevent creation of half
current = next
- elseif (not getstate(current)) then --KE: state can also be init...
+ elseif not getstate(current) then --KE: state can also be init...
setstate(current,s_half)
if not halfpos then
halfpos = current
@@ -1828,8 +2007,8 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
local found = lookupcache[c]
if found then
local next = getnext(current)
- if found[getchar(next)] or contextchain(found, next) then
- if (not getstate(current) and not getstate(next)) then --KE: state can also be init...
+ if contextchain(found, next) then
+ if not getstate(current) and not getstate(next) then --KE: state can also be init...
setstate(current,s_blwf)
setstate(next,s_blwf)
current = next
@@ -1849,8 +2028,8 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
local found = lookupcache[c]
if found then
local next = getnext(current)
- if found[getchar(next)] or contextchain(found, next) then
- if (not getstate(current) and not getstate(next)) then -- KE: state can also be init...
+ if contextchain(found, next) then
+ if not getstate(current) and not getstate(next) then -- KE: state can also be init...
setstate(current,s_pstf)
setstate(next,s_pstf)
current = next
@@ -1877,6 +2056,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
stop = getprev(stop)
head = remove_node(head,current)
flushnode(current)
+ if trace_steps then
+ logprocess("reorder two, remove nbsp")
+ end
return head, stop, nbspaces
else
nbspaces = nbspaces + 1
@@ -1917,6 +2099,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
end
end
end
+ if trace_steps then
+ logprocess("reorder two, handle nbsp")
+ end
end
else -- not Stand Alone cluster
local last = getnext(stop)
@@ -1948,7 +2133,7 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
return head, stop, nbspaces
else
if getstate(base) then -- state can also be init
- setstate(base,unsetvalue)
+ setstate(base,unsetvalue) -- THIS RESETS THE HALF STATE
end
basepos = base
end
@@ -1973,14 +2158,19 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
local cn = getnext(current)
-- not so efficient (needed for malayalam)
local tpm = twopart_mark[char]
- while tpm do
- local extra = copy_node(current)
- copyinjection(extra,current)
- char = tpm[1]
- setchar(current,char)
- setchar(extra,tpm[2])
- head = insertnodeafter(head,current,extra)
- tpm = twopart_mark[char]
+ if tpm then
+ while tpm do
+ local extra = copy_node(current)
+ copyinjection(extra,current)
+ char = tpm[1]
+ setchar(current,char)
+ setchar(extra,tpm[2])
+ head = insertnodeafter(head,current,extra)
+ tpm = twopart_mark[char]
+ end
+ if tpm and trace_steps then
+ logprocess("reorder two, handle matra")
+ end
end
--
if not moved[current] and dependent_vowel[char] then
@@ -2031,6 +2221,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
setlink(getprev(pos),current)
setlink(current,pos)
-- setlink(getprev(pos),current,pos) -- maybe
+ if trace_steps then
+ logprocess("reorder two, handle pre mark")
+ end
elseif above_mark[char] then
-- after main consonant
target = basepos
@@ -2074,13 +2267,16 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
setlink(current,getnext(target))
setlink(target,current)
-- setlink(target,current,getnext(target)) -- maybe
+ if trace_steps then
+ logprocess("reorder two, handle mark")
+ end
end
end
end
current = cn
end
- -- reorder halant+Ra
+ -- reorder halant + Ra
local current = getnext(start)
local last = getnext(stop)
@@ -2104,6 +2300,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
stop = prev
end
cn = next
+ if trace_steps then
+ logprocess("reorder two, handle halant and ra")
+ end
end
end
-- after_postscript
@@ -2143,6 +2342,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
setprev(nextnextnext,current)
end
setlink(nextnext,c)
+ if trace_steps then
+ logprocess("reorder two, handle nukta")
+ end
end
if stop == current then break end
current = getnext(current)
@@ -2155,6 +2357,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
nbspaces = nbspaces - 1
head = remove_node(head, base)
flushnode(base)
+ if trace_steps then
+ logprocess("reorder two, handle nbsp")
+ end
end
return head, stop, nbspaces
@@ -2251,21 +2456,45 @@ local function analyze_next_chars_one(c,font,variant) -- skip one dependent vowe
local already_below_mark -- = false
local already_post_mark -- = false
while dependent_vowel[v] do
- local vowels = twopart_mark[v] or { v }
- for k, v in next, vowels do
- if pre_mark[v] and not already_pre_mark then
- already_pre_mark = true
- elseif above_mark[v] and not already_above_mark then
- already_above_mark = true
- elseif below_mark[v] and not already_below_mark then
- already_below_mark = true
- elseif post_mark[v] and not already_post_mark then
- already_post_mark = true
- else
- return c
- end
- end
- c = getnext(c)
+ local vowels = twopart_mark[v]
+ if vowels then
+ for k=1,#vowels do
+ local v = vowels[k]
+ if pre_mark[v] and not already_pre_mark then
+ already_pre_mark = true
+ elseif above_mark[v] and not already_above_mark then
+ already_above_mark = true
+ elseif below_mark[v] and not already_below_mark then
+ already_below_mark = true
+ elseif post_mark[v] and not already_post_mark then
+ already_post_mark = true
+ elseif devanagarihash[font].conjuncts == "continue" then
+ -- for testing
+ else
+ return c
+ end
+ end
+ else
+ if pre_mark[v] and not already_pre_mark then
+ already_pre_mark = true
+ elseif post_mark[v] and not already_post_mark then
+ if devanagarihash[font].conjuncts == "mixed" then
+ -- for messy fonts
+ return c
+ else
+ already_post_mark = true
+ end
+ elseif below_mark[v] and not already_below_mark then
+ already_below_mark = true
+ elseif above_mark[v] and not already_above_mark then
+ already_above_mark = true
+ elseif devanagarihash[font].conjuncts == "continue" then
+ -- for testing
+ else
+ return c
+ end
+ end
+ c = n
n = getnext(c)
if not n then
return c
@@ -2276,7 +2505,7 @@ local function analyze_next_chars_one(c,font,variant) -- skip one dependent vowe
end
end
if nukta[v] then
- c = getnext(c)
+ c = n
n = getnext(c)
if not n then
return c
@@ -2287,7 +2516,7 @@ local function analyze_next_chars_one(c,font,variant) -- skip one dependent vowe
end
end
if halant[v] then
- c = getnext(c)
+ c = n
n = getnext(c)
if not n then
return c
@@ -2298,7 +2527,7 @@ local function analyze_next_chars_one(c,font,variant) -- skip one dependent vowe
end
end
if vowel_modifier[v] then
- c = getnext(c)
+ c = n
n = getnext(c)
if not n then
return c
@@ -2309,7 +2538,7 @@ local function analyze_next_chars_one(c,font,variant) -- skip one dependent vowe
end
end
if stress_tone_mark[v] then
- c = getnext(c)
+ c = n
n = getnext(c)
if not n then
return c
@@ -2327,11 +2556,12 @@ local function analyze_next_chars_one(c,font,variant) -- skip one dependent vowe
end
local function analyze_next_chars_two(c,font)
- local n = getnext(c)
+ local n, v
+ n = getnext(c)
if not n then
return c
end
- local v = ischar(n,font)
+ v = ischar(n,font)
if v and nukta[v] then
c = n
end
@@ -2393,11 +2623,11 @@ local function analyze_next_chars_two(c,font)
-- This shouldn't happen I guess.
return
end
- local n = getnext(c)
+ n = getnext(c)
if not n then
return c
end
- local v = ischar(n,font)
+ v = ischar(n,font)
if not v then
return c
end
@@ -2440,21 +2670,46 @@ local function analyze_next_chars_two(c,font)
local already_above_mark -- = false
local already_below_mark -- = false
local already_post_mark -- = false
- while dependent_vowel[v] do
- local vowels = twopart_mark[v] or { v }
- for k, v in next, vowels do
- if pre_mark[v] and not already_pre_mark then
- already_pre_mark = true
- elseif above_mark[v] and not already_above_mark then
- already_above_mark = true
- elseif below_mark[v] and not already_below_mark then
- already_below_mark = true
- elseif post_mark[v] and not already_post_mark then
- already_post_mark = true
- else
- return c
- end
- end
+ -- inefficient : too many tests but seldom more than one
+ while dependent_vowel[v] do
+ local vowels = twopart_mark[v]
+ if vowels then
+ for k=1,#vowels do
+ local v = vowels[k]
+ if pre_mark[v] and not already_pre_mark then
+ already_pre_mark = true
+ elseif above_mark[v] and not already_above_mark then
+ already_above_mark = true
+ elseif below_mark[v] and not already_below_mark then
+ already_below_mark = true
+ elseif post_mark[v] and not already_post_mark then
+ already_post_mark = true
+ elseif devanagarihash[font].conjuncts == "continue" then
+ -- for testing
+ else
+ return c
+ end
+ end
+ else
+ if pre_mark[v] and not already_pre_mark then
+ already_pre_mark = true
+ elseif post_mark[v] and not already_post_mark then
+ if devanagarihash[font].conjuncts == "mixed" then
+ -- for messy fonts
+ return c
+ else
+ already_post_mark = true
+ end
+ elseif below_mark[v] and not already_below_mark then
+ already_below_mark = true
+ elseif above_mark[v] and not already_above_mark then
+ already_above_mark = true
+ elseif devanagarihash[font].conjuncts == "continue" then
+ -- for testing
+ else
+ return c
+ end
+ end
c = n
n = getnext(c)
if not n then
@@ -2708,7 +2963,7 @@ local function method_one(head,font,attr)
end
else
if show_syntax_errors then
- local mark = mark_four[char]
+ local mark = mark_pre_above_below_post[char]
if mark then
head, current = inject_syntax_error(head,current,char)
end
@@ -2731,15 +2986,15 @@ local function method_one(head,font,attr)
while current do
local char = ischar(current,font)
if char then
- if n == 0 and not getstate(current) then
- setstate(current,s_init)
- end
- n = n + 1
- else
- n = 0
- end
- current = getnext(current)
- end
+ if n == 0 and not getstate(current) then
+ setstate(current,s_init)
+ end
+ n = n + 1
+ else
+ n = 0
+ end
+ current = getnext(current)
+ end
return head, done
end
@@ -2800,7 +3055,6 @@ local function method_two(head,font,attr)
syllableend = current
elseif consonant[getchar(current)] then
-- WHY current INSTEAD OF c ?
-
-- Consonant syllable: {C+[N]+<H+[<ZWNJ|ZWJ>]|<ZWNJ|ZWJ>+H>} + C+[N]+[A] + [< H+[<ZWNJ|ZWJ>] | {M}+[N]+[H]>]+[SM]+[(VD)]
current = analyze_next_chars_two(current,font) -- not c !
syllableend = current
@@ -2822,7 +3076,7 @@ local function method_two(head,font,attr)
if not syllableend and show_syntax_errors then
local char = ischar(current,font)
if char and not getstate(current) then -- state can also be init
- local mark = mark_four[char]
+ local mark = mark_pre_above_below_post[char]
if mark then
head, current = inject_syntax_error(head,current,char)
end
@@ -2841,15 +3095,19 @@ local function method_two(head,font,attr)
while current do
local char = ischar(current,font)
if char then
- if n == 0 and not getstate(current) then -- state can also be init
- setstate(current,s_init)
- end
- n = n + 1
- else
- n = 0
- end
- current = getnext(current)
- end
+ if n == 0 and not getstate(current) then -- state can also be init
+ setstate(current,s_init)
+ end
+ n = n + 1
+ else
+ n = 0
+ end
+ current = getnext(current)
+ end
+
+ -- if languages.indic then
+ -- head = languages.indic.handler(head)
+ -- end
return head, done
end
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-otc.lua b/macros/luatex/generic/luaotfload/fontloader-font-otc.lua
index 2643d022a5..2c955dbce9 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-otc.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-otc.lua
@@ -102,8 +102,9 @@ local function validspecification(specification,name)
specification = { dataset = dataset }
else
dataset = { { data = specification.data } }
- specification.data = nil
- specification.dataset = dataset
+ specification.data = nil
+ specification.coverage = dataset
+ specification.dataset = dataset
end
local first = dataset[1]
if first then
@@ -232,6 +233,7 @@ local function addfeature(data,feature,specifications)
local unicode = tounicode(code)
local description = descriptions[unicode]
if not nocheck and not description then
+ -- todo: trace !
skip = skip + 1
else
if type(replacement) == "table" then
@@ -436,7 +438,30 @@ local function addfeature(data,feature,specifications)
local prepare_single = prepare_pair -- we could have a better test on the spec
- local function prepare_chain(list,featuretype,sublookups)
+ local function hassteps(lookups)
+ if lookups then
+ for i=1,#lookups do
+ local l = lookups[i]
+ if l then
+ for j=1,#l do
+ local l = l[j]
+ if l then
+ local n = l.nofsteps
+ if not n then
+ -- gsub_remove
+ return true
+ elseif n > 0 then
+ return true
+ end
+ end
+ end
+ end
+ end
+ end
+ return false
+ end
+
+ local function prepare_chain(list,featuretype,sublookups,nocheck)
-- todo: coveractions
local rules = list.rules
local coverage = { }
@@ -473,6 +498,7 @@ local function addfeature(data,feature,specifications)
local lookups = rule.lookups or false
local subtype = nil
if lookups and sublookups then
+ local l = { }
for k, v in sortedhash(lookups) do
local t = type(v)
if t == "table" then
@@ -483,58 +509,66 @@ local function addfeature(data,feature,specifications)
v[i] = { vi }
end
end
+ l[k] = v
elseif t == "number" then
local lookup = sublookups[v]
if lookup then
- lookups[k] = { lookup }
+ l[k] = { lookup }
if not subtype then
subtype = lookup.type
end
elseif v == 0 then
- lookups[k] = { { type = "gsub_remove" } }
+ l[k] = { { type = "gsub_remove", nosteps = true } }
else
- lookups[k] = false -- { false } -- new
+ l[k] = false -- { false } -- new
end
else
- lookups[k] = false -- { false } -- new
+ l[k] = false -- { false } -- new
end
end
+ if nocheck then
+ -- fragile
+ rule.lookups = l --no, because checking can spoil it
+ end
+ lookups = l
end
if nofsequences > 0 then -- we merge coverage into one
-- we copy as we can have different fonts
- 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
+ if hassteps(lookups) 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
- hashed[i] = t
- end
- sequence = hashed
- -- now we create the rule
- rulesize = rulesize + 1
- rulehash[rulesize] = {
- nofrules, -- 1
- lookuptype, -- 2
- sequence, -- 3
- start, -- 4
- stop, -- 5
- lookups, -- 6 (6/7 also signal of what to do)
- replacements, -- 7
- subtype, -- 8
- }
--- for unic in next, sequence[start] do
- for unic in sortedhash(sequence[start]) do
- local cu = coverage[unic]
- if not cu then
- coverage[unic] = rulehash -- can now be done cleaner i think
+ sequence = hashed
+ rulesize = rulesize + 1
+ rulehash[rulesize] = {
+ nofrules, -- 1
+ lookuptype, -- 2
+ sequence, -- 3
+ start, -- 4
+ stop, -- 5
+ lookups, -- 6 (6/7 also signal of what to do)
+ replacements, -- 7
+ subtype, -- 8
+ }
+ for unic in sortedhash(sequence[start]) do
+ local cu = coverage[unic]
+ if not cu then
+ coverage[unic] = rulehash -- can now be done cleaner i think
+ end
end
+ sequence.n = nofsequences
+ else
+ -- report_otf("no steps for %a",lookuptype) -- e.g. in primes feature
end
- sequence.n = nofsequences
end
end
rulehash.n = rulesize
@@ -626,133 +660,164 @@ local function addfeature(data,feature,specifications)
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 featuretype = specification.type or "substitution"
+ local featureaction = false
local featureflags = specification.flags or noflags
local nocheck = specification.nocheck
+ local mapping = specification.mapping
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
+ local steptype = nil
+ local sequence = nil
+ --
+ if fonts.handlers.otf.handlers[featuretype] then
+ featureaction = true -- function based
+ else
+ featuretype = normalized[specification.type or "substitution"] or "substitution"
+ end
--
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)
+ 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
+ --
+ if featureaction then
+
+ category = "gsub"
+ sequence = {
+ features = { [feature] = askedfeatures },
+ flags = featureflags,
+ name = feature, -- redundant
+ order = featureorder,
+ type = featuretype,
+ -- steps = { },
+ nofsteps = 0, -- just in case we test for that
+ }
+
+ else
+
+ 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
+ -- see font-imp-tweaks: we directly pass a mapping so no checks done
+ category = "gsub"
+ coverage = (mapping and list) or 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,nocheck)
+ elseif featuretype == "chainposition" then
+ category = "gpos"
+ coverage = prepare_chain(list,featuretype,sublookups,nocheck)
+ else
+ report_otf("not registering feature %a, unknown category",feature)
+ return
end
- --
- checkmerge(specification)
- checksteps(specification)
- --
- s[i] = {
+ 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
+ sequence = {
+ chain = featurechain,
+ features = { [feature] = askedfeatures },
+ flags = featureflags,
+ name = feature, -- redundant
+ order = featureorder,
[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
+
+ if sequence then
-- script = { lang1, lang2, lang3 } or script = { lang1 = true, ... }
- 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, -- redundant
- order = featureorder,
- [stepkey] = steps,
- nofsteps = nofsteps,
- type = steptype,
- }
- --
checkflags(sequence,resources)
checkmerge(sequence)
checksteps(sequence)
@@ -782,11 +847,13 @@ local function addfeature(data,feature,specifications)
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
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-otl.lua b/macros/luatex/generic/luaotfload/fontloader-font-otl.lua
index 4619e13dcf..ae2dda4f39 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-otl.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-otl.lua
@@ -26,7 +26,7 @@ if not modules then modules = { } end modules ['font-otl'] = {
local lower = string.lower
local type, next, tonumber, tostring, unpack = type, next, tonumber, tostring, unpack
local abs = math.abs
-local derivetable = table.derive
+local derivetable, sortedhash = table.derive, table.sortedhash
local formatters = string.formatters
local setmetatableindex = table.setmetatableindex
@@ -52,7 +52,7 @@ local report_otf = logs.reporter("fonts","otf loading")
local fonts = fonts
local otf = fonts.handlers.otf
-otf.version = 3.116 -- beware: also sync font-mis.lua and in mtx-fonts
+otf.version = 3.119 -- beware: also sync font-mis.lua and in mtx-fonts
otf.cache = containers.define("fonts", "otl", otf.version, true)
otf.svgcache = containers.define("fonts", "svg", otf.version, true)
otf.pngcache = containers.define("fonts", "png", otf.version, true)
@@ -218,6 +218,9 @@ function otf.load(filename,sub,instance)
if cleanup == 0 then
checkmemory(used,threshold,tracememory)
end
+ if context then
+ otfreaders.condense(data)
+ end
otfreaders.pack(data)
report_otf("loading done")
report_otf("saving %a in cache",filename)
@@ -314,7 +317,7 @@ local function copytotfm(data,cache_id)
local properties = derivetable(data.properties)
local descriptions = derivetable(data.descriptions)
local goodies = derivetable(data.goodies)
- local characters = { }
+ local characters = { } -- newtable if we knwo how many
local parameters = { }
local mathparameters = { }
--
@@ -504,7 +507,28 @@ local function copytotfm(data,cache_id)
properties.subfont = subfont
--
if not CONTEXTLMTXMODE or CONTEXTLMTXMODE == 0 then
- properties.encodingbytes = 2
+ --
+ properties.encodingbytes = 2
+elseif CONTEXTLMTXMODE then
+ local duplicates = resources and resources.duplicates
+ if duplicates then
+ local maxindex = data.nofglyphs or metadata.nofglyphs
+ if maxindex then
+ for u, d in sortedhash(duplicates) do
+ local du = descriptions[u]
+ if du then
+ for uu in sortedhash(d) do
+ maxindex = maxindex + 1
+ descriptions[uu].dupindex = du.index
+ descriptions[uu].index = maxindex
+ end
+ else
+ -- report_otf("no %U in font %a, duplicates ignored",u,filename)
+ end
+ end
+ end
+ end
+ --
end
--
-- properties.name = specification.name
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-oto.lua b/macros/luatex/generic/luaotfload/fontloader-font-oto.lua
index 6f5f2fb418..1475fcf678 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-oto.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-oto.lua
@@ -67,7 +67,7 @@ local function gref(descriptions,n)
end
local function cref(feature,sequence)
- return formatters["feature %a, type %a, chain lookup %a"](feature,sequence.type,sequence.name)
+ return formatters["feature %a, type %a, (chain) lookup %a"](feature,sequence.type,sequence.name)
end
local function report_substitution(feature,sequence,descriptions,unicode,substitution)
@@ -170,7 +170,7 @@ end
local function makefake(tfmdata,name,present)
local private = getprivate(tfmdata)
local character = { intermediate = true, ligatures = { } }
- resources.unicodes[name] = private
+ tfmdata.resources.unicodes[name] = private
tfmdata.characters[private] = character
tfmdata.descriptions[private] = { name = name }
present[name] = private
@@ -178,43 +178,55 @@ local function makefake(tfmdata,name,present)
end
local function make_1(present,tree,name)
- for k, v in next, tree do
- if k == "ligature" then
- present[name] = v
+ if tonumber(tree) then
+ present[name] = v
+ else
+ for k, v in next, tree do
+ if k == "ligature" then
+ present[name] = v
+ else
+ make_1(present,v,name .. "_" .. k)
+ end
+ end
+ end
+end
+
+local function make_3(present,tfmdata,characters,tree,name,preceding,unicode,done,v)
+ local character = characters[preceding]
+ if not character then
+ if trace_baseinit then
+ report_prepare("weird ligature in lookup %a, current %C, preceding %C",sequence.name,v,preceding)
+ end
+ character = makefake(tfmdata,name,present)
+ end
+ local ligatures = character.ligatures
+ if ligatures then
+ ligatures[unicode] = { char = v }
+ else
+ character.ligatures = { [unicode] = { char = v } }
+ end
+ if done then
+ local d = done[name]
+ if not d then
+ done[name] = { "dummy", v }
else
- make_1(present,v,name .. "_" .. k)
+ d[#d+1] = v
end
end
end
local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done)
- for k, v in next, tree do
- if k == "ligature" then
- local character = characters[preceding]
- if not character then
- if trace_baseinit then
- report_prepare("weird ligature in lookup %a, current %C, preceding %C",sequence.name,v,preceding)
- end
- character = makefake(tfmdata,name,present)
- end
- local ligatures = character.ligatures
- if ligatures then
- ligatures[unicode] = { char = v }
+ if tonumber(tree) then
+ make_3(present,tfmdata,characters,tree,name,preceding,unicode,done,tree)
+ else
+ for k, v in next, tree do
+ if k == "ligature" then
+ make_3(present,tfmdata,characters,tree,name,preceding,unicode,done,v)
else
- character.ligatures = { [unicode] = { char = v } }
+ local code = present[name] or unicode
+ local name = name .. "_" .. k
+ make_2(present,tfmdata,characters,v,name,code,k,done)
end
- if done then
- local d = done[name]
- if not d then
- done[name] = { "dummy", v }
- else
- d[#d+1] = v
- end
- end
- else
- local code = present[name] or unicode
- local name = name .. "_" .. k
- make_2(present,tfmdata,characters,v,name,code,k,done)
end
end
end
@@ -228,12 +240,11 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis
local ligatures = { }
local alternate = tonumber(value) or true and 1
local defaultalt = otf.defaultbasealternate
-
local trace_singles = trace_baseinit and trace_singles
local trace_alternatives = trace_baseinit and trace_alternatives
local trace_ligatures = trace_baseinit and trace_ligatures
- -- A chain of changes is handled in font-con which is clesner because
+ -- A chain of changes is handled in font-con which is cleaner because
-- we can have shared changes and such.
if not changed then
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-otr.lua b/macros/luatex/generic/luaotfload/fontloader-font-otr.lua
index 4b154b2563..286367ed9e 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-otr.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-otr.lua
@@ -682,15 +682,15 @@ local weights = {
}
local widths = {
- [1] = "ultracondensed",
- [2] = "extracondensed",
- [3] = "condensed",
- [4] = "semicondensed",
- [5] = "normal",
- [6] = "semiexpanded",
- [7] = "expanded",
- [8] = "extraexpanded",
- [9] = "ultraexpanded",
+ "ultracondensed",
+ "extracondensed",
+ "condensed",
+ "semicondensed",
+ "normal",
+ "semiexpanded",
+ "expanded",
+ "extraexpanded",
+ "ultraexpanded",
}
setmetatableindex(weights, function(t,k)
@@ -703,31 +703,31 @@ setmetatableindex(widths,function(t,k)
return "normal"
end)
-local panoseweights = {
- [ 0] = "normal",
- [ 1] = "normal",
- [ 2] = "verylight",
- [ 3] = "light",
- [ 4] = "thin",
- [ 5] = "book",
- [ 6] = "medium",
- [ 7] = "demi",
- [ 8] = "bold",
- [ 9] = "heavy",
- [10] = "black",
+local panoseweights = { [0] =
+ "normal",
+ "normal",
+ "verylight",
+ "light",
+ "thin",
+ "book",
+ "medium",
+ "demi",
+ "bold",
+ "heavy",
+ "black",
}
-local panosewidths = {
- [ 0] = "normal",
- [ 1] = "normal",
- [ 2] = "normal",
- [ 3] = "normal",
- [ 4] = "normal",
- [ 5] = "expanded",
- [ 6] = "condensed",
- [ 7] = "veryexpanded",
- [ 8] = "verycondensed",
- [ 9] = "monospaced",
+local panosewidths = { [0] =
+ "normal",
+ "normal",
+ "normal",
+ "normal",
+ "normal",
+ "expanded",
+ "condensed",
+ "veryexpanded",
+ "verycondensed",
+ "monospaced",
}
-- We implement a reader per table.
@@ -1250,7 +1250,7 @@ readers.post = function(f,fontdata,specification)
local version = readulong(f)
fontdata.postscript = {
version = version,
- italicangle = round(1000*readfixed(f))/1000,
+ italicangle = readfixed(f),
underlineposition = readfword(f),
underlinethickness = readfword(f),
monospaced = readulong(f),
@@ -1962,9 +1962,10 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo,inst
weight = weight and lower(weight),
width = width and lower(width),
pfmweight = metrics.weightclass or 400, -- will become weightclass
- pfmwidth = metrics.widthclass or 5, -- will become widthclass
+ pfmwidth = metrics.widthclass or 5, -- will become widthclass
panosewidth = metrics.panosewidth,
panoseweight = metrics.panoseweight,
+ fstype = metrics.fstype or 0, -- embedding, subsetting and editing
italicangle = postscript.italicangle or 0,
units = fontheader.units or 0,
designsize = fontdata.designsize,
@@ -2522,6 +2523,10 @@ function readers.compact(fontdata)
report("the %a helper is not yet implemented","compact")
end
+function readers.condense(fontdata)
+ report("the %a helper is not yet implemented","condense")
+end
+
-- plug in
local extenders = { }
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-ots.lua b/macros/luatex/generic/luaotfload/fontloader-font-ots.lua
index 30d79c4077..7de108d4c8 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-ots.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-ots.lua
@@ -163,6 +163,8 @@ local trace_testruns = false registertracker("otf.testruns", function
local forcediscretionaries = false
local forcepairadvance = false -- for testing
+local repeatablemultiples = context or false
+
directives.register("otf.forcediscretionaries",function(v)
forcediscretionaries = v
end)
@@ -648,16 +650,52 @@ local function multiple_glyphs(head,start,multiple,skiphash,what,stop) -- what t
insertnodeafter(head,start,n)
start = n
end
- if what == true then
- -- we're ok
- elseif what > 1 then
- local m = multiple[nofmultiples]
- for i=2,what do
- local n = copy_node(start) -- ignore components
- resetinjection(n)
- setchar(n,m)
- insertnodeafter(head,start,n)
- start = n
+ if what ~= true and repeatablemultiples then
+ -- This is just some experimental code; we might introduce gsub_extensible
+ -- some day instead. Beware: when we have a feature that mixes alternates and
+ -- multiples we need to make sure we don't handle the alternate string values
+ -- here. This might eventually become an lmtx only feature.
+ local kind = type(what)
+ local m, f, l
+ if kind == "string" then
+ local what, n = string.match(what,"^repeat(.-)[:=](%d+)$")
+ if what == "middle" then
+ m = tonumber(n)
+ elseif what == "first" then
+ f = tonumber(n)
+ elseif what == "last" then
+ l = tonumber(n)
+ end
+ elseif kind == "table" then
+ -- won't happen because currently we don't split these values
+ m = what.middle
+ f = what.first
+ l = what.last
+ end
+ if f or m or l then
+ if m and m > 1 and nofmultiples == 3 then
+ local middle = getnext(first)
+ for i=2,m do
+ local n = copynode(middle) -- ignore components
+ resetinjection(n)
+ insertnodeafter(head,first,n)
+ end
+ end
+ if f and f > 1 then
+ for i=2,f do
+ local n = copynode(first) -- ignore components
+ resetinjection(n)
+ insertnodeafter(head,first,n)
+ end
+ end
+ if l and l > 1 then
+ for i=2,l do
+ local n = copynode(start) -- ignore components
+ resetinjection(n)
+ insertnodeafter(head,start,n)
+ start = n
+ end
+ end
end
end
end
@@ -763,7 +801,7 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
while current do
local char = ischar(current,currentfont)
if char then
- local lg = ligature[char]
+ local lg = not tonumber(ligature) and ligature[char]
if lg then
stop = current
ligature = lg
@@ -776,14 +814,14 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
end
end
if stop then
- local lig = ligature.ligature
- if lig then
+ local ligature = tonumber(ligature) or ligature.ligature
+ if ligature then
if trace_ligatures then
local stopchar = getchar(stop)
- head, start = markstoligature(head,start,stop,lig)
+ head, start = markstoligature(head,start,stop,ligature)
logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(getchar(start)))
else
- head, start = markstoligature(head,start,stop,lig)
+ head, start = markstoligature(head,start,stop,ligature)
end
return head, start, true, false
else
@@ -799,7 +837,7 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
if skiphash and skiphash[char] then
current = getnext(current)
else
- local lg = ligature[char]
+ local lg = not tonumber(ligature) and ligature[char]
if lg then
if marks[char] then
hasmarks = true
@@ -833,20 +871,20 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
local match
if replace then
local char = ischar(replace,currentfont)
- if char and ligature[char] then
+ if char and (not tonumber(ligature) and ligature[char]) then
match = true
end
end
if not match and pre then
local char = ischar(pre,currentfont)
- if char and ligature[char] then
+ if char and (not tonumber(ligature) and ligature[char]) then
match = true
end
end
if not match and not pre or not replace then
local n = getnext(discfound)
local char = ischar(n,currentfont)
- if char and ligature[char] then
+ if char and (not tonumber(ligature) and ligature[char]) then
match = true
end
end
@@ -890,24 +928,26 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
return head, start, true, true
end
end
- local lig = ligature.ligature
- if lig then
+ local ligature = tonumber(ligature) or ligature.ligature
+ if ligature then
if stop then
if trace_ligatures then
local stopchar = getchar(stop)
- -- head, start = toligature(head,start,stop,lig,dataset,sequence,skiphash,discfound,hasmarks)
- head, start = toligature(head,start,stop,lig,dataset,sequence,skiphash,false,hasmarks)
- logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(lig))
+ -- head, start = toligature(head,start,stop,ligature,dataset,sequence,skiphash,discfound,hasmarks)
+ head, start = toligature(head,start,stop,ligature,dataset,sequence,skiphash,false,hasmarks)
+ logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(ligature))
+ -- we can have a rare case of multiple disc in a lig but that makes no sense language wise but if really
+ -- needed we could backtrack if we're in a disc node
else
- -- head, start = toligature(head,start,stop,lig,dataset,sequence,skiphash,discfound,hasmarks)
- head, start = toligature(head,start,stop,lig,dataset,sequence,skiphash,false,hasmarks)
+ -- head, start = toligature(head,start,stop,ligature,dataset,sequence,skiphash,discfound,hasmarks)
+ head, start = toligature(head,start,stop,ligature,dataset,sequence,skiphash,false,hasmarks)
end
else
-- weird but happens (in some arabic font)
resetinjection(start)
- setchar(start,lig)
+ setchar(start,ligature)
if trace_ligatures then
- logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(dataset,sequence),gref(startchar),gref(lig))
+ logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(dataset,sequence),gref(startchar),gref(ligature))
end
end
return head, start, true, false
@@ -1050,7 +1090,7 @@ function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode,
end
return head, start, true
elseif trace_bugs then
- -- onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
+ -- onetimemessage(currentfont,basechar,"no base anchors")
logwarning("%s: mark %s is not anchored to %s",pref(dataset,sequence),gref(markchar),gref(basechar))
end
elseif trace_bugs then
@@ -1116,7 +1156,7 @@ function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlm
end
elseif trace_bugs then
-- logwarning("%s: char %s is missing in font",pref(dataset,sequence),gref(basechar))
- onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
+ onetimemessage(currentfont,basechar,"no base anchors")
end
elseif trace_bugs then
logwarning("%s: prev node is no char, case %i",pref(dataset,sequence),1)
@@ -1484,7 +1524,7 @@ function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup
current = getnext(current)
-- end
else
- local lg = ligatures[schar]
+ local lg = not tonumber(ligatures) and ligatures[schar]
if lg then
ligatures = lg
last = current
@@ -1503,7 +1543,7 @@ function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup
end
end
end
- local ligature = ligatures.ligature
+ local ligature = tonumber(ligatures) or ligatures.ligature
if ligature then
if chainindex then
stop = last
@@ -1856,7 +1896,7 @@ function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup,
end
end
elseif trace_bugs then
- onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
+ onetimemessage(currentfont,startchar,"no entry anchors")
end
break
end
@@ -1978,7 +2018,9 @@ local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck)
local chainproc = chainprocs[chainkind]
if chainproc then
local ok
- head, start, ok = chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash)
+ -- HH: chainindex 1 added here (for KAI to check too), there are weird ligatures e.g.
+ -- char + mark -> char where mark has to disappear
+ head, start, ok = chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,1)
if ok then
done = true
end
@@ -2471,6 +2513,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
local ck = contexts[k]
local seq = ck[3]
local f = ck[4] -- first current
+local last = start
if not startchar or not seq[f][startchar] then
-- report("no hit in %a at %i of %i contexts",sequence.type,k,nofcontexts)
goto next
@@ -2481,7 +2524,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
else
local l = ck[5] -- last current
local current = start
- local last = start
+-- local last = start
-- current match
@@ -3409,7 +3452,7 @@ local function t_run_single(start,stop,font,attr,lookupcache)
while s do
local char = ischar(s,font)
if char then
- local lg = lookupmatch[char]
+ local lg = not tonumber(lookupmatch) and lookupmatch[char]
if lg then
if sstop then
d = 1
@@ -3439,7 +3482,7 @@ local function t_run_single(start,stop,font,attr,lookupcache)
break
end
end
- if l and l.ligature then -- so we test for ligature
+ if l and (tonumber(l) or l.ligature) then -- so we test for ligature
lastd = d
end
-- why not: if not l then break elseif l.ligature then return d end
@@ -3580,7 +3623,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
while s do
local char = ischar(s)
if char then
- local lg = lookupmatch[char]
+ local lg = not tonumber(lookupmatch) and lookupmatch[char]
if lg then
if sstop then
d = 1
@@ -3610,7 +3653,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
break
end
end
- if l and l.ligature then
+ if l and (tonumber(l) or l.ligature) then
lastd = d
end
end
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-oup.lua b/macros/luatex/generic/luaotfload/fontloader-font-oup.lua
index c93ad47438..3bd2fe4828 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-oup.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-oup.lua
@@ -37,13 +37,16 @@ local f_index = formatters["I%05X"]
local f_character_y = formatters["%C"]
local f_character_n = formatters["[ %C ]"]
-local check_duplicates = true -- can become an option (pseudo feature) / aways needed anyway
-local check_soft_hyphen = true -- can become an option (pseudo feature) / needed for tagging
+local check_duplicates = true -- can become an option (pseudo feature) / always needed anyway
+local check_soft_hyphen = context -- only in context
directives.register("otf.checksofthyphen",function(v)
- check_soft_hyphen = v
+ check_soft_hyphen = v -- only for testing
end)
+-- After (!) the unicodes have been resolved we compact ligature tables so before that happens
+-- we don't need to check for numbers.
+
local function replaced(list,index,replacement)
if type(list) == "number" then
return replacement
@@ -453,31 +456,48 @@ local function copyduplicates(fontdata)
local resources = fontdata.resources
local duplicates = resources.duplicates
if check_soft_hyphen then
- -- ebgaramond has a zero width empty soft hyphen
- -- antykwatorunsks lacks a soft hyphen
- local ds = descriptions[0xAD]
- if not ds or ds.width == 0 then
- if ds then
+ -- ebgaramond has a zero width empty soft hyphen
+ -- antykwatorunska lacks a soft hyphen
+ -- lucidaot has a halfwidth soft hyphen
+
+ -- local dh = descriptions[0x2D]
+ -- if dh then
+ -- descriptions[0xAD] = nil
+ -- local d = duplicates[0x2D]
+ -- if d then
+ -- d[#d+1] = { [0xAD] = true }
+ -- else
+ -- duplicates[0x2D] = { [0xAD] = true }
+ -- end
+ -- end
+
+ local dh = descriptions[0x2D]
+ if dh then
+ local ds = descriptions[0xAD]
+ if not ds or ds.width ~= dh.width then
descriptions[0xAD] = nil
- if trace_unicodes then
- report_unicodes("patching soft hyphen")
+ if ds then
+ if trace_unicodes then
+ report_unicodes("patching soft hyphen")
+ end
+ else
+ if trace_unicodes then
+ report_unicodes("adding soft hyphen")
+ end
end
- else
- if trace_unicodes then
- report_unicodes("adding soft hyphen")
+ if not duplicates then
+ duplicates = { }
+ resources.duplicates = duplicates
+ end
+ local d = duplicates[0x2D]
+ if d then
+ d[0xAD] = true
+ else
+ duplicates[0x2D] = { [0xAD] = true }
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
@@ -759,6 +779,7 @@ local function unifyglyphs(fontdata,usenames)
local resources = fontdata.resources
local zero = glyphs[0]
local zerocode = zero.unicode
+ local nofglyphs = #glyphs
if not zerocode then
zerocode = private
zero.unicode = zerocode
@@ -775,7 +796,7 @@ local function unifyglyphs(fontdata,usenames)
--
if names then
-- seldom uses, we don't issue message ... this branch might even go away
- for index=1,#glyphs do
+ for index=1,nofglyphs do
local glyph = glyphs[index]
local unicode = glyph.unicode -- this is the primary one
if not unicode then
@@ -808,7 +829,7 @@ local function unifyglyphs(fontdata,usenames)
descriptions[unicode] = glyph
end
elseif trace_unicodes then
- for index=1,#glyphs do
+ for index=1,nofglyphs do
local glyph = glyphs[index]
local unicode = glyph.unicode -- this is the primary one
if not unicode then
@@ -849,7 +870,7 @@ local function unifyglyphs(fontdata,usenames)
descriptions[unicode] = glyph
end
else
- for index=1,#glyphs do
+ for index=1,nofglyphs do
local glyph = glyphs[index]
local unicode = glyph.unicode -- this is the primary one
if not unicode then
@@ -876,8 +897,8 @@ local function unifyglyphs(fontdata,usenames)
end
end
--
- for index=1,#glyphs do
- local math = glyphs[index].math
+ for index=1,nofglyphs do
+ local math = glyphs[index].math
if math then
local list = math.vparts
if list then
@@ -902,7 +923,7 @@ local function unifyglyphs(fontdata,usenames)
--
local colorpalettes = resources.colorpalettes
if colorpalettes then
- for index=1,#glyphs do
+ for index=1,nofglyphs do
local colors = glyphs[index].colors
if colors then
for i=1,#colors do
@@ -918,6 +939,7 @@ local function unifyglyphs(fontdata,usenames)
fontdata.names = names
fontdata.descriptions = descriptions
fontdata.hashmethod = hashmethod
+ fontdata.nofglyphs = nofglyphs
--
return indices, names
end
@@ -1024,6 +1046,10 @@ function readers.getcomponents(fontdata) -- handy for resolving ligatures when n
local function traverse(p,k,v)
if k == "ligature" then
collected[v] = { unpack(l) }
+ elseif tonumber(v) then
+ insert(l,k)
+ collected[v] = { unpack(l) }
+ remove(l)
else
insert(l,k)
for k, vv in next, v do
@@ -1211,7 +1237,6 @@ local function tabstr_flat(t)
end
local function tabstr_mixed(t) -- indexed
- local s = { }
local n = #t
if n == 0 then
return ""
@@ -1225,6 +1250,7 @@ local function tabstr_mixed(t) -- indexed
return tostring(k) -- number or string
end
else
+ local s = { }
for i=1,n do
local k = t[i]
if k == true then
@@ -1334,6 +1360,21 @@ function readers.pack(data)
end
end
+ -- local function pack_indexed(v) -- less code
+ -- local tag = concat(v," ")
+ -- local ht = h[tag]
+ -- if ht then
+ -- c[ht] = c[ht] + 1
+ -- else
+ -- ht = nt + 1
+ -- t[ht] = v
+ -- c[ht] = 1
+ -- h[tag] = ht
+ -- nt = ht
+ -- end
+ -- return ht
+ -- end
+
local function pack_mixed(v)
local tag = tabstr_mixed(v)
local ht = h[tag]
@@ -2782,6 +2823,91 @@ function readers.compact(data)
end
end
+if CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 then
+
+ local done = 0
+
+ local function condense_1(k,v,t)
+ if type(v) == "table" then
+ local u = false
+ local l = false
+ for k, v in next, v do
+ if k == "ligature" then
+ l = v
+ if u then
+ break
+ end
+ elseif u then
+ break
+ else
+ u = true
+ end
+ end
+ if l and not u then
+ t[k] = l
+ done = done + 1
+ end
+ if u then
+ for k, vv in next, v do
+ if k ~= "ligature" then
+ condense_1(k,vv,v)
+ end
+ end
+ end
+ end
+ end
+
+ local function condensesteps_1(lookup)
+ done = 0
+ if lookup.type == "gsub_ligature" then
+ local steps = lookup.steps
+ if steps then
+ for i=1,#steps do
+ local step = steps[i]
+ local coverage = step.coverage
+ if coverage then
+ for k, v in next, coverage do
+ if condense_1(k,v,coverage) then
+ coverage[k] = v.ligature
+ done = done + 1
+ end
+ end
+ end
+ end
+ end
+ end
+ return done
+ end
+
+ function readers.condense(data)
+ if not data or data.condensed then
+ return
+ else
+ data.condensed = true
+ end
+ local resources = data.resources
+ local condensed = 0
+ local function condense(what)
+ local lookups = resources[what]
+ if lookups then
+ for i=1,#lookups do
+ condensed = condensed + condensesteps_1(lookups[i])
+ end
+ elseif trace_optimizations then
+ report_optimizations("no lookups in %a",what)
+ end
+ end
+ condense("sequences")
+ condense("sublookups")
+ if trace_optimizations then
+ if condensed > 0 then
+ report_optimizations("%i ligatures condensed",condensed)
+ end
+ end
+ end
+
+end
+
local function mergesteps(t,k)
if k == "merged" then
local merged = { }
@@ -2901,7 +3027,7 @@ function readers.expand(data)
-- about 15% on arabtype .. then moving the a test also saves a bit (even when
-- often a is not set at all so that one is a bit debatable
- local function expandlookups(sequences)
+ local function expandlookups(sequences,whatever)
if sequences then
-- we also need to do sublookups
for i=1,#sequences do
@@ -2977,6 +3103,9 @@ function readers.expand(data)
if lookups then
for k, v in next, lookups do -- actually this one is indexed
local lookup = sublookups[v]
+if not lookup and whatever then
+ lookup = whatever[v]
+end
if lookup then
lookups[k] = lookup
if not subtype then
@@ -3057,5 +3186,5 @@ function readers.expand(data)
end
expandlookups(sequences)
- expandlookups(sublookups)
+ expandlookups(sublookups,sequences)
end
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-shp.lua b/macros/luatex/generic/luaotfload/fontloader-font-shp.lua
index ecf0c94180..2ca3011a5b 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-shp.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-shp.lua
@@ -17,7 +17,7 @@ local pfb = fonts.handlers.pfb
local hashes = fonts.hashes
local identifiers = hashes.identifiers
-local version = 0.010
+local version = otf.version or 0.011
local shapescache = containers.define("fonts", "shapes", version, true)
local streamscache = containers.define("fonts", "streams", version, true)
@@ -346,7 +346,7 @@ local function getstreamhash(fontid)
local fontdata = identifiers[fontid]
if fontdata then
local properties = fontdata.properties
- return makehash(properties.filename,properties.subfont,properties.instance)
+ return makehash(properties.filename,properties.subfont,properties.instance), fontdata
end
end
diff --git a/macros/luatex/generic/luaotfload/fontloader-font-ttf.lua b/macros/luatex/generic/luaotfload/fontloader-font-ttf.lua
index a2732aa5f2..a2658d595a 100644
--- a/macros/luatex/generic/luaotfload/fontloader-font-ttf.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-font-ttf.lua
@@ -35,7 +35,7 @@ if not modules then modules = { } end modules ['font-ttf'] = {
local next, type, unpack = next, type, unpack
local band, rshift = bit32.band, bit32.rshift
-local sqrt, round = math.sqrt, math.round
+local sqrt, round, abs, min, max = math.sqrt, math.round, math.abs, math.min, math.max
local char, rep = string.char, string.rep
local concat = table.concat
local idiv = number.idiv
@@ -136,8 +136,12 @@ local function mergecomposites(glyphs,shapes)
local y = p[2]
nofpoints = nofpoints + 1
points[nofpoints] = {
+ -- unifractur : u n
+ -- seguiemj : 0x270E 0x2710
xscale * x + xrotate * y + xoffset,
yscale * y + yrotate * x + yoffset,
+-- xscale * x + yrotate * y + xoffset,
+-- xrotate * x + yscale * y + yoffset,
p[3]
}
end
@@ -203,77 +207,191 @@ end
-- We had two loops (going backward) but can do it in one loop .. but maybe we
-- should only accept fonts with proper hvar tables.
+-- dowidth is kind of hack ... fonts are not always ok wrt these extra points
+
+local xv = { } -- we share this cache
+local yv = { } -- we share this cache
+
local function applyaxis(glyph,shape,deltas,dowidth)
local points = shape.points
if points then
local nofpoints = #points
- local h = nofpoints + 2 -- weird, the example font seems to have left first
- local l = nofpoints + 1
- ----- v = nofpoints + 3
- ----- t = nofpoints + 4
local dw = 0
local dl = 0
for i=1,#deltas do
local deltaset = deltas[i]
local xvalues = deltaset.xvalues
local yvalues = deltaset.yvalues
- local dpoints = deltaset.points
- local factor = deltaset.factor
- if dpoints then
- -- todo: interpolate
- local nofdpoints = #dpoints
- for i=1,nofdpoints do
- local d = dpoints[i]
- local p = points[d]
- if p then
- if xvalues then
- local x = xvalues[i]
- if x and x ~= 0 then
- p[1] = p[1] + factor * x
+ if xvalues and yvalues then
+ local dpoints = deltaset.points
+ local factor = deltaset.factor
+ if dpoints then
+ local cnt = #dpoints
+ if dowidth then
+ cnt = cnt - 4
+ end
+ if cnt == 1 then
+ local d = dpoints[1]
+ local x = xvalues[d] * factor
+ local y = yvalues[d] * factor
+ for i=1,nofpoints do
+ local p = points[i]
+ if x ~= 0 then
+ p[1] = p[1] + x
+ end
+ if y ~= 0 then
+ p[2] = p[2] + y
end
end
- if yvalues then
- local y = yvalues[i]
- if y and y ~= 0 then
- p[2] = p[2] + factor * y
+ elseif cnt > 0 then
+ -- Not the most efficient solution but we seldom do this. We
+ -- actually need to avoid the extra points here but I'll deal
+ -- with that when needed.
+ local function find(i)
+ local prv = cnt
+ for j=1,cnt do
+ local nxt = dpoints[j]
+ if nxt == i then
+ return false, j, false
+ elseif nxt > i then
+ return prv, false, j
+ end
+ prv = j
+ end
+ return prv, false, 1
+ end
+ -- We need the first and last points untouched so we first
+ -- collect data.
+ for i=1,nofpoints do
+ local d1, d2, d3 = find(i)
+ local p2 = points[i]
+ if d2 then
+ xv[i] = xvalues[d2]
+ yv[i] = yvalues[d2]
+ else
+ local n1 = dpoints[d1]
+ local n3 = dpoints[d3]
+ -- Some day I need to figure out these extra points but
+ -- I'll wait till the standard is more clear and fonts
+ -- become better (ntg-context: fraunces.ttf > abcdef).
+ if n1 > nofpoints then
+ n1 = nofpoints
+ end
+ if n3 > nofpoints then
+ n3 = nofpoints
+ end
+ --
+ local p1 = points[n1]
+ local p3 = points[n3]
+ local p1x = p1[1]
+ local p2x = p2[1]
+ local p3x = p3[1]
+ local p1y = p1[2]
+ local p2y = p2[2]
+ local p3y = p3[2]
+ local x1 = xvalues[d1]
+ local y1 = yvalues[d1]
+ local x3 = xvalues[d3]
+ local y3 = yvalues[d3]
+ --
+ local fx
+ local fy
+ --
+ if p1x == p3x then
+ if x1 == x3 then
+ fx = x1
+ else
+ fx = 0
+ end
+ elseif p2x <= min(p1x,p3x) then
+ if p1x < p3x then
+ fx = x1
+ else
+ fx = x3
+ end
+ elseif p2x >= max(p1x,p3x) then
+ if p1x > p3x then
+ fx = x1
+ else
+ fx = x3
+ end
+ else
+ fx = (p2x - p1x)/(p3x - p1x)
+ fx = (1 - fx) * x1 + fx * x3
+ end
+ --
+ if p1y == p3y then
+ if y1 == y3 then
+ fy = y1
+ else
+ fy = 0
+ end
+ elseif p2y <= min(p1y,p3y) then
+ if p1y < p3y then
+ fy = y1
+ else
+ fy = y3
+ end
+ elseif p2y >= max(p1y,p3y) then
+ if p1y > p3y then
+ fy = y1
+ else
+ fy = y3
+ end
+ else
+ fy = (p2y - p1y)/(p3y - p1y)
+ fy = (1 - fy) * y1 + fy * y3
+ end
+ -- -- maybe:
+ -- if p1y ~= p3y then
+ -- fy = (p2y - p1y)/(p3y - p1y)
+ -- fy = (1 - fy) * y1 + fy * y3
+ -- elseif abs(p1y-p2y) < abs(p3y-p2y) then
+ -- fy = y1
+ -- else
+ -- fy = y3
+ -- end
+ --
+ xv[i] = fx
+ yv[i] = fy
end
end
- elseif dowidth then
- -- we've now ran into phantom points which is a bit fuzzy because:
- -- are there gaps in there?
- --
- -- todo: move this outside the loop (when we can be sure of all 4 being there)
- if d == h then
- -- we have a phantom point hadvance
- local x = xvalues[i]
- if x then
- dw = dw + factor * x
+ for i=1,nofpoints do
+ local pi = points[i]
+ local fx = xv[i]
+ local fy = yv[i]
+ if fx ~= 0 then
+ pi[1] = pi[1] + factor * fx
end
- elseif d == l then
- local x = xvalues[i]
- if x then
- dl = dl + factor * x
+ if fy ~= 0 then
+ pi[2] = pi[2] + factor * fy
end
end
+ else
+ report("bad deltapoint data, maybe a missing hvar table")
end
- end
- else
- for i=1,nofpoints do
- local p = points[i]
- if xvalues then
+ else
+ for i=1,nofpoints do
+ local p = points[i]
local x = xvalues[i]
- if x and x ~= 0 then
- p[1] = p[1] + factor * x
- end
- end
- if yvalues then
- local y = yvalues[i]
- if y and y ~= 0 then
- p[2] = p[2] + factor * y
+ if x then
+ local y = yvalues[i]
+ if x ~= 0 then
+ p[1] = p[1] + factor * x
+ end
+ if y ~= 0 then
+ p[2] = p[2] + factor * y
+ end
+ else
+ break
end
end
end
if dowidth then
+ local h = nofpoints + 2 -- weird, the example font seems to have left first
+ local l = nofpoints + 1
+ ----- v = nofpoints + 3
+ ----- t = nofpoints + 4
local x = xvalues[h]
if x then
dw = dw + factor * x
@@ -930,13 +1048,13 @@ local function readcomposite(f)
yoffset = yoffset * yscale
end
elseif band(flags,0x0080) ~= 0 then -- f_matrix
- xscale = read2dot14(f)
- xrotate = read2dot14(f)
- yrotate = read2dot14(f)
- yscale = read2dot14(f)
+ xscale = read2dot14(f) -- xxpart
+ xrotate = read2dot14(f) -- yxpart
+ yrotate = read2dot14(f) -- xypart
+ yscale = read2dot14(f) -- yypart
if f_xyarg and f_offset then
- xoffset = xoffset * sqrt(xscale ^2 + xrotate^2)
- yoffset = yoffset * sqrt(yrotate^2 + yscale ^2)
+ xoffset = xoffset * sqrt(xscale ^2 + yrotate^2) -- was xrotate
+ yoffset = yoffset * sqrt(xrotate^2 + yscale ^2) -- was yrotate
end
end
nofcomponents = nofcomponents + 1
@@ -1119,50 +1237,6 @@ end
local function readdeltas(f,nofpoints)
local deltas = { }
local p = 0
- local z = 0
- while nofpoints > 0 do
- local control = readbyte(f)
-if not control then
- break
-end
- local allzero = band(control,0x80) ~= 0
- local runlength = band(control,0x3F) + 1
- if allzero then
- z = z + runlength
- else
- local runreader = band(control,0x40) ~= 0 and readshort or readinteger
- if z > 0 then
- for i=1,z do
- p = p + 1
- deltas[p] = 0
- end
- z = 0
- end
- for i=1,runlength do
- p = p + 1
- deltas[p] = runreader(f)
- end
- end
- nofpoints = nofpoints - runlength
- end
- -- saves space
--- if z > 0 then
--- for i=1,z do
--- p = p + 1
--- deltas[p] = 0
--- end
--- end
- if p > 0 then
- -- forget about trailing zeros
- return deltas
- else
- -- forget about all zeros
- end
-end
-
-local function readdeltas(f,nofpoints)
- local deltas = { }
- local p = 0
while nofpoints > 0 do
local control = readbyte(f)
if control then
@@ -1330,7 +1404,8 @@ function readers.gvar(f,fontdata,specification,glyphdata,shapedata)
-- local start = start and start[i] or 0
-- local stop = stop and stop [i] or 0
local start = start and start[i] or (peak < 0 and peak or 0)
- local stop = stop and stop [i] or (peak > 0 and peak or 0)
+ local stop = stop and stop [i] or (peak > 0 and peak or 0) -- or 1 ?
+-- local stop = stop and stop [i] or (peak > 0 and peak or 1) -- or 1 ?
-- do we really need these tests ... can't we assume sane values
if start > peak or peak > stop then
-- * 1
@@ -1343,7 +1418,6 @@ function readers.gvar(f,fontdata,specification,glyphdata,shapedata)
s = 0
break
elseif f < peak then
--- s = - s * (f - start) / (peak - start)
s = s * (f - start) / (peak - start)
elseif f > peak then
s = s * (stop - f) / (stop - peak)
diff --git a/macros/luatex/generic/luaotfload/fontloader-fonts-enc.lua b/macros/luatex/generic/luaotfload/fontloader-fonts-enc.lua
index 2bc6b71bf4..d8725c2140 100644
--- a/macros/luatex/generic/luaotfload/fontloader-fonts-enc.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-fonts-enc.lua
@@ -16,10 +16,18 @@ fonts.encodings = encodings
encodings.agl = { }
encodings.known = { }
+encodings.glyphlistfilename = "font-age.lua"
+
setmetatable(encodings.agl, { __index = function(t,k)
if k == "unicodes" then
logs.report("fonts","loading (extended) adobe glyph list")
- local unicodes = dofile(resolvers.findfile("font-age.lua"))
+ local foundname = resolvers.findfile(encodings.glyphlistfilename) or ""
+ local unicodes = foundname ~= "" and dofile(foundname)
+ if type(unicodes) ~= "table" then
+ logs.report("fonts","missing or invalid (extended) adobe glyph list")
+ -- no message
+ unicodes = { }
+ end
encodings.agl = { unicodes = unicodes }
return unicodes
else
diff --git a/macros/luatex/generic/luaotfload/fontloader-l-file.lua b/macros/luatex/generic/luaotfload/fontloader-l-file.lua
index d0af94f09d..9f8fd65483 100644
--- a/macros/luatex/generic/luaotfload/fontloader-l-file.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-l-file.lua
@@ -456,7 +456,7 @@ function file.join(one, two, three, ...)
if not two then
return one == "" and one or lpegmatch(reslasher,one)
end
- if one == "" then
+ if not one or one == "" then
return lpegmatch(stripper,three and concat({ two, three, ... },"/") or two)
end
if lpegmatch(isnetwork,one) then
diff --git a/macros/luatex/generic/luaotfload/fontloader-l-io.lua b/macros/luatex/generic/luaotfload/fontloader-l-io.lua
index a955262a31..6bf7a97bda 100644
--- a/macros/luatex/generic/luaotfload/fontloader-l-io.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-l-io.lua
@@ -147,9 +147,12 @@ function io.copydata(source,target,action)
end
end
-function io.savedata(filename,data,joiner)
- local f = open(filename,"wb")
+function io.savedata(filename,data,joiner,append)
+ local f = open(filename,append and "ab" or "wb")
if f then
+ if append and joiner and f:seek("end") > 0 then
+ f:write(joiner)
+ end
if type(data) == "table" then
f:write(concat(data,joiner or ""))
elseif type(data) == "function" then
@@ -288,7 +291,8 @@ end
io.noflines = noflines
--- inlined is faster ... beware, better use util-fil
+-- inlined is faster ... beware, better use util-fil so these are obsolete
+-- and will go
local nextchar = {
[ 4] = function(f)
diff --git a/macros/luatex/generic/luaotfload/fontloader-l-lpeg.lua b/macros/luatex/generic/luaotfload/fontloader-l-lpeg.lua
index 50306e4ab6..5f3bea08ca 100644
--- a/macros/luatex/generic/luaotfload/fontloader-l-lpeg.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-l-lpeg.lua
@@ -665,12 +665,12 @@ end
-- lpeg.print(lpeg.P("a","b","c"))
-- lpeg.print(lpeg.S("a","b","c"))
--- print(lpeg.count("äáàa",lpeg.P("á") + lpeg.P("à")))
--- print(lpeg.count("äáàa",lpeg.UP("áà")))
--- print(lpeg.count("äáàa",lpeg.US("àá")))
--- print(lpeg.count("äáàa",lpeg.UR("aá")))
--- print(lpeg.count("äáàa",lpeg.UR("àá")))
--- print(lpeg.count("äáàa",lpeg.UR(0x0000,0xFFFF)))
+-- print(lpeg.counter(lpeg.P("á") + lpeg.P("à"))("äáàa"))
+-- print(lpeg.counter(lpeg.UP("áà"))("äáàa"))
+-- print(lpeg.counter(lpeg.US("àá"))("äáàa"))
+-- print(lpeg.counter(lpeg.UR("aá"))("äáàa"))
+-- print(lpeg.counter(lpeg.UR("àá"))("äáàa"))
+-- print(lpeg.counter(lpeg.UR(0x0000,0xFFFF)))
function lpeg.is_lpeg(p)
return p and lpegtype(p) == "pattern"
diff --git a/macros/luatex/generic/luaotfload/fontloader-l-math.lua b/macros/luatex/generic/luaotfload/fontloader-l-math.lua
index e5668a5db0..69f0a19e98 100644
--- a/macros/luatex/generic/luaotfload/fontloader-l-math.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-l-math.lua
@@ -141,7 +141,7 @@ if not math.ult then
local floor = math.floor
- function math.tointeger(m,n)
+ function math.ult(m,n)
-- not ok but i'm not motivated to look into it now
return floor(m) < floor(n) -- unsigned comparison needed
end
diff --git a/macros/luatex/generic/luaotfload/fontloader-reference.lua b/macros/luatex/generic/luaotfload/fontloader-reference.lua
index 59cbd9ef8c..736856d2be 100644
--- a/macros/luatex/generic/luaotfload/fontloader-reference.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-reference.lua
@@ -1,6 +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 : 2021-05-20 15:57
+-- merge date : 2022-01-21 20:10
do -- begin closure to overcome local limits and interference
@@ -2255,9 +2255,12 @@ function io.copydata(source,target,action)
flush()
end
end
-function io.savedata(filename,data,joiner)
- local f=open(filename,"wb")
+function io.savedata(filename,data,joiner,append)
+ local f=open(filename,append and "ab" or "wb")
if f then
+ if append and joiner and f:seek("end")>0 then
+ f:write(joiner)
+ end
if type(data)=="table" then
f:write(concat(data,joiner or ""))
elseif type(data)=="function" then
@@ -2791,7 +2794,7 @@ function file.join(one,two,three,...)
if not two then
return one=="" and one or lpegmatch(reslasher,one)
end
- if one=="" then
+ if not one or one=="" then
return lpegmatch(stripper,three and concat({ two,three,... },"/") or two)
end
if lpegmatch(isnetwork,one) then
@@ -3099,7 +3102,7 @@ if not math.tointeger then
end
if not math.ult then
local floor=math.floor
- function math.tointeger(m,n)
+ function math.ult(m,n)
return floor(m)<floor(n)
end
end
@@ -3118,12 +3121,13 @@ if not modules then modules={} end modules ['util-str']={
utilities=utilities or {}
utilities.strings=utilities.strings or {}
local strings=utilities.strings
-local format,gsub,rep,sub,find=string.format,string.gsub,string.rep,string.sub,string.find
+local format,gsub,rep,sub,find,char=string.format,string.gsub,string.rep,string.sub,string.find,string.char
local load,dump=load,string.dump
local tonumber,type,tostring,next,setmetatable=tonumber,type,tostring,next,setmetatable
local unpack,concat=table.unpack,table.concat
local P,V,C,S,R,Ct,Cs,Cp,Carg,Cc=lpeg.P,lpeg.V,lpeg.C,lpeg.S,lpeg.R,lpeg.Ct,lpeg.Cs,lpeg.Cp,lpeg.Carg,lpeg.Cc
local patterns,lpegmatch=lpeg.patterns,lpeg.match
+local tsplitat=lpeg.tsplitat
local utfchar,utfbyte,utflen=utf.char,utf.byte,utf.len
local loadstripped=function(str,shortcuts)
if shortcuts then
@@ -3477,6 +3481,14 @@ patterns.escapedquotes=pattern
function string.escapedquotes(s)
return lpegmatch(pattern,s)
end
+local pattern=(1-P("\\"))^1;pattern=Cs (
+ pattern*((P("\\")/""*(digit^-3/function(s) return char(tonumber(s)) end))+pattern )^1
+)
+patterns.unescapedquotes=pattern
+function string.unescapedquotes(s)
+ return lpegmatch(pattern,s) or s
+end
+string.texnewlines=lpeg.replacer(patterns.newline,"\r",true)
local preamble=""
local environment={
global=global or _G,
@@ -4012,7 +4024,6 @@ function number.to16dot16(n)
return f_16_16(n/65536.0)
end
if not string.explode then
- local tsplitat=lpeg.tsplitat
local p_utf=patterns.utf8character
local p_check=C(p_utf)*(P("+")*Cc(true))^0
local p_split=Ct(C(p_utf)^0)
@@ -4032,6 +4043,20 @@ if not string.explode then
end
end
end
+do
+ local p_whitespace=patterns.whitespace^1
+ local cache=setmetatable({},{ __index=function(t,k)
+ local p=tsplitat(p_whitespace*P(k)*p_whitespace)
+ local v=function(s)
+ return lpegmatch(p,s)
+ end
+ t[k]=v
+ return v
+ end })
+ function string.wordsplitter(s)
+ return cache[s]
+ end
+end
end -- closure
@@ -4202,20 +4227,20 @@ function files.readinteger4le(f)
end
end
function files.readfixed2(f)
- local a,b=byte(f:read(2),1,2)
- if a>=0x80 then
- tonumber((a-0x100).."."..b)
- else
- tonumber((a ).."."..b)
+ local n1,n2=byte(f:read(2),1,2)
+ if n1>=0x80 then
+ n1=n1-0x100
end
+ return n1+n2/0xFF
end
function files.readfixed4(f)
local a,b,c,d=byte(f:read(4),1,4)
- if a>=0x80 then
- tonumber((0x100*a+b-0x10000).."."..(0x100*c+d))
- else
- tonumber((0x100*a+b ).."."..(0x100*c+d))
+ local n1=0x100*a+b
+ local n2=0x100*c+d
+ if n1>=0x8000 then
+ n1=n1-0x10000
end
+ return n1+n2/0xFFFF
end
if bit32 then
local extract=bit32.extract
@@ -4996,7 +5021,7 @@ nuts.setcomponents=direct.setcomponents
nuts.setdirection=direct.setdirection
nuts.setdisc=direct.setdisc
nuts.setreplace=direct.setreplace
-nuts.setfield=setfield
+nuts.setfield=direct.setfield
nuts.setkern=direct.setkern
nuts.setlink=direct.setlink
nuts.setlist=direct.setlist
@@ -5379,6 +5404,7 @@ characters.classifiers={
[1562]=5,
[1563]=6,
[1564]=6,
+ [1565]=6,
[1566]=6,
[1567]=6,
[1568]=2,
@@ -5845,9 +5871,9 @@ characters.classifiers={
[2131]=2,
[2132]=3,
[2133]=2,
- [2134]=4,
- [2135]=4,
- [2136]=4,
+ [2134]=3,
+ [2135]=3,
+ [2136]=3,
[2137]=5,
[2138]=5,
[2139]=5,
@@ -5862,6 +5888,47 @@ characters.classifiers={
[2152]=2,
[2153]=3,
[2154]=3,
+ [2160]=3,
+ [2161]=3,
+ [2162]=3,
+ [2163]=3,
+ [2164]=3,
+ [2165]=3,
+ [2166]=3,
+ [2167]=3,
+ [2168]=3,
+ [2169]=3,
+ [2170]=3,
+ [2171]=3,
+ [2172]=3,
+ [2173]=3,
+ [2174]=3,
+ [2175]=3,
+ [2176]=3,
+ [2177]=3,
+ [2178]=3,
+ [2179]=2,
+ [2180]=2,
+ [2181]=2,
+ [2182]=2,
+ [2183]=4,
+ [2184]=4,
+ [2185]=2,
+ [2186]=2,
+ [2187]=2,
+ [2188]=2,
+ [2189]=2,
+ [2190]=3,
+ [2192]=4,
+ [2193]=4,
+ [2200]=5,
+ [2201]=5,
+ [2202]=5,
+ [2203]=5,
+ [2204]=5,
+ [2205]=5,
+ [2206]=5,
+ [2207]=5,
[2208]=2,
[2209]=2,
[2210]=2,
@@ -5883,6 +5950,7 @@ characters.classifiers={
[2226]=3,
[2227]=2,
[2228]=2,
+ [2229]=2,
[2230]=2,
[2231]=2,
[2232]=2,
@@ -5891,6 +5959,26 @@ characters.classifiers={
[2235]=2,
[2236]=2,
[2237]=2,
+ [2238]=2,
+ [2239]=2,
+ [2240]=2,
+ [2241]=2,
+ [2242]=2,
+ [2243]=2,
+ [2244]=2,
+ [2245]=2,
+ [2246]=2,
+ [2247]=2,
+ [2248]=2,
+ [2250]=5,
+ [2251]=5,
+ [2252]=5,
+ [2253]=5,
+ [2254]=5,
+ [2255]=5,
+ [2256]=5,
+ [2257]=5,
+ [2258]=5,
[2259]=5,
[2260]=5,
[2261]=5,
@@ -6010,6 +6098,7 @@ characters.classifiers={
[2883]=5,
[2884]=5,
[2893]=5,
+ [2901]=5,
[2902]=5,
[2914]=5,
[2915]=5,
@@ -6018,6 +6107,7 @@ characters.classifiers={
[3021]=5,
[3072]=5,
[3076]=5,
+ [3132]=5,
[3134]=5,
[3135]=5,
[3136]=5,
@@ -6051,6 +6141,7 @@ characters.classifiers={
[3405]=5,
[3426]=5,
[3427]=5,
+ [3457]=5,
[3530]=5,
[3538]=5,
[3539]=5,
@@ -6230,6 +6321,7 @@ characters.classifiers={
[6156]=5,
[6157]=5,
[6158]=4,
+ [6159]=5,
[6176]=2,
[6177]=2,
[6178]=2,
@@ -6414,6 +6506,22 @@ characters.classifiers={
[6843]=5,
[6844]=5,
[6845]=5,
+ [6847]=5,
+ [6848]=5,
+ [6849]=5,
+ [6850]=5,
+ [6851]=5,
+ [6852]=5,
+ [6853]=5,
+ [6854]=5,
+ [6855]=5,
+ [6856]=5,
+ [6857]=5,
+ [6858]=5,
+ [6859]=5,
+ [6860]=5,
+ [6861]=5,
+ [6862]=5,
[6912]=5,
[6913]=5,
[6914]=5,
@@ -6546,6 +6654,7 @@ characters.classifiers={
[7671]=5,
[7672]=5,
[7673]=5,
+ [7674]=5,
[7675]=5,
[7676]=5,
[7677]=5,
@@ -6647,6 +6756,7 @@ characters.classifiers={
[43019]=5,
[43045]=5,
[43046]=5,
+ [43052]=5,
[43072]=2,
[43073]=2,
[43074]=2,
@@ -6923,6 +7033,8 @@ characters.classifiers={
[68901]=5,
[68902]=5,
[68903]=5,
+ [69291]=5,
+ [69292]=5,
[69424]=2,
[69425]=2,
[69426]=2,
@@ -6960,6 +7072,56 @@ characters.classifiers={
[69458]=2,
[69459]=2,
[69460]=3,
+ [69488]=2,
+ [69489]=2,
+ [69490]=2,
+ [69491]=2,
+ [69492]=3,
+ [69493]=3,
+ [69494]=2,
+ [69495]=2,
+ [69496]=2,
+ [69497]=2,
+ [69498]=2,
+ [69499]=2,
+ [69500]=2,
+ [69501]=2,
+ [69502]=2,
+ [69503]=2,
+ [69504]=2,
+ [69505]=2,
+ [69506]=5,
+ [69507]=5,
+ [69508]=5,
+ [69509]=5,
+ [69552]=2,
+ [69553]=4,
+ [69554]=2,
+ [69555]=2,
+ [69556]=3,
+ [69557]=3,
+ [69558]=3,
+ [69559]=4,
+ [69560]=2,
+ [69561]=3,
+ [69562]=3,
+ [69563]=2,
+ [69564]=2,
+ [69565]=3,
+ [69566]=2,
+ [69567]=2,
+ [69568]=4,
+ [69569]=2,
+ [69570]=3,
+ [69571]=3,
+ [69572]=2,
+ [69573]=4,
+ [69574]=4,
+ [69575]=4,
+ [69576]=4,
+ [69577]=3,
+ [69578]=2,
+ [69579]=1,
[69633]=5,
[69688]=5,
[69689]=5,
@@ -6976,6 +7138,9 @@ characters.classifiers={
[69700]=5,
[69701]=5,
[69702]=5,
+ [69744]=5,
+ [69747]=5,
+ [69748]=5,
[69759]=5,
[69760]=5,
[69761]=5,
@@ -6986,6 +7151,7 @@ characters.classifiers={
[69817]=5,
[69818]=5,
[69821]=4,
+ [69826]=5,
[69837]=4,
[69888]=5,
[69889]=5,
@@ -7018,6 +7184,7 @@ characters.classifiers={
[70090]=5,
[70091]=5,
[70092]=5,
+ [70095]=5,
[70191]=5,
[70192]=5,
[70193]=5,
@@ -7128,6 +7295,10 @@ characters.classifiers={
[71735]=5,
[71737]=5,
[71738]=5,
+ [71995]=5,
+ [71996]=5,
+ [71998]=5,
+ [72003]=5,
[72148]=5,
[72149]=5,
[72150]=5,
@@ -7265,8 +7436,78 @@ characters.classifiers={
[94096]=5,
[94097]=5,
[94098]=5,
+ [94180]=5,
[113821]=5,
[113822]=5,
+ [118528]=5,
+ [118529]=5,
+ [118530]=5,
+ [118531]=5,
+ [118532]=5,
+ [118533]=5,
+ [118534]=5,
+ [118535]=5,
+ [118536]=5,
+ [118537]=5,
+ [118538]=5,
+ [118539]=5,
+ [118540]=5,
+ [118541]=5,
+ [118542]=5,
+ [118543]=5,
+ [118544]=5,
+ [118545]=5,
+ [118546]=5,
+ [118547]=5,
+ [118548]=5,
+ [118549]=5,
+ [118550]=5,
+ [118551]=5,
+ [118552]=5,
+ [118553]=5,
+ [118554]=5,
+ [118555]=5,
+ [118556]=5,
+ [118557]=5,
+ [118558]=5,
+ [118559]=5,
+ [118560]=5,
+ [118561]=5,
+ [118562]=5,
+ [118563]=5,
+ [118564]=5,
+ [118565]=5,
+ [118566]=5,
+ [118567]=5,
+ [118568]=5,
+ [118569]=5,
+ [118570]=5,
+ [118571]=5,
+ [118572]=5,
+ [118573]=5,
+ [118576]=5,
+ [118577]=5,
+ [118578]=5,
+ [118579]=5,
+ [118580]=5,
+ [118581]=5,
+ [118582]=5,
+ [118583]=5,
+ [118584]=5,
+ [118585]=5,
+ [118586]=5,
+ [118587]=5,
+ [118588]=5,
+ [118589]=5,
+ [118590]=5,
+ [118591]=5,
+ [118592]=5,
+ [118593]=5,
+ [118594]=5,
+ [118595]=5,
+ [118596]=5,
+ [118597]=5,
+ [118598]=5,
[119143]=5,
[119144]=5,
[119145]=5,
@@ -7464,6 +7705,7 @@ characters.classifiers={
[123188]=5,
[123189]=5,
[123190]=5,
+ [123566]=5,
[123628]=5,
[123629]=5,
[123630]=5,
@@ -7631,6 +7873,7 @@ characters.indicgroups={
[2879]=true,
[2902]=true,
[3376]=true,
+ [5901]=true,
},
["after_postscript"]={
[2433]=true,
@@ -7806,6 +8049,7 @@ characters.indicgroups={
[2915]=true,
[3009]=true,
[3010]=true,
+ [3132]=true,
[3170]=true,
[3171]=true,
[3260]=true,
@@ -8224,6 +8468,7 @@ characters.indicgroups={
[4225]=true,
[4226]=true,
[4238]=true,
+ [5901]=true,
[43488]=true,
[43489]=true,
[43490]=true,
@@ -8548,6 +8793,7 @@ characters.indicgroups={
[3090]=true,
[3091]=true,
[3092]=true,
+ [3165]=true,
[3168]=true,
[3169]=true,
[3205]=true,
@@ -8564,6 +8810,7 @@ characters.indicgroups={
[3218]=true,
[3219]=true,
[3220]=true,
+ [3293]=true,
[3296]=true,
[3297]=true,
[3333]=true,
@@ -8604,6 +8851,7 @@ characters.indicgroups={
[2620]=true,
[2748]=true,
[2876]=true,
+ [3132]=true,
[3260]=true,
},
["post_mark"]={
@@ -8707,6 +8955,7 @@ characters.indicgroups={
[3120]=true,
[3248]=true,
[3376]=true,
+ [5901]=true,
},
["stress_tone_mark"]={
[2385]=true,
@@ -10252,10 +10501,16 @@ local encodings={}
fonts.encodings=encodings
encodings.agl={}
encodings.known={}
+encodings.glyphlistfilename="font-age.lua"
setmetatable(encodings.agl,{ __index=function(t,k)
if k=="unicodes" then
logs.report("fonts","loading (extended) adobe glyph list")
- local unicodes=dofile(resolvers.findfile("font-age.lua"))
+ local foundname=resolvers.findfile(encodings.glyphlistfilename) or ""
+ local unicodes=foundname~="" and dofile(foundname)
+ if type(unicodes)~="table" then
+ logs.report("fonts","missing or invalid (extended) adobe glyph list")
+ unicodes={}
+ end
encodings.agl={ unicodes=unicodes }
return unicodes
else
@@ -11287,15 +11542,15 @@ local weights={
[900]="black",
}
local widths={
- [1]="ultracondensed",
- [2]="extracondensed",
- [3]="condensed",
- [4]="semicondensed",
- [5]="normal",
- [6]="semiexpanded",
- [7]="expanded",
- [8]="extraexpanded",
- [9]="ultraexpanded",
+ "ultracondensed",
+ "extracondensed",
+ "condensed",
+ "semicondensed",
+ "normal",
+ "semiexpanded",
+ "expanded",
+ "extraexpanded",
+ "ultraexpanded",
}
setmetatableindex(weights,function(t,k)
local r=floor((k+50)/100)*100
@@ -11305,30 +11560,28 @@ end)
setmetatableindex(widths,function(t,k)
return "normal"
end)
-local panoseweights={
- [ 0]="normal",
- [ 1]="normal",
- [ 2]="verylight",
- [ 3]="light",
- [ 4]="thin",
- [ 5]="book",
- [ 6]="medium",
- [ 7]="demi",
- [ 8]="bold",
- [ 9]="heavy",
- [10]="black",
+local panoseweights={ [0]="normal",
+ "normal",
+ "verylight",
+ "light",
+ "thin",
+ "book",
+ "medium",
+ "demi",
+ "bold",
+ "heavy",
+ "black",
}
-local panosewidths={
- [ 0]="normal",
- [ 1]="normal",
- [ 2]="normal",
- [ 3]="normal",
- [ 4]="normal",
- [ 5]="expanded",
- [ 6]="condensed",
- [ 7]="veryexpanded",
- [ 8]="verycondensed",
- [ 9]="monospaced",
+local panosewidths={ [0]="normal",
+ "normal",
+ "normal",
+ "normal",
+ "normal",
+ "expanded",
+ "condensed",
+ "veryexpanded",
+ "verycondensed",
+ "monospaced",
}
local helpers={}
readers.helpers=helpers
@@ -11762,7 +12015,7 @@ readers.post=function(f,fontdata,specification)
local version=readulong(f)
fontdata.postscript={
version=version,
- italicangle=round(1000*readfixed(f))/1000,
+ italicangle=readfixed(f),
underlineposition=readfword(f),
underlinethickness=readfword(f),
monospaced=readulong(f),
@@ -12379,6 +12632,7 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo,inst
pfmwidth=metrics.widthclass or 5,
panosewidth=metrics.panosewidth,
panoseweight=metrics.panoseweight,
+ fstype=metrics.fstype or 0,
italicangle=postscript.italicangle or 0,
units=fontheader.units or 0,
designsize=fontdata.designsize,
@@ -12872,6 +13126,9 @@ end
function readers.compact(fontdata)
report("the %a helper is not yet implemented","compact")
end
+function readers.condense(fontdata)
+ report("the %a helper is not yet implemented","condense")
+end
local extenders={}
function readers.registerextender(extender)
extenders[#extenders+1]=extender
@@ -13339,7 +13596,8 @@ do
top=0
end
local p_dictionary=(
- p_byte+p_positive+p_negative+p_short+p_long+p_nibbles+p_single+p_double+p_unsupported
+ p_byte+p_positive+p_negative+p_short+p_long+p_nibbles+p_single+p_double
++p_unsupported
)^1
parsedictionaries=function(data,dictionaries,version)
stack={}
@@ -13411,6 +13669,7 @@ do
local y=0
local width=false
local lsb=0
+local result={}
local r=0
local stems=0
local globalbias=0
@@ -14365,12 +14624,12 @@ do
stack[top]=-t*256+64148-tab[i+1]
i=i+2
else
- local n=0x100*tab[i+1]+tab[i+2]
- if n>=0x8000 then
- stack[top]=n-0x10000+(0x100*tab[i+3]+tab[i+4])/0xFFFF
- else
- stack[top]=n+(0x100*tab[i+3]+tab[i+4])/0xFFFF
+ local n1=0x100*tab[i+1]+tab[i+2]
+ local n2=0x100*tab[i+3]+tab[i+4]
+ if n1>=0x8000 then
+ n1=n1-0x10000
end
+ stack[top]=n1+n2/0xFFFF
i=i+5
end
elseif t==28 then
@@ -14458,7 +14717,7 @@ do
i=i+s+1
elseif t==1 or t==3 or t==18 or operation==23 then
p_getstem()
- if true then
+ if version=="cff" then
if top>0 then
for i=1,top do
r=r+1;result[r]=encode[stack[i]]
@@ -14471,7 +14730,7 @@ do
end
i=i+1
elseif t==19 or t==20 then
- local s=p_getmask() or 0
+ local s=p_getmask() or 0
if true then
if top>0 then
for i=1,top do
@@ -14494,7 +14753,7 @@ do
i=i+1
elseif t==13 then
hsbw()
- if version=="cff" then
+ if true then
r=r+1;result[r]=encode[lsb]
r=r+1;result[r]=chars[22]
else
@@ -14621,6 +14880,7 @@ do
r=r+1
result[r]=c_endchar
local stream=concat(result)
+result=nil
if glyph then
glyph.stream=stream
else
@@ -14642,6 +14902,7 @@ do
width=width,
name=charset and charset[index] or nil,
}
+result=nil
else
glyphs[index]={
boundingbox=boundingbox,
@@ -15128,7 +15389,7 @@ if not modules then modules={} end modules ['font-ttf']={
}
local next,type,unpack=next,type,unpack
local band,rshift=bit32.band,bit32.rshift
-local sqrt,round=math.sqrt,math.round
+local sqrt,round,abs,min,max=math.sqrt,math.round,math.abs,math.min,math.max
local char,rep=string.char,string.rep
local concat=table.concat
local idiv=number.idiv
@@ -15262,69 +15523,164 @@ local function curveto(m_x,m_y,l_x,l_y,r_x,r_y)
r_x+2/3*(m_x-r_x),r_y+2/3*(m_y-r_y),
r_x,r_y,"c"
end
+local xv={}
+local yv={}
local function applyaxis(glyph,shape,deltas,dowidth)
local points=shape.points
if points then
local nofpoints=#points
- local h=nofpoints+2
- local l=nofpoints+1
local dw=0
local dl=0
for i=1,#deltas do
local deltaset=deltas[i]
local xvalues=deltaset.xvalues
local yvalues=deltaset.yvalues
- local dpoints=deltaset.points
- local factor=deltaset.factor
- if dpoints then
- local nofdpoints=#dpoints
- for i=1,nofdpoints do
- local d=dpoints[i]
- local p=points[d]
- if p then
- if xvalues then
- local x=xvalues[i]
- if x and x~=0 then
- p[1]=p[1]+factor*x
+ if xvalues and yvalues then
+ local dpoints=deltaset.points
+ local factor=deltaset.factor
+ if dpoints then
+ local cnt=#dpoints
+ if dowidth then
+ cnt=cnt-4
+ end
+ if cnt==1 then
+ local d=dpoints[1]
+ local x=xvalues[d]*factor
+ local y=yvalues[d]*factor
+ for i=1,nofpoints do
+ local p=points[i]
+ if x~=0 then
+ p[1]=p[1]+x
+ end
+ if y~=0 then
+ p[2]=p[2]+y
end
end
- if yvalues then
- local y=yvalues[i]
- if y and y~=0 then
- p[2]=p[2]+factor*y
+ elseif cnt>0 then
+ local function find(i)
+ local prv=cnt
+ for j=1,cnt do
+ local nxt=dpoints[j]
+ if nxt==i then
+ return false,j,false
+ elseif nxt>i then
+ return prv,false,j
+ end
+ prv=j
+ end
+ return prv,false,1
+ end
+ for i=1,nofpoints do
+ local d1,d2,d3=find(i)
+ local p2=points[i]
+ if d2 then
+ xv[i]=xvalues[d2]
+ yv[i]=yvalues[d2]
+ else
+ local n1=dpoints[d1]
+ local n3=dpoints[d3]
+ if n1>nofpoints then
+ n1=nofpoints
+ end
+ if n3>nofpoints then
+ n3=nofpoints
+ end
+ local p1=points[n1]
+ local p3=points[n3]
+ local p1x=p1[1]
+ local p2x=p2[1]
+ local p3x=p3[1]
+ local p1y=p1[2]
+ local p2y=p2[2]
+ local p3y=p3[2]
+ local x1=xvalues[d1]
+ local y1=yvalues[d1]
+ local x3=xvalues[d3]
+ local y3=yvalues[d3]
+ local fx
+ local fy
+ if p1x==p3x then
+ if x1==x3 then
+ fx=x1
+ else
+ fx=0
+ end
+ elseif p2x<=min(p1x,p3x) then
+ if p1x<p3x then
+ fx=x1
+ else
+ fx=x3
+ end
+ elseif p2x>=max(p1x,p3x) then
+ if p1x>p3x then
+ fx=x1
+ else
+ fx=x3
+ end
+ else
+ fx=(p2x-p1x)/(p3x-p1x)
+ fx=(1-fx)*x1+fx*x3
+ end
+ if p1y==p3y then
+ if y1==y3 then
+ fy=y1
+ else
+ fy=0
+ end
+ elseif p2y<=min(p1y,p3y) then
+ if p1y<p3y then
+ fy=y1
+ else
+ fy=y3
+ end
+ elseif p2y>=max(p1y,p3y) then
+ if p1y>p3y then
+ fy=y1
+ else
+ fy=y3
+ end
+ else
+ fy=(p2y-p1y)/(p3y-p1y)
+ fy=(1-fy)*y1+fy*y3
+ end
+ xv[i]=fx
+ yv[i]=fy
end
end
- elseif dowidth then
- if d==h then
- local x=xvalues[i]
- if x then
- dw=dw+factor*x
+ for i=1,nofpoints do
+ local pi=points[i]
+ local fx=xv[i]
+ local fy=yv[i]
+ if fx~=0 then
+ pi[1]=pi[1]+factor*fx
end
- elseif d==l then
- local x=xvalues[i]
- if x then
- dl=dl+factor*x
+ if fy~=0 then
+ pi[2]=pi[2]+factor*fy
end
end
+ else
+ report("bad deltapoint data, maybe a missing hvar table")
end
- end
- else
- for i=1,nofpoints do
- local p=points[i]
- if xvalues then
+ else
+ for i=1,nofpoints do
+ local p=points[i]
local x=xvalues[i]
- if x and x~=0 then
- p[1]=p[1]+factor*x
- end
- end
- if yvalues then
- local y=yvalues[i]
- if y and y~=0 then
- p[2]=p[2]+factor*y
+ if x then
+ local y=yvalues[i]
+ if x~=0 then
+ p[1]=p[1]+factor*x
+ end
+ if y~=0 then
+ p[2]=p[2]+factor*y
+ end
+ else
+ break
end
end
end
if dowidth then
+ local h=nofpoints+2
+ local l=nofpoints+1
local x=xvalues[h]
if x then
dw=dw+factor*x
@@ -15903,13 +16259,13 @@ local function readcomposite(f)
yoffset=yoffset*yscale
end
elseif band(flags,0x0080)~=0 then
- xscale=read2dot14(f)
- xrotate=read2dot14(f)
- yrotate=read2dot14(f)
- yscale=read2dot14(f)
+ xscale=read2dot14(f)
+ xrotate=read2dot14(f)
+ yrotate=read2dot14(f)
+ yscale=read2dot14(f)
if f_xyarg and f_offset then
- xoffset=xoffset*sqrt(xscale^2+xrotate^2)
- yoffset=yoffset*sqrt(yrotate^2+yscale^2)
+ xoffset=xoffset*sqrt(xscale^2+yrotate^2)
+ yoffset=yoffset*sqrt(xrotate^2+yscale^2)
end
end
nofcomponents=nofcomponents+1
@@ -16067,40 +16423,6 @@ end
local function readdeltas(f,nofpoints)
local deltas={}
local p=0
- local z=0
- while nofpoints>0 do
- local control=readbyte(f)
-if not control then
- break
-end
- local allzero=band(control,0x80)~=0
- local runlength=band(control,0x3F)+1
- if allzero then
- z=z+runlength
- else
- local runreader=band(control,0x40)~=0 and readshort or readinteger
- if z>0 then
- for i=1,z do
- p=p+1
- deltas[p]=0
- end
- z=0
- end
- for i=1,runlength do
- p=p+1
- deltas[p]=runreader(f)
- end
- end
- nofpoints=nofpoints-runlength
- end
- if p>0 then
- return deltas
- else
- end
-end
-local function readdeltas(f,nofpoints)
- local deltas={}
- local p=0
while nofpoints>0 do
local control=readbyte(f)
if control then
@@ -19458,6 +19780,7 @@ function readers.hvar(f,fontdata,specification)
end
local tableoffset=gotodatatable(f,fontdata,"hvar",specification.variable)
if not tableoffset then
+ report("no hvar table, expect problems due to messy widths")
return
end
local version=readulong(f)
@@ -20842,7 +21165,7 @@ if not modules then modules={} end modules ['font-otl']={
local lower=string.lower
local type,next,tonumber,tostring,unpack=type,next,tonumber,tostring,unpack
local abs=math.abs
-local derivetable=table.derive
+local derivetable,sortedhash=table.derive,table.sortedhash
local formatters=string.formatters
local setmetatableindex=table.setmetatableindex
local allocate=utilities.storage.allocate
@@ -20858,7 +21181,7 @@ local trace_defining=false registertracker("fonts.defining",function(v) trace_d
local report_otf=logs.reporter("fonts","otf loading")
local fonts=fonts
local otf=fonts.handlers.otf
-otf.version=3.116
+otf.version=3.119
otf.cache=containers.define("fonts","otl",otf.version,true)
otf.svgcache=containers.define("fonts","svg",otf.version,true)
otf.pngcache=containers.define("fonts","png",otf.version,true)
@@ -20993,6 +21316,9 @@ function otf.load(filename,sub,instance)
if cleanup==0 then
checkmemory(used,threshold,tracememory)
end
+ if context then
+ otfreaders.condense(data)
+ end
otfreaders.pack(data)
report_otf("loading done")
report_otf("saving %a in cache",filename)
@@ -21063,7 +21389,7 @@ local function copytotfm(data,cache_id)
local properties=derivetable(data.properties)
local descriptions=derivetable(data.descriptions)
local goodies=derivetable(data.goodies)
- local characters={}
+ local characters={}
local parameters={}
local mathparameters={}
local resources=data.resources
@@ -21231,7 +21557,25 @@ local function copytotfm(data,cache_id)
properties.name=filename or fullname
properties.subfont=subfont
if not CONTEXTLMTXMODE or CONTEXTLMTXMODE==0 then
- properties.encodingbytes=2
+ properties.encodingbytes=2
+elseif CONTEXTLMTXMODE then
+ local duplicates=resources and resources.duplicates
+ if duplicates then
+ local maxindex=data.nofglyphs or metadata.nofglyphs
+ if maxindex then
+ for u,d in sortedhash(duplicates) do
+ local du=descriptions[u]
+ if du then
+ for uu in sortedhash(d) do
+ maxindex=maxindex+1
+ descriptions[uu].dupindex=du.index
+ descriptions[uu].index=maxindex
+ end
+ else
+ end
+ end
+ end
+ end
end
properties.private=properties.private or data.private or privateoffset
return {
@@ -21599,7 +21943,7 @@ local function gref(descriptions,n)
end
end
local function cref(feature,sequence)
- return formatters["feature %a, type %a, chain lookup %a"](feature,sequence.type,sequence.name)
+ return formatters["feature %a, type %a, (chain) lookup %a"](feature,sequence.type,sequence.name)
end
local function report_substitution(feature,sequence,descriptions,unicode,substitution)
if unicode==substitution then
@@ -21660,49 +22004,60 @@ end
local function makefake(tfmdata,name,present)
local private=getprivate(tfmdata)
local character={ intermediate=true,ligatures={} }
- resources.unicodes[name]=private
+ tfmdata.resources.unicodes[name]=private
tfmdata.characters[private]=character
tfmdata.descriptions[private]={ name=name }
present[name]=private
return character
end
local function make_1(present,tree,name)
- for k,v in next,tree do
- if k=="ligature" then
- present[name]=v
+ if tonumber(tree) then
+ present[name]=v
+ else
+ for k,v in next,tree do
+ if k=="ligature" then
+ present[name]=v
+ else
+ make_1(present,v,name.."_"..k)
+ end
+ end
+ end
+end
+local function make_3(present,tfmdata,characters,tree,name,preceding,unicode,done,v)
+ local character=characters[preceding]
+ if not character then
+ if trace_baseinit then
+ report_prepare("weird ligature in lookup %a, current %C, preceding %C",sequence.name,v,preceding)
+ end
+ character=makefake(tfmdata,name,present)
+ end
+ local ligatures=character.ligatures
+ if ligatures then
+ ligatures[unicode]={ char=v }
+ else
+ character.ligatures={ [unicode]={ char=v } }
+ end
+ if done then
+ local d=done[name]
+ if not d then
+ done[name]={ "dummy",v }
else
- make_1(present,v,name.."_"..k)
+ d[#d+1]=v
end
end
end
local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done)
- for k,v in next,tree do
- if k=="ligature" then
- local character=characters[preceding]
- if not character then
- if trace_baseinit then
- report_prepare("weird ligature in lookup %a, current %C, preceding %C",sequence.name,v,preceding)
- end
- character=makefake(tfmdata,name,present)
- end
- local ligatures=character.ligatures
- if ligatures then
- ligatures[unicode]={ char=v }
+ if tonumber(tree) then
+ make_3(present,tfmdata,characters,tree,name,preceding,unicode,done,tree)
+ else
+ for k,v in next,tree do
+ if k=="ligature" then
+ make_3(present,tfmdata,characters,tree,name,preceding,unicode,done,v)
else
- character.ligatures={ [unicode]={ char=v } }
- end
- if done then
- local d=done[name]
- if not d then
- done[name]={ "dummy",v }
- else
- d[#d+1]=v
- end
+ local code=present[name] or unicode
+ local name=name.."_"..k
+ make_2(present,tfmdata,characters,v,name,code,k,done)
end
- else
- local code=present[name] or unicode
- local name=name.."_"..k
- make_2(present,tfmdata,characters,v,name,code,k,done)
end
end
end
@@ -23522,9 +23877,9 @@ 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
+local check_soft_hyphen=context
directives.register("otf.checksofthyphen",function(v)
- check_soft_hyphen=v
+ check_soft_hyphen=v
end)
local function replaced(list,index,replacement)
if type(list)=="number" then
@@ -23913,27 +24268,30 @@ local function copyduplicates(fontdata)
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
+ local dh=descriptions[0x2D]
+ if dh then
+ local ds=descriptions[0xAD]
+ if not ds or ds.width~=dh.width then
descriptions[0xAD]=nil
- if trace_unicodes then
- report_unicodes("patching soft hyphen")
+ if ds then
+ if trace_unicodes then
+ report_unicodes("patching soft hyphen")
+ end
+ else
+ if trace_unicodes then
+ report_unicodes("adding soft hyphen")
+ end
end
- else
- if trace_unicodes then
- report_unicodes("adding soft hyphen")
+ if not duplicates then
+ duplicates={}
+ resources.duplicates=duplicates
+ end
+ local d=duplicates[0x2D]
+ if d then
+ d[0xAD]=true
+ else
+ duplicates[0x2D]={ [0xAD]=true }
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
@@ -24199,6 +24557,7 @@ local function unifyglyphs(fontdata,usenames)
local resources=fontdata.resources
local zero=glyphs[0]
local zerocode=zero.unicode
+ local nofglyphs=#glyphs
if not zerocode then
zerocode=private
zero.unicode=zerocode
@@ -24213,7 +24572,7 @@ local function unifyglyphs(fontdata,usenames)
indices[0]=zerocode
end
if names then
- for index=1,#glyphs do
+ for index=1,nofglyphs do
local glyph=glyphs[index]
local unicode=glyph.unicode
if not unicode then
@@ -24246,7 +24605,7 @@ local function unifyglyphs(fontdata,usenames)
descriptions[unicode]=glyph
end
elseif trace_unicodes then
- for index=1,#glyphs do
+ for index=1,nofglyphs do
local glyph=glyphs[index]
local unicode=glyph.unicode
if not unicode then
@@ -24287,7 +24646,7 @@ local function unifyglyphs(fontdata,usenames)
descriptions[unicode]=glyph
end
else
- for index=1,#glyphs do
+ for index=1,nofglyphs do
local glyph=glyphs[index]
local unicode=glyph.unicode
if not unicode then
@@ -24313,7 +24672,7 @@ local function unifyglyphs(fontdata,usenames)
descriptions[unicode]=glyph
end
end
- for index=1,#glyphs do
+ for index=1,nofglyphs do
local math=glyphs[index].math
if math then
local list=math.vparts
@@ -24336,7 +24695,7 @@ local function unifyglyphs(fontdata,usenames)
end
local colorpalettes=resources.colorpalettes
if colorpalettes then
- for index=1,#glyphs do
+ for index=1,nofglyphs do
local colors=glyphs[index].colors
if colors then
for i=1,#colors do
@@ -24351,6 +24710,7 @@ local function unifyglyphs(fontdata,usenames)
fontdata.names=names
fontdata.descriptions=descriptions
fontdata.hashmethod=hashmethod
+ fontdata.nofglyphs=nofglyphs
return indices,names
end
local p_crappyname do
@@ -24423,6 +24783,10 @@ function readers.getcomponents(fontdata)
local function traverse(p,k,v)
if k=="ligature" then
collected[v]={ unpack(l) }
+ elseif tonumber(v) then
+ insert(l,k)
+ collected[v]={ unpack(l) }
+ remove(l)
else
insert(l,k)
for k,vv in next,v do
@@ -24583,7 +24947,6 @@ local function tabstr_flat(t)
end
end
local function tabstr_mixed(t)
- local s={}
local n=#t
if n==0 then
return ""
@@ -24597,6 +24960,7 @@ local function tabstr_mixed(t)
return tostring(k)
end
else
+ local s={}
for i=1,n do
local k=t[i]
if k==true then
@@ -25920,6 +26284,85 @@ function readers.compact(data)
end
end
end
+if CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 then
+ local done=0
+ local function condense_1(k,v,t)
+ if type(v)=="table" then
+ local u=false
+ local l=false
+ for k,v in next,v do
+ if k=="ligature" then
+ l=v
+ if u then
+ break
+ end
+ elseif u then
+ break
+ else
+ u=true
+ end
+ end
+ if l and not u then
+ t[k]=l
+ done=done+1
+ end
+ if u then
+ for k,vv in next,v do
+ if k~="ligature" then
+ condense_1(k,vv,v)
+ end
+ end
+ end
+ end
+ end
+ local function condensesteps_1(lookup)
+ done=0
+ if lookup.type=="gsub_ligature" then
+ local steps=lookup.steps
+ if steps then
+ for i=1,#steps do
+ local step=steps[i]
+ local coverage=step.coverage
+ if coverage then
+ for k,v in next,coverage do
+ if condense_1(k,v,coverage) then
+ coverage[k]=v.ligature
+ done=done+1
+ end
+ end
+ end
+ end
+ end
+ end
+ return done
+ end
+ function readers.condense(data)
+ if not data or data.condensed then
+ return
+ else
+ data.condensed=true
+ end
+ local resources=data.resources
+ local condensed=0
+ local function condense(what)
+ local lookups=resources[what]
+ if lookups then
+ for i=1,#lookups do
+ condensed=condensed+condensesteps_1(lookups[i])
+ end
+ elseif trace_optimizations then
+ report_optimizations("no lookups in %a",what)
+ end
+ end
+ condense("sequences")
+ condense("sublookups")
+ if trace_optimizations then
+ if condensed>0 then
+ report_optimizations("%i ligatures condensed",condensed)
+ end
+ end
+ end
+end
local function mergesteps(t,k)
if k=="merged" then
local merged={}
@@ -26024,7 +26467,7 @@ function readers.expand(data)
end
end
end
- local function expandlookups(sequences)
+ local function expandlookups(sequences,whatever)
if sequences then
for i=1,#sequences do
local sequence=sequences[i]
@@ -26097,6 +26540,9 @@ function readers.expand(data)
if lookups then
for k,v in next,lookups do
local lookup=sublookups[v]
+if not lookup and whatever then
+ lookup=whatever[v]
+end
if lookup then
lookups[k]=lookup
if not subtype then
@@ -26155,7 +26601,7 @@ function readers.expand(data)
end
end
expandlookups(sequences)
- expandlookups(sublookups)
+ expandlookups(sublookups,sequences)
end
end -- closure
@@ -26698,6 +27144,7 @@ local trace_compruns=false registertracker("otf.compruns",function(v) trace_com
local trace_testruns=false registertracker("otf.testruns",function(v) trace_testruns=v end)
local forcediscretionaries=false
local forcepairadvance=false
+local repeatablemultiples=context or false
directives.register("otf.forcediscretionaries",function(v)
forcediscretionaries=v
end)
@@ -27076,15 +27523,47 @@ local function multiple_glyphs(head,start,multiple,skiphash,what,stop)
insertnodeafter(head,start,n)
start=n
end
- if what==true then
- elseif what>1 then
- local m=multiple[nofmultiples]
- for i=2,what do
- local n=copy_node(start)
- resetinjection(n)
- setchar(n,m)
- insertnodeafter(head,start,n)
- start=n
+ if what~=true and repeatablemultiples then
+ local kind=type(what)
+ local m,f,l
+ if kind=="string" then
+ local what,n=string.match(what,"^repeat(.-)[:=](%d+)$")
+ if what=="middle" then
+ m=tonumber(n)
+ elseif what=="first" then
+ f=tonumber(n)
+ elseif what=="last" then
+ l=tonumber(n)
+ end
+ elseif kind=="table" then
+ m=what.middle
+ f=what.first
+ l=what.last
+ end
+ if f or m or l then
+ if m and m>1 and nofmultiples==3 then
+ local middle=getnext(first)
+ for i=2,m do
+ local n=copynode(middle)
+ resetinjection(n)
+ insertnodeafter(head,first,n)
+ end
+ end
+ if f and f>1 then
+ for i=2,f do
+ local n=copynode(first)
+ resetinjection(n)
+ insertnodeafter(head,first,n)
+ end
+ end
+ if l and l>1 then
+ for i=2,l do
+ local n=copynode(start)
+ resetinjection(n)
+ insertnodeafter(head,start,n)
+ start=n
+ end
+ end
end
end
end
@@ -27172,7 +27651,7 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
while current do
local char=ischar(current,currentfont)
if char then
- local lg=ligature[char]
+ local lg=not tonumber(ligature) and ligature[char]
if lg then
stop=current
ligature=lg
@@ -27185,14 +27664,14 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
end
end
if stop then
- local lig=ligature.ligature
- if lig then
+ local ligature=tonumber(ligature) or ligature.ligature
+ if ligature then
if trace_ligatures then
local stopchar=getchar(stop)
- head,start=markstoligature(head,start,stop,lig)
+ head,start=markstoligature(head,start,stop,ligature)
logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(getchar(start)))
else
- head,start=markstoligature(head,start,stop,lig)
+ head,start=markstoligature(head,start,stop,ligature)
end
return head,start,true,false
else
@@ -27207,7 +27686,7 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
if skiphash and skiphash[char] then
current=getnext(current)
else
- local lg=ligature[char]
+ local lg=not tonumber(ligature) and ligature[char]
if lg then
if marks[char] then
hasmarks=true
@@ -27233,20 +27712,20 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
local match
if replace then
local char=ischar(replace,currentfont)
- if char and ligature[char] then
+ if char and (not tonumber(ligature) and ligature[char]) then
match=true
end
end
if not match and pre then
local char=ischar(pre,currentfont)
- if char and ligature[char] then
+ if char and (not tonumber(ligature) and ligature[char]) then
match=true
end
end
if not match and not pre or not replace then
local n=getnext(discfound)
local char=ischar(n,currentfont)
- if char and ligature[char] then
+ if char and (not tonumber(ligature) and ligature[char]) then
match=true
end
end
@@ -27289,21 +27768,21 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
return head,start,true,true
end
end
- local lig=ligature.ligature
- if lig then
+ local ligature=tonumber(ligature) or ligature.ligature
+ if ligature then
if stop then
if trace_ligatures then
local stopchar=getchar(stop)
- head,start=toligature(head,start,stop,lig,dataset,sequence,skiphash,false,hasmarks)
- logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(lig))
+ head,start=toligature(head,start,stop,ligature,dataset,sequence,skiphash,false,hasmarks)
+ logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(ligature))
else
- head,start=toligature(head,start,stop,lig,dataset,sequence,skiphash,false,hasmarks)
+ head,start=toligature(head,start,stop,ligature,dataset,sequence,skiphash,false,hasmarks)
end
else
resetinjection(start)
- setchar(start,lig)
+ setchar(start,ligature)
if trace_ligatures then
- logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(dataset,sequence),gref(startchar),gref(lig))
+ logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(dataset,sequence),gref(startchar),gref(ligature))
end
end
return head,start,true,false
@@ -27498,7 +27977,7 @@ function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlm
end
end
elseif trace_bugs then
- onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
+ onetimemessage(currentfont,basechar,"no base anchors")
end
elseif trace_bugs then
logwarning("%s: prev node is no char, case %i",pref(dataset,sequence),1)
@@ -27777,7 +28256,7 @@ function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup
if skiphash and skiphash[schar] then
current=getnext(current)
else
- local lg=ligatures[schar]
+ local lg=not tonumber(ligatures) and ligatures[schar]
if lg then
ligatures=lg
last=current
@@ -27796,7 +28275,7 @@ function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup
end
end
end
- local ligature=ligatures.ligature
+ local ligature=tonumber(ligatures) or ligatures.ligature
if ligature then
if chainindex then
stop=last
@@ -28138,7 +28617,7 @@ function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup,
end
end
elseif trace_bugs then
- onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
+ onetimemessage(currentfont,startchar,"no entry anchors")
end
break
end
@@ -28208,7 +28687,7 @@ local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck)
local chainproc=chainprocs[chainkind]
if chainproc then
local ok
- head,start,ok=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash)
+ head,start,ok=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,1)
if ok then
done=true
end
@@ -28625,6 +29104,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
local ck=contexts[k]
local seq=ck[3]
local f=ck[4]
+local last=start
if not startchar or not seq[f][startchar] then
goto next
end
@@ -28633,7 +29113,6 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
else
local l=ck[5]
local current=start
- local last=start
if l>f then
local discfound
local n=f+1
@@ -29417,7 +29896,7 @@ local function t_run_single(start,stop,font,attr,lookupcache)
while s do
local char=ischar(s,font)
if char then
- local lg=lookupmatch[char]
+ local lg=not tonumber(lookupmatch) and lookupmatch[char]
if lg then
if sstop then
d=1
@@ -29447,7 +29926,7 @@ local function t_run_single(start,stop,font,attr,lookupcache)
break
end
end
- if l and l.ligature then
+ if l and (tonumber(l) or l.ligature) then
lastd=d
end
else
@@ -29572,7 +30051,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
while s do
local char=ischar(s)
if char then
- local lg=lookupmatch[char]
+ local lg=not tonumber(lookupmatch) and lookupmatch[char]
if lg then
if sstop then
d=1
@@ -29602,7 +30081,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
break
end
end
- if l and l.ligature then
+ if l and (tonumber(l) or l.ligature) then
lastd=d
end
end
@@ -30378,6 +30857,7 @@ local function validspecification(specification,name)
else
dataset={ { data=specification.data } }
specification.data=nil
+ specification.coverage=dataset
specification.dataset=dataset
end
local first=dataset[1]
@@ -30677,7 +31157,28 @@ local function addfeature(data,feature,specifications)
return coverage
end
local prepare_single=prepare_pair
- local function prepare_chain(list,featuretype,sublookups)
+ local function hassteps(lookups)
+ if lookups then
+ for i=1,#lookups do
+ local l=lookups[i]
+ if l then
+ for j=1,#l do
+ local l=l[j]
+ if l then
+ local n=l.nofsteps
+ if not n then
+ return true
+ elseif n>0 then
+ return true
+ end
+ end
+ end
+ end
+ end
+ end
+ return false
+ end
+ local function prepare_chain(list,featuretype,sublookups,nocheck)
local rules=list.rules
local coverage={}
if rules then
@@ -30713,6 +31214,7 @@ local function addfeature(data,feature,specifications)
local lookups=rule.lookups or false
local subtype=nil
if lookups and sublookups then
+ local l={}
for k,v in sortedhash(lookups) do
local t=type(v)
if t=="table" then
@@ -30722,55 +31224,63 @@ local function addfeature(data,feature,specifications)
v[i]={ vi }
end
end
+ l[k]=v
elseif t=="number" then
local lookup=sublookups[v]
if lookup then
- lookups[k]={ lookup }
+ l[k]={ lookup }
if not subtype then
subtype=lookup.type
end
elseif v==0 then
- lookups[k]={ { type="gsub_remove" } }
+ l[k]={ { type="gsub_remove",nosteps=true } }
else
- lookups[k]=false
+ l[k]=false
end
else
- lookups[k]=false
+ l[k]=false
end
end
+ if nocheck then
+ rule.lookups=l
+ end
+ lookups=l
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
+ if hassteps(lookups) 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
- 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
+ sequence.n=nofsequences
+ else
end
- sequence.n=nofsequences
end
end
rulehash.n=rulesize
@@ -30857,126 +31367,148 @@ local function addfeature(data,feature,specifications)
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 featuretype=specification.type or "substitution"
+ local featureaction=false
local featureflags=specification.flags or noflags
local nocheck=specification.nocheck
+ local mapping=specification.mapping
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
+ local steptype=nil
+ local sequence=nil
+ if fonts.handlers.otf.handlers[featuretype] then
+ featureaction=true
+ else
+ featuretype=normalized[specification.type or "substitution"] or "substitution"
+ end
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)
+ 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
+ if featureaction then
+ category="gsub"
+ sequence={
+ features={ [feature]=askedfeatures },
+ flags=featureflags,
+ name=feature,
+ order=featureorder,
+ type=featuretype,
+ nofsteps=0,
+ }
+ else
+ 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=(mapping and list) or 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,nocheck)
+ elseif featuretype=="chainposition" then
+ category="gpos"
+ coverage=prepare_chain(list,featuretype,sublookups,nocheck)
+ else
+ report_otf("not registering feature %a, unknown category",feature)
+ return
end
- checkmerge(specification)
- checksteps(specification)
- s[i]={
+ 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
+ sequence={
+ chain=featurechain,
+ features={ [feature]=askedfeatures },
+ flags=featureflags,
+ name=feature,
+ order=featureorder,
[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,
- }
+ if sequence then
checkflags(sequence,resources)
checkmerge(sequence)
checksteps(sequence)
@@ -31055,8 +31587,10 @@ if not modules then modules={} end modules ['font-osd']={
copyright="TAT Zetwerk / PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local insert,imerge,copy,tohash=table.insert,table.imerge,table.copy,table.tohash
-local next,type=next,type
+local insert,remove,imerge,copy,tohash=table.insert,table.remove,table.imerge,table.copy,table.tohash
+local next,type,rawget=next,type,rawget
+local formatters=string.formatters
+local settings_to_hash=utilities.parsers.settings_to_hash
local report=logs.reporter("otf","devanagari")
fonts=fonts or {}
fonts.analyzers=fonts.analyzers or {}
@@ -31066,6 +31600,7 @@ local handlers=otf.handlers
local methods=fonts.analyzers.methods
local otffeatures=fonts.constructors.features.otf
local registerotffeature=otffeatures.register
+local trace_steps=false
local nuts=nodes.nuts
local getnext=nuts.getnext
local getprev=nuts.getprev
@@ -31091,7 +31626,8 @@ local flushnode=nuts.flushnode
local copyinjection=nodes.injections.copy
local unsetvalue=attributes.unsetvalue
local fontdata=fonts.hashes.identifiers
-local a_syllabe=attributes.private('syllabe')
+local a_syllabe="syllable"
+local a_reordered="reordered"
local dotted_circle=0x25CC
local c_nbsp=0x00A0
local c_zwnj=0x200C
@@ -31111,6 +31647,7 @@ replace_all_nbsp=function(head)
return replace_all_nbsp(head)
end
local processcharacters=nil
+local logprocess=nil
if context then
--removed
@@ -31123,6 +31660,8 @@ else
end
return head
end
+ logprocess=function(str)
+ end
end
local indicgroups=characters and characters.indicgroups
if not indicgroups and characters then
@@ -31232,7 +31771,7 @@ local before_subscript=indicgroups.before_subscript
local after_subscript=indicgroups.after_subscript
local before_main=indicgroups.before_main
local after_main=indicgroups.after_main
-local mark_four=table.merged (
+local mark_pre_above_below_post=table.merged (
pre_mark,
above_mark,
below_mark,
@@ -31243,6 +31782,11 @@ local mark_above_below_post=table.merged (
below_mark,
post_mark
)
+local devanagarihash=table.setmetatableindex(function(t,k)
+ local v=fontdata[k].resources.devanagari or false
+ t[k]=v
+ return v
+end)
local zw_char={
[c_zwnj]=true,
[c_zwj ]=true,
@@ -31363,7 +31907,7 @@ local function initializedevanagi(tfmdata)
local resources=tfmdata.resources
local devanagari=resources.devanagari
if not devanagari then
- report("adding devanagari features to font")
+ report("adding features to font")
local gsubfeatures=resources.features.gsub
local sequences=resources.sequences
local sharedfeatures=tfmdata.shared.features
@@ -31390,7 +31934,7 @@ local function initializedevanagi(tfmdata)
for k,v in next,pre_mark do
local locl=coverage[k]
if locl then
- if #locl>0 then
+ if #locl>0 then
for j=1,#locl do
local ck=locl[j]
local f=ck[4]
@@ -31411,6 +31955,7 @@ local function initializedevanagi(tfmdata)
end
end
end
+ else
end
if locl then
reorder_matras.steps[1].coverage[locl]=true
@@ -31423,7 +31968,7 @@ local function initializedevanagi(tfmdata)
if basic_shaping_forms[k] then
lastmatch=lastmatch+1
if s~=lastmatch then
- table.insert(sequences,lastmatch,table.remove(sequences,s))
+ insert(sequences,lastmatch,remove(sequences,s))
end
end
end
@@ -31441,9 +31986,7 @@ local function initializedevanagi(tfmdata)
local vatucache={}
local pstfcache={}
local seqsubset={}
- local rephstep={
- coverage={}
- }
+ local rephstep={ coverage={} }
local devanagari={
reph=false,
vattu=false,
@@ -31468,7 +32011,7 @@ local function initializedevanagi(tfmdata)
local has_pstf=features.pstf
if has_rphf and has_rphf[script] then
devanagari.reph=true
- elseif (has_blwf and has_blwf[script] ) or (has_vatu and has_vatu[script] ) then
+ elseif (has_blwf and has_blwf[script]) or (has_vatu and has_vatu[script]) then
devanagari.vattu=true
for i=1,nofsteps do
local step=steps[i]
@@ -31476,10 +32019,8 @@ local function initializedevanagi(tfmdata)
if coverage then
for k,v in next,coverage do
for h,w in next,halant do
- if v[h] then
- if not blwfcache[k] then
- blwfcache[k]=v
- end
+ if v[h] and not blwfcache[k] then
+ blwfcache[k]=v
end
if has_vatu and has_vatu[script] and not vatucache[k] then
vatucache[k]=v
@@ -31502,33 +32043,37 @@ local function initializedevanagi(tfmdata)
local r=coverage[k]
if r then
local found=false
- if #r>0 then
+ if #r>0 then
for j=1,#r do
local ck=r[j]
local f=ck[4]
local chainlookups=ck[6]
- if chainlookups and chainlookups[f] then
+ if chainlookups then
local chainlookup=chainlookups[f]
- for j=1,#chainlookup do
- local chainstep=chainlookup[j]
- local steps=chainstep.steps
- local nofsteps=chainstep.nofsteps
- for i=1,nofsteps do
- local step=steps[i]
- local coverage=step.coverage
- if coverage then
- local h=coverage[k]
- if h then
- for k,v in next,h do
- found=v and v.ligature
+ if chainlookup then
+ for j=1,#chainlookup do
+ local chainstep=chainlookup[j]
+ local steps=chainstep.steps
+ local nofsteps=chainstep.nofsteps
+ for i=1,nofsteps do
+ local step=steps[i]
+ local coverage=step.coverage
+ if coverage then
+ local h=coverage[k]
+ if h then
+ for k,v in next,h do
+ if v then
+ found=tonumber(v) or v.ligature
+ if found then
+ pre_base_reordering_consonants[found]=true
+ break
+ end
+ end
+ end
if found then
- pre_base_reordering_consonants[found]=true
break
end
end
- if found then
- break
- end
end
end
end
@@ -31537,10 +32082,12 @@ local function initializedevanagi(tfmdata)
end
else
for k,v in next,r do
- found=v and v.ligature
- if found then
- pre_base_reordering_consonants[found]=true
- break
+ if v then
+ found=tonumber(v) or v.ligature
+ if found then
+ pre_base_reordering_consonants[found]=true
+ break
+ end
end
end
end
@@ -31558,14 +32105,15 @@ local function initializedevanagi(tfmdata)
local step=steps[i]
local coverage=step.coverage
if coverage then
- local reph,rephbase=false,false
+ local reph=false
+ local base=false
if kind=="rphf" then
for k,v in next,ra do
local r=coverage[k]
if r then
- rephbase=k
+ base=k
local h=false
- if #r>0 then
+ if #r>0 then
for j=1,#r do
local ck=r[j]
local f=ck[4]
@@ -31585,7 +32133,7 @@ local function initializedevanagi(tfmdata)
for k,v in next,halant do
local h=r[k]
if h then
- reph=h.ligature or false
+ reph=tonumber(h) or h.ligature or false
break
end
end
@@ -31602,7 +32150,7 @@ local function initializedevanagi(tfmdata)
for k,v in next,halant do
local h=r[k]
if h then
- reph=h.ligature or false
+ reph=tonumber(h) or h.ligature or false
break
end
end
@@ -31613,7 +32161,7 @@ local function initializedevanagi(tfmdata)
end
end
end
- seqsubset[#seqsubset+1]={ kind,coverage,reph,rephbase }
+ seqsubset[#seqsubset+1]={ kind,coverage,reph,base }
end
end
end
@@ -31628,7 +32176,7 @@ local function initializedevanagi(tfmdata)
local h=coverage[k]
if h then
local found=false
- if #h>0 then
+ if #h>0 then
for j=1,#h do
local ck=h[j]
local f=ck[4]
@@ -31646,10 +32194,12 @@ local function initializedevanagi(tfmdata)
local h=coverage[k]
if h then
for k,v in next,h do
- found=v and v.ligature
- if found then
- pre_base_reordering_consonants[found]=true
- break
+ if v then
+ found=tonumber(v) or v.ligature
+ if found then
+ pre_base_reordering_consonants[found]=true
+ break
+ end
end
end
if found then
@@ -31663,7 +32213,7 @@ local function initializedevanagi(tfmdata)
end
else
for k,v in next,h do
- found=v and v.ligature
+ found=v and (tonumber(v) or v.ligature)
if found then
pre_base_reordering_consonants[found]=true
break
@@ -31689,9 +32239,6 @@ local function initializedevanagi(tfmdata)
sharedfeatures["dv03"]=true
sharedfeatures["dv04"]=true
end
- if script=="mlym" or script=="taml" then
- devanagari.left_matra_before_base=true
- end
end
end
end
@@ -31703,6 +32250,44 @@ registerotffeature {
node=initializedevanagi,
},
}
+local function initializeconjuncts(tfmdata,value)
+ if value then
+ local resources=tfmdata.resources
+ local devanagari=resources.devanagari
+ if devanagari then
+ local conjuncts="auto"
+ local movematra="auto"
+ if type(value)=="string" and value~="auto" then
+ value=settings_to_hash(value)
+ conjuncts=rawget(value,"conjuncts") or conjuncts
+ movematra=rawget(value,"movematra") or movematra
+ end
+ if conjuncts=="auto" then
+ conjuncts="mixed"
+ end
+ if movematra=="auto" and
+ script=="mlym" or
+ script=="taml" then
+ movematra="leftbeforebase"
+ else
+ movematra="default"
+ end
+ devanagari.conjuncts=conjuncts
+ devanagari.movematra=movematra
+ if trace_steps then
+ report("conjuncts %a, movematra %a",conjuncts,movematra)
+ end
+ end
+ end
+end
+registerotffeature {
+ name="indic",
+ description="control indic",
+ default="auto",
+ initializers={
+ node=initializeconjuncts,
+ },
+}
local show_syntax_errors=false
local function inject_syntax_error(head,current,char)
local signal=copy_node(current)
@@ -31748,36 +32333,40 @@ local function initialize_one(font,attr)
end
local function contextchain(contexts,n)
local char=getchar(n)
- for k=1,#contexts do
- local ck=contexts[k]
- local seq=ck[3]
- local f=ck[4]
- local l=ck[5]
- if (l-f)==1 and seq[f+1][char] then
- local ok=true
- local c=n
- for i=l+1,#seq do
- c=getnext(c)
- if not c or not seq[i][ischar(c)] then
- ok=false
- break
- end
- end
- if ok then
- c=getprev(n)
- for i=1,f-1 do
- c=getprev(c)
- if not c or not seq[f-i][ischar(c)] then
+ if not contexts.n then
+ return contexts[char]
+ else
+ for k=1,#contexts do
+ local ck=contexts[k]
+ local seq=ck[3]
+ local f=ck[4]
+ local l=ck[5]
+ if (l-f)==1 and seq[f+1][char] then
+ local ok=true
+ local c=n
+ for i=l+1,#seq do
+ c=getnext(c)
+ if not c or not seq[i][ischar(c)] then
ok=false
+ break
end
end
- end
- if ok then
- return true
+ if ok then
+ c=getprev(n)
+ for i=1,f-1 do
+ c=getprev(c)
+ if not c or not seq[f-i][ischar(c)] then
+ ok=false
+ end
+ end
+ end
+ if ok then
+ return true
+ end
end
end
+ return false
end
- return false
end
local function order_matras(c)
local cn=getnext(c)
@@ -31806,9 +32395,9 @@ local function order_matras(c)
char=getchar(cn)
end
end
+local swapped=table.swapped(states)
local function reorder_one(head,start,stop,font,attr,nbspaces)
- local reph,vattu,blwfcache,vatucache,pstfcache=initialize_one(font,attr)
- local devanagari=fontdata[font].resources.devanagari
+ local reph,vattu,blwfcache,vatucache,pstfcache=initialize_one(font,attr)
local current=start
local n=getnext(start)
local base=nil
@@ -31831,6 +32420,9 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
stop=getprev(stop)
head=remove_node(head,current)
flushnode(current)
+ if trace_steps then
+ logprocess("reorder one, remove nbsp")
+ end
return head,stop,nbspaces
else
nbspaces=nbspaces+1
@@ -31874,6 +32466,9 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
stop=current
end
end
+ if trace_steps then
+ logprocess("reorder one, handle nbsp")
+ end
end
end
end
@@ -31928,6 +32523,9 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
if lastcons==stop then
stop=n
end
+ if trace_steps then
+ logprocess("reorder one, handle halant")
+ end
end
end
n=getnext(start)
@@ -31952,6 +32550,9 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
if matra==stop then
stop=n
end
+ if trace_steps then
+ logprocess("reorder one, handle matra")
+ end
end
local current=start
while current~=stop do
@@ -31990,14 +32591,19 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
ch=getchar(n)
end
local tpm=twopart_mark[ch]
- while tpm do
- local extra=copy_node(n)
- copyinjection(extra,n)
- ch=tpm[1]
- setchar(n,ch)
- setchar(extra,tpm[2])
- head=insertnodeafter(head,current,extra)
- tpm=twopart_mark[ch]
+ if tpm then
+ while tpm do
+ local extra=copy_node(n)
+ copyinjection(extra,n)
+ ch=tpm[1]
+ setchar(n,ch)
+ setchar(extra,tpm[2])
+ head=insertnodeafter(head,current,extra)
+ tpm=twopart_mark[ch]
+ end
+ if trace_steps then
+ logprocess("reorder one, handle mark")
+ end
end
while c~=stop and dependent_vowel[ch] do
c=n
@@ -32020,9 +32626,10 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
local bp=getprev(firstcons)
local cn=getnext(current)
local last=getnext(c)
+ local done=false
while cn~=last do
if pre_mark[getchar(cn)] then
- if devanagari.left_matra_before_base then
+ if devanagarihash[font].movematra=="leftbeforebase" then
local prev,next=getboth(cn)
setlink(prev,next)
if cn==stop then
@@ -32059,6 +32666,7 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
end
cn=next
end
+ done=true
elseif current~=base and dependent_vowel[getchar(cn)] then
local prev,next=getboth(cn)
if next then
@@ -32071,6 +32679,7 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
setlink(b,cn,getnext(b))
order_matras(cn)
cn=next
+ done=true
elseif current==base and dependent_vowel[getchar(cn)] then
local cnn=getnext(cn)
order_matras(cn)
@@ -32084,9 +32693,14 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
end
allreordered=c==stop
current=getnext(c)
+ if done and trace_steps then
+ logprocess("reorder one, matra")
+ end
end
if reph or vattu then
- local current,cns=start,nil
+ local current=start
+ local cns=nil
+ local done=false
while current~=stop do
local c=current
local n=getnext(current)
@@ -32117,6 +32731,7 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
local next=getnext(b)
setlink(c,next)
setlink(b,current)
+ done=true
end
elseif cns and getnext(cns)~=current then
local cp=getprev(current)
@@ -32124,6 +32739,7 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
setlink(cp,n)
setlink(cns,current)
setlink(c,cnsn)
+ done=true
if c==stop then
stop=cp
break
@@ -32163,11 +32779,14 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
end
current=getnext(current)
end
+ if done and trace_steps then
+ logprocess("reorder one, handle reph and vata")
+ end
end
if getchar(base)==c_nbsp then
nbspaces=nbspaces-1
if base==stop then
- stop=getprev(stop)
+ stop=getprev(stop)
end
head=remove_node(head,base)
flushnode(base)
@@ -32195,6 +32814,9 @@ function handlers.devanagari_reorder_matras(head,start)
setlink(start,next)
setlink(current,start)
start=startnext
+ if trace_steps then
+ logprocess("reorder matra")
+ end
break
end
else
@@ -32223,6 +32845,9 @@ function handlers.devanagari_reorder_reph(head,start)
local char=ischar(current,startfont)
if char and getprop(current,a_syllabe)==startattr then
if halant[char] then
+ if trace_steps then
+ logprocess("reorder reph, handling halant")
+ end
local next=getnext(current)
if next then
local nextchar=ischar(next,startfont)
@@ -32253,6 +32878,9 @@ function handlers.devanagari_reorder_reph(head,start)
local char=ischar(current,startfont)
if char and getprop(current,a_syllabe)==startattr then
if consonant[char] and not getstate(current,s_pref) then
+ if trace_steps then
+ logprocess("reorder reph, handling consonant")
+ end
startnext=getnext(start)
head=remove_node(head,start)
setlink(current,start)
@@ -32277,6 +32905,9 @@ function handlers.devanagari_reorder_reph(head,start)
local char=ischar(current,startfont)
if char and getprop(current,a_syllabe)==startattr then
if getstate(current,s_pstf) then
+ if trace_steps then
+ logprocess("reorder reph, before postscript, post base")
+ end
startnext=getnext(start)
head=remove_node(head,start)
setlink(getprev(current),start)
@@ -32284,12 +32915,15 @@ function handlers.devanagari_reorder_reph(head,start)
start=startnext
startattr=getprop(start,a_syllabe)
break
- elseif not c and (vowel_modifier[char] or stress_tone_mark[char] ) then
+ elseif not c and (vowel_modifier[char] or stress_tone_mark[char]) then
c=current
end
current=getnext(current)
else
if c then
+ if trace_steps then
+ logprocess("reorder reph, before postscript")
+ end
startnext=getnext(start)
head=remove_node(head,start)
setlink(getprev(c),start)
@@ -32312,7 +32946,13 @@ function handlers.devanagari_reorder_reph(head,start)
local state=getstate(current)
if before_subscript[rephbase] and (state==s_blwf or state==s_pstf) then
c=current
+ if trace_steps then
+ logprocess("reorder reph, before subscript")
+ end
elseif after_subscript[rephbase] and (state==s_pstf) then
+ if trace_steps then
+ logprocess("reorder reph, after subscript")
+ end
c=current
end
current=getnext(current)
@@ -32343,6 +32983,9 @@ function handlers.devanagari_reorder_reph(head,start)
end
end
if start~=current then
+ if trace_steps then
+ logprocess("reorder reph, to end")
+ end
startnext=getnext(start)
head=remove_node(head,start)
setlink(start,getnext(current))
@@ -32352,9 +32995,8 @@ function handlers.devanagari_reorder_reph(head,start)
end
return head,start,true
end
-local reordered_pre_base_reordering_consonants={}
function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
- if reordered_pre_base_reordering_consonants[start] then
+ if getprop(start,a_reordered) then
return head,start,true
end
local current=start
@@ -32365,6 +33007,9 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
local next=getnext(current)
if char and getprop(current,a_syllabe)==startattr then
if halant[char] then
+ if trace_steps then
+ logprocess("reorder pre base consonants, handle halant")
+ end
if next then
local char=ischar(next,startfont)
if char and zw_char[char] and getprop(next,a_syllabe)==startattr then
@@ -32376,7 +33021,7 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
head=remove_node(head,start)
setlink(start,next)
setlink(current,start)
- reordered_pre_base_reordering_consonants[start]=true
+ setprop(start,"reordered",true)
start=startnext
return head,start,true
end
@@ -32390,6 +33035,9 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
while current and getprop(current,a_syllabe)==startattr do
local char=ischar(current)
if (not dependent_vowel[char] and (not getstate(current) or getstate(current,s_init))) then
+ if trace_steps then
+ logprocess("reorder pre base consonants, handle vowel or initial")
+ end
startnext=getnext(start)
head=remove_node(head,start)
if current==head then
@@ -32399,7 +33047,7 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
setlink(getprev(current),start)
setlink(start,current)
end
- reordered_pre_base_reordering_consonants[start]=true
+ setprop(start,"reordered",true)
start=startnext
break
end
@@ -32431,6 +33079,9 @@ function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replaceme
head=stop
end
flushlist(start)
+ if trace_steps then
+ logprocess("remove joiners")
+ end
return head,stop,true
end
local function initialize_two(font,attr)
@@ -32447,15 +33098,17 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
local basepos=nil
local subpos=nil
local postpos=nil
- reorderreph.coverage={}
- rephbase[font]={}
+ reorderreph.coverage={}
+ rephbase[font]={}
for i=1,#seqsubset do
local subset=seqsubset[i]
local kind=subset[1]
local lookupcache=subset[2]
if kind=="rphf" then
- reorderreph.coverage[subset[3]]=true
- rephbase[font][subset[3]]=subset[4]
+ local reph=subset[3]
+ local base=subset[4]
+ reorderreph.coverage[reph]=true
+ rephbase[font][reph]=base
local current=start
local last=getnext(stop)
while current~=last do
@@ -32464,15 +33117,15 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
local found=lookupcache[c]
if found then
local next=getnext(current)
- if found[getchar(next)] or contextchain(found,next) then
+ if contextchain(found,next) then
local afternext=next~=stop and getnext(next)
if afternext and zw_char[getchar(afternext)] then
current=afternext
elseif current==start then
setstate(current,s_rphf)
- current=next
+ current=next
else
- current=next
+ current=next
end
end
end
@@ -32488,8 +33141,8 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
local found=lookupcache[c]
if found then
local next=getnext(current)
- if found[getchar(next)] or contextchain(found,next) then
- if (not getstate(current) and not getstate(next)) then
+ if contextchain(found,next) then
+ if not getstate(current) and not getstate(next) then
setstate(current,s_pref)
setstate(next,s_pref)
current=next
@@ -32508,10 +33161,10 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
local found=lookupcache[c]
if found then
local next=getnext(current)
- if found[getchar(next)] or contextchain(found,next) then
+ if contextchain(found,next) then
if next~=stop and getchar(getnext(next))==c_zwnj then
current=next
- elseif (not getstate(current)) then
+ elseif not getstate(current) then
setstate(current,s_half)
if not halfpos then
halfpos=current
@@ -32532,8 +33185,8 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
local found=lookupcache[c]
if found then
local next=getnext(current)
- if found[getchar(next)] or contextchain(found,next) then
- if (not getstate(current) and not getstate(next)) then
+ if contextchain(found,next) then
+ if not getstate(current) and not getstate(next) then
setstate(current,s_blwf)
setstate(next,s_blwf)
current=next
@@ -32553,8 +33206,8 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
local found=lookupcache[c]
if found then
local next=getnext(current)
- if found[getchar(next)] or contextchain(found,next) then
- if (not getstate(current) and not getstate(next)) then
+ if contextchain(found,next) then
+ if not getstate(current) and not getstate(next) then
setstate(current,s_pstf)
setstate(next,s_pstf)
current=next
@@ -32576,6 +33229,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
stop=getprev(stop)
head=remove_node(head,current)
flushnode(current)
+ if trace_steps then
+ logprocess("reorder two, remove nbsp")
+ end
return head,stop,nbspaces
else
nbspaces=nbspaces+1
@@ -32616,6 +33272,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
end
end
end
+ if trace_steps then
+ logprocess("reorder two, handle nbsp")
+ end
end
else
local last=getnext(stop)
@@ -32645,7 +33304,7 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
return head,stop,nbspaces
else
if getstate(base) then
- setstate(base,unsetvalue)
+ setstate(base,unsetvalue)
end
basepos=base
end
@@ -32666,14 +33325,19 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
local target=nil
local cn=getnext(current)
local tpm=twopart_mark[char]
- while tpm do
- local extra=copy_node(current)
- copyinjection(extra,current)
- char=tpm[1]
- setchar(current,char)
- setchar(extra,tpm[2])
- head=insertnodeafter(head,current,extra)
- tpm=twopart_mark[char]
+ if tpm then
+ while tpm do
+ local extra=copy_node(current)
+ copyinjection(extra,current)
+ char=tpm[1]
+ setchar(current,char)
+ setchar(extra,tpm[2])
+ head=insertnodeafter(head,current,extra)
+ tpm=twopart_mark[char]
+ end
+ if tpm and trace_steps then
+ logprocess("reorder two, handle matra")
+ end
end
if not moved[current] and dependent_vowel[char] then
if pre_mark[char] then
@@ -32714,6 +33378,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
end
setlink(getprev(pos),current)
setlink(current,pos)
+ if trace_steps then
+ logprocess("reorder two, handle pre mark")
+ end
elseif above_mark[char] then
target=basepos
if subpos==basepos then
@@ -32753,6 +33420,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
end
setlink(current,getnext(target))
setlink(target,current)
+ if trace_steps then
+ logprocess("reorder two, handle mark")
+ end
end
end
end
@@ -32780,6 +33450,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
stop=prev
end
cn=next
+ if trace_steps then
+ logprocess("reorder two, handle halant and ra")
+ end
end
end
end
@@ -32812,6 +33485,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
setprev(nextnextnext,current)
end
setlink(nextnext,c)
+ if trace_steps then
+ logprocess("reorder two, handle nukta")
+ end
end
if stop==current then break end
current=getnext(current)
@@ -32823,6 +33499,9 @@ local function reorder_two(head,start,stop,font,attr,nbspaces)
nbspaces=nbspaces-1
head=remove_node(head,base)
flushnode(base)
+ if trace_steps then
+ logprocess("reorder two, handle nbsp")
+ end
end
return head,stop,nbspaces
end
@@ -32910,21 +33589,42 @@ local function analyze_next_chars_one(c,font,variant)
local already_below_mark
local already_post_mark
while dependent_vowel[v] do
- local vowels=twopart_mark[v] or { v }
- for k,v in next,vowels do
- if pre_mark[v] and not already_pre_mark then
- already_pre_mark=true
- elseif above_mark[v] and not already_above_mark then
- already_above_mark=true
- elseif below_mark[v] and not already_below_mark then
- already_below_mark=true
- elseif post_mark[v] and not already_post_mark then
- already_post_mark=true
- else
- return c
- end
- end
- c=getnext(c)
+ local vowels=twopart_mark[v]
+ if vowels then
+ for k=1,#vowels do
+ local v=vowels[k]
+ if pre_mark[v] and not already_pre_mark then
+ already_pre_mark=true
+ elseif above_mark[v] and not already_above_mark then
+ already_above_mark=true
+ elseif below_mark[v] and not already_below_mark then
+ already_below_mark=true
+ elseif post_mark[v] and not already_post_mark then
+ already_post_mark=true
+ elseif devanagarihash[font].conjuncts=="continue" then
+ else
+ return c
+ end
+ end
+ else
+ if pre_mark[v] and not already_pre_mark then
+ already_pre_mark=true
+ elseif post_mark[v] and not already_post_mark then
+ if devanagarihash[font].conjuncts=="mixed" then
+ return c
+ else
+ already_post_mark=true
+ end
+ elseif below_mark[v] and not already_below_mark then
+ already_below_mark=true
+ elseif above_mark[v] and not already_above_mark then
+ already_above_mark=true
+ elseif devanagarihash[font].conjuncts=="continue" then
+ else
+ return c
+ end
+ end
+ c=n
n=getnext(c)
if not n then
return c
@@ -32935,7 +33635,7 @@ local function analyze_next_chars_one(c,font,variant)
end
end
if nukta[v] then
- c=getnext(c)
+ c=n
n=getnext(c)
if not n then
return c
@@ -32946,7 +33646,7 @@ local function analyze_next_chars_one(c,font,variant)
end
end
if halant[v] then
- c=getnext(c)
+ c=n
n=getnext(c)
if not n then
return c
@@ -32957,7 +33657,7 @@ local function analyze_next_chars_one(c,font,variant)
end
end
if vowel_modifier[v] then
- c=getnext(c)
+ c=n
n=getnext(c)
if not n then
return c
@@ -32968,7 +33668,7 @@ local function analyze_next_chars_one(c,font,variant)
end
end
if stress_tone_mark[v] then
- c=getnext(c)
+ c=n
n=getnext(c)
if not n then
return c
@@ -32985,11 +33685,12 @@ local function analyze_next_chars_one(c,font,variant)
end
end
local function analyze_next_chars_two(c,font)
- local n=getnext(c)
+ local n,v
+ n=getnext(c)
if not n then
return c
end
- local v=ischar(n,font)
+ v=ischar(n,font)
if v and nukta[v] then
c=n
end
@@ -33048,11 +33749,11 @@ local function analyze_next_chars_two(c,font)
if not c then
return
end
- local n=getnext(c)
+ n=getnext(c)
if not n then
return c
end
- local v=ischar(n,font)
+ v=ischar(n,font)
if not v then
return c
end
@@ -33092,22 +33793,43 @@ local function analyze_next_chars_two(c,font)
local already_pre_mark
local already_above_mark
local already_below_mark
- local already_post_mark
- while dependent_vowel[v] do
- local vowels=twopart_mark[v] or { v }
- for k,v in next,vowels do
- if pre_mark[v] and not already_pre_mark then
- already_pre_mark=true
- elseif above_mark[v] and not already_above_mark then
- already_above_mark=true
- elseif below_mark[v] and not already_below_mark then
- already_below_mark=true
- elseif post_mark[v] and not already_post_mark then
- already_post_mark=true
- else
- return c
- end
- end
+ local already_post_mark
+ while dependent_vowel[v] do
+ local vowels=twopart_mark[v]
+ if vowels then
+ for k=1,#vowels do
+ local v=vowels[k]
+ if pre_mark[v] and not already_pre_mark then
+ already_pre_mark=true
+ elseif above_mark[v] and not already_above_mark then
+ already_above_mark=true
+ elseif below_mark[v] and not already_below_mark then
+ already_below_mark=true
+ elseif post_mark[v] and not already_post_mark then
+ already_post_mark=true
+ elseif devanagarihash[font].conjuncts=="continue" then
+ else
+ return c
+ end
+ end
+ else
+ if pre_mark[v] and not already_pre_mark then
+ already_pre_mark=true
+ elseif post_mark[v] and not already_post_mark then
+ if devanagarihash[font].conjuncts=="mixed" then
+ return c
+ else
+ already_post_mark=true
+ end
+ elseif below_mark[v] and not already_below_mark then
+ already_below_mark=true
+ elseif above_mark[v] and not already_above_mark then
+ already_above_mark=true
+ elseif devanagarihash[font].conjuncts=="continue" then
+ else
+ return c
+ end
+ end
c=n
n=getnext(c)
if not n then
@@ -33342,7 +34064,7 @@ local function method_one(head,font,attr)
end
else
if show_syntax_errors then
- local mark=mark_four[char]
+ local mark=mark_pre_above_below_post[char]
if mark then
head,current=inject_syntax_error(head,current,char)
end
@@ -33363,15 +34085,15 @@ local function method_one(head,font,attr)
while current do
local char=ischar(current,font)
if char then
- if n==0 and not getstate(current) then
- setstate(current,s_init)
- end
- n=n+1
- else
- n=0
- end
- current=getnext(current)
- end
+ if n==0 and not getstate(current) then
+ setstate(current,s_init)
+ end
+ n=n+1
+ else
+ n=0
+ end
+ current=getnext(current)
+ end
return head,done
end
local function method_two(head,font,attr)
@@ -33441,7 +34163,7 @@ local function method_two(head,font,attr)
if not syllableend and show_syntax_errors then
local char=ischar(current,font)
if char and not getstate(current) then
- local mark=mark_four[char]
+ local mark=mark_pre_above_below_post[char]
if mark then
head,current=inject_syntax_error(head,current,char)
end
@@ -33458,15 +34180,15 @@ local function method_two(head,font,attr)
while current do
local char=ischar(current,font)
if char then
- if n==0 and not getstate(current) then
- setstate(current,s_init)
- end
- n=n+1
- else
- n=0
- end
- current=getnext(current)
- end
+ if n==0 and not getstate(current) then
+ setstate(current,s_init)
+ end
+ n=n+1
+ else
+ n=0
+ end
+ current=getnext(current)
+ end
return head,done
end
for i=1,nofscripts do
@@ -36161,7 +36883,7 @@ local afm=fonts.handlers.afm
local pfb=fonts.handlers.pfb
local hashes=fonts.hashes
local identifiers=hashes.identifiers
-local version=0.010
+local version=otf.version or 0.011
local shapescache=containers.define("fonts","shapes",version,true)
local streamscache=containers.define("fonts","streams",version,true)
local compact_streams=false
@@ -36469,7 +37191,7 @@ local function getstreamhash(fontid)
local fontdata=identifiers[fontid]
if fontdata then
local properties=fontdata.properties
- return makehash(properties.filename,properties.subfont,properties.instance)
+ return makehash(properties.filename,properties.subfont,properties.instance),fontdata
end
end
local function loadstreamdata(fontdata)
diff --git a/macros/luatex/generic/luaotfload/fontloader-util-fil.lua b/macros/luatex/generic/luaotfload/fontloader-util-fil.lua
index 183f7bea81..0b20264ecc 100644
--- a/macros/luatex/generic/luaotfload/fontloader-util-fil.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-util-fil.lua
@@ -203,23 +203,23 @@ function files.readinteger4le(f)
end
function files.readfixed2(f)
- local a, b = byte(f:read(2),1,2)
- if a >= 0x80 then
- tonumber((a - 0x100) .. "." .. b)
- else
- tonumber(( a ) .. "." .. b)
+ local n1, n2 = byte(f:read(2),1,2)
+ if n1 >= 0x80 then
+ n1 = n1 - 0x100
end
+ return n1 + n2/0xFF
end
-- (real) (n>>16) + ((n&0xffff)/65536.0)) but no cast in lua (we could use unpack)
function files.readfixed4(f)
local a, b, c, d = byte(f:read(4),1,4)
- if a >= 0x80 then
- tonumber((0x100 * a + b - 0x10000) .. "." .. (0x100 * c + d))
- else
- tonumber((0x100 * a + b ) .. "." .. (0x100 * c + d))
+ local n1 = 0x100 * a + b
+ local n2 = 0x100 * c + d
+ if n1 >= 0x8000 then
+ n1 = n1 - 0x10000
end
+ return n1 + n2/0xFFFF
end
-- (real) ((n<<16)>>(16+14)) + ((n&0x3fff)/16384.0))
diff --git a/macros/luatex/generic/luaotfload/fontloader-util-str.lua b/macros/luatex/generic/luaotfload/fontloader-util-str.lua
index 0d1f39de9d..b5c721a41d 100644
--- a/macros/luatex/generic/luaotfload/fontloader-util-str.lua
+++ b/macros/luatex/generic/luaotfload/fontloader-util-str.lua
@@ -10,12 +10,13 @@ utilities = utilities or { }
utilities.strings = utilities.strings or { }
local strings = utilities.strings
-local format, gsub, rep, sub, find = string.format, string.gsub, string.rep, string.sub, string.find
+local format, gsub, rep, sub, find, char = string.format, string.gsub, string.rep, string.sub, string.find, string.char
local load, dump = load, string.dump
local tonumber, type, tostring, next, setmetatable = tonumber, type, tostring, next, setmetatable
local unpack, concat = table.unpack, table.concat
local P, V, C, S, R, Ct, Cs, Cp, Carg, Cc = lpeg.P, lpeg.V, lpeg.C, lpeg.S, lpeg.R, lpeg.Ct, lpeg.Cs, lpeg.Cp, lpeg.Carg, lpeg.Cc
local patterns, lpegmatch = lpeg.patterns, lpeg.match
+local tsplitat = lpeg.tsplitat
local utfchar, utfbyte, utflen = utf.char, utf.byte, utf.len
----- loadstripped = utilities.lua.loadstripped
@@ -622,7 +623,7 @@ local template = [[
return function(%s) return %s end
]]
--- this might move
+-- We only use fast serialize in controlled cases.
local pattern = Cs(Cc('"') * (
(1-S('"\\\n\r'))^1
@@ -632,12 +633,43 @@ local pattern = Cs(Cc('"') * (
+ P('\r') / '\\r'
)^0 * Cc('"'))
+-- -- I need to do more experiments with this:
+--
+-- local pattern = Cs(Cc('"') * (
+-- (1-S('"\\\n\r'))^1
+-- + P('"') / '\\034'
+-- + P('\\') / '\\092'
+-- + P('\n') / '\\013'
+-- + P('\r') / '\\010'
+-- )^0 * Cc('"'))
+
patterns.escapedquotes = pattern
function string.escapedquotes(s)
return lpegmatch(pattern,s)
end
+local pattern = (1 - P("\\"))^1 ; pattern = Cs (
+ pattern
+ * ( (P("\\") / "" * (digit^-3 / function(s) return char(tonumber(s)) end)) + pattern )^1
+)
+
+patterns.unescapedquotes = pattern
+
+function string.unescapedquotes(s)
+ return lpegmatch(pattern,s) or s
+end
+
+-- function string.longifneeded(s)
+-- if find(s,'["\\\n\r]') then
+-- return "[===[" .. s .. "]===]"
+-- else
+-- return '"' .. s ..'"'
+-- end
+-- end
+
+string.texnewlines = lpeg.replacer(patterns.newline,"\r",true)
+
-- print(string.escapedquotes('1\\23\n"'))
-- but for now here
@@ -1476,7 +1508,7 @@ end
if not string.explode then
- local tsplitat = lpeg.tsplitat
+ -- local tsplitat = lpeg.tsplitat
local p_utf = patterns.utf8character
local p_check = C(p_utf) * (P("+") * Cc(true))^0
@@ -1499,3 +1531,24 @@ if not string.explode then
end
end
+
+
+do
+
+ local p_whitespace = patterns.whitespace^1
+
+ local cache = setmetatable({ }, { __index = function(t,k)
+ local p = tsplitat(p_whitespace * P(k) * p_whitespace)
+ local v = function(s)
+ return lpegmatch(p,s)
+ end
+ t[k] = v
+ return v
+ end })
+
+ function string.wordsplitter(s)
+ return cache[s]
+ end
+
+end
+
diff --git a/macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua b/macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua
index 9c2d204aaa..86aff98fb4 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua
@@ -6,8 +6,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-auxiliary",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --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 c6a437c92a..e0bd759de5 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-colors.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-colors.lua
@@ -5,8 +5,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-colors",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --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 7baffef63e..9e3b6c6557 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 76a8d68754..50618d72af 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-configuration.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-configuration.lua
@@ -7,8 +7,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-configuration",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
description = "luaotfload submodule / config file reader",
license = "GPL v2.0"
}
@@ -218,6 +218,7 @@ local default_config = {
version = luaotfload.version,
statistics = false,
termwidth = nil,
+ keepnames = true,
},
paths = {
names_dir = "names",
@@ -611,6 +612,7 @@ local option_spec = {
return w
end,
},
+ keepnames = { in_t = boolean_t, },
},
paths = {
names_dir = { in_t = string_t, },
@@ -741,7 +743,7 @@ local formatters = {
anon_sequence = { false, format_list },
color_callback = { false, format_string },
definer = { false, format_string },
- fontloader = { false, format_string },
+ fontloader = { true, format_string },
log_level = { false, format_integer },
resolver = { false, format_string },
},
diff --git a/macros/luatex/generic/luaotfload/luaotfload-database.lua b/macros/luatex/generic/luaotfload/luaotfload-database.lua
index b1d264f9b7..8f0ef41fc7 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
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-database",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
description = "luaotfload submodule / database",
license = "GPL v2.0",
author = "Khaled Hosny, Elie Roux, Philipp Gesang, Marcel Krüger",
@@ -142,8 +142,7 @@ do
end
local otfhandler = fonts.handlers.otf or { }
-local gzipload = gzip.load
-local gzipsave = gzip.save
+local gzipopen = gzip.open
local iolines = io.lines
local ioopen = io.open
local kpseexpand_path = kpse.expand_path
@@ -159,6 +158,7 @@ local mathmin = math.min
local osgetenv = os.getenv
local osgettimeofday = os.gettimeofday
local osremove = os.remove
+local dump = string.dump
local stringfind = string.find
local stringformat = string.format
local stringgmatch = string.gmatch
@@ -486,42 +486,47 @@ local function initialize_namedata (formats, created)
}
end
+-- A helper to load a file which might be gziped
+local function load_maybe_gzip (path, binary)
+ local gzippath = path .. '.gz'
+ local f = ioopen (gzippath, 'rb')
+ if f then
+ path = gzippath
+ local result = f:read'*a'
+ result = gzip.decompress(result, 31)
+ f:close()
+ return path, result
+ else
+ f, msg = ioopen (path, binary and 'rb' or 'r')
+ if f then
+ local result = f:read'*a'
+ f:close()
+ return path, result
+ end
+ end
+
+ return nil, msg
+end
+
--- When loading a lua file we try its binary complement first, which
--- is assumed to be located at an identical path, carrying the suffix
--- .luc.
---- string -> (string * table)
-local function load_lua_file (path)
- local foundname = filereplacesuffix (path, "luc")
- local code = nil
-
- local fh = ioopen (foundname, "rb") -- try bin first
- if fh then
- local chunk = fh:read"*all"
- fh:close()
- code = load (chunk, "b")
- end
-
- if not code then --- fall back to text file
- foundname = filereplacesuffix (path, "lua")
- fh = ioopen(foundname, "rb")
- if fh then
- local chunk = fh:read"*all"
- fh:close()
- code = load (chunk, "t")
- end
- end
-
- if not code then --- probe gzipped file
- foundname = filereplacesuffix (path, "lua.gz")
- local chunk = gzipload (foundname)
- if chunk then
- code = load (chunk, "t")
+--- string -> string -> (string * table)
+local function load_lua_file (path_lua, path_luc)
+ local foundname, chunk = load_maybe_gzip (path_luc, true)
+ if foundname then
+ chunk = assert (load (chunk, 'b'))
+ else
+ foundname, chunk = load_maybe_gzip (path_lua, false)
+ if foundname then
+ chunk = assert (load (chunk, 't'))
+ else
+ return nil
end
end
- if not code then return nil, nil end
- return foundname, code ()
+ return foundname, chunk()
end
--- define locals in scope
@@ -543,7 +548,8 @@ local fuzzy_limit = 1 --- display closest only
--- bool? -> -> bool? -> dbobj option
local function load_names (dry_run, no_rebuild)
local starttime = osgettimeofday ()
- local foundname, data = load_lua_file (config.luaotfload.paths.index_path_lua)
+ local foundname, data = load_lua_file (config.luaotfload.paths.index_path_lua,
+ config.luaotfload.paths.index_path_luc)
if data then
logreport ("log", 0, "db",
@@ -624,7 +630,8 @@ end
--- unit -> unit
local function load_lookups ( )
- local foundname, data = load_lua_file(config.luaotfload.paths.lookup_path_lua)
+ local foundname, data = load_lua_file(config.luaotfload.paths.lookup_path_lua,
+ config.luaotfload.paths.lookup_path_luc)
if data then
logreport ("log", 0, "cache", "Lookup cache loaded from %s.", foundname)
logreport ("term", 3, "cache",
@@ -638,11 +645,12 @@ local function load_lookups ( )
end
local regular_synonym = {
- book = true,
- normal = true,
- plain = true,
- regular = true,
- roman = true,
+ book = 0,
+ normal = 0,
+ plain = 0,
+ regular = 0,
+ roman = 0,
+ medium = 1000, -- Some font authors haven't got the memo that medium is not regular
}
local style_synonym = {
@@ -1577,8 +1585,6 @@ local function organize_namedata (rawinfo,
or nametable.family
or rawinfo.familyname
or info.familyname
--- local default_modifier = nametable.typographicsubfamily
--- or nametable.subfamily
local fontnames = {
--- see
--- https://developer.apple.com/fonts/TTRefMan/RM06/Chap6name.html
@@ -1642,7 +1648,7 @@ local function split_fontname (fontname)
end
end
-local function organize_styledata (metadata, rawinfo, info)
+local function organize_styledata (metadata, rawinfo)
local pfminfo = metadata.pfminfo
local names = rawinfo.names
return {
@@ -1686,8 +1692,7 @@ local function ot_fullinfo (filename,
basename,
info)
local style = organize_styledata (metadata,
- rawinfo,
- info)
+ rawinfo)
local res = {
file = { base = basename,
full = filename,
@@ -1929,7 +1934,7 @@ local function read_font_names (fullname,
if insert_fullinfo (fullname, basename, n_font,
loader, format, location,
targetmappings, targetentrystatus,
- info)
+ info[n_font])
then
success = true
end
@@ -2368,7 +2373,7 @@ local function collect_font_filenames_texmf ()
fontdirs = fontdirs .. path_separator .. expanded_path "type1 fonts"
fontdirs = fontdirs .. path_separator .. expanded_path "afm"
- fontdirs = filesplitpath (fontdirs) or { }
+ fontdirs = filesplitpath (fontdirs) or { }
local tasks = filter_out_pwd (fontdirs)
logreport ("both", 3, "db",
@@ -2725,95 +2730,51 @@ local function generate_filedata (mappings)
return files
end
-local bold_spectrum_low = 501 --- 500 is medium, 900 heavy/black
-local normal_weight = 400
-local bold_weight = 700
-local normal_width = 5
-
-local pick_style
-local pick_fallback_style
-local check_regular
-
-do
- function pick_style (typographicsubfamily, subfamily)
- return style_synonym [typographicsubfamily or subfamily or ""]
- end
-
- function pick_fallback_style (italicangle, pfmweight, width)
- --[[--
- More aggressive, but only to determine bold faces.
- Note: Before you make this test more inclusive, ensure
- no fonts are matched in the bold synonym spectrum over
- a literally “bold[italic]” one. In the past, heuristics
- been tried but ultimately caused unwanted modifiers
- polluting the lookup table. What doesn’t work is, e. g.
- treating weights > 500 as bold or allowing synonyms like
- “heavy”, “black”.
- --]]--
- if width == normal_width then
- if pfmweight == bold_weight then
- --- bold spectrum matches
- if italicangle == 0 then
- return "b"
- end
- return "bi"
- elseif pfmweight == normal_weight then
- if italicangle ~= 0 then
- return "i"
- end
- end
- return tostring(pfmweight) .. (italicangle == 0 and "" or "i")
- end
- return false
- end
-
- --- we use only exact matches here since there are constructs
- --- like “regularitalic” (Cabin, Bodoni Old Fashion)
-
- function check_regular (typographicsubfamily,
- subfamily,
- italicangle,
- weight,
- width,
- pfmweight)
- local plausible_weight = false
- --[[--
- This filters out undesirable candidates that specify their
- typographicsubfamily or subfamily as “regular” but are actually of
- “semibold” or other weight—another drawback of the
- oversimplifying classification into only three styles (r, i,
- b, bi).
- --]]--
- if italicangle == 0 then
- if pfmweight == 400 then
- --[[--
- Some fonts like Dejavu advertise an undistinguished
- regular and a “condensed” version with the same
- weight whilst also providing the style info in the
- typographic subfamily instead of the subfamily (i. e.
- the converse of what Adobe’s doing). The only way to
- weed out the undesired pseudo-regular shape is to
- peek at its advertised width (4 vs. 5).
- --]]--
- if width then
- plausible_weight = width == normal_width
- else
- plausible_weight = true
- end
- elseif weight and regular_synonym [weight] then
- plausible_weight = true
- end
- end
-
- if plausible_weight then
- if subfamily then
- if regular_synonym [subfamily] then return "r" end
- elseif typographicsubfamily then
- if regular_synonym [typographicsubfamily] then return "r" end
- end
- end
- return false
- end
+local function regular_score(entry)
+ return 10000 * (entry.italicangle or 0)^2 -- We really don't want italic fonts here (italic font have an angle around 10)
+ + .01 * ((entry.pfmweight or 400) - 400)^2 -- weights are normally multiples of 100, so they are still quite large after .01
+ + ((entry.width or 5) - 5)^2
+ + (regular_synonym[entry.subfamily or entry.typographicsubfamily] or 1000000)
+ + (entry.pfmweight > 500 and 1000 or 0)
+end
+local function italic_score(entry, regular_entry)
+ local regularangle = regular_entry.italicangle or 0
+ local angle = entry.italicangle or 0
+ if (angle == 0 or angle == regularangle)
+ and (entry.subfamily == regular_entry.subfamily or style_synonym[entry.subfamily] ~= 'i') then
+ return -- This font is not italic in any way
+ end
+ return .1 * (angle - regularangle - 10)^2 -- Should there ever be multiple levels of italicness...
+ + 0.1 * ((entry.pfmweight or 400) - (regular_entry.pfmweight or 400))^2 -- weights are normally multiples of 100, so they are still quite large after .01
+ + ((entry.width or 5) - regular_entry.width)^2
+ + (style_synonym[entry.subfamily or entry.typographicsubfamily] == 'i' and 0 or 1000000)
+end
+local function bold_score(entry, regular_entry)
+ local regularweight = regular_entry.pfmweight or 400
+ local weight = entry.pfmweight
+ if weight < regularweight + 100
+ and (entry.subfamily == regular_entry.subfamily or style_synonym[entry.subfamily] ~= 'b') then
+ return -- This font is not bold in any way
+ end
+ return 10000 * (entry.italicangle or 0)^2 -- We really don't want italic fonts here (italic font have an angle around 10)
+ + .01 * ((entry.pfmweight or 400) - (regularweight + 200))^2 -- weights are normally multiples of 100, so they are still quite large after .01
+ + ((entry.width or 5) - regular_entry.width)^2
+ + (style_synonym[entry.subfamily or entry.typographicsubfamily] == 'b' and 0 or 1000000)
+ + (entry.pfmweight > 500 and 0 or 10000)
+end
+local function bolditalic_score(entry, bold_entry, italic_entry)
+ local italicangle = italic_entry.italicangle or 0
+ local angle = entry.italicangle or 0
+ local boldweight = bold_entry.pfmweight or 400
+ local weight = entry.pfmweight or 400
+ if (angle == 0 or weight < boldweight)
+ and (entry.subfamily == bold_entry.subfamily or entry.subfamily == italic_entry.subfamily or style_synonym[entry.subfamily] ~= 'bi') then
+ return -- This font is not italic in any way
+ end
+ return 100 * (angle - italicangle)^2
+ + (weight - boldweight)^2
+ + ((entry.width or 5) - bold_entry.width)^2
+ + (style_synonym[entry.subfamily or entry.typographicsubfamily] == 'bi' and 0 or 1000000)
end
local function pull_values (entry)
@@ -2854,7 +2815,7 @@ local function pull_values (entry)
end
end
-local function add_family (name, subtable, modifier, entry)
+local function add_family (name, subtable, entry)
if not name then --- probably borked font
return
end
@@ -2866,22 +2827,9 @@ local function add_family (name, subtable, modifier, entry)
familytable [#familytable + 1] = {
index = entry.index,
- modifier = modifier,
}
end
-local function add_lastresort_regular (name, subtable, entry)
- if not name then --- probably borked font
- return
- end
- local familytable = subtable [name]
- if not familytable then
- familytable = { }
- subtable [name] = familytable
- end
- familytable.fallback = entry.index
-end
-
local function get_subtable (families, entry)
local location = entry.location
local format = entry.format
@@ -2919,27 +2867,7 @@ local function collect_families (mappings)
local width = entry.width
local pfmweight = entry.pfmweight
local italicangle = entry.italicangle
- local modifier = pick_style (typographicsubfamily, subfamily)
-
- if not modifier then --- regular, exact only
- modifier = check_regular (typographicsubfamily,
- subfamily,
- italicangle,
- weight,
- width,
- pfmweight)
- end
-
- if not modifier then
- modifier = pick_fallback_style (italicangle, pfmweight, width)
- end
-
- if modifier then
- add_family (familyname, subtable, modifier, entry)
- end
- if modifier ~= 'r' and regular_synonym[typographicsubfamily or subfamily or ''] then
- add_lastresort_regular (familyname, subtable, entry)
- end
+ add_family (familyname, subtable, entry)
end
collectgarbage "collect"
@@ -2983,99 +2911,135 @@ end
local style_categories = { "r", "b", "i", "bi" }
local bold_categories = { "b", "bi" }
+local huge = math.huge
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
for familyname, collected in next, format_data do
- local styledata = { } --- will replace the “collected” table
- local lastresort_regular = collected.fallback
- collected.fallback = nil
- --- First, fill in the ordinary style data that
- --- fits neatly into the four relevant modifier
- --- categories.
- for _, modifier in next, style_categories do
- local entries
- for key, info in next, collected do
- if info.modifier == modifier then
- if not entries then
- entries = { }
- end
- local index = info.index
- local entry = mappings [index]
- local size = entry.size
+ local best_score = huge
+ local best_match
+ for i=1,#collected do
+ local v = collected[i]
+ local entry = mappings[v.index]
+ local score = regular_score(entry)
+ if score <= best_score then
+ v.prev = best_score == score and best_match or nil
+ best_score = score
+ best_match = v
+ end
+ end
+ local regular = {}
+ repeat
+ local index = best_match.index
+ local entry = mappings[index]
+ local size = entry.size
+ if size then
+ regular [#regular + 1] = {
+ size [1],
+ size [2],
+ size [3],
+ index,
+ }
+ else
+ regular.default = index
+ end
+ best_match = best_match.prev
+ until not best_match
+ local regular_entry = mappings[regular.default or regular[1][4]]
+ local best_match_i, best_match_b
+ local best_score_i, best_score_b = 10000000000, 10000000000
+ for i=1,#collected do
+ local v = collected[i]
+ local entry = mappings[v.index]
+ local score_i = italic_score(entry, regular_entry)
+ local score_b = bold_score(entry, regular_entry)
+ if score_i and score_i <= best_score_i then
+ v.prev = best_score_i == score_i and best_match_i or nil
+ best_score_i = score_i
+ best_match_i = v
+ end
+ if score_b and score_b <= best_score_b then
+ v.prev = best_score_b == score_b and best_match_b or nil
+ best_score_b = score_b
+ best_match_b = v
+ end
+ end
+ local italic, bold
+ if best_match_i then
+ italic = {}
+ repeat
+ local index = best_match_i.index
+ local entry = mappings[index]
+ local size = entry.size
+ if size then
+ italic [#italic + 1] = {
+ size [1],
+ size [2],
+ size [3],
+ index,
+ }
+ else
+ italic.default = index
+ end
+ best_match_i = best_match_i.prev
+ until not best_match_i
+ end
+ if best_match_b then
+ bold = {}
+ repeat
+ local index = best_match_b.index
+ local entry = mappings[index]
+ local size = entry.size
+ if size then
+ bold [#bold + 1] = {
+ size [1],
+ size [2],
+ size [3],
+ index,
+ }
+ else
+ bold.default = index
+ end
+ best_match_b = best_match_b.prev
+ until not best_match_b
+ end
+ local bolditalic
+ if bold and italic then
+ best_score = 1000000000000
+ local bold_entry = mappings[bold.default or bold[1][4]]
+ local italic_entry = mappings[italic.default or italic[1][4]]
+ for i=1,#collected do
+ local v = collected[i]
+ local entry = mappings[v.index]
+ local score = bolditalic_score(entry, bold_entry, italic_entry)
+ if score and score <= best_score then
+ v.prev = best_score == score and best_match or nil
+ best_score = score
+ best_match = v
+ end
+ end
+ if best_match then
+ bolditalic = {}
+ repeat
+ local index = best_match.index
+ local entry = mappings[index]
+ local size = entry.size
if size then
- entries [#entries + 1] = {
+ bolditalic [#bolditalic + 1] = {
size [1],
size [2],
size [3],
index,
}
else
- entries.default = index
+ bolditalic.default = index
end
- collected [key] = nil
- end
- styledata [modifier] = entries
+ best_match = best_match.prev
+ until not best_match
end
end
- if not styledata.r and lastresort_regular then
- styledata.r = {default = lastresort_regular}
- end
-
- --- At this point the family set may still lack
- --- entries for bold or bold italic. We will fill
- --- those in using the modifier with the numeric
- --- weight that is closest to bold (700).
- if next (collected) then --- there are uncategorized entries
- for _, modifier in next, bold_categories do
- if not styledata [modifier] then
- local closest
- local minimum = 2^51
- for key, info in next, collected do
- local info_modifier = tonumber (info.modifier) and "b" or "bi"
- if modifier == info_modifier then
- local index = info.index
- local entry = mappings [index]
- local weight = entry.pfmweight
- local diff = weight < 700 and 700 - weight or weight - 700
- if weight > 500 and diff < minimum then
- minimum = diff
- closest = weight
- end
- end
- end
- if closest then
- --- We know there is a substitute face for the modifier.
- --- Now we scan the list again to extract the size data
- --- in case the shape is available at multiple sizes.
- local entries = { }
- for key, info in next, collected do
- local info_modifier = tonumber (info.modifier) and "b" or "bi"
- if modifier == info_modifier then
- local index = info.index
- local entry = mappings [index]
- local size = entry.size
- if entry.pfmweight == closest then
- if size then
- entries [#entries + 1] = {
- size [1],
- size [2],
- size [3],
- index,
- }
- else
- entries.default = index
- end
- end
- end
- end
- styledata [modifier] = entries
- end
- end
- end
- end
- format_data [familyname] = styledata
+ format_data [familyname] = { r = regular, b = bold, i = italic, bi = bolditalic }
end
end
end
@@ -3514,28 +3478,62 @@ function update_names (currentnames, force, dry_run)
return targetnames
end
+local function compress_dummy(data) return data end
+--- string -> string -> (string * table)
+local function save_lua_table (data, path_lua, path_luc, compress)
+ if compress then
+ osremove(path_lua)
+ osremove(path_luc)
+ path_lua, path_luc = path_lua .. '.gz', path_luc .. '.gz'
+ else
+ osremove(path_lua .. '.gz')
+ osremove(path_luc .. '.gz')
+ end
+ local file_lua, msg = ioopen(path_lua, compress and 'wb' or 'w')
+ if not file_lua then
+ logreport ("info", 0, "cache", "Failed to write %q: %s", path_lua, msg)
+ end
+ local file_luc file_luc, msg = ioopen(path_luc, 'wb')
+ if not file_luc then
+ logreport ("info", 0, "cache", "Failed to write %q: %s", path_luc, msg)
+ end
+ if not (file_lua or file_luc) then
+ return
+ end
+ -- If we can only write one of the files, try to remove the other
+ -- one to avoid them beiing inconsistent. This will probably fail,
+ -- but in some situations we might be allowed to delete a file we
+ -- can't write to.
+ if not file_lua then
+ osremove(path_lua)
+ elseif not file_luc then
+ osremove(path_luc)
+ end
+ local serialized = tableserialize (data, true)
+ if file_lua then
+ file_lua:write(compress and gzip.compress(serialized, 31) or serialized)
+ file_lua:close()
+ end
+ if file_luc then
+ local compiled = dump(assert(load(serialized, 't')), true)
+ file_luc:write(compress and gzip.compress(compiled, 31) or compiled)
+ file_luc:close()
+ end
+ -- Even if we could write one file but not the other one it's still an
+ -- error since reloading is then unreliable.
+ return file_lua and path_lua or nil, file_luc and path_luc or nil
+end
+
--- unit -> bool
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
- tabletofile (luaname, lookup_cache, true)
- osremove (lucname)
- caches.compile (lookup_cache, luaname, lucname)
- --- double check ...
- if lfsisfile (luaname) and lfsisfile (lucname) then
- logreport ("both", 3, "cache", "Lookup cache saved.")
- return true
- end
- logreport ("info", 0, "cache", "Could not compile lookup cache.")
- return false
- end
- logreport ("info", 0, "cache", "Lookup cache file not writable.")
- if not fileiswritable (luaname) then
- logreport ("info", 0, "cache", "Failed to write %s.", luaname)
- end
- if not fileiswritable (lucname) then
- logreport ("info", 0, "cache", "Failed to write %s.", lucname)
+ luaname, lucname = save_lua_table(lookup_cache, luaname, lucname)
+ if luaname and lucname then
+ logreport ("both", 3, "cache", "Lookup cache saved.")
+ return true
+ else
+ logreport ("info", 0, "cache", "Lookup cache file not writable.")
end
return false
end
@@ -3553,45 +3551,15 @@ function save_names (currentnames)
end
local paths = config.luaotfload.paths
local luaname, lucname = paths.index_path_lua, paths.index_path_luc
- if fileiswritable (luaname) and fileiswritable (lucname) then
- osremove (lucname)
- local gzname = luaname .. ".gz"
- if config.luaotfload.db.compress then
- local serialized = tableserialize (currentnames, true)
- gzipsave (gzname, serialized)
- caches.compile (currentnames, "", lucname)
- else
- tabletofile (luaname, currentnames, true)
- caches.compile (currentnames, luaname, lucname)
- end
+ local compress = config.luaotfload.db.compress
+ luaname, lucname = save_lua_table(currentnames, luaname, lucname, compress)
+ if luaname and lucname then
logreport ("info", 2, "db", "Font index saved at ...")
- local success = false
- if lfsisfile (luaname) then
- logreport ("info", 2, "db", "Text: " .. luaname)
- success = true
- end
- if lfsisfile (gzname) then
- logreport ("info", 2, "db", "Gzip: " .. gzname)
- success = true
- end
- if lfsisfile (lucname) then
- logreport ("info", 2, "db", "Byte: " .. lucname)
- success = true
- end
- if success then
- return true
- else
- logreport ("info", 0, "db", "Could not compile font index.")
- return false
- end
+ logreport ("info", 2, "db", "Text: " .. luaname)
+ logreport ("info", 2, "db", "Byte: " .. lucname)
+ return true
end
logreport ("info", 0, "db", "Index file not writable")
- if not fileiswritable (luaname) then
- logreport ("info", 0, "db", "Failed to write %s.", luaname)
- end
- if not fileiswritable (lucname) then
- logreport ("info", 0, "db", "Failed to write %s.", lucname)
- end
return false
end
@@ -3829,10 +3797,7 @@ return function ()
fonts.definers = fonts.definers or { resolvers = { } }
names.blacklist = blacklist
- -- MK Changed to rebuild with case insensitive fallback.
- -- Negative version to indicate generation by modified code.
- names.version = -2 --- decrease monotonically
- -- /MK
+ names.version = 6 --- increase monotonically
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 fe959a50de..622714d14b 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-diagnostics.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-diagnostics.lua
@@ -7,8 +7,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-diagnostics",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --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
index f368c3ae5a..2f8abefa93 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-dvi.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-dvi.lua
@@ -6,8 +6,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-dvi",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
description = "luaotfload submodule / DVI",
license = "GPL v2.0",
author = "Marcel Krüger",
diff --git a/macros/luatex/generic/luaotfload/luaotfload-embolden.lua b/macros/luatex/generic/luaotfload/luaotfload-embolden.lua
index ca035bc4cd..d0a2e60555 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-embolden.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-embolden.lua
@@ -5,8 +5,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-embolden",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --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 3e5d65eaca..a3f28e77a4 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-fallback.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-fallback.lua
@@ -5,8 +5,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-fallback",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --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 bedcd59d76..eecf1aa0f5 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-features.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-features.lua
@@ -5,8 +5,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-features",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
description = "luaotfload submodule / features",
license = "GPL v2.0",
author = "Hans Hagen, Khaled Hosny, Elie Roux, Philipp Gesang, Marcel Krüger",
@@ -30,6 +30,8 @@ local table = table
local tabletohash = table.tohash
local tablesort = table.sort
+local stringunpack = string.unpack
+
--- this appears to be based in part on luatex-fonts-def.lua
local fonts = fonts
@@ -322,6 +324,7 @@ local supported = {
b = "b",
i = "i",
bi = "bi",
+ r = "r",
aat = false,
icu = false,
gr = false,
@@ -777,6 +780,100 @@ do
}
end
+do
+ local function restore(tfmdata, value, features)
+ if not tfmdata.properties.monospaced then return end
+ if features.fixedspace then return end -- In this case, 'auto' is true
+ local parameters = tfmdata.parameters
+ local space = parameters.space
+ parameters.space_stretch, parameters.space_shrink = space/2, space/3
+ end
+ fonts.constructors.features.otf.register {
+ name = 'internal__variablespace',
+ default = true,
+ initializers = {
+ base = restore,
+ node = restore,
+ },
+ }
+ local function node_fixedspace(tfmdata, value, features)
+ if value == 'auto' then return end
+ if tfmdata.properties.monospaced then return end -- handled by internal__variablespace
+ local parameters = tfmdata.parameters
+ parameters.space_stretch, parameters.space_shrink = 0, 0
+ end
+ local hb = luaotfload.harfbuzz
+ local post_tag = hb and hb.Tag.new'post'
+ local function harf_fixedspace(tfmdata, value, features)
+ if value == 'auto' then
+ -- We have to determine if we have a monospace font.
+ -- Let's be honest, it would be boring if that were easy.
+ local post_table = tfmdata.hb.shared.face:get_table(post_tag):get_data()
+ if #post_table < 16 then
+ -- Invalid OpenType font... Let's assume that it's not
+ -- monospaced:
+ return
+ end
+ local monospaced = string.unpack('>I4', post_table, 13) ~= 0
+ if not monospaced then return end -- FIXME: How to determine?
+ end
+ local parameters = tfmdata.parameters
+ parameters.space_stretch, parameters.space_shrink = 0, 0
+ end
+ fonts.constructors.features.otf.register {
+ name = 'fixedspace',
+ description = 'Do not stretch or shrink spaces',
+ default = 'auto',
+ initializers = {
+ base = node_fixedspace,
+ node = node_fixedspace,
+ plug = harf_fixedspace,
+ },
+ }
+end
+
+local uni_normalize = require'lua-uni-normalize'.direct
+local normalize_lookup = setmetatable({}, {__index = function(t, f)
+ local fontdir = assert(font.getfont(f))
+ local normalize_func = t[fontdir]
+ local characters = fontdir.characters
+ local function result(head)
+ return normalize_func(head, f, characters, true)
+ end
+ t[fontdir] = result
+ return result
+end})
+local normalize_funcs = {
+ nfc = uni_normalize.NFC,
+ nfd = uni_normalize.NFD,
+ nfkd = uni_normalize.NFKD,
+}
+fonts.constructors.features.otf.register {
+ name = 'normalize',
+ default = 'nfc',
+ description = 'Normalize text to NFC before shaping',
+ manipulators = {
+ node = function(fonttable, _, value)
+ if value == true then
+ value = 'nfc'
+ end
+ local func = normalize_funcs[value]
+ if not func then
+ report ("report", 0, "features",
+ "Unsupported normalization method replaced by NFC")
+ func = normalize_funcs.nfc
+ end
+ normalize_lookup[fonttable] = func
+ end,
+ },
+ processors = {
+ node = function(head, f, _, _, _)
+ return normalize_lookup[f](head)
+ 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 e3fc38acd3..abd6458db9 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-filelist.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-filelist.lua
@@ -6,8 +6,8 @@
if luaotfload_module then luaotfload_module {
name = "luaotfload-filelist",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
description = "luaotfload submodule / filelist",
license = "GPL v2.0"
} end
diff --git a/macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua b/macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua
index 93a2eaeffd..ce3cc314b4 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua
@@ -1,8 +1,8 @@
if luaotfload_module then
luaotfload_module {
name = "luaotfload-glyphlist",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --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 f128adbaae..d7ee7c11bb 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-harf-define.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-harf-define.lua
@@ -5,8 +5,8 @@
do -- block to avoid to many local variables error
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-harf-define",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
description = "luaotfload submodule / HarfBuzz font loading",
license = "GPL v2.0",
author = "Khaled Hosny, Marcel Krüger",
@@ -21,14 +21,14 @@ local gsub = string.gsub
local hb = luaotfload.harfbuzz
local scriptlang_to_harfbuzz = require'luaotfload-scripts'.to_harfbuzz
+local cff2_handler = require'luaotfload-harf-var-cff2'
+local ttf_handler = require'luaotfload-harf-var-ttf'
local harf_settings = luaotfload.harf or {}
luaotfload.harf = harf_settings
harf_settings.default_buf_flags = hb.Buffer.FLAGS_DEFAULT or 0
-local hbfonts = {}
-
local cfftag = hb.Tag.new("CFF ")
local cff2tag = hb.Tag.new("CFF2")
local os2tag = hb.Tag.new("OS/2")
@@ -36,9 +36,15 @@ local posttag = hb.Tag.new("post")
local glyftag = hb.Tag.new("glyf")
local gpostag = hb.Tag.new("GPOS")
+local italtag = hb.Tag.new("ital")
+local wghttag = hb.Tag.new("wght")
+local slnttag = hb.Tag.new("slnt")
+local opsztag = hb.Tag.new("opsz")
+
local invalid_l = hb.Language.new()
local invalid_s = hb.Script.new()
+local tointeger = math.tointeger
local floor = math.floor
local function round(x)
return floor(x + 0.5)
@@ -71,27 +77,123 @@ local get_designsize do
end
local containers = luaotfload.fontloader.containers
-local hbcacheversion = 1.2
-local facecache = containers.define("fonts", "hb", hbcacheversion, true)
+local hbcacheversion = 1.4
+local fontcache = containers.define("fonts", "hb", hbcacheversion, true)
+local facecache = {}
+
+local variable_pattern do
+ local l = lpeg or require'lpeg'
+ local white = l.S' \t'^0
+ local number = l.C(l.S'+-'^-1 * (l.R'09'^1 * ('.' * l.R'09'^0)^-1 + '.' * l.R'09'^1))
+ local name_or_tag = l.C(l.R('AZ', 'az')^1)
+ local pair = l.Ct(name_or_tag * white * '=' * white * (number + l.Cc(nil) * 'auto'))
+ variable_pattern = l.Ct(pair * (white * ',' * white * pair)^0)
+end
local function loadfont(spec)
local path, sub = spec.resolved, spec.sub or 1
- local key = string.format("%s:%d", gsub(path, "[/\\]", ":"), sub)
+ local key = gsub(string.format("%s:%d:%s", path, sub, instance), "[/\\]", ":")
local attributes = lfs.attributes(path)
if not attributes then return end
local size, date = attributes.size or 0, attributes.modification or 0
- local cached = containers.read(facecache, key)
+ local hbface = facecache[key]
+ if not hbface then
+ hbface = hb.Face.new(path, sub - 1)
+ facecache[key] = hbface
+ end
+
+ local normalized
+ local varkey
+ if hbface.ot_var_has_data and hbface:ot_var_has_data() then
+ local design_coords
+ local instance = spec.features.raw.instance
+ local axis = spec.features.raw.axis
+ local assignments = axis and variable_pattern:match(axis)
+ if axis and not assignments and not instance then
+ instance, axis = axis, nil
+ end
+ if instance then
+ instance = instance:lower()
+ local instances = hbface:ot_var_named_instance_get_infos()
+ for i = 1, #instances do
+ local inst = instances[i]
+ if instance == hbface:get_name(inst.subfamily_name_id):lower() then
+ design_coords = {hbface:ot_var_named_instance_get_design_coords(inst.index)}
+ break
+ end
+ end
+ if not design_coords then
+ texio.write_nl'Warning (luaotfload): Unknown instance name ignored.'
+ end
+ end
+ local axes = hbface:ot_var_get_axis_infos()
+ design_coords = design_coords or lua.newtable(#axes, 0)
+ if assignments then
+ for i = 1, #assignments do
+ local found
+ local name = assignments[i][1]
+ local tag
+ if #name <= 4 then
+ tag = hb.Tag.new(name)
+ end
+ name = string.lower(name)
+ for j = 1, #axes do
+ local axis = axes[j]
+ if tag and tag == axis.tag then
+ found = axis
+ break
+ end
+ if name == hbface:get_name(axis.name_id):lower() then
+ found = axis
+ if not tag then break end
+ end
+ end
+ if found then
+ design_coords[found.axis_index] = assignments[i][2]
+ else
+ texio.write_nl'Warning (luaotfload): Unknown axis name ignored.'
+ end
+ end
+ end
+ for i = 1, #axes do
+ local axis = axes[i]
+ local index = axis.axis_index -- == i in practise
+ if not design_coords[index] then
+ local tag = axis.tag
+ if tag == italtag and spec.style then
+ design_coords[index] = spec.style == 'i' or spec.style == 'bi' and 1 or 0
+ elseif tag == slnttag and spec.style then
+ design_coords[index] = spec.style == 'i' or spec.style == 'bi' and -5 or 0
+ elseif tag == wghttag and spec.style then
+ design_coords[index] = (spec.style == 'b' or spec.style == 'bi') and 600 or 400
+ elseif tag == opsztag and (spec.optsize or spec.size > 0) then
+ design_coords[index] = spec.optsize or spec.size / 65536
+ else
+ design_coords[index] = axis.default_value
+ end
+ end
+ end
+ normalized = {hbface:ot_var_normalize_coords(table.unpack(design_coords))}
+ varkey = ':' .. table.concat(normalized, ':')
+ key = key .. varkey
+ else
+ varkey = ''
+ end
+
+ local cached = containers.read(fontcache, key)
local iscached = cached and cached.date == date and cached.size == size
- local hbface = iscached and cached.face or hb.Face.new(path, sub - 1)
local tags = hbface and hbface:get_table_tags()
-- If the face has no table tags then it isn’t a valid SFNT font that
-- HarfBuzz can handle.
if not tags then return end
local hbfont = iscached and cached.font or hb.Font.new(hbface)
+ if normalized then
+ hbfont:set_var_coords_normalized(table.unpack(normalized))
+ end
if not iscached then
local upem = hbface:get_upem()
@@ -174,7 +276,7 @@ local function loadfont(spec)
local glyph = hbfont:get_nominal_glyph(uni)
if glyph then
characters[uni] = glyph
- nominals[glyph] = uni
+ nominals[glyph] = tointeger(uni)
end
end
@@ -224,12 +326,13 @@ local function loadfont(spec)
nominals = nominals,
unicodes = characters,
psname = hbface:get_name(hb.ot.NAME_ID_POSTSCRIPT_NAME),
- fullname = hbface:get_name(hb.ot.NAME_ID_FULL_NAME),
+ fullname = hbface:get_name(hb.ot.NAME_ID_FULL_NAME) .. varkey,
haspng = hbface:ot_color_has_png(),
loaded = {}, -- Cached loaded glyph data.
+ normalized = normalized,
}
- containers.write(facecache, key, cached)
+ containers.write(fontcache, key, cached)
end
cached.face = hbface
cached.font = hbfont
@@ -340,6 +443,7 @@ local function scalefont(data, spec)
hscale = upem,
vscale = upem,
buf_flags = harf_settings.default_buf_flags,
+ obj_repl = characters[0xFFFC] and 0xD800 or 0xFFFC,
},
specification = spec,
shared = {
@@ -349,6 +453,7 @@ local function scalefont(data, spec)
resources = {
unicodes = data.name_to_char,
},
+ streamprovider = data.normalized and (data.fonttype == 'opentype' and 1 or 3) or nil,
}
tfmdata.shared.processes = fonts.handlers.otf.setfeatures(tfmdata, features)
fonts.constructors.applymanipulators("otf", tfmdata, features, false)
@@ -391,7 +496,7 @@ fonts.readers.harf = function(spec)
val = (val and '+' or '-')..key
hb_features[#hb_features + 1] = hb.Feature.new(val)
elseif tonumber(val) then
- val = '+'..key..'='..tonumber(val) - 1
+ val = '+'..key..'='..tonumber(val)
hb_features[#hb_features + 1] = hb.Feature.new(val)
end
end
@@ -409,3 +514,36 @@ luatexbase.add_to_callback('find_truetype_file', function(name)
return find_file(name, 'truetype fonts')
or name:gsub('^harfloaded:', '')
end, 'luaotfload.harf.strip_prefix')
+
+local glyph_stream_data
+local glyph_stream_mapping, glyph_stream_mapping_inverse
+local extents_hbfont
+local cb = luatexbase.remove_from_callback('glyph_stream_provider', 'luaotfload.glyph_stream')
+luatexbase.add_to_callback('glyph_stream_provider', function(fid, cid, kind, ocid)
+ if cid == 0 then -- Always the first call for a font
+ glyph_stream_data, extents_hbfont = nil
+ collectgarbage()
+ local fontdir = font.getfont(fid)
+ if fontdir and fontdir.hb then
+ if kind == 3 then
+ glyph_stream_mapping = {[ocid] = cid}
+ glyph_stream_mapping_inverse = {[cid] = ocid}
+ extents_hbfont = fontdir.hb.shared.font
+ elseif kind == 2 then
+ glyph_stream_data = ttf_handler(fontdir.hb.shared.face, fontdir.hb.shared.font, glyph_stream_mapping, glyph_stream_mapping_inverse)
+ else
+ glyph_stream_data = cff2_handler(fontdir.hb.shared.face, fontdir.hb.shared.font)
+ end
+ end
+ end
+ if glyph_stream_data then
+ return glyph_stream_data(cid)
+ elseif extents_hbfont then
+ glyph_stream_mapping[ocid] = cid
+ glyph_stream_mapping_inverse[cid] = ocid
+ local extents = extents_hbfont:get_glyph_extents(ocid)
+ return extents.width, extents.x_bearing, extents.height, extents.y_bearing
+ else
+ return cb(fid, cid, kind, ocid)
+ end
+end, 'luaotfload.harf.glyphstream')
diff --git a/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua b/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua
index 1577aa7004..634da68786 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua
@@ -4,8 +4,8 @@
-----------------------------------------------------------------------
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-harf-plug",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
description = "luaotfload submodule / HarfBuzz shaping",
license = "GPL v2.0",
author = "Khaled Hosny, Marcel Krüger",
@@ -110,6 +110,11 @@ local endactual_p = "luaotfload_endactualtext"
local empty_table = {}
+local function is_empty_disc(n)
+ local pre, post, rep = getdisc(n)
+ return not pre and not post and not rep
+end
+
-- "Copy" properties as done by LuaTeX: Make old properties metatable
local function copytable(old)
local new = {}
@@ -174,6 +179,7 @@ local function itemize(head, fontid, direction)
local hbdata = fontdata and fontdata.hb
local spec = fontdata and fontdata.specification
local options = spec and spec.features.raw
+ local obj_repl = hbdata and hbdata.obj_repl
local runs, codes = {}, {}
local dirstack = {}
@@ -187,7 +193,7 @@ local function itemize(head, fontid, direction)
for n, id, subtype in traverse(head) do
if in_disc == n then in_disc = nil end
local disc
- local code = 0xFFFC -- OBJECT REPLACEMENT CHARACTER
+ local code = obj_repl -- OBJECT REPLACEMENT CHARACTER, substitute invalid surrogate if otherwise colliding with font glyph
local skip = lastskip
local props = properties[n]
@@ -205,7 +211,7 @@ local function itemize(head, fontid, direction)
elseif id == glue_t and subtype == spaceskip_t then
code = 0x0020 -- SPACE
elseif id == disc_t then
- if uses_font(n, fontid) then
+ if uses_font(n, fontid) or not lastskip and is_empty_disc(n) then
local _, _, rep, _, _, rep_tail = getdisc(n, true)
setfield(n, 'replace', nil)
local prev, next = getboth(n)
@@ -347,6 +353,7 @@ function shape(head, firstnode, run)
local options = spec.features.raw
local hbshared = hbdata.shared
local hbfont = hbshared.font
+ local obj_repl = hbdata.obj_repl
local lang = spec.language
local script = spec.script
@@ -430,7 +437,9 @@ function shape(head, firstnode, run)
end
-- Is this a safe breakpoint?
- if discs and ((not glyph) or codes[cluster] == 0x20 or codes[cluster+1] == 0x20 or codes[cluster+1] == 0xFFFC
+ if discs and ((not glyph)
+ or codes[cluster] == 0x20 or codes[cluster+1] == 0x20
+ or codes[cluster] == obj_repl or codes[cluster+1] == obj_repl
or not unsafetobreak(glyph)) then
-- Should we change the discretionary state?
local anchor_cluster, after_cluster = offset + discs.anchor_cluster, offset + discs.after_cluster
@@ -478,20 +487,20 @@ function shape(head, firstnode, run)
local precodes, postcodes, repcodes = {}, {}
table.move(codes, disc_cluster + 1, anchor_cluster, 1, precodes)
for n in traverse(pre) do
- precodes[#precodes + 1] = is_char(n, fontid) or 0xFFFC
+ precodes[#precodes + 1] = is_char(n, fontid) or obj_repl
end
for n in traverse(post) do
- postcodes[#postcodes + 1] = is_char(n, fontid) or 0xFFFC
+ postcodes[#postcodes + 1] = is_char(n, fontid) or obj_repl
end
table.move(codes, after_cluster + 1, cluster, #postcodes + 1, postcodes)
if saved_after then
repcodes = table.move(codes, disc_cluster + 1, cluster, 1, {})
table.move(codes, cluster + 1, #codes + cluster - disc_cluster, disc_cluster + 3)
- codes[disc_cluster + 1], codes[disc_cluster + 2] = 0xFFFC, 0xFFFC
+ codes[disc_cluster + 1], codes[disc_cluster + 2] = obj_repl, obj_repl
else
table.move(codes, cluster + 1, #codes + cluster - disc_cluster, disc_cluster + 2)
- codes[disc_cluster + 1] = 0xFFFC
+ codes[disc_cluster + 1] = obj_repl
end
do
@@ -535,7 +544,7 @@ function shape(head, firstnode, run)
post = makesub(run, postcodes, post),
cluster = disc_cluster,
nextcluster = disc_cluster + 1,
- codepoint = 0xFFFC,
+ codepoint = obj_repl,
}
if saved_after then
local next_disc = discs.next
@@ -550,10 +559,10 @@ function shape(head, firstnode, run)
local saved_anchor, saved_after = saved_anchor + saved_offset, saved_after + saved_offset
table.move(postcodes, 1, saved_anchor, 1, next_precodes)
for n in traverse(next_pre) do
- next_precodes[#next_precodes + 1] = is_char(n, fontid) or 0xFFFC
+ next_precodes[#next_precodes + 1] = is_char(n, fontid) or obj_repl
end
for n in traverse(next_post) do
- next_postcodes[#next_postcodes + 1] = is_char(n, fontid) or 0xFFFC
+ next_postcodes[#next_postcodes + 1] = is_char(n, fontid) or obj_repl
end
table.move(postcodes, saved_after + 1, #postcodes, #next_postcodes + 1, next_postcodes)
@@ -576,7 +585,7 @@ function shape(head, firstnode, run)
local saved_anchor = saved_anchor - disc_cluster
table.move(repcodes, 1, saved_anchor, 1, next_repcodes)
for n in traverse(next_rep) do
- next_repcodes[#next_repcodes + 1] = is_char(n, fontid) or 0xFFFC
+ next_repcodes[#next_repcodes + 1] = is_char(n, fontid) or obj_repl
end
local rep = glyphs[disc_glyph].replace.head
@@ -599,7 +608,7 @@ function shape(head, firstnode, run)
post = makesub(run, next_postcodes, next_post),
cluster = disc_cluster,
nextcluster = disc_cluster + 1,
- codepoint = 0xFFFC,
+ codepoint = obj_repl,
}
end
i = disc_glyph + 1
@@ -772,9 +781,15 @@ local function tonodes(head, node, run, glyphs)
nodeindex = glyph.cluster + 1
elseif nextcluster + 1 == nodeindex then -- Oops, we went too far
nodeindex = nodeindex - 1
- local new = inherit(glyph_t, getprev(node), lastprops)
- setfont(new, fontid)
- head, node = insertbefore(head, node, new)
+ if node then
+ local new = inherit(glyph_t, getprev(node), lastprops)
+ head, node = insertbefore(head, node, new)
+ else
+ node = tail(head)
+ local new = inherit(glyph_t, node, lastprops)
+ head, node = insertafter(head, node, new)
+ end
+ setfont(node, fontid)
end
local gid = glyph.codepoint
local char = nominals[gid] or gid_offset + gid
@@ -1134,6 +1149,8 @@ local function get_glyph_info(n)
local c = getchar(n)
if c == 0 then
return '^^@'
+ elseif c < 0 then -- These are left and right boundaries in ligature lists
+ return ''
elseif c < 0x110000 then
return utfchar(c)
else
diff --git a/macros/luatex/generic/luaotfload/luaotfload-harf-var-cff2.lua b/macros/luatex/generic/luaotfload/luaotfload-harf-var-cff2.lua
new file mode 100644
index 0000000000..9c05b7a6c7
--- /dev/null
+++ b/macros/luatex/generic/luaotfload/luaotfload-harf-var-cff2.lua
@@ -0,0 +1,442 @@
+-----------------------------------------------------------------------
+-- FILE: luaotfload-harf-var-cff2.lua
+-- DESCRIPTION: part of luaotfload / HarfBuzz / Parse and convert CFF2 tables
+-----------------------------------------------------------------------
+do
+ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
+ name = "luaotfload-harf-var-cff2",
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
+ description = "luaotfload submodule / CFF2 table processing",
+ license = "GPL v2.0",
+ author = "Marcel Krüger",
+ copyright = "Luaotfload Development Team",
+ }
+end
+
+local hb = assert(luaotfload.harfbuzz)
+local cff2 = hb.Tag.new'CFF2'
+local serialize = require'luaotfload-harf-var-t2-writer'
+
+local offsetfmt = ">I%i"
+local function parse_index(buf, i)
+ local count, offsize
+ count, offsize, i = string.unpack(">I4B", buf, i)
+ if count == 0 then return {}, i-1 end
+ local fmt = offsetfmt:format(offsize)
+ local offsets = {}
+ local dataoffset = i + offsize*count - 1
+ for j=1,count+1 do
+ offsets[j], i = string.unpack(fmt, buf, i)
+ end
+ for j=1,count+1 do
+ offsets[j] = offsets[j] + i - 1
+ end
+ return offsets, offsets[#offsets]
+end
+
+local real_mapping = { [0] = '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '.', 'E', 'E-', nil, '-', nil}
+local function parse_real(cs, offset)
+ local c = cs:byte(offset)
+ if not c then return offset end
+ local c1, c2 = real_mapping[c>>4], real_mapping[c&0xF]
+ if not c1 or not c2 then
+ return c1 or offset, c1 and offset
+ else
+ return c1, c2, parse_real(cs, offset+1) --Warning: This is not a tail-call,
+ -- so we are affected by the stack limit. On the other hand, as long as
+ -- there are less than ~50 bytes we should be safe.
+ end
+end
+
+local function get_number(result)
+ if #result ~= 1 then
+ print(require'inspect'(result))
+ end
+ assert(#result == 1)
+ local num = result[1]
+ result[1] = nil
+ return num
+end
+
+local function get_bool(result)
+ return get_number(result) == 1
+end
+
+local function get_array(result)
+ local arr = table.move(result, 1, #result, 1, {})
+ for i=1,#result do result[i] = nil end
+ return arr
+end
+
+local function get_delta(result)
+ local arr = get_array(result)
+ local last = 0
+ for i=1,#arr do
+ arr[i] = arr[i]+last
+ last = arr[i]
+ end
+ return arr
+end
+
+local function get_private(result)
+ local arr = get_array(result)
+ assert(#arr == 2)
+ return arr
+end
+
+local function do_blend(result, vstore)
+ if not vstore then
+ error'blend operator only allowed in Private disctionary of variable fonts'
+ end
+ local vsindex = (result.vsindex or 0) + 1
+ local factors = vstore[vsindex]
+ local n = result[#result]
+ local k = #factors
+ local before = #result - 1 - n*(k+1)
+ for i = 1, n do
+ local val = result[before + i]
+ for j = 1, k do
+ val = val + factors[j] * result[before + n + (i-1) * k + j]
+ end
+ result[before + i] = math.floor(val + .5)
+ end
+ for i = before + n + 1, #result do
+ result[i] = nil
+ end
+ return arr
+end
+
+local function apply_matrix(m, x, y)
+ return (m[1] * x + m[3] * y + m[5])*1000, (m[2] * x + m[4] * y + m[6])*1000
+end
+
+local operators = {
+ [6] = {'BlueValues', get_delta},
+ [7] = {'OtherBlues', get_delta},
+ [8] = {'FamilyBlues', get_delta},
+ [9] = {'FamilyOtherBlues', get_delta},
+ [10] = {'StdHW', get_number},
+ [11] = {'StdVW', get_number},
+ [17] = {'CharStrings', get_number},
+ [18] = {'Private', get_private},
+ [19] = {'Subrs', get_number},
+ [22] = {'vsindex', get_number},
+ [23] = {'blend', do_blend},
+ [24] = {'vstore', get_number},
+ [-8] = {'FontMatrix', get_array},
+[-10] = {'BlueScale', get_number},
+[-11] = {'BlueShift', get_number},
+[-12] = {'BlueFuzz', get_number},
+[-13] = {'StemSnapH', get_delta},
+[-14] = {'StemSnapV', get_delta},
+[-15] = {'ForceBold', get_bool}, -- ???
+[-18] = {'LanguageGroup', get_number},
+[-19] = {'ExpansionFactor', get_number},
+[-20] = {'initialRandomSeed', get_number}, -- ???
+[-37] = {'FDArray', get_number},
+[-38] = {'FDSelect', get_number},
+}
+local function parse_dict(buf, i, j, vstore)
+ result = {}
+ while i<=j do
+ local cmd = buf:byte(i)
+ if cmd == 29 then
+ result[#result+1] = string.unpack(">i4", buf:sub(i+1, i+4))
+ i = i+4
+ elseif cmd == 28 then
+ result[#result+1] = string.unpack(">i2", buf:sub(i+1, i+2))
+ i = i+2
+ elseif cmd >= 251 then -- Actually "and cmd ~= 255", but 255 is reserved
+ result[#result+1] = -((cmd-251)*256)-string.byte(buf, i+1)-108
+ i = i+1
+ elseif cmd >= 247 then
+ result[#result+1] = (cmd-247)*256+string.byte(buf, i+1)+108
+ i = i+1
+ elseif cmd >= 32 then
+ result[#result+1] = cmd-139
+ elseif cmd == 30 then -- 31 is reserved again
+ local real = {parse_real(buf, i+1)}
+ i = real[#real]
+ real[#real] = nil
+ result[#result+1] = tonumber(table.concat(real))
+ else
+ if cmd == 12 then
+ i = i+1
+ cmd = -buf:byte(i)-1
+ end
+ local op = operators[cmd]
+ if not op then error[[Unknown CFF operator]] end
+ result[op[1]] = op[2](result, vstore)
+ end
+ i = i+1
+ end
+ return result
+end
+
+local function parse_charstring(buf, start, after, globalsubrs, subrs, result)
+ local lastresult = result[#result]
+ while start ~= after do
+ local cmd = buf:byte(start)
+ if cmd == 28 then
+ lastresult[#lastresult+1] = string.unpack(">i2", buf:sub(start+1, start+2))
+ start = start+2
+ elseif cmd == 255 then
+ lastresult[#lastresult+1] = string.unpack(">i4", buf:sub(start+1, start+4))/0x10000
+ start = start+4
+ elseif cmd >= 251 then
+ lastresult[#lastresult+1] = -((cmd-251)*256)-string.byte(buf, start+1)-108
+ start = start+1
+ elseif cmd >= 247 then
+ lastresult[#lastresult+1] = (cmd-247)*256+string.byte(buf, start+1)+108
+ start = start+1
+ elseif cmd >= 32 then
+ lastresult[#lastresult+1] = cmd-139
+ elseif cmd == 10 then
+ local idx = lastresult[#lastresult]+subrs.bias
+ local sub_start = subrs[idx]
+ local sub_stop = subrs[idx+1]
+ lastresult[#lastresult] = nil
+ parse_charstring(buf, sub_start, sub_stop, globalsubrs, subrs, result)
+ lastresult = result[#result]
+ elseif cmd == 29 then
+ local idx = lastresult[#lastresult]+globalsubrs.bias
+ local sub_start = globalsubrs[idx]
+ local sub_stop = globalsubrs[idx+1]
+ lastresult[#lastresult] = nil
+ parse_charstring(buf, sub_start, sub_stop, globalsubrs, subrs, result)
+ lastresult = result[#result]
+ elseif cmd == 11 then
+ break -- We do not keep subroutines, so drop returns and continue with the outer commands
+ elseif cmd == 15 then -- vsindex
+ assert(#lastresult == 2)
+ result.factors = result.vstore[lastresult[2] + 1]
+ lastresult[2] = nil
+ elseif cmd == 16 then -- blend
+ local factors = result.factors
+ if not factors then
+ error'blend operator outside of variable font or with invalid vsindex'
+ end
+ local n = lastresult[#lastresult]
+ local k = #factors
+ local before = #lastresult - 1 - n*(k+1)
+ for i = 1, n do
+ local val = lastresult[before + i]
+ for j = 1, k do
+ val = val + factors[j] * lastresult[before + n + (i-1) * k + j]
+ end
+ lastresult[before + i] = math.floor(val + .5)
+ end
+ for i = before + n + 1, #lastresult do
+ lastresult[i] = nil
+ end
+ elseif cmd == 12 then
+ start = start+1
+ cmd = buf:byte(start)
+ lastresult[1] = -cmd-1
+ lastresult = {false}
+ result[#result+1] = lastresult
+ elseif cmd == 19 or cmd == 20 then
+ if #result == 1 then
+ lastresult = {}
+ result[#result+1] = lastresult
+ end
+ lastresult[1] = cmd
+ local newi = start+(result.stemcount+7)//8
+ lastresult[2] = buf:sub(start+1, newi)
+ start = newi
+ else
+ if cmd == 21 and #result == 1 then
+ table.insert(result, 1, {false})
+ if #lastresult == 4 then
+ result[1][2] = lastresult[2]
+ table.remove(lastresult, 2)
+ end
+ elseif (cmd == 4 or cmd == 22) and #result == 1 then
+ table.insert(result, 1, {false})
+ if #lastresult == 3 then
+ result[1][2] = lastresult[2]
+ table.remove(lastresult, 2)
+ end
+ elseif cmd == 14 and #result == 1 then
+ table.insert(result, 1, {false})
+ if #lastresult == 2 or #lastresult == 6 then
+ result[1][2] = lastresult[2]
+ table.remove(lastresult, 2)
+ end
+ elseif cmd == 1 or cmd == 3 or cmd == 18 or cmd == 23 then
+ if #result == 1 then
+ table.insert(result, 1, {false})
+ if #lastresult % 2 == 0 then
+ result[1][2] = lastresult[2]
+ table.remove(lastresult, 2)
+ end
+ end
+ result.stemcount = result.stemcount + #lastresult//2
+ end
+ lastresult[1] = cmd
+ lastresult = {false}
+ result[#result+1] = lastresult
+ end
+ start = start+1
+ end
+ return result
+end
+
+local function parse_fdselect(buf, offset, CharStrings)
+ local format
+ format, offset = string.unpack(">B", buf, offset)
+ if format == 0 then
+ for i=0,#CharStrings-1 do
+ local code
+ code, offset = string.unpack(">B", buf, offset)
+ CharStrings[i][3] = code + 1
+ end -- Reimplement with string.byte
+ elseif format == 3 then
+ local count, last
+ count, offset = string.unpack(">I2", buf, offset)
+ for i=1,count do
+ local first, code, after = string.unpack(">I2BI2", buf, offset)
+ for j=first, after-1 do
+ CharStrings[j][3] = code + 1
+ end
+ offset = offset + 3
+ end
+ elseif format == 4 then
+ local count, last
+ count, offset = string.unpack(">I4", buf, offset)
+ for i=1,count do
+ local first, code, after = string.unpack(">I4I2I4", buf, offset)
+ for j=first, after-1 do
+ CharStrings[j][3] = code + 1
+ end
+ offset = offset + 6
+ end
+ else
+ error[[Invalid FDSelect format]]
+ end
+end
+
+local function parse_vstore(buf, offset, variation)
+ local size, format, region_list_off, item_variation_count, off = string.unpack(">I2I2I4I2", buf, offset)
+ if format ~= 1 then
+ error'Unsupported vstore format'
+ end
+ offset = offset + 2 -- Skip the size
+ region_list_off = offset + region_list_off
+
+ local axis_count, region_count
+ axis_count, region_count, region_list_off = string.unpack(">I2I2", buf, region_list_off)
+
+ local variation_regions = {}
+ for i = 1, region_count do
+ local factor = 1
+ for j = 1, axis_count do
+ local start, peak, stop
+ start, peak, stop, region_list_off = string.unpack(">i2i2i2", buf, region_list_off)
+ local coord = variation[j]
+ if peak == 0 then -- Skip
+ elseif peak == coord then
+ -- factor = factor * 1
+ elseif coord <= start or coord >= stop then
+ factor = 0
+ break
+ elseif coord < peak then
+ factor = factor * ((coord-start) / (peak-start))
+ else--if coord > peak then
+ factor = factor * ((stop-coord) / (stop-peak))
+ end
+ end
+ variation_regions[i] = factor
+ end
+
+ local variation_data = {}
+ for i = 1, item_variation_count do
+ local item_off
+ item_off, off = string.unpack(">I4", buf, off)
+ local i_count, short_count, region_count
+ i_count, short_count, region_count, item_off = string.unpack(">I2I2I2", buf, item_off + offset)
+ if i_count ~= 0 or short_count ~= 0 then
+ error'Unexpected variation items in CFF2 table'
+ end
+ local factors = {}
+ for j = 1, region_count do
+ local region
+ region, item_off = string.unpack(">I2", buf, item_off)
+ factors[j] = variation_regions[region+1]
+ end
+ variation_data[i] = factors
+ end
+ return variation_data
+end
+
+function parse_cff2(buf, i0, coords)
+ local fontid = 1
+ local major, minor, hdrSize, topSize = string.unpack(">BBBH", buf, i0)
+ if major ~= 2 then error[[Unsupported CFF version]] end
+ local i = i0 + hdrSize
+ local top = parse_dict(buf, i, i + topSize - 1)
+ i = i + topSize
+ local globalsubrs
+ globalsubrs, i = parse_index(buf, i)
+ globalsubrs.bias = #globalsubrs-1 < 1240 and 108 or #globalsubrs-1 < 33900 and 1132 or 32769
+ top.GlobalSubrs = globalsubrs
+ local CharStrings = parse_index(buf, i0+top.CharStrings)
+ for i=1,#CharStrings-1 do
+ CharStrings[i-1] = {CharStrings[i], CharStrings[i+1]-1}
+ end
+ CharStrings[#CharStrings] = nil
+ CharStrings[#CharStrings] = nil
+ local fonts = parse_index(buf, i0+top.FDArray)
+ top.FDArray = nil
+ top.vstore = parse_vstore(buf, i0 + top.vstore, coords)
+ local privates = {}
+ top.Privates = privates
+ for i=1,#fonts-1 do
+ local font = fonts[i]
+ local fontdir = parse_dict(buf, fonts[i], fonts[i+1]-1)
+ privates[i] = parse_dict(buf, i0+fontdir.Private[2], i0+fontdir.Private[2]+fontdir.Private[1]-1, top.vstore)
+ local subrs = privates[i].Subrs
+ if subrs then
+ subrs = parse_index(buf, i0+fontdir.Private[2]+subrs)
+ subrs.bias = #subrs-1 < 1240 and 108 or #subrs-1 < 33900 and 1132 or 32769
+ privates[i].Subrs = subrs
+ end
+ end
+ if top.FDSelect then
+ parse_fdselect(buf, i0+top.FDSelect, CharStrings)
+ else
+ for i=0,#CharStrings-1 do
+ CharStrings[i][3] = 1
+ end
+ end
+ top.CharStrings = CharStrings
+ local bbox
+ if top.FontMatrix then
+ local x0, y0 = apply_matrix(top.FontMatrix, top.FontBBox[1], top.FontBBox[2])
+ local x1, y1 = apply_matrix(top.FontMatrix, top.FontBBox[3], top.FontBBox[4])
+ bbox = {x0, y0, x1, y1}
+ else
+ bbox = top.FontBBox
+ end
+ return top, bbox
+end
+
+local function parse_glyph(buffer, top, gid)
+ local cs = top.CharStrings[gid]
+ local Private = top.Privates[cs[3]]
+ return parse_charstring(buffer, cs[1], cs[2] + 1,
+ top.GlobalSubrs, Private.Subrs,
+ {{false}, stemcount = 0, vstore = top.vstore, factors = top.vstore and top.vstore[(Private.vsindex or 0) + 1]})
+end
+
+return function(face, font)
+ local data = face:get_table(cff2):get_data()
+ local content = parse_cff2(data, 1, {font:get_var_coords_normalized()})
+ return function(gid)
+ local glyph = parse_glyph(data, content, gid)
+ glyph[1][2] = font:get_glyph_h_advance(gid)
+ return serialize(glyph)
+ end
+end
diff --git a/macros/luatex/generic/luaotfload/luaotfload-harf-var-t2-writer.lua b/macros/luatex/generic/luaotfload/luaotfload-harf-var-t2-writer.lua
new file mode 100644
index 0000000000..f10bf6d860
--- /dev/null
+++ b/macros/luatex/generic/luaotfload/luaotfload-harf-var-t2-writer.lua
@@ -0,0 +1,120 @@
+-----------------------------------------------------------------------
+-- FILE: luaotfload-harf-var-t2-writer.lua
+-- DESCRIPTION: part of luaotfload / HarfBuzz / Serialize Type 2 charstrings
+-----------------------------------------------------------------------
+do
+ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
+ name = "luaotfload-harf-var-t2-writer",
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
+ description = "luaotfload submodule / Type 2 charstring writer",
+ license = "GPL v2.0",
+ author = "Marcel Krüger",
+ copyright = "Luaotfload Development Team",
+ }
+end
+
+local pack = string.pack
+local function numbertot2(n)
+ if math.abs(n) > 2^15 then
+ error[[Number too big]]
+ end
+ local num = math.floor(n + .5)
+ if n ~= 0 and math.abs((num-n)/n) > 0.001 then
+ num = math.floor(n * 2^16 + 0.5)
+ return pack(">Bi4", 255, math.floor(n * 2^16 + 0.5))
+ elseif num >= -107 and num <= 107 then
+ return string.char(num + 139)
+ elseif num >= 108 and num <= 1131 then
+ return pack(">I2", num+0xF694) -- -108+(247*0x100)
+ elseif num >= -1131 and num <= -108 then
+ return pack(">I2", -num+0xFA94) -- -108+(251*0x100)
+ else
+ return pack(">Bi2", 28, num)
+ end
+end
+local function convert_cs(cs, upem)
+ local cs_parts = {}
+ local function add(cmd, first, ...)
+ if cmd == 19 or cmd == 20 then
+ cs_parts[#cs_parts+1] = string.char(cmd)
+ cs_parts[#cs_parts+1] = first
+ return
+ end
+ if first then
+ cs_parts[#cs_parts+1] = numbertot2(first*upem/1000)
+ return add(cmd, ...)
+ end
+ if cmd then
+ if cmd < 0 then
+ cs_parts[#cs_parts+1] = string.char(12, -cmd-1)
+ else
+ cs_parts[#cs_parts+1] = string.char(cmd)
+ end
+ end
+ end
+ for _, args in ipairs(cs) do
+ if args then
+ local cmd = args[1]
+ local height = #args - 1
+ local i = 2
+ while height > 48 do
+ -- Special cases: hhcurveto, vvcurveto, rcurveline, rlinecurve
+ -- hhvurveto/vvcurveto: In odd argument case, the first argument must be
+ -- followed by a multiple of four arguments.
+ if cmd == 27 and i == 2 and height % 4 == 1 then -- hhcurveto
+ add(cmd, table.unpack(args, i, i + 44))
+ height = height - 45
+ i = i + 45
+ elseif cmd == 26 and i == 2 and height % 4 == 1 then -- vvcurveto
+ add(cmd, table.unpack(args, i, i + 44))
+ height = height - 45
+ i = i + 45
+ -- rcurveline/rlinecurve: At least 8 arguments must be preserved, all previous instances
+ -- need different commands
+ elseif cmd == 24 then -- rcurveline
+ height = height - 48
+ local count
+ if height >= 8 then
+ count = 48
+ else
+ count = 48 - 8 + height
+ height = 8
+ end
+ add(8, table.unpack(args, i, i + count - 1)) -- 8 = rrcurveto
+ i = i + count
+ elseif cmd == 25 then -- rlinecurve
+ height = height - 48
+ local count
+ if height >= 8 then
+ count = 48
+ else
+ count = 48 - 8 + height
+ height = 8
+ end
+ add(5, table.unpack(args, i, i + count - 1)) -- 5 = rlineto
+ i = i + count
+ else -- Some commands have an optional last argument which can appear after multiple of 48 arguments,
+ -- so it's safer to never leave a element alone in a line.
+ height = height - 48
+ local count
+ if height > 1 then
+ count = 48
+ else
+ -- assert(height == 1)
+ count = 24--48 - 25 + height
+ height = 25
+ end
+ add(cmd, table.unpack(args, i, i + count - 1))
+ i = i + count
+ end
+ end
+ add(cmd, table.unpack(args, i))
+ end
+ end
+ return table.concat(cs_parts)
+end
+
+return function(cs, upem)
+ return convert_cs(cs, upem or 1000)
+end
diff --git a/macros/luatex/generic/luaotfload/luaotfload-harf-var-ttf.lua b/macros/luatex/generic/luaotfload/luaotfload-harf-var-ttf.lua
new file mode 100644
index 0000000000..80cf6768ae
--- /dev/null
+++ b/macros/luatex/generic/luaotfload/luaotfload-harf-var-ttf.lua
@@ -0,0 +1,564 @@
+-----------------------------------------------------------------------
+-- FILE: luaotfload-harf-var-ttf.lua
+-- DESCRIPTION: part of luaotfload / HarfBuzz / Parse and apply gvar tables
+-----------------------------------------------------------------------
+do
+ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
+ name = "luaotfload-harf-var-ttf",
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
+ description = "luaotfload submodule / gvar table processing",
+ license = "GPL v2.0",
+ author = "Marcel Krüger",
+ copyright = "Luaotfload Development Team",
+ }
+end
+
+local hb = assert(luaotfload.harfbuzz)
+local gvar_tag = hb.Tag.new'gvar'
+local glyf_tag = hb.Tag.new'glyf'
+local loca_tag = hb.Tag.new'loca'
+
+local function read_tuple(data, offset, axes_count)
+ local tuple = lua.newtable(axes_count, 0)
+ for i=1, axes_count do
+ tuple[i] = sio.readinteger2(data, offset + 2*i-2)
+ end
+ return tuple, offset + 2*axes_count
+end
+
+local function read_gvar(data)
+ if 1 ~= sio.readcardinal2(data, 1) then
+ return nil, 'Unknown gvar version'
+ end
+ local axes_count = sio.readcardinal2(data, 5)
+ local shared_count = sio.readcardinal2(data, 7)
+ local shared_offset = sio.readcardinal4(data, 9) + 1
+ local glyph_count = sio.readcardinal2(data, 13)
+ local flags = sio.readcardinal2(data, 15)
+ local variation_offset = sio.readcardinal4(data, 17) + 1
+ local variation_offsets = sio.readcardinaltable(data, 21, glyph_count+1, flags & 1 == 1 and 4 or 2)
+ if flags & 1 == 1 then
+ for i = 1, glyph_count+1 do
+ variation_offsets[i] = variation_offset + variation_offsets[i]
+ end
+ else
+ for i = 1, glyph_count+1 do
+ variation_offsets[i] = variation_offset + 2*variation_offsets[i]
+ end
+ end
+
+ local shared = lua.newtable(shared_count, 0)
+ for i=1, shared_count do
+ shared[i], shared_offset = read_tuple(data, shared_offset, axes_count)
+ end
+
+ local glyph_variation = lua.newtable(glyph_count, 0)
+ for i = 1, glyph_count do
+ local offset = variation_offsets[i]
+ if variation_offsets[i+1] ~= offset then
+ local tuple_variations = sio.readcardinal2(data, offset)
+ local flags = tuple_variations >> 12
+ tuple_variations = tuple_variations & 0xFFF
+ local data_offset = offset + sio.readcardinal2(data, offset + 2)
+
+ local headers = lua.newtable(tuple_variations, 0)
+ offset = offset + 4
+ for j=1, tuple_variations do
+ local data_size = sio.readcardinal2(data, offset)
+ local tuple_index = sio.readcardinal2(data, offset + 2)
+ local peak, start_inter, end_inter
+ offset = offset + 4
+ if tuple_index & 0x8000 == 0x8000 then
+ peak, offset = read_tuple(data, offset, axes_count)
+ else
+ peak = shared[(tuple_index & 0xFFF) + 1]
+ end
+ if tuple_index & 0x4000 == 0x4000 then
+ start_inter, offset = read_tuple(data, offset, axes_count)
+ end_inter, offset = read_tuple(data, offset, axes_count)
+ end
+ headers[j] = {
+ size = data_size,
+ peak = peak,
+ start_inter = start_inter,
+ end_inter = end_inter,
+ private_points = tuple_index & 0x2000 == 0x2000 or nil,
+ }
+ end
+ glyph_variation[i] = {
+ offset = data_offset,
+ shared_points = flags & 0x8 == 0x8 or nil,
+ headers = headers,
+ }
+ end
+ end
+ return glyph_variation
+end
+
+local function read_loca(face)
+ local data = face:get_table(loca_tag):get_data()
+ local count = face:get_glyph_count() + 1
+ if #data == count * 2 then
+ local result = sio.readcardinaltable(data, 1, count, 2)
+ for i=1, count do
+ result[i] = 2 * result[i]
+ end
+ return result
+ elseif #data == count * 4 then
+ return sio.readcardinaltable(data, 1, count, 4)
+ else
+ return nil, 'Invalid loca format'
+ end
+end
+
+local function parse_glyf(loca, glyf, gid)
+ local offset = loca[gid + 1] + 1
+ if loca[gid + 2] + 1 == offset then return end
+ local num_contours = sio.readinteger2(glyf, offset)
+ -- local xmin = sio.readinteger2(glyf, offset + 2)
+ -- local ymin = sio.readinteger2(glyf, offset + 4)
+ -- local xmax = sio.readinteger2(glyf, offset + 6)
+ -- local ymax = sio.readinteger2(glyf, offset + 8)
+ if num_contours < 0 then
+ -- composite
+ local xmin = sio.readinteger2(glyf, offset + 2)
+ local ymin = sio.readinteger2(glyf, offset + 4)
+ local xmax = sio.readinteger2(glyf, offset + 6)
+ local ymax = sio.readinteger2(glyf, offset + 8)
+ local components = { -- FIXME: These are likely incorrect
+ xmin = xmin,
+ ymin = ymin,
+ xmax = xmax,
+ ymax = ymax,
+ }
+ local flags
+ offset = offset + 10
+ repeat
+ local component = {}
+ flags = sio.readcardinal2(glyf, offset)
+ component.glyph = sio.readcardinal2(glyf, offset + 2)
+ local payload_length
+ if flags & 0x2 == 0x2 then
+ if flags & 0x1 == 0x1 then
+ component.x = sio.readinteger2(glyf, offset + 4)
+ component.y = sio.readinteger2(glyf, offset + 6)
+ offset = offset + 8
+ else
+ component.x = sio.readinteger1(glyf, offset + 4)
+ component.y = sio.readinteger1(glyf, offset + 5)
+ offset = offset + 6
+ end
+ payload_length = 0
+ else
+ offset = offset + 4
+ if flags & 0x1 == 0x1 then
+ payload_length = 4
+ else
+ payload_length = 2
+ end
+ end
+ if flags & 0x8 == 0x8 then
+ payload_length = payload_length + 2
+ elseif flags & 0x40 == 0x40 then
+ payload_length = payload_length + 4
+ elseif flags & 0x80 == 0x80 then
+ payload_length = payload_length + 8
+ end
+ if flags & 0x120 == 0x100 then -- Only applies to the last character
+ payload_length = payload_length + 2 + sio.readcardinal2(offset + payload_length)
+ end
+ component.flags = flags
+ component.payload = glyf:sub(offset, offset + payload_length - 1)
+ components[#components+1] = component
+ until flags & 0x20 == 0
+ return components
+ else
+ local end_contours = sio.readcardinaltable(glyf, offset+10, num_contours, 2)
+ offset = offset + 10 + num_contours * 2
+ local instruction_length = sio.readcardinal2(glyf, offset)
+ local instructions = glyf:sub(offset+2, offset+1+instruction_length)
+ offset = offset+2+instruction_length
+ local total_points = end_contours[num_contours] + 1
+ local points = lua.newtable(total_points, 2)
+ do
+ local i = 1
+ while i <= total_points do
+ local flags = sio.readcardinal1(glyf, offset)
+ offset = offset + 1
+ local count = 0
+ if flags & 0x8 == 0x8 then
+ count = sio.readcardinal1(glyf, offset)
+ offset = offset + 1
+ end
+ for j=i, i + count do
+ points[j] = {flags = flags}
+ end
+ i = i + 1 + count
+ end
+ end
+ do
+ local last = 0
+ for i=1, total_points do
+ local point = points[i]
+ local flags = point.flags
+ local value
+ if flags & 0x2 == 0x2 then -- short
+ value = sio.readcardinal1(glyf, offset)
+ offset = offset + 1
+ if flags & 0x10 == 0 then
+ value = -value
+ end
+ elseif flags & 0x10 == 0 then
+ value = sio.readinteger2(glyf, offset)
+ offset = offset + 2
+ else
+ value = 0
+ end
+ last = last + value
+ point.x = last
+ end
+ last = 0
+ for i=1, total_points do
+ local point = points[i]
+ local flags = point.flags
+ local value
+ if flags & 0x4 == 0x4 then -- short
+ value = sio.readcardinal1(glyf, offset)
+ offset = offset + 1
+ if flags & 0x20 == 0 then
+ value = -value
+ end
+ elseif flags & 0x20 == 0 then
+ value = sio.readinteger2(glyf, offset)
+ offset = offset + 2
+ else
+ value = 0
+ end
+ last = last + value
+ point.y = last
+ point.flags = flags & 0xC1 -- Discard all flags we aready used
+ end
+ -- assert (i == total_points)
+ end
+ points.contours = end_contours
+ points.instructions = instructions
+ return points
+ end
+end
+
+local function serialize_glyf(points, map)
+ local contours = points.contours
+ if points.contours then
+ local flagdata, xdata, ydata = {}, {}, {}
+ local last_flags, last_x, last_y = 0x100 -- Impossible flag to avoid triggering a repeated flag in the first step
+ local xmin, ymin, xmax, ymax
+ for i=1, #points do
+ local point = points[i]
+ local flags, x, y = point.flags, math.floor(point.x + .5), math.floor(point.y + .5)
+ xmin = xmin and xmin < x and xmin or x
+ xmax = xmax and xmax > x and xmax or x
+ ymin = ymin and ymin < y and ymin or y
+ ymax = ymax and ymax > y and ymax or y
+ x, last_x = x - (last_x or 0), x
+ if x == 0 then
+ flags = flags | 0x10
+ elseif x < 0x100 and x > -0x100 then
+ if x < 0 then
+ x = -x
+ flags = flags | 0x2
+ else
+ flags = flags | 0x12
+ end
+ xdata[#xdata+1] = x
+ else
+ if x > 0x7FFF then
+ x = 0x7FFF
+ elseif x < -0x8000 then
+ x = -0x8000
+ end
+ if x < 0 then
+ x = x + 0x10000
+ end
+ xdata[#xdata+1] = x >> 8
+ xdata[#xdata+1] = x & 0xFF
+ end
+ y, last_y = y - (last_y or 0), y
+ if y == 0 then
+ flags = flags | 0x20
+ elseif y < 0x100 and y > -0x100 then
+ if y < 0 then
+ y = -y
+ flags = flags | 0x4
+ else
+ flags = flags | 0x24
+ end
+ ydata[#ydata+1] = y
+ else
+ if y > 0x7FFF then
+ y = 0x7FFF
+ elseif y < -0x8000 then
+ y = -0x8000
+ end
+ if y < 0 then
+ y = y + 0x10000
+ end
+ ydata[#ydata+1] = y >> 8
+ ydata[#ydata+1] = y & 0xFF
+ end
+ if flags == last_flags & 0x1F7 then
+ if last_flags & 0x8 == 0x8 then
+ flagdata[#flagdata] = flagdata[#flagdata] + 1
+ else
+ last_flags = last_flags | 0x8
+ flagdata[#flagdata] = last_flags
+ flagdata[#flagdata+1] = 1
+ end
+ else
+ last_flags = flags
+ flagdata[#flagdata+1] = last_flags
+ end
+ end
+ local header = string.pack(">i2i2i2i2i2" .. string.rep('I2', #contours), #contours, xmin, ymin, xmax, ymax, table.unpack(contours))
+ return header .. string.pack(">s2", points.instructions) .. string.char(table.unpack(flagdata)) .. string.char(table.unpack(xdata)) .. string.char(table.unpack(ydata))
+ else
+ local result = string.pack(">i2i2i2i2i2", -1, points.xmin, points.ymin, points.xmax, points.ymax)
+ for i = 1, #points do
+ local component = points[i]
+ local x, y = component.x, component.y
+ x = x and math.floor(x + .5)
+ y = y and math.floor(y + .5)
+ result = result
+ .. string.pack(component.flags & 0x2 == 0 and '>I2I2'
+ or component.flags & 0x1 == 0x1 and '>I2I2i2i2'
+ or '>I2I2i1i1',
+ component.flags, map[component.glyph], x, y)
+ .. component.payload
+ end
+ return result
+ end
+end
+
+local function read_points(gvar_data, offset)
+ local point_count = sio.readcardinal1(gvar_data, offset)
+ offset = offset + 1
+ if point_count == 0 then
+ return true, offset
+ end
+ if point_count & 0x80 ~= 0 then
+ point_count = ((point_count & 0x7F) << 8) | sio.readcardinal1(gvar_data, suboffset)
+ offset = offset + 1
+ end
+ local points = lua.newtable(point_count, 0)
+ local i, last = 1, 1
+ while i <= point_count do
+ local control = sio.readcardinal1(gvar_data, offset)
+ offset = offset + 1
+ local count = (control & 0x7F) + 1
+ local size = control & 0x80 == 0x80 and 2 or 1
+ local read = size == 2 and sio.readcardinal2 or sio.readcardinal1
+ for j=0, count - 1 do
+ last = last + read(gvar_data, offset + j * size)
+ points[i + j] = last
+ end
+ i, offset = i + count, offset + size * count
+ end
+ return points, offset
+end
+
+local function read_deltas(gvar_data, offset, count)
+ local deltas = lua.newtable(count, 0)
+ local i = 1
+ while i <= count do
+ local control = sio.readcardinal1(gvar_data, offset)
+ offset = offset + 1
+ local length = (control & 0x3F) + 1
+ if control & 0x80 == 0x80 then
+ for j=0, length - 1 do
+ deltas[i + j] = 0
+ end
+ else
+ local size = control & 0x40 == 0x40 and 2 or 1
+ local read = size == 2 and sio.readinteger2 or sio.readinteger1
+ for j=0, length - 1 do
+ deltas[i + j] = read(gvar_data, offset + j * size)
+ end
+ offset = offset + size * length
+ end
+ i = i + length
+ end
+ return deltas, offset
+end
+
+local function interpolate_glyf(loca, gvar_index, gvar, glyf, gid, coords, map)
+ local var = gvar_index[gid+1]
+ if not var then
+ local start = loca[gid+1] + 1
+ local stop = loca[gid+2]
+ return glyf:sub(start, stop)
+ end
+ local points = parse_glyf(loca, glyf, gid)
+ if not points then return '' end
+ local offset = var.offset
+ local shared_points
+ if var.shared_points then
+ shared_points, offset = read_points(gvar, offset)
+ end
+ for i=1, #var.headers do
+ local header = var.headers[i]
+ local size = header.size
+ local factor = 1
+ local start, peak, stop = header.start_inter, header.peak, header.end_inter
+ for j = 1, #coords do
+ local coord = coords[j]
+ local peak = peak[j]
+ local start = start and start[j] or peak < 0 and peak or 0
+ local stop = stop and stop[j] or peak > 0 and peak or 0
+ if peak == 0 then -- Skip
+ elseif peak == coord then
+ -- factor = factor * 1
+ elseif coord <= start or coord >= stop then
+ factor = 0
+ break
+ elseif coord < peak then
+ factor = factor * ((coord-start) / (peak-start))
+ else--if coord > peak then
+ factor = factor * ((stop-coord) / (stop-peak))
+ end
+ end
+ if factor ~= 0 then
+ local base_points, suboffset
+ if header.private_points then
+ base_points, suboffset = read_points(gvar, offset)
+ else
+ base_points, suboffset = shared_points, offset
+ end
+ local count = base_points == true and #points + 4 or #base_points
+ local x_deltas, y_deltas
+ x_deltas, suboffset = read_deltas(gvar, suboffset, count)
+ y_deltas, suboffset = read_deltas(gvar, suboffset, count)
+ local contours = points.contours
+ if contours then
+ if base_points == true then
+ for i=1, #points do
+ local point = points[i]
+ point.x = point.x + factor * x_deltas[i]
+ point.y = point.y + factor * y_deltas[i]
+ end
+ else
+ local contour = 1
+ local last, last_x, last_y, last_dx, last_dy
+ local first, first_x, first_y, first_dx, first_dy
+ local cur = 1
+ local skip = base_points[1] > contours[1] + 1
+ local n_points = #points
+ for i = 1, n_points do
+ if i == contours[contour] + 2 then
+ contour = contour + 1
+ last_x, last_y, last_dx, last_dy = nil
+ first_x, first_y, first_dx, first_dy = nil
+ skip = (base_points[cur] or n_points + 1) > contours[contour] + 1
+ end
+ if not skip then
+ local point = points[i]
+ local this_x, this_y = point.x, point.y
+ if base_points[cur] == i then
+ repeat
+ last_x, last_y = this_x, this_y
+ last_dx, last_dy = x_deltas[cur], y_deltas[cur]
+ if not first_x then
+ first_x, first_y, first_dx, first_dy = last_x, last_y, last_dx, last_dy
+ end
+ point.x = last_x + factor * last_dx
+ point.y = last_y + factor * last_dy
+ cur = cur + 1
+ until base_points[cur] ~= i
+ else
+ if not last_x then -- We started a new contour and haven't seen a real point yet. Look for the last one instead.
+ local idx = cur
+ while (base_points[idx + 1] or n_points + 1) <= contours[contour] + 1 do
+ idx = idx + 1
+ end
+ local idx_point = points[base_points[idx]]
+ last_x, last_y = idx_point.x, idx_point.y
+ last_dx, last_dy = x_deltas[idx], y_deltas[idx]
+ end
+ local after_x, after_y, after_dx, after_dy
+ if (base_points[cur] or n_points + 1) <= contours[contour] + 1 then -- If the next point is part of the contour, use it. Otherwise use the first point in our contour)
+ local next_point = points[base_points[cur]]
+ after_x, after_y = next_point.x, next_point.y
+ after_dx, after_dy = x_deltas[cur], y_deltas[cur]
+ else
+ after_x, after_y = first_x, first_y
+ after_dx, after_dy = first_dx, first_dy
+ end
+
+ -- The first case is a bit weird, but afterwards we just interpolate while clipping to the boundaries.
+ -- See the gvar spec for details.
+ if last_x == after_x then
+ if last_dx == after_dx then
+ point.x = this_x + factor * last_dx
+ end
+ elseif this_x <= last_x and this_x <= after_x then
+ point.x = this_x + factor * (last_x < after_x and last_dx or after_dx)
+ elseif this_x >= last_x and this_x >= after_x then
+ point.x = this_x + factor * (last_x > after_x and last_dx or after_dx)
+ else -- We have to interpolate
+ local t = (this_x - last_x) / (after_x - last_x)
+ point.x = this_x + factor * ((1-t) * last_dx + t * after_dx)
+ end
+
+ -- And again for y
+ if last_y == after_y then
+ if last_dy == after_dy then
+ point.y = this_y + factor * last_dy
+ end
+ elseif this_y <= last_y and this_y <= after_y then
+ point.y = this_y + factor * (last_y < after_y and last_dy or after_dy)
+ elseif this_y >= last_y and this_y >= after_y then
+ point.y = this_y + factor * (last_y > after_y and last_dy or after_dy)
+ else -- We have to interpolate
+ local t = (this_y - last_y) / (after_y - last_y)
+ point.y = this_y + factor * ((1-t) * last_dy + t * after_dy)
+ end
+ end
+ end
+ end
+ end
+ else
+ -- Composite glyph
+ if base_points == true then
+ for i=1, #points do
+ local point = points[i]
+ if point.x then
+ point.x = point.x + factor * x_deltas[i]
+ point.y = point.y + factor * y_deltas[i]
+ end
+ end
+ else
+ for i=1, #base_points do
+ local point = points[base_points[i]]
+ if point and point.x then
+ point.x = point.x + factor * x_deltas[i]
+ point.y = point.y + factor * y_deltas[i]
+ end
+ end
+ end
+ end
+ assert(suboffset == offset + size)
+ end
+ offset = offset + size
+ end
+ return serialize_glyf(points, map)
+end
+
+return function(face, font, map, map_inv)
+ local gvar = assert(face:get_table(gvar_tag):get_data())
+ local gvar_index = assert(read_gvar(gvar))
+ local loca = assert(read_loca(face))
+ local glyf = assert(face:get_table(glyf_tag):get_data())
+ local normalized = {font:get_var_coords_normalized()}
+ return function(gid)
+ return interpolate_glyf(loca, gvar_index, gvar, glyf, map_inv[gid], normalized, map)
+ end
+end
diff --git a/macros/luatex/generic/luaotfload/luaotfload-init.lua b/macros/luatex/generic/luaotfload/luaotfload-init.lua
index 9ce1d2494d..73a6544e72 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-init.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-init.lua
@@ -7,8 +7,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-init",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
description = "luaotfload submodule / initialization",
license = "GPL v2.0"
}
@@ -551,10 +551,16 @@ local function init_post_load_agl ()
end
+local function init_post_apply_keepnames ()
+ local keepnames = config.luaotfload.misc.keepnames
+ luaotfload.fontloader.fonts.privateoffsets.keepnames = keepnames
+end
+
--- (unit -> unit) list
local init_post_actions = {
init_post_install_callbacks,
init_post_load_agl,
+ init_post_apply_keepnames
}
--- unit -> size_t
diff --git a/macros/luatex/generic/luaotfload/luaotfload-latex.pdf b/macros/luatex/generic/luaotfload/luaotfload-latex.pdf
index 7931d9d1d4..b87b90e0c8 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 7963a839b9..2e69cb92a6 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-letterspace.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-letterspace.lua
@@ -5,8 +5,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-letterspace",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
description = "luaotfload submodule / letterspacing",
license = "GPL v2.0",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -70,7 +70,7 @@ local todirect = nodedirect.todirect
local tonode = nodedirect.tonode
local insert_node_before = nodedirect.insert_before
-local free_node = nodedirect.free
+local real_free_node = nodedirect.free
local copy_node = nodedirect.copy
local new_node = nodedirect.new
@@ -86,9 +86,25 @@ local chardata = fonthashes.characters
local otffeatures = fonts.constructors.newfeatures "otf"
local markdata
+-- For every attribute list cached in attribute_table, we have to make
+-- sure that it doesn't get deleted. Therefore attribute_cleanup maps
+-- from a node which has the attribute_list referenced in
+-- attribute_table to the key from attribute_table.
+-- Whenever a node which has an entry in attribute_cleanup is deleted,
+-- we delete the corresponding entry from attribute_table since we can
+-- no longer guarantee that it's references somewhere.
local attribute_table = {}
+local attribute_cleanup = {}
local attr = luatexbase.new_attribute("luaotfload.letterspace_done")
+local function free_node(n)
+ local k = attribute_cleanup[n]
+ if k then
+ attribute_cleanup[n], attribute_table[k] = nil
+ end
+ return real_free_node(n)
+end
+
local function getprevreal(n)
repeat
n = getprev(n)
@@ -445,6 +461,7 @@ kerncharacters = function (head)
setattributelist(start, new_attr_list)
else
setattribute(start, attr, 1)
+ attribute_cleanup[start] = attr_list
attribute_table[attr_list] = getattributelist(start)
end
end --[[if prev]]
@@ -500,7 +517,8 @@ local function enablefontkerning ( )
"kerncharacters() failed to return a valid new head")
end
- for k in next, attribute_table do attribute_table[k] = nil end
+ for k, v in next, attribute_cleanup do attribute_cleanup[k], attribute_table[v] = nil end
+ assert(not next(attribute_table))
return tonode (direct_hd)
end
diff --git a/macros/luatex/generic/luaotfload/luaotfload-loaders.lua b/macros/luatex/generic/luaotfload/luaotfload-loaders.lua
index 1ed66aebea..5a84113a1f 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-loaders.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-loaders.lua
@@ -8,8 +8,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-loaders",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --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 74c5fd6929..41f9f4b877 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-log.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-log.lua
@@ -6,8 +6,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-log",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --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.tex b/macros/luatex/generic/luaotfload/luaotfload-main.tex
index ccc20ca578..cdf5590057 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 {2021-05-21 v3.18}
+ \setdocumentdate {2022-02-24 v3.19}
\setdocumentauthor {LaTeX3 Project\\
Elie Roux · Khaled Hosny · Philipp Gesang · Ulrike Fischer · Marcel Krüger\\
Home: \hyperlink {https://github.com/latex3/luaotfload}}
@@ -62,6 +62,23 @@ Supported is the \identifier{luatex} versions of a current TeXLive 2019 (and a c
\endsection
\beginsection{Changes}
+\beginsubsection {New in version 3.19 (by Ulrike Fischer/Marcel Krüger)}
+\begin{itemize}
+ \item When used with Lua\TeX\ 1.15.0 or newer, variable fonts are supported
+ when using the \texttt{harf} shaper too.
+ \item A new algorithm for selecting fonts based on font family names allows
+ to more reliably load fonts based on their family name.
+ \item The compiled font database gets compressed to reduce disk space and
+ improve performance on newer systems.
+ \item Broken rendering of some TrueType based variable fonts has been fixed.
+ \item Text automatically gets normalized to Unicode's NFC before shaping.
+ This improves rendering for text written in decomposed forms for many
+ fonts. This can be turned off by passing the \texttt{-normalize} font
+ feature.
+ \item A number of small bugfixes.
+ \end{itemize}
+\endsubsection
+
\beginsubsection {New in version 3.18 (by Ulrike Fischer/Marcel Krüger)}
\begin{itemize}
\item Now variable fonts can be loaded with default values without specifying
@@ -504,7 +521,7 @@ where \meta{prefix} is either \inlinecode{file:} or \inlinecode {name:}.\footnot
%
For a working example see the
\hyperlink [test in the luaotfload
- repo]{https://github.com/latex3/luaotfload/blob/master/testfiles/my-resolver.lvt}.
+ repo]{https://github.com/latex3/luaotfload/blob/main/testfiles/my-resolver.lvt}.
}
%
It determines whether the font loader should interpret the request as
@@ -2477,7 +2494,8 @@ code imported from \CONTEXT.
The complete text of the license is given as a separate file \fileent
{COPYING} in the toplevel directory of the
-\hyperlink [\fileent {Luaotfload} Git repository]{https://github.com/lualatex/luaotfload/blob/master/COPYING}.\\
+\hyperlink [\fileent {Luaotfload} Git
+repository]{https://github.com/latex3/luaotfload/blob/main/COPYING}.\\
Distributions probably package it as \fileent
{doc/luatex/luaotfload/COPYING} in the relevant \fileent {texmf} tree.
diff --git a/macros/luatex/generic/luaotfload/luaotfload-multiscript.lua b/macros/luatex/generic/luaotfload/luaotfload-multiscript.lua
index e3cf9a0cbf..ab688fe704 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-multiscript.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-multiscript.lua
@@ -5,8 +5,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-multiscript",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --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 d8cc677723..28a371dd35 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-notdef.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-notdef.lua
@@ -5,8 +5,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-notdef",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
description = "luaotfload submodule / notdef",
license = "GPL v2.0",
author = "Marcel Krüger"
diff --git a/macros/luatex/generic/luaotfload/luaotfload-parsers.lua b/macros/luatex/generic/luaotfload/luaotfload-parsers.lua
index cd452b40c2..099363fad5 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-parsers.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-parsers.lua
@@ -7,8 +7,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-parsers",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
description = "luaotfload submodule / parsers",
license = "GPL v2.0"
}
@@ -528,7 +528,7 @@ local featuresep = comma + semicolon
we only support the shorthands for italic / bold / bold italic
shapes, as well as setting optical size, the rest is ignored.
--doc]]--
-local style_modifier = (S'bB' * S'iI'^-1 + S'iI' * S'bB'^-1)
+local style_modifier = (S'bB' * S'iI'^-1 + S'iI' * S'bB'^-1 + S'rR')
/ stringlower
local size_modifier = S"Ss" * P"=" --- optical size
* Cc"optsize" * C(decimal)
diff --git a/macros/luatex/generic/luaotfload/luaotfload-resolvers.lua b/macros/luatex/generic/luaotfload/luaotfload-resolvers.lua
index a24757777e..a91216b79d 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-resolvers.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-resolvers.lua
@@ -11,8 +11,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-resolvers",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
description = "luaotfload submodule / resolvers",
license = "GPL v2.0"
}
diff --git a/macros/luatex/generic/luaotfload/luaotfload-scripts.lua b/macros/luatex/generic/luaotfload/luaotfload-scripts.lua
index 8a4f51ea58..c3c918ef3b 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-scripts.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-scripts.lua
@@ -5,8 +5,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-script",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --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 6743a025c3..d722bfe03b 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-status.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-status.lua
@@ -1,99 +1,99 @@
return {
["hashes"]={
- { "fontloader-2021-05-20.lua", "d3d971e3e79aefcb828157b97cc33378" },
- { "fontloader-util-fil.lua", "aae2a2add764144bb58dd8216fd59260" },
- { "fontloader-util-str.lua", "f3480da8f9a6f34fe320900f7224719b" },
+ { "fontloader-2022-02-24.lua", "4dc8ce07471f8af7aa98d835df654768" },
+ { "fontloader-util-fil.lua", "d0accf4180201efd567816a25ad5e037" },
+ { "fontloader-util-str.lua", "f4a9dd15c3e40cd3915749ac13837c95" },
{ "fontloader-l-unicode.lua", "f368874f11f3c525de5864fd413e4b24" },
- { "fontloader-l-math.lua", "082add08e0bb79f39191ae9534a79849" },
+ { "fontloader-l-math.lua", "5a0740b359e2d55d6dca06a23e3c9df6" },
{ "fontloader-l-boolean.lua", "abe28515dd33e8f6c416c09bca351cf8" },
- { "fontloader-l-file.lua", "352b42b8360ada02ceb26a41f0bd2a76" },
- { "fontloader-l-io.lua", "bbcc4824d0ded30b415d7d2d5763028a" },
+ { "fontloader-l-file.lua", "5839d88d4de96b9e9c7e7f8f8eb885b3" },
+ { "fontloader-l-io.lua", "3396a8644bae37e49b2cfc0c388c78f8" },
{ "fontloader-l-table.lua", "0330da8b3a08d39876def70df8d9c0e5" },
{ "fontloader-l-string.lua", "9457f2af85723e0e6c46d0b5122e9000" },
{ "fontloader-l-function.lua", "a7e68a9703c35238729da41a474e951b" },
- { "fontloader-l-lpeg.lua", "446dc07c8f6d2884122679fb4c8589e2" },
+ { "fontloader-l-lpeg.lua", "8315a56e6bc7b2ede3f70c49bf2b5af5" },
{ "fontloader-l-lua.lua", "420bc442e6d81f4624728a6c56fcd175" },
{ "fontloader-fonts-gbn.lua", "34e4543a02f6fbc8c2ade896cb6dc7df" },
{ "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-enc.lua", "c24fd6b4f34f87b9c4ff5e6193ce2656" },
{ "fontloader-fonts-mis.lua", "17e967c9ec4d001deefd43ddf25e98f7" },
- { "fontloader-basics-chr.lua", "64fafe4eaf55d64aead6513c1e74a024" },
- { "fontloader-basics-nod.lua", "b2e0a0e5e1e27349aed464fa738b8db1" },
+ { "fontloader-basics-chr.lua", "ce4afac7ba19471f3c8f90800839f315" },
+ { "fontloader-basics-nod.lua", "1750af43148def9e7a75c6900a96f9dc" },
{ "fontloader-font-imp-effects.lua", "d05997c1826355548ec9aec1346f9f23" },
{ "fontloader-font-imp-italics.lua", "defcb415bc1e0a0999b27773902adc18" },
{ "fontloader-font-imp-ligatures.lua", "26ffcf089391445f7af59536c8814364" },
{ "fontloader-font-imp-tex.lua", "ceb087ef6fa2f89aed7179f60ddf8f35" },
- { "fontloader-font-shp.lua", "2bb36adb4b264a895a2c4d97e1ac1d1e" },
+ { "fontloader-font-shp.lua", "a40862fe382d26c1f3753431254bcfdd" },
{ "fontloader-font-def.lua", "b9d908c2338b7dc443ce9d1e9fcb7139" },
{ "fontloader-font-lua.lua", "1fbfdf7b689b2bdfd0e3bb9bf74ce136" },
{ "fontloader-font-afk.lua", "9da14e0fb22129c053acc599d1312544" },
{ "fontloader-font-one.lua", "bd39d42055a44ca2002f8ddbbbbf27c3" },
{ "fontloader-font-onr.lua", "6d161533f3437435e12a0ad64866df44" },
{ "fontloader-font-ocl.lua", "2a377351ae23c339764ec8ce2e8e9164" },
- { "fontloader-font-osd.lua", "0e051ca0d3b1a8e0604ced27e753fde8" },
- { "fontloader-font-otc.lua", "0f12230ea07b5151f75d52726977e91f" },
- { "fontloader-font-ots.lua", "cb106ae882e8548051f00aac8b7fa862" },
+ { "fontloader-font-osd.lua", "a67b6fb465e7a8b9ecf7c6bbf8dfda03" },
+ { "fontloader-font-otc.lua", "582295d3d1e44cd4a31e8bbc1156f7c1" },
+ { "fontloader-font-ots.lua", "55316a605d11a1d07d38795224c90a63" },
{ "fontloader-font-ota.lua", "2bb12d708e35bc05443eba791e2554e7" },
- { "fontloader-font-oup.lua", "4eb2f26e51835239e26a8df2ecf04366" },
+ { "fontloader-font-oup.lua", "e6e2cc0a202aec2c787d5524e64d340a" },
{ "fontloader-font-otj.lua", "b2c165bd6771a57633f992d07384b739" },
- { "fontloader-font-oto.lua", "2b1d6bc63b2ebf8f2655a15e1cda6541" },
- { "fontloader-font-otl.lua", "6f701653de713e8aa80d82c7cdf32d75" },
+ { "fontloader-font-oto.lua", "9febc4d75d17a543cd73fb17918f7307" },
+ { "fontloader-font-otl.lua", "67078f58bc1a612e4646523538a4e3eb" },
{ "fontloader-font-ott.lua", "3f67b1b1d40bbc222681d8db4aff0f42" },
{ "fontloader-font-oti.lua", "309a75f9c14b77d87e94eba827dc4e71" },
- { "fontloader-font-dsp.lua", "174ce11f3ba0bddf270f48d8d2addd56" },
- { "fontloader-font-ttf.lua", "ffffc827e1bcddc33a2b615340ecff7f" },
- { "fontloader-font-cff.lua", "01e7c6fbc8961a566f4e4f8cbedb7004" },
- { "fontloader-font-otr.lua", "ad238624c9ebd488d4bbe9af3b620189" },
+ { "fontloader-font-dsp.lua", "7616dae672693fd8ec0f1892358019a2" },
+ { "fontloader-font-ttf.lua", "feba1fdc80160343b24f89ef978e53cb" },
+ { "fontloader-font-cff.lua", "e38c1a40e1d1d577cdf7920fa50d0654" },
+ { "fontloader-font-otr.lua", "91f70c1216e60227e1437b6c8dcd8647" },
{ "fontloader-font-vfc.lua", "a81c29eda98cd62cbebdb6c93544b50d" },
{ "fontloader-font-map.lua", "c4a39db5ad822b348aa61bca5f4a599a" },
{ "fontloader-font-cid.lua", "22b0367742fb253deef84ef7ccf5e8de" },
{ "fontloader-font-con.lua", "724e5dd14aec2d4d189f8619898004cf" },
{ "fontloader-font-ini.lua", "5343de60613adb24cdd7a8d2ee1d153c" },
{ "fontloader-data-con.lua", "23a0f5386d46a1c157ae82a373e35fa0" },
- { "fontloader-reference.lua", "29911e74397766ee36205736166dd763" },
- { "fontloader-basics-gen.lua", "4bc43036e9796fccb0b8869f4b05bf2e" },
+ { "fontloader-reference.lua", "066680a4fe38fad14eb27f56d4616104" },
+ { "fontloader-basics-gen.lua", "e470c13b1ed41e38932e93518219ad74" },
{ "mktests", "918cb50be9ee8bd645ac1a27dc501e8c" },
- { "mkstatus", "7f2fd945c1247f6af6b96c4ed49ddeab" },
+ { "mkstatus", "3a71ea95e4daeac77ead843edb0ce283" },
{ "mkcharacters", "bfca0e96e1e351afe7077502f9595af9" },
{ "mkglyphlist", "7a8a8fdc0eac7fac2f13ec8f4e8e7aa9" },
{ "mkimport", "7d62f1042e548f8b9368f26b9ba4be5c" },
- { "luaotfload-glyphlist.lua", "54908a38bf531914f350614afff2ccf6" },
+ { "luaotfload-glyphlist.lua", "dc0ed15ca157aec56a509819d4c24046" },
{ "luaotfload-characters.lua", "76415ca3ede312cad6e09038323489ae" },
- { "luaotfload-dvi.lua", "403603ff9e267d2b9ac631e63b869718" },
- { "luaotfload-tounicode.lua", "8f7850323417188eef5197d4e420bd34" },
- { "luaotfload-unicode.lua", "5bc464447c3f5b154d8368904044d654" },
- { "luaotfload-resolvers.lua", "3655371360dd87b4a7c83e355357e6eb" },
- { "luaotfload-parsers.lua", "c715cb6ea43d644ec26d6e87d25b5d27" },
- { "luaotfload-fallback.lua", "78a566243c0ad99e74f93fface672fb5" },
- { "luaotfload-szss.lua", "4c431d8f76e06200b2df3269615097cc" },
- { "luaotfload-scripts.lua", "12bf373853ead3eab3c83ec62e37bbd6" },
- { "luaotfload-multiscript.lua", "a46096b20f5442acea29c75b77f763a7" },
- { "luaotfload-loaders.lua", "ba59f0161e985f4c97c54245a74a8d29" },
- { "luaotfload-harf-plug.lua", "bded3b2beccab4943f616b3069cbb372" },
- { "luaotfload-harf-define.lua", "a5e760f71e08a8ff40a40defc9d59e4e" },
- { "luaotfload-notdef.lua", "dbb4718b4c1b46adc5870af3f5cc6cac" },
- { "luaotfload-embolden.lua", "7cc1563093c005c40c11b8c327e617f1" },
- { "luaotfload-letterspace.lua", "e7ee541a56954ebfa1a227aa59614bb9" },
- { "luaotfload-features.lua", "bf81e7630c3786ce12c1f9b61ef73037" },
- { "luaotfload-database.lua", "9b911605805ca1fab7d4088c0c50a5d2" },
- { "luaotfload-configuration.lua", "ddedd9c27f810b254547c6a799aba892" },
- { "luaotfload-colors.lua", "f4e86b8cbbcc790a64dae59b6b05b3d1" },
- { "luaotfload-auxiliary.lua", "e814d7c408817ae01a96f279c278ed08" },
- { "luaotfload-filelist.lua", "1108447545fbcb08aa0f6d586988c2e1" },
- { "luaotfload-tool.lua", "4ca593bc9413e4de889f1c0df6e48219" },
- { "luaotfload-diagnostics.lua", "4fa11f02259f2f9e7cd60d4b668b6a33" },
- { "luaotfload-log.lua", "e1af43403d8bf68d95276c0dc00e64f0" },
- { "luaotfload-init.lua", "f80c78b2296664ba42514674d104d093" },
+ { "luaotfload-dvi.lua", "f4e4d6cc443f477820521abcd87ef3f8" },
+ { "luaotfload-tounicode.lua", "79795ade0ccdb99cd5e6cf989770db69" },
+ { "luaotfload-unicode.lua", "68904dd143491dc0a4a1c0a063a118f9" },
+ { "luaotfload-resolvers.lua", "1e844bc5d9b3d207f8914a11254afd67" },
+ { "luaotfload-parsers.lua", "b0c087c6dbf75939d7be9523b7a0ca34" },
+ { "luaotfload-fallback.lua", "88ed544bc0429f94606f72dace5704f0" },
+ { "luaotfload-szss.lua", "7266e9d2122fb0785b595f9605627640" },
+ { "luaotfload-scripts.lua", "c6c11811531c7e42194304d65bed7877" },
+ { "luaotfload-multiscript.lua", "f9d7bedf75629d83f8d99397d15fdf86" },
+ { "luaotfload-loaders.lua", "b2ef32297527eec59131de3b56f4d846" },
+ { "luaotfload-harf-plug.lua", "7f3739c1b32de1f8e76275c317f5ed9a" },
+ { "luaotfload-harf-define.lua", "1c2ce18281caede23d93c8b825df7239" },
+ { "luaotfload-notdef.lua", "8b448aed817a764b675d1ead6bf932a7" },
+ { "luaotfload-embolden.lua", "00ae296b36724c4f8dd4da62051039b2" },
+ { "luaotfload-letterspace.lua", "f98fbda3ea174058b515b9234dfba495" },
+ { "luaotfload-features.lua", "5c0d7d66953c7ecdd2a610d758d70f0d" },
+ { "luaotfload-database.lua", "2ac2d6e5960257a7c5688c931bb91924" },
+ { "luaotfload-configuration.lua", "05e6c5032b9ac6f05230d06c866161d6" },
+ { "luaotfload-colors.lua", "3e1cd496c920d0e8296a9e99357f27eb" },
+ { "luaotfload-auxiliary.lua", "32c6b48ab66a2ddf2a7d3063529e85f8" },
+ { "luaotfload-filelist.lua", "b80ed418d9d297370182e9fcc9e497e5" },
+ { "luaotfload-tool.lua", "2a6a1c510e44c4432724657259b12cbf" },
+ { "luaotfload-diagnostics.lua", "e831068d26e0266cd081de8585c3cbc9" },
+ { "luaotfload-log.lua", "889508edccd01035ecbeafdeeff60e35" },
+ { "luaotfload-init.lua", "56ac12fac2e63d1a901463850062dd58" },
{ "luaotfload-main.lua", "b19c9cc34cf1d676c39f872cfb41aef6" },
},
["notes"]={
["committer"]="Marcel Fabian Krüger <tex@2krueger.de>",
- ["description"]="v3.18/2021-05-21",
- ["loader"]="fontloader-2021-05-20.lua",
- ["revision"]="3f2cacb9d2136142cffb183774c0edaeb4ea3314",
- ["timestamp"]="2021-05-21 02:12:47 +0200",
+ ["description"]="v3.19/2022-02-24",
+ ["loader"]="fontloader-2022-02-24.lua",
+ ["revision"]="ef3a55e0da3709e95551c62376f31149771dcc18",
+ ["timestamp"]="2022-02-24 14:16:28 +0100",
},
} \ 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 8ea049ba91..e0f3989c22 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-suppress.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-suppress.lua
@@ -5,8 +5,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-suppress",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --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 26c89eafa2..dcd8eacf65 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-szss.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-szss.lua
@@ -5,8 +5,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-szss",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
description = "luaotfload submodule / Special feature handling",
license = "GPL v2.0",
author = "Marcel Krüger"
diff --git a/macros/luatex/generic/luaotfload/luaotfload-t3.lua b/macros/luatex/generic/luaotfload/luaotfload-t3.lua
new file mode 100644
index 0000000000..2588346724
--- /dev/null
+++ b/macros/luatex/generic/luaotfload/luaotfload-t3.lua
@@ -0,0 +1,142 @@
+-----------------------------------------------------------------------
+-- FILE: luaotfload-t3.lua
+-- DESCRIPTION: part of luaotfload / Type 3
+-----------------------------------------------------------------------
+do -- block to avoid to many local variables error
+ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
+ name = "luaotfload-t3",
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
+ description = "luaotfload submodule / Type 3 font handling",
+ license = "GPL v2.0",
+ author = "Marcel Krüger",
+ copyright = "Luaotfload Development Team",
+ }
+end
+
+--[[
+local function u8_to_utf16be(s)
+ local d = {}
+ local i = 0
+ for _, cp, cp2 in utf8.codes(s) do
+ i = i + 1
+ if cp > 0x10000 then
+ cp = cp - 0x10000
+ local high = (cp>>10) | 0xD800
+ local low = (cp&0x3FF) | 0xDC00
+ d[i] = string.format('%04X%04X', high, low)
+ else
+ d[i] = string.format('%04X', cp)
+ end
+ end
+ return table.concat(d, '', 1, i)
+end
+]]
+
+local function t3factory(basename, designsize, callback)
+ local count = 0
+ local gid_to_t3 = {}
+ local t3_to_gid = {}
+ return function(size)
+ local fids = {}
+ return function(gid, width, unicode)
+ local t3id = gid_to_t3[gid]
+ if not t3id then
+ t3id = count
+ count = count + 1
+ gid_to_t3[gid] = t3id
+ t3_to_gid[t3id] = gid
+ end
+ local t3fid, t3cid = t3id >> 8, ~(t3id & 0xFF)
+ local fid = fids[t3fid + 1]
+ local fontdir = fid and font.getfont(fid)
+ local characters = fontdir and fontdir.characters
+ if not (characters and characters[t3cid]) then
+ characters = characters or {}
+ -- First create the character
+ local char = {
+ width = width,
+ height = 0, -- We never look at these two anyway
+ depth = 0,
+ tounicode = unicode,
+ }
+ characters[t3cid] = char
+ if fid then -- Font already exists
+ font.addcharacters(fid, {
+ characters = {
+ [t3cid] = char,
+ },
+ })
+ else
+ fontdir = {
+ name = basename .. '_' .. basesize .. '_' .. t3fid,
+ format = 'type3',
+ psname = 'none',
+ filename = 'not_a_real_filename', -- Can't be null to ensure reuse
+ fullname = basename .. basesize .. '_' .. t3fid,
+ characters = characters,
+ designsize = basesize,
+ size = size,
+ cidinfo = {}, -- Can't be null to ensure reuse
+ attributes = '/FontDescriptor<<\z
+ /Type/FontDescriptor\z
+ /FontName/VirtualLuaFont\z
+ /Flags 4\z
+ /ItalicAngle 0\z
+ >>', -- TODO: Needs work
+ t3_handler = function(stage, _, cid)
+ cid = cid and assert(t3_to_gid[(t3fid << 8) | ~cid])
+ return callback(stage, cid)
+ end
+ }
+ fid = font.define(fontdir)
+ fids[t3fid + 1] = fid
+ end
+ end
+ vf.font(fid)
+ vf.char(t3cid)
+ end
+ end
+end
+
+luatexbase.add_to_callback('provide_charproc_data', function(stage, fid, ...)
+ local fontdir = font.getfont(fid)
+ if not fontdir then error'Unknown font' end
+ local handler = fontdir.t3_handler
+ if not handler then error'Missing t3handler in Type 3 font' end
+ return handler(stage, fid, ...)
+end, 'luaotfload.t3')
+
+return t3factory
+--[===[
+ function callback(stage, cid)
+ if stage == 1 then
+ local char = assert(characters[cid])
+ local head = assert(char.head)
+ local resource = tex.saveboxresource(head, nil--[[attributes]], nil--[[resources]], true--[[immediate]], 0--[[mode]], nil--[[margin]])
+ local name = string.format('/F%i', pdf.getxformname(resource))
+ local resources = characters.resources
+ if resources then
+ characters.resources = string.format('%s %s %i 0 R', resources, name, resource)
+ else
+ characters.resources = string.format('%s %i 0 R', name, resource)
+ end
+ char.resource = name
+ elseif stage == 2 then
+ local char = assert(characters[cid])
+ width = char.width/65781
+ return pdf.obj{
+ type = 'stream',
+ immediate = true,
+ -- objnum =
+ -- attr =
+ -- compresslevel =
+ string = string.format('%g 0 d0 %s Do', width, char.resource)
+ }, width
+ elseif stage == 3 then
+ return 65781/655360, string.format('/XObject<<%s>>', characters.resources)
+ end
+ print(stage, fid, cid)
+ end,
+ }
+]===]
diff --git a/macros/luatex/generic/luaotfload/luaotfload-tool.1 b/macros/luatex/generic/luaotfload/luaotfload-tool.1
index 9e2b12aed0..3f2782eb18 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 "2021-05-21" "3.18" "text processing"
+.TH LUAOTFLOAD-TOOL 1 "2022-02-24" "3.19" "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 df80d4da78..808afe0313 100755..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.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
description = "luaotfload-tool / database functionality",
license = "GPL v2.0"
}
diff --git a/macros/luatex/generic/luaotfload/luaotfload-tool.pdf b/macros/luatex/generic/luaotfload/luaotfload-tool.pdf
index fb44487640..a218f77367 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 085a371386..1eddd510f1 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: 2021-05-21
+:Date: 2022-02-24
:Copyright: GPL v2.0
-:Version: 3.18
+:Version: 3.19
: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 928dfd30fc..09ca40adbe 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-tounicode.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-tounicode.lua
@@ -5,8 +5,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-tounicode",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --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 ccc3988ba1..25a7b2046e 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-unicode.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-unicode.lua
@@ -5,8 +5,8 @@
assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
name = "luaotfload-unicode",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --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 8285e71d7d..f7d8aa8ae4 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 "2021-05-21" "3.18" "text processing"
+.TH LUAOTFLOAD.CONF 5 "2022-02-24" "3.19" "text processing"
.SH NAME
luaotfload.conf \- Luaotfload configuration file
.
@@ -373,6 +373,14 @@ T} T{
<Luaotfload version>
T}
_
+T{
+keepnames
+T} T{
+b
+T} T{
+\fBtrue\fP
+T}
+_
.TE
.sp
With \fBstatistics\fP enabled, extra statistics will be collected during
@@ -386,6 +394,10 @@ terminal dimensions cannot be retrieved.
.sp
The value of \fBversion\fP is derived from the version string hard\-coded
in the Luaotfload source. Override at your own risk.
+.sp
+The \fBkeepnames\fP option decides if the ConTeXt fontloader should keep
+names it considers useless or if they should be discarded. This option
+only takes effect after font caches are regenererated.
.SS Section \fBpaths\fP
.TS
center;
diff --git a/macros/luatex/generic/luaotfload/luaotfload.conf.rst b/macros/luatex/generic/luaotfload/luaotfload.conf.rst
index 84db4dca17..4e0347b907 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: 2021-05-21
+:Date: 2022-02-24
:Copyright: GPL v2.0
-:Version: 3.18
+:Version: 3.19
:Manual section: 5
:Manual group: text processing
@@ -228,6 +228,8 @@ Section ``misc``
+---------------+--------+-------------------------+
| version | s | <Luaotfload version> |
+---------------+--------+-------------------------+
+| keepnames | b | ``true`` |
++---------------+--------+-------------------------+
With ``statistics`` enabled, extra statistics will be collected during
index creation and appended to the index file. It may then be queried
@@ -241,6 +243,10 @@ terminal dimensions cannot be retrieved.
The value of ``version`` is derived from the version string hard-coded
in the Luaotfload source. Override at your own risk.
+The ``keepnames`` option decides if the ConTeXt fontloader should keep
+names it considers useless or if they should be discarded. This option
+only takes effect after font caches are regenererated.
+
Section ``paths``
-----------------------------------------------------------------------
diff --git a/macros/luatex/generic/luaotfload/luaotfload.lua b/macros/luatex/generic/luaotfload/luaotfload.lua
index 8d769d7dc8..f21ded5ae6 100644
--- a/macros/luatex/generic/luaotfload/luaotfload.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload.lua
@@ -20,8 +20,8 @@ local authors = "\z
-- version number is used below!
local ProvidesLuaModule = {
name = "luaotfload",
- version = "3.18", --TAGVERSION
- date = "2021-05-21", --TAGDATE
+ version = "3.19", --TAGVERSION
+ date = "2022-02-24", --TAGDATE
description = "Lua based OpenType font support",
author = authors,
copyright = authors,
@@ -172,11 +172,6 @@ local function make_loader_name (prefix, name)
return prefix .. "-" .. name .. ".lua"
end
-local timing_info = {
- t_load = { },
- t_init = { },
-}
-
local function make_loader (prefix, load_helper)
return function (name)
local t_0 = osgettimeofday ()
@@ -184,7 +179,6 @@ local function make_loader (prefix, load_helper)
--- We don’t want the stack info from inside, so just pcall().
local ok, data = pcall (load_helper or require, modname)
local t_end = osgettimeofday ()
- timing_info.t_load [name] = t_end - t_0
if not ok then
io.write "\n"
local msg = luaotfload.log and luaotfload.log.report or print
@@ -256,7 +250,6 @@ local function context_loader (name, path)
end
local ret = context_isolated_load (modpath)
local t_end = osgettimeofday ()
- timing_info.t_load [name] = t_end - t_0
if ret ~= nil then
--- require () returns “true” upon success unless the loaded file
@@ -293,7 +286,6 @@ local function install_loaders ()
logreport ("log", 4, "load",
"Module %q loaded in %g ms.",
name, d_t * 1000)
- timing_info.t_init [name] = d_t
end
end
@@ -368,7 +360,6 @@ luaotfload.main = function ()
logreport ("log", 1, "main",
"initialization completed in %0.3f seconds\n",
osgettimeofday() - starttime)
-----inspect (timing_info)
luaotfload_module = nil
end
diff --git a/macros/luatex/generic/luaotfload/luaotfload.sty b/macros/luatex/generic/luaotfload/luaotfload.sty
index 20dc5ffb4f..7dbccb1f8c 100644
--- a/macros/luatex/generic/luaotfload/luaotfload.sty
+++ b/macros/luatex/generic/luaotfload/luaotfload.sty
@@ -39,7 +39,7 @@
\fi
\ifdefined\ProvidesPackage
\ProvidesPackage{luaotfload}%
- [2021/05/21 v3.18 OpenType layout system]
+ [2022/02/24 v3.19 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 d6513d6869..e119a1ef16 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 29b7c229f7..ded892e99b 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 a604a8c557..d889e43e79 100644
--- a/macros/luatex/generic/luaotfload/shaper-demo.pdf
+++ b/macros/luatex/generic/luaotfload/shaper-demo.pdf
Binary files differ