summaryrefslogtreecommitdiff
path: root/tex
diff options
context:
space:
mode:
Diffstat (limited to 'tex')
-rw-r--r--tex/context/base/mkii/cont-new.mkii2
-rw-r--r--tex/context/base/mkii/context.mkii2
-rw-r--r--tex/context/base/mkiv/char-def.lua1
-rw-r--r--tex/context/base/mkiv/cont-new.mkiv2
-rw-r--r--tex/context/base/mkiv/context.mkiv2
-rw-r--r--tex/context/base/mkiv/font-cff.lua28
-rw-r--r--tex/context/base/mkiv/font-dsp.lua4
-rw-r--r--tex/context/base/mkiv/font-otr.lua45
-rw-r--r--tex/context/base/mkiv/font-ott.lua64
-rw-r--r--tex/context/base/mkiv/math-act.lua76
-rw-r--r--tex/context/base/mkiv/math-dim.lua1
-rw-r--r--tex/context/base/mkiv/mult-prm.lua4
-rw-r--r--tex/context/base/mkiv/status-files.pdfbin24578 -> 24588 bytes
-rw-r--r--tex/context/base/mkiv/status-lua.pdfbin263632 -> 264506 bytes
-rw-r--r--tex/context/base/mkxl/anch-box.mkxl1
-rw-r--r--tex/context/base/mkxl/catc-def.mkxl14
-rw-r--r--tex/context/base/mkxl/catc-ini.mkxl237
-rw-r--r--tex/context/base/mkxl/cont-new.mkxl2
-rw-r--r--tex/context/base/mkxl/context.mkxl2
-rw-r--r--tex/context/base/mkxl/driv-shp.lmt35
-rw-r--r--tex/context/base/mkxl/driv-usr.lmt16
-rw-r--r--tex/context/base/mkxl/font-con.lmt7
-rw-r--r--tex/context/base/mkxl/font-dsp.lmt4646
-rw-r--r--tex/context/base/mkxl/font-imp-text.lmt2
-rw-r--r--tex/context/base/mkxl/font-lib.mklx2
-rw-r--r--tex/context/base/mkxl/lang-mis.mkxl167
-rw-r--r--tex/context/base/mkxl/lang-tra.mkxl4
-rw-r--r--tex/context/base/mkxl/lang-url.mkxl6
-rw-r--r--tex/context/base/mkxl/math-act.lmt332
-rw-r--r--tex/context/base/mkxl/math-ali.mkxl3
-rw-r--r--tex/context/base/mkxl/math-def.mkxl2
-rw-r--r--tex/context/base/mkxl/math-del.mklx10
-rw-r--r--tex/context/base/mkxl/math-dim.lmt1
-rw-r--r--tex/context/base/mkxl/math-fen.mkxl16
-rw-r--r--tex/context/base/mkxl/math-ini.mkxl139
-rw-r--r--tex/context/base/mkxl/math-twk.mkxl7
-rw-r--r--tex/context/base/mkxl/node-fnt.lmt551
-rw-r--r--tex/context/base/mkxl/node-nut.lmt1
-rw-r--r--tex/context/base/mkxl/spac-chr.mkxl4
-rw-r--r--tex/context/base/mkxl/spac-hor.mkxl6
-rw-r--r--tex/context/base/mkxl/tabl-tab.mkxl58
-rw-r--r--tex/context/base/mkxl/typo-rub.mkxl3
-rw-r--r--tex/context/fonts/mkiv/bonum-math.lfg26
-rw-r--r--tex/context/fonts/mkiv/cambria-math.lfg65
-rw-r--r--tex/context/fonts/mkiv/common-math.lfg1
-rw-r--r--tex/context/fonts/mkiv/concrete-math.lfg46
-rw-r--r--tex/context/fonts/mkiv/dejavu-math.lfg25
-rw-r--r--tex/context/fonts/mkiv/ebgaramond-math.lfg17
-rw-r--r--tex/context/fonts/mkiv/erewhon-math.lfg13
-rw-r--r--tex/context/fonts/mkiv/kpfonts-math.lfg12
-rw-r--r--tex/context/fonts/mkiv/libertinus-math.lfg19
-rw-r--r--tex/context/fonts/mkiv/lucida-math.lfg24
-rw-r--r--tex/context/fonts/mkiv/minion-math.lfg48
-rw-r--r--tex/context/fonts/mkiv/modern-math.lfg35
-rw-r--r--tex/context/fonts/mkiv/newcomputermodern-math.lfg57
-rw-r--r--tex/context/fonts/mkiv/pagella-math.lfg19
-rw-r--r--tex/context/fonts/mkiv/schola-math.lfg14
-rw-r--r--tex/context/fonts/mkiv/stixtwo-math.lfg19
-rw-r--r--tex/context/fonts/mkiv/termes-math.lfg17
-rw-r--r--tex/context/fonts/mkiv/type-imp-dejavu.mkiv4
-rw-r--r--tex/context/fonts/mkiv/type-imp-modernlatin.mkiv6
-rw-r--r--tex/context/fonts/mkiv/type-imp-newcomputermodern.mkiv8
-rw-r--r--tex/context/fonts/mkiv/type-imp-texgyre.mkiv8
-rw-r--r--tex/context/fonts/mkiv/xcharter-math.lfg10
-rw-r--r--tex/context/modules/mkiv/s-fonts-variable.lua7
-rw-r--r--tex/context/modules/mkiv/s-fonts-variable.mkiv4
-rw-r--r--tex/generic/context/luatex/luatex-fonts-merged.lua86
67 files changed, 6253 insertions, 842 deletions
diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii
index ad689d99c..163951adb 100644
--- a/tex/context/base/mkii/cont-new.mkii
+++ b/tex/context/base/mkii/cont-new.mkii
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\newcontextversion{2022.11.18 13:15}
+\newcontextversion{2022.12.01 12:38}
%D This file is loaded at runtime, thereby providing an
%D excellent place for hacks, patches, extensions and new
diff --git a/tex/context/base/mkii/context.mkii b/tex/context/base/mkii/context.mkii
index 09f548302..d07c96f1a 100644
--- a/tex/context/base/mkii/context.mkii
+++ b/tex/context/base/mkii/context.mkii
@@ -20,7 +20,7 @@
%D your styles an modules.
\edef\contextformat {\jobname}
-\edef\contextversion{2022.11.18 13:15}
+\edef\contextversion{2022.12.01 12:38}
%D For those who want to use this:
diff --git a/tex/context/base/mkiv/char-def.lua b/tex/context/base/mkiv/char-def.lua
index a5a21687b..276d0f700 100644
--- a/tex/context/base/mkiv/char-def.lua
+++ b/tex/context/base/mkiv/char-def.lua
@@ -1467,6 +1467,7 @@ characters.data={
description="TILDE",
direction="on",
linebreak="al",
+ mathclass="relation",
synonyms={ "spacing tilde" },
unicodeslot=0x7E,
},
diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv
index db7e8f9a2..820a372bb 100644
--- a/tex/context/base/mkiv/cont-new.mkiv
+++ b/tex/context/base/mkiv/cont-new.mkiv
@@ -13,7 +13,7 @@
% \normalend % uncomment this to get the real base runtime
-\newcontextversion{2022.11.18 13:15}
+\newcontextversion{2022.12.01 12:38}
%D This file is loaded at runtime, thereby providing an excellent place for hacks,
%D patches, extensions and new features. There can be local overloads in cont-loc
diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv
index 107874ffd..d7a655b4f 100644
--- a/tex/context/base/mkiv/context.mkiv
+++ b/tex/context/base/mkiv/context.mkiv
@@ -49,7 +49,7 @@
%D {YYYY.MM.DD HH:MM} format.
\edef\contextformat {\jobname}
-\edef\contextversion{2022.11.18 13:15}
+\edef\contextversion{2022.12.01 12:38}
%D Kind of special:
diff --git a/tex/context/base/mkiv/font-cff.lua b/tex/context/base/mkiv/font-cff.lua
index 4b60cd6c0..f1c377637 100644
--- a/tex/context/base/mkiv/font-cff.lua
+++ b/tex/context/base/mkiv/font-cff.lua
@@ -2061,24 +2061,26 @@ end
if t == 8 and top > 48 then
-- let's assume this only happens for rrcurveto .. the other ones would need some more
-- complex handling (cff2 stuff)
+ --
+ -- dx1 dy1 (dx1+dx2) (dy1+dy2) (dx1+dx2+dx3) (dy1+dy2+dy3) rcurveto.
local n = 0
for i=1,top do
-- if n == 42 then
if n == 48 then
- local zero = encode[0]
- local res3 = result[r-3]
- local res2 = result[r-2]
- local res1 = result[r-1]
- local res0 = result[r]
- result[r-3] = zero
- result[r-2] = zero
+-- local zero = encode[0]
+-- local res3 = result[r-3]
+-- local res2 = result[r-2]
+-- local res1 = result[r-1]
+-- local res0 = result[r]
+-- result[r-3] = zero
+-- result[r-2] = zero
r = r + 1 ; result[r] = chars[t]
- r = r + 1 ; result[r] = zero
- r = r + 1 ; result[r] = zero
- r = r + 1 ; result[r] = res3
- r = r + 1 ; result[r] = res2
- r = r + 1 ; result[r] = res1
- r = r + 1 ; result[r] = res0
+-- r = r + 1 ; result[r] = zero
+-- r = r + 1 ; result[r] = zero
+-- r = r + 1 ; result[r] = res3
+-- r = r + 1 ; result[r] = res2
+-- r = r + 1 ; result[r] = res1
+-- r = r + 1 ; result[r] = res0
n = 1
else
n = n + 1
diff --git a/tex/context/base/mkiv/font-dsp.lua b/tex/context/base/mkiv/font-dsp.lua
index f5e12c0ef..80e623929 100644
--- a/tex/context/base/mkiv/font-dsp.lua
+++ b/tex/context/base/mkiv/font-dsp.lua
@@ -3089,9 +3089,11 @@ function readers.colr(f,fontdata,specification)
local tableoffset = gotodatatable(f,fontdata,"colr",specification.glyphs)
if tableoffset then
local version = readushort(f)
- if version ~= 0 then
+ if version == 0 or version == 1 then
report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"colr",fontdata.filename)
return
+ else
+ -- both versions have this in common
end
if not fontdata.tables.cpal then
report("color table %a in font %a has no mandate %a table","colr",fontdata.filename,"cpal")
diff --git a/tex/context/base/mkiv/font-otr.lua b/tex/context/base/mkiv/font-otr.lua
index 339de109f..0b4bb65bb 100644
--- a/tex/context/base/mkiv/font-otr.lua
+++ b/tex/context/base/mkiv/font-otr.lua
@@ -66,6 +66,7 @@ if not modules then modules = { } end modules ['font-otr'] = {
-- require("char-ini")
-- end
+local number = number
local next, type, tonumber, rawget = next, type, tonumber, rawget
local byte, lower, char, gsub = string.byte, string.lower, string.char, string.gsub
local fullstrip = string.fullstrip
@@ -1683,7 +1684,7 @@ end
function readers.cmap(f,fontdata,specification)
local tableoffset = gotodatatable(f,fontdata,"cmap",specification.glyphs)
if tableoffset then
- local version = readushort(f)
+ local version = readushort(f) -- check later versions
local noftables = readushort(f)
local records = { }
local unicodecid = false
@@ -2425,25 +2426,29 @@ function readers.loadfont(filename,n,instance)
nofsubfonts = fontdata.subfonts and #fontdata.subfonts or nil,
},
resources = {
- -- filename = fontdata.filename,
- filename = filename,
- private = privateoffset,
- duplicates = fontdata.duplicates or { },
- features = fontdata.features or { }, -- we need to add these in the loader
- sublookups = fontdata.sublookups or { }, -- we need to add these in the loader
- marks = fontdata.marks or { }, -- we need to add these in the loader
- markclasses = fontdata.markclasses or { }, -- we need to add these in the loader
- marksets = fontdata.marksets or { }, -- we need to add these in the loader
- sequences = fontdata.sequences or { }, -- we need to add these in the loader
- variants = fontdata.variants, -- variant -> unicode -> glyph
- version = getname(fontdata,"version"),
- cidinfo = fontdata.cidinfo,
- mathconstants = fontdata.mathconstants,
- colorpalettes = fontdata.colorpalettes,
- svgshapes = fontdata.svgshapes,
- pngshapes = fontdata.pngshapes,
- variabledata = fontdata.variabledata,
- foundtables = fontdata.foundtables,
+ -- filename = fontdata.filename,
+ filename = filename,
+ private = privateoffset,
+ duplicates = fontdata.duplicates or { },
+ features = fontdata.features or { }, -- we need to add these in the loader
+ sublookups = fontdata.sublookups or { }, -- we need to add these in the loader
+ marks = fontdata.marks or { }, -- we need to add these in the loader
+ markclasses = fontdata.markclasses or { }, -- we need to add these in the loader
+ marksets = fontdata.marksets or { }, -- we need to add these in the loader
+ sequences = fontdata.sequences or { }, -- we need to add these in the loader
+ variants = fontdata.variants, -- variant -> unicode -> glyph
+ version = getname(fontdata,"version"),
+ cidinfo = fontdata.cidinfo,
+ mathconstants = fontdata.mathconstants,
+ colorpalettes = fontdata.colorpalettes,
+ colorpaintdata = fontdata.colorpaintdata,
+ colorpaintlist = fontdata.colorpaintlist,
+ colorlinesdata = fontdata.colorlinesdata,
+ coloraffinedata = fontdata.coloraffinedata,
+ svgshapes = fontdata.svgshapes,
+ pngshapes = fontdata.pngshapes,
+ variabledata = fontdata.variabledata,
+ foundtables = fontdata.foundtables,
},
}
end
diff --git a/tex/context/base/mkiv/font-ott.lua b/tex/context/base/mkiv/font-ott.lua
index aa1defd6a..74fd58375 100644
--- a/tex/context/base/mkiv/font-ott.lua
+++ b/tex/context/base/mkiv/font-ott.lua
@@ -52,16 +52,20 @@ local scripts = allocate {
["cari"] = "carian",
["cham"] = "cham",
["cher"] = "cherokee",
+ ["chrs"] = "chorasmian",
["copt"] = "coptic",
+ ["cpmn"] = "cypro-minoan",
["cprt"] = "cypriot syllabary",
["cyrl"] = "cyrillic",
["dev2"] = "devanagari variant 2",
["deva"] = "devanagari",
+ ["diak"] = "dives akuru",
["dogr"] = "dogra",
["dsrt"] = "deseret",
["dupl"] = "duployan",
["egyp"] = "egyptian heiroglyphs",
["elba"] = "elbasan",
+ ["elym"] = "elymaic",
["ethi"] = "ethiopic",
["geor"] = "georgian",
["gjr2"] = "gujarati variant 2",
@@ -81,6 +85,7 @@ local scripts = allocate {
["hebr"] = "hebrew",
["hluw"] = "anatolian hieroglyphs",
["hmng"] = "pahawh hmong",
+ ["hmnp"] = "nyiakeng puachue hmong",
["hung"] = "old hungarian",
["ital"] = "old italic",
["jamo"] = "hangul jamo",
@@ -90,6 +95,7 @@ local scripts = allocate {
["khar"] = "kharosthi",
["khmr"] = "khmer",
["khoj"] = "khojki",
+ ["kits"] = "khitan small script",
["knd2"] = "kannada variant 2",
["knda"] = "kannada",
["kthi"] = "kaithi",
@@ -123,6 +129,7 @@ local scripts = allocate {
["musc"] = "musical symbols",
["mym2"] = "myanmar variant 2",
["mymr"] = "myanmar",
+ ["nand"] = "nandinagari",
["narb"] = "old north arabian",
["nbat"] = "nabataean",
["newa"] = "newa",
@@ -132,9 +139,10 @@ local scripts = allocate {
["olck"] = "ol chiki",
["orkh"] = "old turkic and orkhon runic",
["ory2"] = "odia variant 2",
- ["orya"] = "oriya",
+ ["orya"] = "odia",
["osge"] = "osage",
["osma"] = "osmanya",
+ ["ougr"] = "old uyghur",
["palm"] = "palmyrene",
["pauc"] = "pau cin hau",
["perm"] = "old permic",
@@ -166,7 +174,7 @@ local scripts = allocate {
["tagb"] = "tagbanwa",
["takr"] = "takri",
["tale"] = "tai le",
- ["talu"] = "tai lu",
+ ["talu"] = "new tai lue",
["taml"] = "tamil",
["tang"] = "tangut",
["tavt"] = "tai viet",
@@ -178,12 +186,16 @@ local scripts = allocate {
["thai"] = "thai",
["tibt"] = "tibetan",
["tirh"] = "tirhuta",
+ ["tnsa"] = "tangsa",
["tml2"] = "tamil variant 2",
+ ["toto"] = "toto",
["ugar"] = "ugaritic cuneiform",
["vai" ] = "vai",
["wara"] = "warang citi",
+ ["wcho"] = "wancho",
["xpeo"] = "old persian cuneiform",
["xsux"] = "sumero-akkadian cuneiform",
+ ["yezi"] = "yezidi",
["yi" ] = "yi",
["zanb"] = "zanabazar square",
}
@@ -199,6 +211,7 @@ local languages = allocate {
["agw" ] = "agaw",
["aio" ] = "aiton",
["aka" ] = "akan",
+ ["akb" ] = "batak angkola",
["als" ] = "alsatian",
["alt" ] = "altai",
["amh" ] = "amharic",
@@ -211,6 +224,7 @@ local languages = allocate {
["asm" ] = "assamese",
["ast" ] = "asturian",
["ath" ] = "athapaskan",
+ ["avn" ] = "avatime",
["avr" ] = "avar",
["awa" ] = "awadhi",
["aym" ] = "aymara",
@@ -256,8 +270,12 @@ local languages = allocate {
["brx" ] = "bodo",
["bsh" ] = "bashkir",
["bsk" ] = "burushaski",
+ ["bta" ] = "batak alas kluet",
+ ["btd" ] = "batak dairi (pakpak)",
["bti" ] = "beti",
+ ["btm" ] = "batak mandailing",
["bts" ] = "batak simalungun",
+ ["btx" ] = "batak karo",
["bug" ] = "bugis",
["byv" ] = "medumba",
["cak" ] = "kaqchikel",
@@ -292,14 +310,16 @@ local languages = allocate {
["csl" ] = "church slavonic",
["csy" ] = "czech",
["ctg" ] = "chittagonian",
+ ["ctt" ] = "wayanad chetti",
["cuk" ] = "san blas kuna",
+ ["dag" ] = "dagbani",
["dan" ] = "danish",
["dar" ] = "dargwa",
["dax" ] = "dayi",
["dcr" ] = "woods cree",
["deu" ] = "german",
- ["dgo" ] = "dogri",
- ["dgr" ] = "dogri",
+ ["dgo" ] = "dogri (individual language)",
+ ["dgr" ] = "dogri (macro language)",
["dhg" ] = "dhangu",
["dhv" ] = "divehi (dhivehi, maldivian)",
["diq" ] = "dimli",
@@ -371,13 +391,16 @@ local languages = allocate {
["guj" ] = "gujarati",
["guz" ] = "gusii",
["hai" ] = "haitian (haitian creole)",
+ ["hai0"] = "haida",
["hal" ] = "halam",
["har" ] = "harauti",
["hau" ] = "hausa",
["haw" ] = "hawaiian",
["hay" ] = "haya",
["haz" ] = "hazaragi",
+ ["hmz" ] = "hmong shuat",
["hbn" ] = "hammer-banna",
+ ["hei" ] = "heiltsuk",
["her" ] = "herero",
["hil" ] = "hiligaynon",
["hin" ] = "hindi",
@@ -402,10 +425,12 @@ local languages = allocate {
["ind" ] = "indonesian",
["ing" ] = "ingush",
["inu" ] = "inuktitut",
+ ["inuk"] = "nunavik inuktitut",
["ipk" ] = "inupiat",
["ipph"] = "phonetic transcription—ipa conventions",
["iri" ] = "irish",
["irt" ] = "irish traditional",
+ ["uri" ] = "irula",
["isl" ] = "icelandic",
["ism" ] = "inari sami",
["ita" ] = "italian",
@@ -425,6 +450,7 @@ local languages = allocate {
["kan" ] = "kannada",
["kar" ] = "karachay",
["kat" ] = "georgian",
+ ["kaw" ] = "kawi (old javanese)",
["kaz" ] = "kazakh",
["kde" ] = "makonde",
["kea" ] = "kabuverdianu (crioulo)",
@@ -482,6 +508,7 @@ local languages = allocate {
["kur" ] = "kurdish",
["kuu" ] = "kurukh",
["kuy" ] = "kuy",
+ ["kwk" ] = "kwakʼwala",
["kyk" ] = "koryak",
["kyu" ] = "western kayah",
["lad" ] = "ladin",
@@ -493,6 +520,7 @@ local languages = allocate {
["laz" ] = "laz",
["lcr" ] = "l-cree",
["ldk" ] = "ladakhi",
+ ["lef" ] = "lelemi",
["lez" ] = "lezgi",
["lij" ] = "ligurian",
["lim" ] = "limburgish",
@@ -505,6 +533,7 @@ local languages = allocate {
["lmo" ] = "lombard",
["lmw" ] = "lomwe",
["lom" ] = "loma",
+ ["lpo" ] = "lipo",
["lrc" ] = "luri",
["lsb" ] = "lower sorbian",
["lsm" ] = "lule sami",
@@ -521,7 +550,7 @@ local languages = allocate {
["mah" ] = "marshallese",
["maj" ] = "majang",
["mak" ] = "makhuwa",
- ["mal" ] = "malayalam reformed",
+ ["mal" ] = "malayalam",
["mam" ] = "mam",
["man" ] = "mansi",
["map" ] = "mapudungun",
@@ -556,6 +585,7 @@ local languages = allocate {
["mok" ] = "moksha",
["mol" ] = "moldavian",
["mon" ] = "mon",
+ ["mnw" ] = "thailand mon",
["mor" ] = "moroccan",
["mos" ] = "mossi",
["mri" ] = "maori",
@@ -594,7 +624,7 @@ local languages = allocate {
["nor" ] = "norwegian",
["nov" ] = "novial",
["nsm" ] = "northern sami",
- ["nso" ] = "sotho, northern",
+ ["nso" ] = "northern sotho",
["nta" ] = "northern tai",
["nto" ] = "esperanto",
["nym" ] = "nyamwezi",
@@ -642,6 +672,7 @@ local languages = allocate {
["rbu" ] = "russian buriat",
["rcr" ] = "r-cree",
["rej" ] = "rejang",
+ ["rhg" ] = "rohingya",
["ria" ] = "riang",
["rif" ] = "tarifit",
["rit" ] = "ritarungo",
@@ -666,6 +697,7 @@ local languages = allocate {
["scs" ] = "north slavey",
["sek" ] = "sekota",
["sel" ] = "selkup",
+ ["sfm" ] = "small flowery miao",
["sga" ] = "old irish",
["sgo" ] = "sango",
["sgs" ] = "samogitian",
@@ -687,7 +719,7 @@ local languages = allocate {
["snk" ] = "soninke",
["sog" ] = "sodo gurage",
["sop" ] = "songe",
- ["sot" ] = "sotho, southern",
+ ["sot" ] = "southern sotho",
["sqi" ] = "albanian",
["srb" ] = "serbian",
["srd" ] = "sardinian",
@@ -728,7 +760,9 @@ local languages = allocate {
["tht" ] = "tahitian",
["tib" ] = "tibetan",
["tiv" ] = "tiv",
+ ["tj;" ] = "tai laing",
["tkm" ] = "turkmen",
+ ["tli" ] = "tlingit",
["tmh" ] = "tamashek",
["tmn" ] = "temne",
["tna" ] = "tswana",
@@ -742,7 +776,7 @@ local languages = allocate {
["tsj" ] = "tshangla",
["tua" ] = "turoyo aramaic",
["tul" ] = "tulu",
- ["tum" ] = "tulu",
+ ["tum" ] = "tumbuka",
["tuv" ] = "tuvin",
["tvl" ] = "tuvalu",
["twi" ] = "twi",
@@ -764,6 +798,7 @@ local languages = allocate {
["wa" ] = "wa",
["wag" ] = "wagdi",
["war" ] = "waray-waray",
+ ["wci" ] = "waci gbe",
["wcr" ] = "west-cree",
["wel" ] = "welsh",
["wlf" ] = "wolof",
@@ -775,17 +810,23 @@ local languages = allocate {
["xkf" ] = "khengkha",
["xog" ] = "soga",
["xpe" ] = "kpelle (liberia)",
+ ["xub" ] = "bette kuruma",
+ ["xuj" ] = "jennu kuruma",
["yak" ] = "sakha",
["yao" ] = "yao",
["yap" ] = "yapese",
["yba" ] = "yoruba",
["ycr" ] = "y-cree",
+ ["ygp" ] = "gepo",
["yic" ] = "yi classic",
["yim" ] = "yi modern",
+ ["yna" ] = "aluo",
+ ["ywq" ] = "wuding-luquan",
["zea" ] = "zealandic",
["zgh" ] = "standard morrocan tamazigh",
["zha" ] = "zhuang",
["zhh" ] = "chinese, hong kong sar",
+ ["zho" ] = "chinese traditional, macao",
["zhp" ] = "chinese phonetic",
["zhs" ] = "chinese simplified",
["zht" ] = "chinese traditional",
@@ -794,7 +835,6 @@ local languages = allocate {
["zza" ] = "zazaki",
}
-
local features = allocate {
["aalt"] = "access all alternates",
["abvf"] = "above-base forms",
@@ -811,6 +851,7 @@ local features = allocate {
["case"] = "case-sensitive forms",
["ccmp"] = "glyph composition/decomposition",
["cfar"] = "conjunct form after ro",
+ ["chws"] = "contextual half-width spacing",
["cjct"] = "conjunct forms",
["clig"] = "contextual ligatures",
["cpct"] = "centered cjk punctuation",
@@ -866,7 +907,7 @@ local features = allocate {
["nukt"] = "nukta forms",
["numr"] = "numerators",
["onum"] = "old style figures",
- ["opbd"] = "optical bounds",
+ ["opbd"] = "optical bounds", -- funny, this is obsolete (too hard?) (and was recomended always true)
["ordn"] = "ordinals",
["ornm"] = "ornaments",
["palt"] = "proportional alternate width",
@@ -887,8 +928,8 @@ local features = allocate {
["rtbd"] = "right bounds",
["rtla"] = "right-to-left alternates",
["rtlm"] = "right to left mirrored forms",
- ["rvrn"] = "required variation alternates",
["ruby"] = "ruby notation forms",
+ ["rvrn"] = "required variation alternates",
["salt"] = "stylistic alternates",
["sinf"] = "scientific inferiors",
["size"] = "optical size", -- now stat table
@@ -928,6 +969,7 @@ local features = allocate {
["unic"] = "unicase",
["valt"] = "alternate vertical metrics",
["vatu"] = "vattu variants",
+ ["vchw"] = "vertical contextual half-width spacing",
["vert"] = "vertical writing",
["vhal"] = "alternate vertical half metrics",
["vjmo"] = "vowel jamo forms",
diff --git a/tex/context/base/mkiv/math-act.lua b/tex/context/base/mkiv/math-act.lua
index a77fdc020..d56efbbfd 100644
--- a/tex/context/base/mkiv/math-act.lua
+++ b/tex/context/base/mkiv/math-act.lua
@@ -62,6 +62,9 @@ function mathematics.initializeparameters(target,original)
if not mathparameters.SpaceBeforeScript then
mathparameters.SpaceBeforeScript = mathparameters.SpaceAfterScript
end
+ if not mathparameters.SubscriptShiftDownWithSuperscript then
+ mathparameters.SubscriptShiftDownWithSuperscript = mathparameters.SubscriptShiftDown * 1.5
+ end
target.mathparameters = mathparameters
end
end
@@ -155,28 +158,67 @@ function mathematics.overloadparameters(target,original)
if trace_defining then
report_math("overloading math parameters in %a @ %p",target.properties.fullname,target.parameters.size)
end
+ -- for name, value in next, parameters do
+ -- local tvalue = type(value)
+ -- if tvalue == "string" then
+ -- report_math("comment for math parameter %a: %s",name,value)
+ -- else
+ -- local oldvalue = mathparameters[name]
+ -- local newvalue = oldvalue
+ -- if oldvalue then
+ -- if tvalue == "number" then
+ -- newvalue = value
+ -- elseif tvalue == "function" then
+ -- newvalue = value(oldvalue,target,original)
+ -- elseif not tvalue then
+ -- newvalue = nil
+ -- end
+ -- if trace_defining and oldvalue ~= newvalue then
+ -- report_math("overloading math parameter %a: %S => %S",name,oldvalue,newvalue)
+ -- end
+ -- else
+ -- -- report_math("invalid math parameter %a",name)
+ -- end
+ -- mathparameters[name] = newvalue
+ -- end
+ -- end
+ for name, value in next, parameters do
+ local tvalue = type(value)
+ local oldvalue = mathparameters[name]
+ local newvalue = oldvalue
+ if tvalue == "number" then
+ newvalue = value
+ elseif tvalue == "string" then
+ -- delay till all set
+ elseif tvalue == "function" then
+ newvalue = value(oldvalue,target,original)
+ elseif not tvalue then
+ newvalue = nil
+ end
+ if trace_defining and oldvalue ~= newvalue then
+ report_math("overloading math parameter %a: %S => %S",name,oldvalue or 0,newvalue)
+ end
+ mathparameters[name] = newvalue
+ end
for name, value in next, parameters do
local tvalue = type(value)
if tvalue == "string" then
- report_math("comment for math parameter %a: %s",name,value)
- else
- local oldvalue = mathparameters[name]
- local newvalue = oldvalue
- if oldvalue then
- if tvalue == "number" then
- newvalue = value
- elseif tvalue == "function" then
- newvalue = value(oldvalue,target,original)
- elseif not tvalue then
- newvalue = nil
- end
- if trace_defining and oldvalue ~= newvalue then
- report_math("overloading math parameter %a: %S => %S",name,oldvalue,newvalue)
+ local newvalue = mathparameters[value]
+ if not newvalue then
+ local code = loadstring("return " .. value,"","t",mathparameters)
+ if type(code) == "function" then
+ local okay, v = pcall(code)
+ if okay then
+ newvalue = v
+ end
end
- else
- -- report_math("invalid math parameter %a",name)
end
- mathparameters[name] = newvalue
+ if newvalue then
+ -- split in number and string
+ mathparameters[name] = newvalue
+ elseif trace_defining then
+ report_math("ignoring math parameter %a: %S",name,value)
+ end
end
end
end
diff --git a/tex/context/base/mkiv/math-dim.lua b/tex/context/base/mkiv/math-dim.lua
index 06b4bbd97..c46e16faf 100644
--- a/tex/context/base/mkiv/math-dim.lua
+++ b/tex/context/base/mkiv/math-dim.lua
@@ -132,7 +132,6 @@ end
function mathematics.dimensions(dimens) -- beware, dimens get spoiled
if dimens.SpaceAfterScript then
- dimens.SubscriptShiftDownWithSuperscript = dimens.SubscriptShiftDown * 1.5 -- move this one
return table.fastcopy(dimens), { }
elseif dimens.AxisHeight or dimens.axis_height then
local t = { }
diff --git a/tex/context/base/mkiv/mult-prm.lua b/tex/context/base/mkiv/mult-prm.lua
index 32b8aa440..891b795ad 100644
--- a/tex/context/base/mkiv/mult-prm.lua
+++ b/tex/context/base/mkiv/mult-prm.lua
@@ -266,6 +266,7 @@ return {
"alltextstyles",
"alluncrampedstyles",
"allunsplitstyles",
+ "amcode",
"atendofgroup",
"atendofgrouped",
"attribute",
@@ -297,6 +298,7 @@ return {
"boxymove",
"boxyoffset",
"catcodetable",
+ "cfcode",
"clearmarks",
"copymathatomrule",
"copymathparent",
@@ -305,6 +307,7 @@ return {
"crampedscriptscriptstyle",
"crampedscriptstyle",
"crampedtextstyle",
+ "csactive",
"csstring",
"currentloopiterator",
"currentloopnesting",
@@ -328,6 +331,7 @@ return {
"everytab",
"exceptionpenalty",
"expand",
+ "expandactive",
"expandafterpars",
"expandafterspaces",
"expandcstoken",
diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf
index c5ec75d70..da390abd8 100644
--- a/tex/context/base/mkiv/status-files.pdf
+++ b/tex/context/base/mkiv/status-files.pdf
Binary files differ
diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf
index afc189b09..ffd8cb5f2 100644
--- a/tex/context/base/mkiv/status-lua.pdf
+++ b/tex/context/base/mkiv/status-lua.pdf
Binary files differ
diff --git a/tex/context/base/mkxl/anch-box.mkxl b/tex/context/base/mkxl/anch-box.mkxl
index 0dec78838..88809152e 100644
--- a/tex/context/base/mkxl/anch-box.mkxl
+++ b/tex/context/base/mkxl/anch-box.mkxl
@@ -93,7 +93,6 @@
{\setupmathfence[\c!leftsource=,\c!rightsource=]%
\glet\m_anch_matrix_list\empty}
-
\defineboxanchorcontent
[arrow]
[\c!mp=mypos:boxanchor:arrow,
diff --git a/tex/context/base/mkxl/catc-def.mkxl b/tex/context/base/mkxl/catc-def.mkxl
index 896dd35d3..e24aa9cb3 100644
--- a/tex/context/base/mkxl/catc-def.mkxl
+++ b/tex/context/base/mkxl/catc-def.mkxl
@@ -24,13 +24,13 @@
\ifdefined\texcatcodes \else \newcatcodetable \texcatcodes \fi
\ifdefined\luacatcodes \else \newcatcodetable \luacatcodes \fi
\ifdefined\notcatcodes \else \newcatcodetable \notcatcodes \fi
-\ifdefined\rlncatcodes \else \newcatcodetable \rlncatcodes \fi
+\ifdefined\rlncatcodes \else \newcatcodetable \rlncatcodes \fi % readline, not for context
\ifdefined\vrbcatcodes \else \newcatcodetable \vrbcatcodes \fi
\ifdefined\prtcatcodes \else \newcatcodetable \prtcatcodes \fi
\ifdefined\ctxcatcodes \else \newcatcodetable \ctxcatcodes \fi
\ifdefined\txtcatcodes \else \newcatcodetable \txtcatcodes \fi
-\ifdefined\tpacatcodes \else \newcatcodetable \tpacatcodes \fi % { }
-\ifdefined\tpbcatcodes \else \newcatcodetable \tpbcatcodes \fi % < >
+\ifdefined\tpacatcodes \else \newcatcodetable \tpacatcodes \fi % verbatim: { }
+\ifdefined\tpbcatcodes \else \newcatcodetable \tpbcatcodes \fi % verbatim: < >
\ifdefined\ctdcatcodes \else \newcatcodetable \ctdcatcodes \fi % context definitions
\startcatcodetable \nilcatcodes
@@ -254,6 +254,9 @@
\letcatcodecommand \ctxcatcodes \barasciicode \relax
\letcatcodecommand \ctxcatcodes \tildeasciicode \relax
+% \letcatcodecommand \prtcatcodes \barasciicode \relax
+% \letcatcodecommand \prtcatcodes \tildeasciicode \relax
+
%D Because some characters have a special meaning, we provide shortcuts to their
%D character representation. Some will be overloaded (which might change).
@@ -273,4 +276,9 @@
\aliased\let\defaultcatcodetable\ctxcatcodes
\popoverloadmode
+\amcode \circumflexasciicode \superscriptcatcode
+\amcode \underscoreasciicode \subscriptcatcode
+\amcode \barasciicode \othercatcode
+\amcode \tildeasciicode \othercatcode
+
\endinput
diff --git a/tex/context/base/mkxl/catc-ini.mkxl b/tex/context/base/mkxl/catc-ini.mkxl
index 4376acd83..0740e7e2a 100644
--- a/tex/context/base/mkxl/catc-ini.mkxl
+++ b/tex/context/base/mkxl/catc-ini.mkxl
@@ -39,18 +39,19 @@
%D We predefine some prefixes ahead of syst-aux and mult-sys. We reserve 8 slots for
%D catcodes. (This active mess probably needs an update some day.)
-\installsystemnamespace{catcodelet} % let : \let
-\installsystemnamespace{catcodedef} % def : \def
-\installsystemnamespace{catcodeued} % ued : \protected\def
-\installsystemnamespace{catcodeget} % \meaning
+% \installsystemnamespace{catcodelet} % let : \let
+% \installsystemnamespace{catcodedef} % def : \def
+% \installsystemnamespace{catcodeued} % ued : \protected\def
+% \installsystemnamespace{catcodeget} % \meaning
\installsystemnamespace{catcodetablet}
\installsystemnamespace{catcodetablen}
\newcount\c_syst_catcodes_n \c_syst_catcodes_n\zerocount % 0 = signal, so advance before allocate
-\newcount\c_syst_catcodes_a
-\newcount\c_syst_catcodes_b
-\newcount\c_syst_catcodes_c
+
+% \newcount\c_syst_catcodes_a
+% \newcount\c_syst_catcodes_b
+% \newcount\c_syst_catcodes_c
\permanent\protected\def\newcatcodetable#1% we could move the cctdefcounter to lua
{\global\advance\c_syst_catcodes_n\plusone
@@ -92,6 +93,8 @@
\aliased\let\permitcaretescape\permitcircumflexescape
+\newconstant\defaultcatcodetable
+
% ==
%
% \protected\def\startextendcatcodetable#1#2\stopextendcatcodetable
@@ -104,99 +107,147 @@
%D The next command can be defined in a cleaner way in the MkIV way but we want
%D to have a fast one with a minimal chance for interference. Do we still need
%D this complex mechanism? Probably not. Future versions of \MKIV\ might only use
-%D active characters for very special cases.
-
-\setnewconstant\c_syst_catcodes_hack\tildeasciicode
-
-%D Once a catcode is assigned, the next assignments will happen faster. However,
-%D redefinitions probably happen seldom so it's sort of overkill.
-
-\permanent\protected\def\letcatcodecommand{\afterassignment\syst_catcodes_let_a\c_syst_catcodes_a}
-\permanent\protected\def\defcatcodecommand{\afterassignment\syst_catcodes_def_a\c_syst_catcodes_a}
-\permanent\protected\def\uedcatcodecommand{\afterassignment\syst_catcodes_ued_a\c_syst_catcodes_a}
-
-\def\syst_catcodes_let_a{\afterassignment\syst_catcodes_let_b\c_syst_catcodes_b}
-\def\syst_catcodes_def_a{\afterassignment\syst_catcodes_def_b\c_syst_catcodes_b}
-\def\syst_catcodes_ued_a{\afterassignment\syst_catcodes_ued_b\c_syst_catcodes_b}
-
-\def\syst_catcodes_let_b % each time
- {\ifcsname\??catcodelet\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname
- \expandafter\lastnamedcs
- \else
- \expandafter\syst_catcodes_let_c
- \fi}
-
-\def\syst_catcodes_def_b % each time
- {\ifcsname\??catcodedef\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname
- \expandafter\lastnamedcs
- \else
- \expandafter\syst_catcodes_def_c
- \fi}
+%D active characters for very special cases. Older files demonstrate this old
+%D hackery tilde abuse.
-\def\syst_catcodes_ued_b % each time
- {\ifcsname\??catcodeued\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname
- \expandafter\lastnamedcs
- \else
- \expandafter\syst_catcodes_ued_c
- \fi}
-
-\def\syst_catcodes_let_c % only first time
- {\frozen\enforced\gdefcsname\??catcodelet\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\expandafter\endcsname\expandafter
- {\enforced\letcsname\??catcodeget\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname}%
- \syst_catcodes_reinstate_unexpanded
- \csname\??catcodelet\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname}
-
-\def\syst_catcodes_def_c % only first time (we could use \normalexpanded here)
- {\frozen\enforced\gdefcsname\??catcodedef\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\expandafter\endcsname
- \expandafter##\expandafter1\expandafter
- {\frozen\enforced\defcsname\??catcodeget\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname{##1}}%
- \syst_catcodes_reinstate_normal
- \csname\??catcodedef\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname}
-
-\def\syst_catcodes_ued_c % only first time
- {\frozen\enforced\gdefcsname\??catcodeued\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\expandafter\endcsname
- \expandafter##\expandafter1\expandafter
- {\frozen\enforced\protected\defcsname\??catcodeget\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname{##1}}%
- \syst_catcodes_reinstate_unexpanded
- \csname\??catcodeued\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname}
-
-\permanent\def\reinstatecatcodecommand{\afterassignment\syst_catcodes_reinstate_normal\c_syst_catcodes_b}
+% %D Once a catcode is assigned, the next assignments will happen faster. However,
+% %D redefinitions probably happen seldom so it's sort of overkill. We also need to
+% %D take care of the initial (shared between catcode regfimes) binding.
+%
+% \permanent\protected\def\letcatcodecommand{\afterassignment\syst_catcodes_let_a\c_syst_catcodes_a}
+% \permanent\protected\def\defcatcodecommand{\afterassignment\syst_catcodes_def_a\c_syst_catcodes_a} % obsolete
+% \permanent\protected\def\uedcatcodecommand{\afterassignment\syst_catcodes_ued_a\c_syst_catcodes_a} % obsolete
+%
+% \def\syst_catcodes_let_a{\afterassignment\syst_catcodes_let_b\c_syst_catcodes_b}
+% \def\syst_catcodes_def_a{\afterassignment\syst_catcodes_def_b\c_syst_catcodes_b}
+% \def\syst_catcodes_ued_a{\afterassignment\syst_catcodes_ued_b\c_syst_catcodes_b}
+%
+% % The two step definition is used because we need to fetch the third argument.
+%
+% \def\syst_catcodes_let_b % each time
+% {\ifcsname\??catcodelet\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname
+% \expandafter\lastnamedcs
+% \else
+% \expandafter\syst_catcodes_let_c
+% \fi}
+%
+% \def\syst_catcodes_def_b % each time
+% {\ifcsname\??catcodedef\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname
+% \expandafter\lastnamedcs
+% \else
+% \expandafter\syst_catcodes_def_c
+% \fi}
+%
+% \def\syst_catcodes_ued_b % each time
+% {\ifcsname\??catcodeued\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname
+% \expandafter\lastnamedcs
+% \else
+% \expandafter\syst_catcodes_ued_c
+% \fi}
+%
+% \def\syst_catcodes_let_c % only first time
+% {\frozen\enforced\gdefcsname\??catcodelet\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\expandafter\endcsname\expandafter
+% {\expandafter\enforced\letcsname\??catcodeget\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname}%
+% \syst_catcodes_reinstate_unexpanded
+% \csname\??catcodelet\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname}
+%
+% \def\syst_catcodes_def_c % only first time (we could use \normalexpanded here)
+% {\frozen\enforced\gdefcsname\??catcodedef\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\expandafter\endcsname
+% \expandafter##\expandafter1\expandafter
+% {\expandafter\frozen\expandafter\enforced\defcsname\??catcodeget\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname{##1}}%
+% \syst_catcodes_reinstate_normal
+% \csname\??catcodedef\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname}
+%
+% \def\syst_catcodes_ued_c % only first time
+% {\frozen\enforced\gdefcsname\??catcodeued\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\expandafter\endcsname
+% \expandafter##\expandafter1\expandafter
+% {\expandafter\frozen\expandafter\enforced\expandafter\protected\defcsname\??catcodeget\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname{##1}}%
+% \syst_catcodes_reinstate_unexpanded
+% \csname\??catcodeued\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname}
+%
+% %D We can simplify this a bit (not that critical):
+%
+% \def\syst_catcodes_let_b
+% {\afterassignment\syst_catcodes_let_c\let\m_syst_catcodes_temp}
+%
+% \def\syst_catcodes_let_c
+% {\enforced\letcsname\??catcodeget\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname\m_syst_catcodes_temp
+% \protected\edef\m_syst_catcodes_temp{\noexpand\catcodecommand{\number\c_syst_catcodes_b}}%
+% \letcharcode\c_syst_catcodes_b\m_syst_catcodes_temp}
+%
+% \def\syst_catcodes_let_c
+% {\letcharcode\c_syst_catcodes_b\m_syst_catcodes_temp}
+%
+% % not that much gain:
+%
+% \def\syst_catcodes_let_c % only first time
+% {\expandafter\integerdef\csname\??catcodelet\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname\c_syst_catcodes_b
+% \letcsname\??catcodeget\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname\m_syst_catcodes_temp
+% \protected\edef\m_syst_catcodes_temp{\noexpand\catcodecommand\csname\??catcodelet\number\c_syst_catcodes_a:\number\c_syst_catcodes_b\endcsname}%
+% \letcharcode\c_syst_catcodes_b\m_syst_catcodes_temp}
%D This can be used when a direct definition has been done and the selector has been
-%D lost. A problem is that \type {\next} needs to be unique (as it gets bound) (still?).
+%D lost. I really need to get rid of this ...
+% \permanent\def\reinstatecatcodecommand{\afterassignment\syst_catcodes_reinstate_normal\c_syst_catcodes_b}
+%
+% \let\m_syst_catcodes_temp\relax
+%
% \def\syst_catcodes_reinstate_normal
-% {\begingroup
-% \edef\temp{\noexpand\catcodecommand{\number\c_syst_catcodes_b}}%
-% \global\letcharcode\c_syst_catcodes_b\temp
-% \endgroup}
+% {\edef\m_syst_catcodes_temp{\noexpand\catcodecommand{\number\c_syst_catcodes_b}}%
+% \letcharcode\c_syst_catcodes_b\m_syst_catcodes_temp}
%
% \def\syst_catcodes_reinstate_unexpanded
-% {\begingroup
-% \protected\edef\temp{\noexpand\catcodecommand{\number\c_syst_catcodes_b}}%
-% \global\letcharcode\c_syst_catcodes_b\temp
-% \endgroup}
-
-% I really need to get rid of this ...
-
-\let\m_syst_catcodes_temp\relax
-
-\def\syst_catcodes_reinstate_normal
- {\edef\m_syst_catcodes_temp{\noexpand\catcodecommand{\number\c_syst_catcodes_b}}%
- \letcharcode\c_syst_catcodes_b\m_syst_catcodes_temp}
-
-\def\syst_catcodes_reinstate_unexpanded
- {\protected\edef\m_syst_catcodes_temp{\noexpand\catcodecommand{\number\c_syst_catcodes_b}}%
- \letcharcode\c_syst_catcodes_b\m_syst_catcodes_temp}
-
-\newconstant\defaultcatcodetable
-
-\permanent\def\catcodecommand#1%
- {\csname\??catcodeget\number
- \ifcsname\??catcodeget\number\currentcatcodetable:\number#1\endcsname
- \currentcatcodetable \else \defaultcatcodetable
- \fi
- :\number#1\endcsname}
+% {\protected\edef\m_syst_catcodes_temp{\noexpand\catcodecommand{\number\c_syst_catcodes_b}}%
+% \letcharcode\c_syst_catcodes_b\m_syst_catcodes_temp}
+%
+% \permanent\def\catcodecommand#1%
+% {\csname\??catcodeget\number
+% \ifcsname\??catcodeget\number\currentcatcodetable:\number#1\endcsname
+% \currentcatcodetable \else \defaultcatcodetable
+% \fi
+% :\number#1\endcsname}
+
+%D For now, will become just letcharcode:
+
+\permanent\protected\def\letcatcodecommand{\afterassignment\letcharcode\scratchcounter}
+
+%D \startbuffer
+%D \def\foo{foo}
+%D \start
+%D \pushactivechar | \letcharcode124 \foo test||test\par
+%D \popactivechar | test||test\par
+%D \stop
+%D \start
+%D \pushactivecharcode124 \letcharcode124 \foo test||test\par
+%D \popactivecharcode 124 test||test\par
+%D \stop
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\permanent\protected\def\pushactivechar#1%
+ {\expandafter\let\expandafter\m_active\csname\csactive#1\endcsname
+ %\expandafter\let\expandafter\m_active\csname\Uchar"FFFF\Uchar\expandafter`\string#1\endcsname
+ \pushmacro\m_active}
+
+\permanent\protected\def\popactivechar#1%
+ {\popmacro\m_active
+ %\letcsname\Uchar"FFFF\Uchar\expandafter`\string#1\endcsname\m_active
+ \letcsname\csactive#1\endcsname\m_active}
+
+\permanent\protected\def\pushactivecharcode{\afterassignment\syst_active_push\integerdef\c_active_char_code}
+\permanent\protected\def\popactivecharcode {\afterassignment\syst_active_pop\integerdef \c_active_char_code}
+
+\permanent\protected\def\syst_active_push
+ {\expandafter\let\expandafter\m_active\csname\csactive\Uchar\c_active_char_code\endcsname
+ %\expandafter\let\expandafter\m_active\csname\Uchar"FFFF\Uchar\c_active_char_code\endcsname
+ \pushmacro\m_active}
+
+\permanent\protected\def\syst_active_pop
+ {\popmacro\m_active
+ %\letcsname\Uchar"FFFF\Uchar\c_active_char_code\endcsname\m_active
+ \letcsname\csactive\Uchar\c_active_char_code\endcsname\m_active}
%D \macros
%D {restorecatcodes,pushcatcodetable,popcatcodetable}
diff --git a/tex/context/base/mkxl/cont-new.mkxl b/tex/context/base/mkxl/cont-new.mkxl
index 2d953077e..2ac4217cd 100644
--- a/tex/context/base/mkxl/cont-new.mkxl
+++ b/tex/context/base/mkxl/cont-new.mkxl
@@ -13,7 +13,7 @@
% \normalend % uncomment this to get the real base runtime
-\newcontextversion{2022.11.18 13:15}
+\newcontextversion{2022.12.01 12:38}
%D This file is loaded at runtime, thereby providing an excellent place for hacks,
%D patches, extensions and new features. There can be local overloads in cont-loc
diff --git a/tex/context/base/mkxl/context.mkxl b/tex/context/base/mkxl/context.mkxl
index 47a9ffb4b..1391f64e7 100644
--- a/tex/context/base/mkxl/context.mkxl
+++ b/tex/context/base/mkxl/context.mkxl
@@ -29,7 +29,7 @@
%D {YYYY.MM.DD HH:MM} format.
\immutable\edef\contextformat {\jobname}
-\immutable\edef\contextversion{2022.11.18 13:15}
+\immutable\edef\contextversion{2022.12.01 12:38}
%overloadmode 1 % check frozen / warning
%overloadmode 2 % check frozen / error
diff --git a/tex/context/base/mkxl/driv-shp.lmt b/tex/context/base/mkxl/driv-shp.lmt
index 941365f59..7f74bd2e3 100644
--- a/tex/context/base/mkxl/driv-shp.lmt
+++ b/tex/context/base/mkxl/driv-shp.lmt
@@ -659,7 +659,6 @@ local hlist_out, vlist_out do
if si then
local box = si -- si[1]
finalize(box) -- tricky: we might need to group
--- print(getanchors(box))
if getid(box) == vlist_code then
vlist_out(current,box)
else
@@ -717,11 +716,6 @@ local hlist_out, vlist_out do
local function applyanchor(anchor,shift,anchor_h,anchor_v,width,height,depth)
local h = 0
local v = 0
- if shift then
- anchor = (anchor & 0xFFFF0000) >> 16
- else
- anchor = (anchor & 0x0000FFFF)
- end
local a = anchor & 0x00FF
local s = anchor & 0x0F00
if a == 0x02 then
@@ -805,8 +799,12 @@ local hlist_out, vlist_out do
-- we can encounter par, boundary and penalty nodes but a special
-- iterator over content nodes won't save much
for current, id, subtype in nextnode, current do
+-- if id == nil then
+-- print("bad node",current)
+-- end
if id == glyph_code then
local char, font = isglyph(current)
+-- if char then
local x_offset, y_offset, left, right, raise = getoffsets(current)
if x_offset ~= 0 or y_offset ~= 0 then
if pos_r == righttoleft_code then
@@ -823,6 +821,9 @@ local hlist_out, vlist_out do
local wd = flush_character(current,font,char,false,true,pos_h,pos_v,pos_r)
-- cur_h = cur_h + wd - right -- hm, no left here?
cur_h = cur_h + wd -- see new tabulate alignment code
+-- else
+-- print("bad character",current,nuts.getfont(current),nuts.getchar(current))
+-- end
elseif id == glue_code then
-- local gluewidth = effectiveglue(current,this_box)
local gluewidth = effectiveglue(current,this_box,true)
@@ -975,13 +976,11 @@ local hlist_out, vlist_out do
local boxdir = getdirection(current) or lefttoright_code
local shift = getshift(current)
local geometry, hasoffset, hasorientation, hasanchor = getgeometry(current,true)
- local anchor, source, target, targetdata
+ local anchor, source, target, targetdata, s_anchor, t_anchor
local anc_h, anc_v
local usedorientation = false
if hasanchor then
- anchor, source, target = getanchors(current)
--- print(getanchors(current))
--- if not anchor then anchor = 0 end
+ anchor, source, target, s_anchor, t_anchor = getanchors(current)
end
if hasorientation then
local orientation, xoffset, yoffset, woffset, hoffset, doffset = getorientation(current)
@@ -1074,8 +1073,10 @@ local hlist_out, vlist_out do
end
pos_v = targetdata[2] + anc_v
if anchor and anchor > 0 then
- pos_h, pos_v = applyanchor(anchor,true,pos_h,pos_v,targetdata[3],targetdata[4],targetdata[5])
- pos_h, pos_v = applyanchor(anchor,false,pos_h,pos_v,width,height,depth)
+-- pos_h, pos_v = applyanchor(anchor,true,t_anchor,pos_h,pos_v,targetdata[3],targetdata[4],targetdata[5])
+-- pos_h, pos_v = applyanchor(anchor,false,s_anchor,pos_h,pos_v,width,height,depth)
+ pos_h, pos_v = applyanchor(t_anchor,true, pos_h,pos_v,targetdata[3],targetdata[4],targetdata[5])
+ pos_h, pos_v = applyanchor(s_anchor,false,pos_h,pos_v,width,height,depth)
end
::process::
if source then
@@ -1365,10 +1366,10 @@ local glueheight = effectiveglue(current,this_box,true)
local boxdir = getdirection(current) or lefttoright_code
local shift = getshift(current)
local geometry, hasoffset, hasorientation, hasanchor = getgeometry(current,true)
- local anchor, source, target, targetdata
+ local anchor, source, target, targetdata, s_anchor, t_anchor
local usedorientation = false
if hasanchor then
- anchor, source, target = getanchors(current)
+ anchor, source, target, s_anchor, t_anchor = getanchors(current)
end
if hasorientation then
local orientation, xoffset, yoffset, woffset, hoffset, doffset = getorientation(current)
@@ -1469,8 +1470,10 @@ local glueheight = effectiveglue(current,this_box,true)
goto process
::posdone::
if anchor and anchor > 0 then
- pos_h, pos_v = applyanchor(anchor,true,pos_h,pos_v,targetdata[3],targetdata[4],targetdata[5])
- pos_h, pos_v = applyanchor(anchor,false,pos_h,pos_v,width,height,depth)
+-- pos_h, pos_v = applyanchor(anchor,true,t_anchor,pos_h,pos_v,targetdata[3],targetdata[4],targetdata[5])
+-- pos_h, pos_v = applyanchor(anchor,false,s_anchor,pos_h,pos_v,width,height,depth)
+ pos_h, pos_v = applyanchor(t_anchor,true, pos_h,pos_v,targetdata[3],targetdata[4],targetdata[5])
+ pos_h, pos_v = applyanchor(s_anchor,false,pos_h,pos_v,width,height,depth)
end
::process::
if source then
diff --git a/tex/context/base/mkxl/driv-usr.lmt b/tex/context/base/mkxl/driv-usr.lmt
index 04e7da5e6..0542228aa 100644
--- a/tex/context/base/mkxl/driv-usr.lmt
+++ b/tex/context/base/mkxl/driv-usr.lmt
@@ -125,11 +125,11 @@ cur_h = cur_h + effectiveglue(current,this_box,true)
local boxdir = getdirection(current) or lefttoright_code
local shift = getshift(current)
local geometry, hasoffset, hasorientation, hasanchor = getgeometry(current,true)
- local anchor, source, target, targetdata
+ local anchor, source, target, targetdata, s_anchor, t_anchor
local anc_h, anc_v
local usedorientation = false
if hasanchor then
- anchor, source, target = getanchors(current)
+ anchor, source, target, s_anchor, t_anchor = getanchors(current)
end
if hasorientation then
local orientation, xoffset, yoffset, woffset, hoffset, doffset = getorientation(current)
@@ -221,8 +221,8 @@ cur_h = cur_h + effectiveglue(current,this_box,true)
end
pos_v = targetdata[2] + anc_v
if anchor and anchor > 0 then
- pos_h, pos_v = applyanchor(anchor,true,pos_h,pos_v,targetdata[3],targetdata[4],targetdata[5])
- pos_h, pos_v = applyanchor(anchor,false,pos_h,pos_v,width,height,depth)
+ pos_h, pos_v = applyanchor(t_anchor,true, pos_h,pos_v,targetdata[3],targetdata[4],targetdata[5])
+ pos_h, pos_v = applyanchor(s_anchor,false,pos_h,pos_v,width,height,depth)
end
::process::
if source then
@@ -359,10 +359,10 @@ cur_v = cur_v + effectiveglue(current,this_box,true)
local boxdir = getdirection(current) or lefttoright_code
local shift = getshift(current)
local geometry, hasoffset, hasorientation, hasanchor = getgeometry(current,true)
- local anchor, source, target, targetdata
+ local anchor, source, target, targetdata, s_anchor, t_anchor
local usedorientation = false
if hasanchor then
- anchor, source, target = getanchors(current)
+ anchor, source, target, s_anchor, t_anchor = getanchors(current)
end
if hasorientation then
local orientation, xoffset, yoffset, woffset, hoffset, doffset = getorientation(current)
@@ -462,8 +462,8 @@ cur_v = cur_v + effectiveglue(current,this_box,true)
goto process
::posdone::
if anchor and anchor > 0 then
- pos_h, pos_v = applyanchor(anchor,true,pos_h,pos_v,targetdata[3],targetdata[4],targetdata[5])
- pos_h, pos_v = applyanchor(anchor,false,pos_h,pos_v,width,height,depth)
+ pos_h, pos_v = applyanchor(t_anchor,true, pos_h,pos_v,targetdata[3],targetdata[4],targetdata[5])
+ pos_h, pos_v = applyanchor(s_anchor,false,pos_h,pos_v,width,height,depth)
end
::process::
if source then
diff --git a/tex/context/base/mkxl/font-con.lmt b/tex/context/base/mkxl/font-con.lmt
index daf106a8a..117e81a66 100644
--- a/tex/context/base/mkxl/font-con.lmt
+++ b/tex/context/base/mkxl/font-con.lmt
@@ -502,7 +502,12 @@ function constructors.scale(tfmdata,specification)
local scaledheight = defaultheight * vdelta
local scaleddepth = defaultdepth * vdelta
--
- local textcontrol = properties.textcontrol
+ local textcontrol = properties.textcontrol or 0
+ if targetproperties.mode == "base" then
+ textcontrol = textcontrol | 0x02 | 0x04 -- todo symbolic
+ elseif targetproperties.mode == "none" then
+ textcontrol = textcontrol | 0x08 -- todo symbolic
+ end
targetproperties.textcontrol = textcontrol
target.textcontrol = textcontrol
--
diff --git a/tex/context/base/mkxl/font-dsp.lmt b/tex/context/base/mkxl/font-dsp.lmt
new file mode 100644
index 000000000..28a1d4e3c
--- /dev/null
+++ b/tex/context/base/mkxl/font-dsp.lmt
@@ -0,0 +1,4646 @@
+if not modules then modules = { } end modules ['font-dsp'] = {
+ version = 1.001,
+ optimize = true,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- many 0,0 entry/exit
+
+-- This loader went through a few iterations. First I made a ff compatible one so
+-- that we could do some basic checking. Also some verbosity was added (named
+-- glyphs). Eventually all that was dropped for a context friendly format, simply
+-- because keeping the different table models in sync too to much time. I have the
+-- old file somewhere. A positive side effect is that we get an (upto) much smaller
+-- smaller tma/tmc file. In the end the loader will be not much slower than the
+-- c based ff one.
+
+-- Being binary encoded, an opentype is rather compact. When expanded into a Lua table
+-- quite some memory can be used. This is very noticeable in the ff loader, which for
+-- a good reason uses a verbose format. However, when we use that data we create a couple
+-- of hashes. In the Lua loader we create these hashes directly, which save quite some
+-- memory.
+--
+-- We convert a font file only once and then cache it. Before creating the cached instance
+-- packing takes place: common tables get shared. After (re)loading and unpacking we then
+-- get a rather efficient internal representation of the font. In the new loader there is a
+-- pitfall. Because we use some common coverage magic we put a bit more information in
+-- the mark and cursive coverage tables than strickly needed: a reference to the coverage
+-- itself. This permits a fast lookup of the second glyph involved. In the marks we
+-- expand the class indicator to a class hash, in the cursive we use a placeholder that gets
+-- a self reference. This means that we cannot pack these subtables unless we add a unique
+-- id per entry (the same one per coverage) and that makes the tables larger. Because only a
+-- few fonts benefit from this, I decided to not do this. Experiments demonstrated that it
+-- only gives a few percent gain (on for instance husayni we can go from 845K to 828K
+-- bytecode). Better stay conceptually clean than messy compact.
+
+-- When we can reduce all basic lookups to one step we might safe a bit in the processing
+-- so then only chains are multiple.
+
+-- I used to flatten kerns here but that has been moved elsewhere because it polutes the code
+-- here and can be done fast afterwards. One can even wonder if it makes sense to do it as we
+-- pack anyway. In a similar fashion the unique placeholders in anchors in marks have been
+-- removed because packing doesn't save much there anyway.
+
+-- Although we have a bit more efficient tables in the cached files, the internals are still
+-- pretty similar. And although we have a slightly more direct coverage access the processing
+-- of node lists is not noticeable faster for latin texts, but for arabic we gain some 10%
+-- (and could probably gain a bit more).
+
+-- All this packing in the otf format is somewhat obsessive as nowadays 4K resolution
+-- multi-gig videos pass through our networks and storage and memory is abundant.
+
+-- Although we use a few table readers there i sno real gain in there (apart from having
+-- less code. After all there are often not that many demanding features.
+
+local next, type, tonumber = next, type, tonumber
+local band = bit32.band
+local extract = bit32.extract
+local bor = bit32.bor
+local lshift = bit32.lshift
+local rshift = bit32.rshift
+local gsub = string.gsub
+local lower = string.lower
+local sub = string.sub
+local strip = string.strip
+local tohash = table.tohash
+local concat = table.concat
+local copy = table.copy
+local reversed = table.reversed
+local sort = table.sort
+local insert = table.insert
+local round = math.round
+
+local settings_to_hash = utilities.parsers.settings_to_hash_colon_too
+local setmetatableindex = table.setmetatableindex
+local formatters = string.formatters
+local sortedkeys = table.sortedkeys
+local sortedhash = table.sortedhash
+local sequenced = table.sequenced
+
+local report = logs.reporter("otf reader")
+
+local readers = fonts.handlers.otf.readers
+local streamreader = readers.streamreader
+
+local setposition = streamreader.setposition
+local getposition = streamreader.getposition
+local readuinteger = streamreader.readcardinal1
+local readushort = streamreader.readcardinal2
+local readuoffset = streamreader.readcardinal3
+local readulong = streamreader.readcardinal4
+local readinteger = streamreader.readinteger1
+local readshort = streamreader.readinteger2
+local readstring = streamreader.readstring
+local readtag = streamreader.readtag
+local readbytes = streamreader.readbytes
+local readfixed = streamreader.readfixed4
+local read2dot14 = streamreader.read2dot14
+local skipshort = streamreader.skipshort
+local skipbytes = streamreader.skip
+local readbytetable = streamreader.readbytetable
+local readbyte = streamreader.readbyte
+local readcardinaltable = streamreader.readcardinaltable
+local readintegertable = streamreader.readintegertable
+local readfword = readshort
+
+local short = 2
+local ushort = 2
+local uoffset = 3
+local ulong = 4
+
+directives.register("fonts.streamreader",function()
+
+ streamreader = utilities.streams
+
+ setposition = streamreader.setposition
+ getposition = streamreader.getposition
+ readuinteger = streamreader.readcardinal1
+ readushort = streamreader.readcardinal2
+ readuoffset = streamreader.readcardinal3
+ readulong = streamreader.readcardinal4
+ readinteger = streamreader.readinteger1
+ readshort = streamreader.readinteger2
+ readstring = streamreader.readstring
+ readtag = streamreader.readtag
+ readbytes = streamreader.readbytes
+ readfixed = streamreader.readfixed4
+ read2dot14 = streamreader.read2dot14
+ skipshort = streamreader.skipshort
+ skipbytes = streamreader.skip
+ readbytetable = streamreader.readbytetable
+ readbyte = streamreader.readbyte
+ readcardinaltable = streamreader.readcardinaltable
+ readintegertable = streamreader.readintegertable
+ readfword = readshort
+
+end)
+
+local gsubhandlers = { }
+local gposhandlers = { }
+
+readers.gsubhandlers = gsubhandlers
+readers.gposhandlers = gposhandlers
+
+local helpers = readers.helpers
+local gotodatatable = helpers.gotodatatable
+local setvariabledata = helpers.setvariabledata
+
+local lookupidoffset = -1 -- will become 1 when we migrate (only -1 for comparign with old)
+
+local classes = {
+ "base",
+ "ligature",
+ "mark",
+ "component",
+}
+
+local gsubtypes = {
+ "single",
+ "multiple",
+ "alternate",
+ "ligature",
+ "context",
+ "chainedcontext",
+ "extension",
+ "reversechainedcontextsingle",
+}
+
+local gpostypes = {
+ "single",
+ "pair",
+ "cursive",
+ "marktobase",
+ "marktoligature",
+ "marktomark",
+ "context",
+ "chainedcontext",
+ "extension",
+}
+
+local chaindirections = {
+ context = 0,
+ chainedcontext = 1,
+ reversechainedcontextsingle = -1,
+}
+
+local function setmetrics(data,where,tag,d)
+ local w = data[where]
+ if w then
+ local v = w[tag]
+ if v then
+ -- it looks like some fonts set the value and not the delta
+ -- report("adding %s to %s.%s value %s",d,where,tag,v)
+ w[tag] = v + d
+ end
+ end
+end
+
+local variabletags = {
+ hasc = function(data,d) setmetrics(data,"windowsmetrics","typoascender",d) end,
+ hdsc = function(data,d) setmetrics(data,"windowsmetrics","typodescender",d) end,
+ hlgp = function(data,d) setmetrics(data,"windowsmetrics","typolinegap",d) end,
+ hcla = function(data,d) setmetrics(data,"windowsmetrics","winascent",d) end,
+ hcld = function(data,d) setmetrics(data,"windowsmetrics","windescent",d) end,
+ vasc = function(data,d) setmetrics(data,"vhea not done","ascent",d) end,
+ vdsc = function(data,d) setmetrics(data,"vhea not done","descent",d) end,
+ vlgp = function(data,d) setmetrics(data,"vhea not done","linegap",d) end,
+ xhgt = function(data,d) setmetrics(data,"windowsmetrics","xheight",d) end,
+ cpht = function(data,d) setmetrics(data,"windowsmetrics","capheight",d) end,
+ sbxs = function(data,d) setmetrics(data,"windowsmetrics","subscriptxsize",d) end,
+ sbys = function(data,d) setmetrics(data,"windowsmetrics","subscriptysize",d) end,
+ sbxo = function(data,d) setmetrics(data,"windowsmetrics","subscriptxoffset",d) end,
+ sbyo = function(data,d) setmetrics(data,"windowsmetrics","subscriptyoffset",d) end,
+ spxs = function(data,d) setmetrics(data,"windowsmetrics","superscriptxsize",d) end,
+ spys = function(data,d) setmetrics(data,"windowsmetrics","superscriptysize",d) end,
+ spxo = function(data,d) setmetrics(data,"windowsmetrics","superscriptxoffset",d) end,
+ spyo = function(data,d) setmetrics(data,"windowsmetrics","superscriptyoffset",d) end,
+ strs = function(data,d) setmetrics(data,"windowsmetrics","strikeoutsize",d) end,
+ stro = function(data,d) setmetrics(data,"windowsmetrics","strikeoutpos",d) end,
+ unds = function(data,d) setmetrics(data,"postscript","underlineposition",d) end,
+ undo = function(data,d) setmetrics(data,"postscript","underlinethickness",d) end,
+}
+
+local read_cardinal = {
+ streamreader.readcardinal1,
+ streamreader.readcardinal2,
+ streamreader.readcardinal3,
+ streamreader.readcardinal4,
+}
+
+local read_integer = {
+ streamreader.readinteger1,
+ streamreader.readinteger2,
+ streamreader.readinteger3,
+ streamreader.readinteger4,
+}
+
+-- Traditionally we use these unique names (so that we can flatten the lookup list
+-- (we create subsets runtime) but I will adapt the old code to newer names.
+
+-- chainsub
+-- reversesub
+
+local lookupnames = {
+ gsub = {
+ single = "gsub_single",
+ multiple = "gsub_multiple",
+ alternate = "gsub_alternate",
+ ligature = "gsub_ligature",
+ context = "gsub_context",
+ chainedcontext = "gsub_contextchain",
+ reversechainedcontextsingle = "gsub_reversecontextchain", -- reversesub
+ },
+ gpos = {
+ single = "gpos_single",
+ pair = "gpos_pair",
+ cursive = "gpos_cursive",
+ marktobase = "gpos_mark2base",
+ marktoligature = "gpos_mark2ligature",
+ marktomark = "gpos_mark2mark",
+ context = "gpos_context",
+ chainedcontext = "gpos_contextchain",
+ }
+}
+
+-- keep this as reference:
+--
+-- local lookupbits = {
+-- [0x0001] = "righttoleft",
+-- [0x0002] = "ignorebaseglyphs",
+-- [0x0004] = "ignoreligatures",
+-- [0x0008] = "ignoremarks",
+-- [0x0010] = "usemarkfilteringset",
+-- [0x00E0] = "reserved",
+-- [0xFF00] = "markattachmenttype",
+-- }
+--
+-- local lookupstate = setmetatableindex(function(t,k)
+-- local v = { }
+-- for kk, vv in next, lookupbits do
+-- if band(k,kk) ~= 0 then
+-- v[vv] = true
+-- end
+-- end
+-- t[k] = v
+-- return v
+-- end)
+
+local lookupflags = setmetatableindex(function(t,k)
+ local v = {
+ band(k,0x0008) ~= 0 and true or false, -- ignoremarks
+ band(k,0x0004) ~= 0 and true or false, -- ignoreligatures
+ band(k,0x0002) ~= 0 and true or false, -- ignorebaseglyphs
+ band(k,0x0001) ~= 0 and true or false, -- r2l
+ }
+ t[k] = v
+ return v
+end)
+
+-- Variation stores: it's not entirely clear if the regions are a shared
+-- resource (it looks like they are). Anyway, we play safe and use a
+-- share.
+
+-- values can be anything the min/max permits so we can either think of
+-- real values of a fraction along the axis (probably easier)
+
+-- wght=400,wdth=100,ital=1
+
+local function axistofactors(str)
+ local t = settings_to_hash(str)
+ for k, v in next, t do
+ t[k] = tonumber(v) or v -- this also normalizes numbers itself
+ end
+ return t
+end
+
+local hash = table.setmetatableindex(function(t,k)
+ local v = sequenced(axistofactors(k),",")
+ t[k] = v
+ return v
+end)
+
+helpers.normalizedaxishash = hash
+
+local cleanname = fonts.names and fonts.names.cleanname or function(name)
+ return name and (gsub(lower(name),"[^%a%d]","")) or nil
+end
+
+helpers.cleanname = cleanname
+
+function helpers.normalizedaxis(str)
+ return hash[str] or str
+end
+
+-- contradicting spec ... (signs) so i'll check it and fix it once we have
+-- proper fonts
+
+local function getaxisscale(segments,minimum,default,maximum,user)
+ --
+ -- returns the right values cf example in standard
+ --
+ if not minimum or not default or not maximum then
+ return false
+ end
+ if user < minimum then
+ user = minimum
+ elseif user > maximum then
+ user = maximum
+ end
+ if user < default then
+ default = - (default - user) / (default - minimum)
+ elseif user > default then
+ default = (user - default) / (maximum - default)
+ else
+ default = 0
+ end
+ if not segments then
+ return default
+ end
+ local e
+ for i=1,#segments do
+ local s = segments[i]
+ if type(s) ~= "number" then
+ report("using default axis scale")
+ return default
+ elseif s[1] >= default then
+ if s[2] == default then
+ return default
+ else
+ e = i
+ break
+ end
+ end
+ end
+ if e then
+ local b = segments[e-1]
+ local e = segments[e]
+ return b[2] + (e[2] - b[2]) * (default - b[1]) / (e[1] - b[1])
+ else
+ return false
+ end
+end
+
+local function getfactors(data,instancespec)
+ if instancespec == true then
+ -- take default
+ elseif type(instancespec) ~= "string" or instancespec == "" then
+ return
+ end
+ local variabledata = data.variabledata
+ if not variabledata then
+ return
+ end
+ local instances = variabledata.instances
+ local axis = variabledata.axis
+ local segments = variabledata.segments
+ if instances and axis then
+ local values
+ if instancespec == true then
+ -- first instance:
+ -- values = instances[1].values
+ -- axis defaults:
+ values = { }
+ for i=1,#axis do
+ values[i] = {
+ -- axis = axis[i].tag,
+ value = axis[i].default,
+ }
+ end
+
+ else
+ for i=1,#instances do
+ local instance = instances[i]
+ if cleanname(instance.subfamily) == instancespec then
+ values = instance.values
+ break
+ end
+ end
+ end
+ if values then
+ local factors = { }
+ for i=1,#axis do
+ local a = axis[i]
+ factors[i] = getaxisscale(segments,a.minimum,a.default,a.maximum,values[i].value)
+ end
+ return factors
+ end
+ local values = axistofactors(hash[instancespec] or instancespec)
+ if values then
+ local factors = { }
+ for i=1,#axis do
+ local a = axis[i]
+ local d = a.default
+ factors[i] = getaxisscale(segments,a.minimum,d,a.maximum,values[a.name or a.tag] or d)
+ end
+ return factors
+ end
+ end
+end
+
+local function getscales(regions,factors)
+ local scales = { }
+ for i=1,#regions do
+ local region = regions[i]
+ local s = 1
+ for j=1,#region do
+ local axis = region[j]
+ local f = factors[j]
+ local start = axis.start
+ local peak = axis.peak
+ local stop = axis.stop
+ -- get rid of these tests, false flag
+ if start > peak or peak > stop then
+ -- * 1
+ elseif start < 0 and stop > 0 and peak ~= 0 then
+ -- * 1
+ elseif peak == 0 then
+ -- * 1
+ elseif f < start or f > stop then
+ -- * 0
+ 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)
+ else
+ -- * 1
+ end
+ end
+ scales[i] = s
+ end
+ return scales
+end
+
+helpers.getaxisscale = getaxisscale
+helpers.getfactors = getfactors
+helpers.getscales = getscales
+helpers.axistofactors = axistofactors
+
+local function readvariationdata(f,storeoffset,factors) -- store
+ local position = getposition(f)
+ setposition(f,storeoffset)
+ -- header
+ local format = readushort(f)
+ local regionoffset = storeoffset + readulong(f)
+ local nofdeltadata = readushort(f)
+ local deltadata = readcardinaltable(f,nofdeltadata,ulong)
+ -- regions
+ setposition(f,regionoffset)
+ local nofaxis = readushort(f)
+ local nofregions = readushort(f)
+ local regions = { }
+ for i=1,nofregions do -- 0
+ local t = { }
+ for i=1,nofaxis do
+ t[i] = { -- maybe no keys, just 1..3
+ start = read2dot14(f),
+ peak = read2dot14(f),
+ stop = read2dot14(f),
+ }
+ end
+ regions[i] = t
+ end
+ -- deltas
+ -- if factors then
+ for i=1,nofdeltadata do
+ setposition(f,storeoffset+deltadata[i])
+ local nofdeltasets = readushort(f)
+ local nofshorts = readushort(f)
+ local nofregions = readushort(f)
+ local usedregions = { }
+ local deltas = { }
+ for i=1,nofregions do
+ usedregions[i] = regions[readushort(f)+1]
+ end
+ -- we could test before and save a for
+ for i=1,nofdeltasets do
+ local t = readintegertable(f,nofshorts,short)
+ for i=nofshorts+1,nofregions do
+ t[i] = readinteger(f)
+ end
+ deltas[i] = t
+ end
+ deltadata[i] = {
+ regions = usedregions,
+ deltas = deltas,
+ scales = factors and getscales(usedregions,factors) or nil,
+ }
+ end
+ -- end
+ setposition(f,position)
+ return regions, deltadata
+end
+
+helpers.readvariationdata = readvariationdata
+
+-- Beware: only use the simple variant if we don't set keys/values (otherwise too many entries). We
+-- could also have a variant that applies a function but there is no real benefit in this.
+
+local function readcoverage(f,offset,simple)
+ setposition(f,offset)
+ local coverageformat = readushort(f)
+ if coverageformat == 1 then
+ local nofcoverage = readushort(f)
+ if simple then
+ -- often 1 or 2
+ if nofcoverage == 1 then
+ return { readushort(f) }
+ elseif nofcoverage == 2 then
+ return { readushort(f), readushort(f) }
+ else
+ return readcardinaltable(f,nofcoverage,ushort)
+ end
+ elseif nofcoverage == 1 then
+ return { [readushort(f)] = 0 }
+ elseif nofcoverage == 2 then
+ return { [readushort(f)] = 0, [readushort(f)] = 1 }
+ else
+ local coverage = { }
+ for i=0,nofcoverage-1 do
+ coverage[readushort(f)] = i -- index in record
+ end
+ return coverage
+ end
+ elseif coverageformat == 2 then
+ local nofranges = readushort(f)
+ local coverage = { }
+ local n = simple and 1 or 0 -- needs checking
+ for i=1,nofranges do
+ local firstindex = readushort(f)
+ local lastindex = readushort(f)
+ local coverindex = readushort(f)
+ if simple then
+ for i=firstindex,lastindex do
+ coverage[n] = i
+ n = n + 1
+ end
+ else
+ for i=firstindex,lastindex do
+ coverage[i] = n
+ n = n + 1
+ end
+ end
+ end
+ return coverage
+ else
+ report("unknown coverage format %a ",coverageformat)
+ return { }
+ end
+end
+
+local function readclassdef(f,offset,preset)
+ setposition(f,offset)
+ local classdefformat = readushort(f)
+ local classdef = { }
+ if type(preset) == "number" then
+ for k=0,preset-1 do
+ classdef[k] = 1
+ end
+ end
+ if classdefformat == 1 then
+ local index = readushort(f)
+ local nofclassdef = readushort(f)
+ for i=1,nofclassdef do
+ classdef[index] = readushort(f) + 1
+ index = index + 1
+ end
+ elseif classdefformat == 2 then
+ local nofranges = readushort(f)
+ local n = 0
+ for i=1,nofranges do
+ local firstindex = readushort(f)
+ local lastindex = readushort(f)
+ local class = readushort(f) + 1
+ for i=firstindex,lastindex do
+ classdef[i] = class
+ end
+ end
+ else
+ report("unknown classdef format %a ",classdefformat)
+ end
+ if type(preset) == "table" then
+ for k in next, preset do
+ if not classdef[k] then
+ classdef[k] = 1
+ end
+ end
+ end
+ return classdef
+end
+
+local function classtocoverage(defs)
+ if defs then
+ local list = { }
+ for index, class in next, defs do
+ local c = list[class]
+ if c then
+ c[#c+1] = index
+ else
+ list[class] = { index }
+ end
+ end
+ return list
+ end
+end
+
+-- extra readers
+
+local skips = { [0] =
+ 0, -- ----
+ 1, -- ---x
+ 1, -- --y-
+ 2, -- --yx
+ 1, -- -h--
+ 2, -- -h-x
+ 2, -- -hy-
+ 3, -- -hyx
+ 2, -- v--x
+ 2, -- v-y-
+ 3, -- v-yx
+ 2, -- vh--
+ 3, -- vh-x
+ 3, -- vhy-
+ 4, -- vhyx
+}
+
+-- We can assume that 0 is nothing and in fact we can start at 1 as
+-- usual in Lua to make sure of that.
+
+local function readvariation(f,offset)
+ local p = getposition(f)
+ setposition(f,offset)
+ local outer = readushort(f)
+ local inner = readushort(f)
+ local format = readushort(f)
+ setposition(f,p)
+ if format == 0x8000 then
+ return outer, inner
+ end
+end
+
+local function readposition(f,format,mainoffset,getdelta)
+ if format == 0 then
+ return false
+ end
+ -- a few happen often
+ if format == 0x04 then
+ local h = readshort(f)
+ if h == 0 then
+ return true -- all zero
+ else
+ return { 0, 0, h, 0 }
+ end
+ end
+ if format == 0x05 then
+ local x = readshort(f)
+ local h = readshort(f)
+ if x == 0 and h == 0 then
+ return true -- all zero
+ else
+ return { x, 0, h, 0 }
+ end
+ end
+ if format == 0x44 then
+ local h = readshort(f)
+ if getdelta then
+ local d = readshort(f) -- short or ushort
+ if d > 0 then
+ local outer, inner = readvariation(f,mainoffset+d)
+ if outer then
+ h = h + getdelta(outer,inner)
+ end
+ end
+ else
+ skipshort(f,1)
+ end
+ if h == 0 then
+ return true -- all zero
+ else
+ return { 0, 0, h, 0 }
+ end
+ end
+ --
+ -- todo:
+ --
+ -- if format == 0x55 then
+ -- local x = readshort(f)
+ -- local h = readshort(f)
+ -- ....
+ -- end
+ --
+ local x = band(format,0x1) ~= 0 and readshort(f) or 0 -- x placement
+ local y = band(format,0x2) ~= 0 and readshort(f) or 0 -- y placement
+ local h = band(format,0x4) ~= 0 and readshort(f) or 0 -- h advance
+ local v = band(format,0x8) ~= 0 and readshort(f) or 0 -- v advance
+ if format >= 0x10 then
+ local X = band(format,0x10) ~= 0 and skipshort(f) or 0
+ local Y = band(format,0x20) ~= 0 and skipshort(f) or 0
+ local H = band(format,0x40) ~= 0 and skipshort(f) or 0
+ local V = band(format,0x80) ~= 0 and skipshort(f) or 0
+ local s = skips[extract(format,4,4)]
+ if s > 0 then
+ skipshort(f,s)
+ end
+ if getdelta then
+ if X > 0 then
+ local outer, inner = readvariation(f,mainoffset+X)
+ if outer then
+ x = x + getdelta(outer,inner)
+ end
+ end
+ if Y > 0 then
+ local outer, inner = readvariation(f,mainoffset+Y)
+ if outer then
+ y = y + getdelta(outer,inner)
+ end
+ end
+ if H > 0 then
+ local outer, inner = readvariation(f,mainoffset+H)
+ if outer then
+ h = h + getdelta(outer,inner)
+ end
+ end
+ if V > 0 then
+ local outer, inner = readvariation(f,mainoffset+V)
+ if outer then
+ v = v + getdelta(outer,inner)
+ end
+ end
+ end
+ return { x, y, h, v }
+ elseif x == 0 and y == 0 and h == 0 and v == 0 then
+ return true -- all zero
+ else
+ return { x, y, h, v }
+ end
+end
+
+local function readanchor(f,offset,getdelta) -- maybe also ignore 0's as in pos
+ if not offset or offset == 0 then
+ return nil -- false
+ end
+ setposition(f,offset)
+ -- no need to skip as we position each
+ local format = readshort(f) -- 1: x y 2: x y index 3 x y X Y
+ local x = readshort(f)
+ local y = readshort(f)
+ if format == 3 then
+ if getdelta then
+ local X = readshort(f)
+ local Y = readshort(f)
+ if X > 0 then
+ local outer, inner = readvariation(f,offset+X)
+ if outer then
+ x = x + getdelta(outer,inner)
+ end
+ end
+ if Y > 0 then
+ local outer, inner = readvariation(f,offset+Y)
+ if outer then
+ y = y + getdelta(outer,inner)
+ end
+ end
+ else
+ skipshort(f,2)
+ end
+ return { x, y } -- , { xindex, yindex }
+ else
+ return { x, y }
+ end
+end
+
+-- common handlers: inlining can be faster but we cache anyway
+-- so we don't bother too much about speed here
+
+local function readfirst(f,offset)
+ if offset then
+ setposition(f,offset)
+ end
+ return { readushort(f) }
+end
+
+-- quite often 0, 1, 2
+
+local function readarray(f,offset)
+ if offset then
+ setposition(f,offset)
+ end
+ local n = readushort(f)
+ if n == 1 then
+ return { readushort(f) }, 1
+ elseif n > 0 then
+ return readcardinaltable(f,n,ushort), n
+ end
+end
+
+local function readcoveragearray(f,offset,t,simple)
+ if not t then
+ return nil
+ end
+ local n = #t
+ if n == 0 then
+ return nil
+ end
+ for i=1,n do
+ t[i] = readcoverage(f,offset+t[i],simple)
+ end
+ return t
+end
+
+local function covered(subset,all)
+ local used, u
+ for i=1,#subset do
+ local s = subset[i]
+ if all[s] then
+ if used then
+ u = u + 1
+ used[u] = s
+ else
+ u = 1
+ used = { s }
+ end
+ end
+ end
+ return used
+end
+
+-- We generalize the chained lookups so that we can do with only one handler
+-- when processing them.
+
+-- pruned
+
+local function readlookuparray(f,noflookups,nofcurrent)
+ local lookups = { }
+ if noflookups > 0 then
+ local length = 0
+ for i=1,noflookups do
+ local index = readushort(f) + 1
+ if index > length then
+ length = index
+ end
+ local lookup = readushort(f) + 1
+ local list = lookups[index]
+ if list then
+ list[#list+1] = lookup
+ else
+ lookups[index] = { lookup }
+ end
+ end
+ for index=1,length do
+ if not lookups[index] then
+ lookups[index] = false
+ end
+ end
+ -- if length > nofcurrent then
+ -- report("more lookups than currently matched characters")
+ -- end
+ end
+ return lookups
+end
+
+-- not pruned
+--
+-- local function readlookuparray(f,noflookups,nofcurrent)
+-- local lookups = { }
+-- for i=1,nofcurrent do
+-- lookups[i] = false
+-- end
+-- for i=1,noflookups do
+-- local index = readushort(f) + 1
+-- if index > nofcurrent then
+-- report("more lookups than currently matched characters")
+-- for i=nofcurrent+1,index-1 do
+-- lookups[i] = false
+-- end
+-- nofcurrent = index
+-- end
+-- lookups[index] = readushort(f) + 1
+-- end
+-- return lookups
+-- end
+
+local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what)
+ local tableoffset = lookupoffset + offset
+ setposition(f,tableoffset)
+ local subtype = readushort(f)
+ if subtype == 1 then
+ local coverage = readushort(f)
+ local subclasssets = readarray(f)
+ local rules = { }
+ if subclasssets then
+ coverage = readcoverage(f,tableoffset+coverage,true)
+ for i=1,#subclasssets do
+ local offset = subclasssets[i]
+ if offset > 0 then
+ local firstcoverage = coverage[i]
+ local rulesoffset = tableoffset + offset
+ local subclassrules = readarray(f,rulesoffset)
+ for rule=1,#subclassrules do
+ setposition(f,rulesoffset + subclassrules[rule])
+ local nofcurrent = readushort(f)
+ local noflookups = readushort(f)
+ local current = { { firstcoverage } }
+ for i=2,nofcurrent do
+ current[i] = { readushort(f) }
+ end
+ local lookups = readlookuparray(f,noflookups,nofcurrent)
+ rules[#rules+1] = {
+ current = current,
+ lookups = lookups
+ }
+ end
+ end
+ end
+ else
+ report("empty subclassset in %a subtype %i","unchainedcontext",subtype)
+ end
+ return {
+ format = "glyphs",
+ rules = rules,
+ }
+ elseif subtype == 2 then
+ -- We expand the classes as later on we do a pack over the whole table so then we get
+ -- back efficiency. This way we can also apply the coverage to the first current.
+ local coverage = readushort(f)
+ local currentclassdef = readushort(f)
+ local subclasssets = readarray(f)
+ local rules = { }
+ if subclasssets then
+ coverage = readcoverage(f,tableoffset + coverage)
+ currentclassdef = readclassdef(f,tableoffset + currentclassdef,coverage)
+ local currentclasses = classtocoverage(currentclassdef,fontdata.glyphs)
+ for class=1,#subclasssets do
+ local offset = subclasssets[class]
+ if offset > 0 then
+ local firstcoverage = currentclasses[class]
+ if firstcoverage then
+ firstcoverage = covered(firstcoverage,coverage) -- bonus
+ if firstcoverage then
+ local rulesoffset = tableoffset + offset
+ local subclassrules = readarray(f,rulesoffset)
+ for rule=1,#subclassrules do
+ setposition(f,rulesoffset + subclassrules[rule])
+ local nofcurrent = readushort(f)
+ local noflookups = readushort(f)
+ local current = { firstcoverage }
+ for i=2,nofcurrent do
+ current[i] = currentclasses[readushort(f) + 1]
+ end
+ local lookups = readlookuparray(f,noflookups,nofcurrent)
+ rules[#rules+1] = {
+ current = current,
+ lookups = lookups
+ }
+ end
+ else
+ report("no coverage")
+ end
+ else
+ report("no coverage class")
+ end
+ end
+ end
+ else
+ report("empty subclassset in %a subtype %i","unchainedcontext",subtype)
+ end
+ return {
+ format = "class",
+ rules = rules,
+ }
+ elseif subtype == 3 then
+ local nofglyphs = readushort(f)
+ local noflookups = readushort(f)
+ local current = readcardinaltable(f,nofglyphs,ushort)
+ local lookups = readlookuparray(f,noflookups,#current)
+ current = readcoveragearray(f,tableoffset,current,true)
+ return {
+ format = "coverage",
+ rules = {
+ {
+ current = current,
+ lookups = lookups,
+ }
+ }
+ }
+ else
+ report("unsupported subtype %a in %a %s",subtype,"unchainedcontext",what)
+ end
+end
+
+-- todo: optimize for n=1 ?
+
+-- class index needs checking, probably no need for +1
+
+local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what)
+ local tableoffset = lookupoffset + offset
+ setposition(f,tableoffset)
+ local subtype = readushort(f)
+ if subtype == 1 then
+ local coverage = readushort(f)
+ local subclasssets = readarray(f)
+ local rules = { }
+ if subclasssets then
+ coverage = readcoverage(f,tableoffset+coverage,true)
+ for i=1,#subclasssets do
+ local offset = subclasssets[i]
+ if offset > 0 then
+ local firstcoverage = coverage[i]
+ local rulesoffset = tableoffset + offset
+ local subclassrules = readarray(f,rulesoffset)
+ for rule=1,#subclassrules do
+ setposition(f,rulesoffset + subclassrules[rule])
+ local nofbefore = readushort(f)
+ local before
+ if nofbefore > 0 then
+ before = { }
+ for i=1,nofbefore do
+ before[i] = { readushort(f) }
+ end
+ end
+ local nofcurrent = readushort(f)
+ local current = { { firstcoverage } }
+ for i=2,nofcurrent do
+ current[i] = { readushort(f) }
+ end
+ local nofafter = readushort(f)
+ local after
+ if nofafter > 0 then
+ after = { }
+ for i=1,nofafter do
+ after[i] = { readushort(f) }
+ end
+ end
+ local noflookups = readushort(f)
+ local lookups = readlookuparray(f,noflookups,nofcurrent)
+ rules[#rules+1] = {
+ before = before,
+ current = current,
+ after = after,
+ lookups = lookups,
+ }
+ end
+ end
+ end
+ else
+ report("empty subclassset in %a subtype %i","chainedcontext",subtype)
+ end
+ return {
+ format = "glyphs",
+ rules = rules,
+ }
+ elseif subtype == 2 then
+ local coverage = readushort(f)
+ local beforeclassdef = readushort(f)
+ local currentclassdef = readushort(f)
+ local afterclassdef = readushort(f)
+ local subclasssets = readarray(f)
+ local rules = { }
+ if subclasssets then
+ local coverage = readcoverage(f,tableoffset + coverage)
+ local beforeclassdef = readclassdef(f,tableoffset + beforeclassdef,nofglyphs)
+ local currentclassdef = readclassdef(f,tableoffset + currentclassdef,coverage)
+ local afterclassdef = readclassdef(f,tableoffset + afterclassdef,nofglyphs)
+ local beforeclasses = classtocoverage(beforeclassdef,fontdata.glyphs)
+ local currentclasses = classtocoverage(currentclassdef,fontdata.glyphs)
+ local afterclasses = classtocoverage(afterclassdef,fontdata.glyphs)
+ for class=1,#subclasssets do
+ local offset = subclasssets[class]
+ if offset > 0 then
+ local firstcoverage = currentclasses[class]
+ if firstcoverage then
+ firstcoverage = covered(firstcoverage,coverage) -- bonus
+ if firstcoverage then
+ local rulesoffset = tableoffset + offset
+ local subclassrules = readarray(f,rulesoffset)
+ for rule=1,#subclassrules do
+ -- watch out, in context we first get the counts and then the arrays while
+ -- here we get them mixed
+ setposition(f,rulesoffset + subclassrules[rule])
+ local nofbefore = readushort(f)
+ local before
+ if nofbefore > 0 then
+ before = { }
+ for i=1,nofbefore do
+ before[i] = beforeclasses[readushort(f) + 1]
+ end
+ end
+ local nofcurrent = readushort(f)
+ local current = { firstcoverage }
+ for i=2,nofcurrent do
+ current[i] = currentclasses[readushort(f)+ 1]
+ end
+ local nofafter = readushort(f)
+ local after
+ if nofafter > 0 then
+ after = { }
+ for i=1,nofafter do
+ after[i] = afterclasses[readushort(f) + 1]
+ end
+ end
+ -- no sequence index here (so why in context as it saves nothing)
+ local noflookups = readushort(f)
+ local lookups = readlookuparray(f,noflookups,nofcurrent)
+ rules[#rules+1] = {
+ before = before,
+ current = current,
+ after = after,
+ lookups = lookups,
+ }
+ end
+ else
+ report("no coverage")
+ end
+ else
+ report("class is not covered")
+ end
+ end
+ end
+ else
+ report("empty subclassset in %a subtype %i","chainedcontext",subtype)
+ end
+ return {
+ format = "class",
+ rules = rules,
+ }
+ elseif subtype == 3 then
+ local before = readarray(f)
+ local current = readarray(f)
+ local after = readarray(f)
+ local noflookups = readushort(f)
+ local lookups = readlookuparray(f,noflookups,#current)
+ before = readcoveragearray(f,tableoffset,before,true)
+ current = readcoveragearray(f,tableoffset,current,true)
+ after = readcoveragearray(f,tableoffset,after,true)
+ return {
+ format = "coverage",
+ rules = {
+ {
+ before = before,
+ current = current,
+ after = after,
+ lookups = lookups,
+ }
+ }
+ }
+ else
+ report("unsupported subtype %a in %a %s",subtype,"chainedcontext",what)
+ end
+end
+
+local function extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,types,handlers,what)
+ local tableoffset = lookupoffset + offset
+ setposition(f,tableoffset)
+ local subtype = readushort(f)
+ if subtype == 1 then
+ local lookuptype = types[readushort(f)]
+ local faroffset = readulong(f)
+ local handler = handlers[lookuptype]
+ if handler then
+ -- maybe we can just pass one offset (or tableoffset first)
+ return handler(f,fontdata,lookupid,tableoffset + faroffset,0,glyphs,nofglyphs), lookuptype
+ else
+ report("no handler for lookuptype %a subtype %a in %s %s",lookuptype,subtype,what,"extension")
+ end
+ else
+ report("unsupported subtype %a in %s %s",subtype,what,"extension")
+ end
+end
+
+-- gsub handlers
+
+function gsubhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ local tableoffset = lookupoffset + offset
+ setposition(f,tableoffset)
+ local subtype = readushort(f)
+ if subtype == 1 then
+ local coverage = readushort(f)
+ local delta = readshort(f) -- can be negative
+ local coverage = readcoverage(f,tableoffset+coverage) -- not simple as we need to set key/value anyway
+ for index in next, coverage do
+ local newindex = (index + delta) % 65536 -- modulo is new in 1.8.3
+ if index > nofglyphs or newindex > nofglyphs then
+ report("invalid index in %s format %i: %i -> %i (max %i)","single",subtype,index,newindex,nofglyphs)
+ coverage[index] = nil
+ else
+ coverage[index] = newindex
+ end
+ end
+ return {
+ coverage = coverage
+ }
+ elseif subtype == 2 then -- in streamreader a seek and fetch is faster than a temp table
+ local coverage = readushort(f)
+ local nofreplacements = readushort(f)
+ local replacements = readcardinaltable(f,nofreplacements,ushort)
+ local coverage = readcoverage(f,tableoffset + coverage) -- not simple as we need to set key/value anyway
+ for index, newindex in next, coverage do
+ newindex = newindex + 1
+ if index > nofglyphs or newindex > nofglyphs then
+ report("invalid index in %s format %i: %i -> %i (max %i)","single",subtype,index,newindex,nofglyphs)
+ coverage[index] = nil
+ else
+ coverage[index] = replacements[newindex]
+ end
+ end
+ return {
+ coverage = coverage
+ }
+ else
+ report("unsupported subtype %a in %a substitution",subtype,"single")
+ end
+end
+
+-- we see coverage format 0x300 in some old ms fonts
+
+local function sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what)
+ local tableoffset = lookupoffset + offset
+ setposition(f,tableoffset)
+ local subtype = readushort(f)
+ if subtype == 1 then
+ local coverage = readushort(f)
+ local nofsequence = readushort(f)
+ local sequences = readcardinaltable(f,nofsequence,ushort)
+ for i=1,nofsequence do
+ setposition(f,tableoffset + sequences[i])
+ sequences[i] = readcardinaltable(f,readushort(f),ushort)
+ end
+ local coverage = readcoverage(f,tableoffset + coverage)
+ for index, newindex in next, coverage do
+ newindex = newindex + 1
+ if index > nofglyphs or newindex > nofglyphs then
+ report("invalid index in %s format %i: %i -> %i (max %i)",what,subtype,index,newindex,nofglyphs)
+ coverage[index] = nil
+ else
+ coverage[index] = sequences[newindex]
+ end
+ end
+ return {
+ coverage = coverage
+ }
+ else
+ report("unsupported subtype %a in %a substitution",subtype,what)
+ end
+end
+
+function gsubhandlers.multiple(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ return sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"multiple")
+end
+
+function gsubhandlers.alternate(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ return sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"alternate")
+end
+
+function gsubhandlers.ligature(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ local tableoffset = lookupoffset + offset
+ setposition(f,tableoffset)
+ local subtype = readushort(f)
+ if subtype == 1 then
+ local coverage = readushort(f)
+ local nofsets = readushort(f)
+ local ligatures = readcardinaltable(f,nofsets,ushort)
+ for i=1,nofsets do
+ local offset = lookupoffset + offset + ligatures[i]
+ setposition(f,offset)
+ local n = readushort(f)
+ if n == 1 then
+ ligatures[i] = { offset + readushort(f) }
+ else
+ local l = { }
+ for i=1,n do
+ l[i] = offset + readushort(f)
+ end
+ ligatures[i] = l
+ end
+ end
+ local coverage = readcoverage(f,tableoffset + coverage)
+ for index, newindex in next, coverage do
+ local hash = { }
+ local ligatures = ligatures[newindex+1]
+ for i=1,#ligatures do
+ local offset = ligatures[i]
+ setposition(f,offset)
+ local lig = readushort(f)
+ local cnt = readushort(f)
+ local hsh = hash
+ for i=2,cnt do
+ local c = readushort(f)
+ local h = hsh[c]
+ if not h then
+ h = { }
+ hsh[c] = h
+ end
+ hsh = h
+ end
+ hsh.ligature = lig
+ end
+ coverage[index] = hash
+ end
+ return {
+ coverage = coverage
+ }
+ else
+ report("unsupported subtype %a in %a substitution",subtype,"ligature")
+ end
+end
+
+function gsubhandlers.context(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ return unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"substitution"), "context"
+end
+
+function gsubhandlers.chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ return chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"substitution"), "chainedcontext"
+end
+
+function gsubhandlers.extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ return extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,gsubtypes,gsubhandlers,"substitution")
+end
+
+function gsubhandlers.reversechainedcontextsingle(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ local tableoffset = lookupoffset + offset
+ setposition(f,tableoffset)
+ local subtype = readushort(f)
+ if subtype == 1 then -- NEEDS CHECKING
+ local current = readfirst(f)
+ local before = readarray(f)
+ local after = readarray(f)
+ local replacements = readarray(f)
+ current = readcoveragearray(f,tableoffset,current,true)
+ before = readcoveragearray(f,tableoffset,before,true)
+ after = readcoveragearray(f,tableoffset,after,true)
+ return {
+ format = "reversecoverage", -- reversesub
+ rules = {
+ {
+ before = before,
+ current = current,
+ after = after,
+ replacements = replacements,
+ }
+ }
+ }, "reversechainedcontextsingle"
+ else
+ report("unsupported subtype %a in %a substitution",subtype,"reversechainedcontextsingle")
+ end
+end
+
+-- gpos handlers
+
+local function readpairsets(f,tableoffset,sets,format1,format2,mainoffset,getdelta)
+ local done = { }
+ for i=1,#sets do
+ local offset = sets[i]
+ local reused = done[offset]
+ if not reused then
+ offset = tableoffset + offset
+ setposition(f,offset)
+ local n = readushort(f)
+ reused = { }
+ for i=1,n do
+ reused[i] = {
+ readushort(f), -- second glyph id
+ readposition(f,format1,offset,getdelta),
+ readposition(f,format2,offset,getdelta),
+ }
+ end
+ done[offset] = reused
+ end
+ sets[i] = reused
+ end
+ return sets
+end
+
+local function readpairclasssets(f,nofclasses1,nofclasses2,format1,format2,mainoffset,getdelta)
+ local classlist1 = { }
+ for i=1,nofclasses1 do
+ local classlist2 = { }
+ classlist1[i] = classlist2
+ for j=1,nofclasses2 do
+ local one = readposition(f,format1,mainoffset,getdelta)
+ local two = readposition(f,format2,mainoffset,getdelta)
+ if one or two then
+ classlist2[j] = { one, two }
+ else
+ classlist2[j] = false
+ end
+ end
+ end
+ return classlist1
+end
+
+-- no real gain in kerns as we pack
+
+function gposhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ local tableoffset = lookupoffset + offset
+ setposition(f,tableoffset)
+ local subtype = readushort(f)
+ local getdelta = fontdata.temporary.getdelta
+ if subtype == 1 then
+ local coverage = readushort(f)
+ local format = readushort(f)
+ local value = readposition(f,format,tableoffset,getdelta)
+ local coverage = readcoverage(f,tableoffset+coverage)
+ for index, newindex in next, coverage do
+ coverage[index] = value -- will be packed and shared anyway
+ end
+ return {
+ format = "single",
+ coverage = coverage,
+ }
+ elseif subtype == 2 then
+ local coverage = readushort(f)
+ local format = readushort(f)
+ local nofvalues = readushort(f)
+ local values = { }
+ for i=1,nofvalues do
+ values[i] = readposition(f,format,tableoffset,getdelta)
+ end
+ local coverage = readcoverage(f,tableoffset+coverage)
+ for index, newindex in next, coverage do
+ coverage[index] = values[newindex+1]
+ end
+ return {
+ format = "single",
+ coverage = coverage,
+ }
+ else
+ report("unsupported subtype %a in %a positioning",subtype,"single")
+ end
+end
+
+-- this needs checking! if no second pair then another advance over the list
+
+-- ValueFormat1 applies to the ValueRecord of the first glyph in each pair. ValueRecords for all first glyphs must use ValueFormat1. If ValueFormat1 is set to zero (0), the corresponding glyph has no ValueRecord and, therefore, should not be repositioned.
+-- ValueFormat2 applies to the ValueRecord of the second glyph in each pair. ValueRecords for all second glyphs must use ValueFormat2. If ValueFormat2 is set to null, then the second glyph of the pair is the “next” glyph for which a lookup should be performed.
+
+-- local simple = {
+-- [true] = { [true] = { true, true }, [false] = { true } },
+-- [false] = { [true] = { false, true }, [false] = { false } },
+-- }
+
+-- function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+-- local tableoffset = lookupoffset + offset
+-- setposition(f,tableoffset)
+-- local subtype = readushort(f)
+-- local getdelta = fontdata.temporary.getdelta
+-- if subtype == 1 then
+-- local coverage = readushort(f)
+-- local format1 = readushort(f)
+-- local format2 = readushort(f)
+-- local sets = readarray(f)
+-- sets = readpairsets(f,tableoffset,sets,format1,format2,mainoffset,getdelta)
+-- coverage = readcoverage(f,tableoffset + coverage)
+-- local shared = { } -- partial sparse, when set also needs to be handled in the packer
+-- for index, newindex in next, coverage do
+-- local set = sets[newindex+1]
+-- local hash = { }
+-- for i=1,#set do
+-- local value = set[i]
+-- if value then
+-- local other = value[1]
+-- if shared then
+-- local s = shared[value]
+-- if s == nil then
+-- local first = value[2]
+-- local second = value[3]
+-- if first or second then
+-- s = { first, second or nil } -- needs checking
+-- else
+-- s = false
+-- end
+-- shared[value] = s
+-- end
+-- hash[other] = s or nil
+-- else
+-- local first = value[2]
+-- local second = value[3]
+-- if first or second then
+-- hash[other] = { first, second or nil } -- needs checking
+-- else
+-- hash[other] = nil -- what if set, maybe warning
+-- end
+-- end
+-- end
+-- end
+-- coverage[index] = hash
+-- end
+-- return {
+-- shared = shared and true or nil,
+-- format = "pair",
+-- coverage = coverage,
+-- }
+-- elseif subtype == 2 then
+-- local coverage = readushort(f)
+-- local format1 = readushort(f)
+-- local format2 = readushort(f)
+-- local classdef1 = readushort(f)
+-- local classdef2 = readushort(f)
+-- local nofclasses1 = readushort(f) -- incl class 0
+-- local nofclasses2 = readushort(f) -- incl class 0
+-- local classlist = readpairclasssets(f,nofclasses1,nofclasses2,format1,format2,tableoffset,getdelta)
+-- coverage = readcoverage(f,tableoffset+coverage)
+-- classdef1 = readclassdef(f,tableoffset+classdef1,coverage)
+-- classdef2 = readclassdef(f,tableoffset+classdef2,nofglyphs)
+-- local usedcoverage = { }
+-- local shared = { } -- partial sparse, when set also needs to be handled in the packer
+-- for g1, c1 in next, classdef1 do
+-- if coverage[g1] then
+-- local l1 = classlist[c1]
+-- if l1 then
+-- local hash = { }
+-- for paired, class in next, classdef2 do
+-- local offsets = l1[class]
+-- if offsets then
+-- local first = offsets[1]
+-- local second = offsets[2]
+-- if first or second then
+-- if shared then
+-- local s1 = shared[first]
+-- if s1 == nil then
+-- s1 = { }
+-- shared[first] = s1
+-- end
+-- local s2 = s1[second]
+-- if s2 == nil then
+-- s2 = { first, second or nil }
+-- s1[second] = s2
+-- end
+-- hash[paired] = s2
+-- else
+-- hash[paired] = { first, second or nil }
+-- end
+-- else
+-- -- upto the next lookup for this combination
+-- end
+-- end
+-- end
+-- usedcoverage[g1] = hash
+-- end
+-- end
+-- end
+-- return {
+-- shared = shared and true or nil,
+-- format = "pair",
+-- coverage = usedcoverage,
+-- }
+-- elseif subtype == 3 then
+-- report("yet unsupported subtype %a in %a positioning",subtype,"pair")
+-- else
+-- report("unsupported subtype %a in %a positioning",subtype,"pair")
+-- end
+-- end
+
+function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ local tableoffset = lookupoffset + offset
+ setposition(f,tableoffset)
+ local subtype = readushort(f)
+ local getdelta = fontdata.temporary.getdelta
+ if subtype == 1 then
+ local coverage = readushort(f)
+ local format1 = readushort(f)
+ local format2 = readushort(f)
+ local sets = readarray(f)
+ sets = readpairsets(f,tableoffset,sets,format1,format2,mainoffset,getdelta)
+ coverage = readcoverage(f,tableoffset + coverage)
+ local shared = { } -- partial sparse, when set also needs to be handled in the packer
+ for index, newindex in next, coverage do
+ local set = sets[newindex+1]
+ local hash = { }
+ for i=1,#set do
+ local value = set[i]
+ if value then
+ local other = value[1]
+ local share = shared[value]
+ if share == nil then
+ local first = value[2]
+ local second = value[3]
+ if first or second then
+ share = { first, second or nil } -- needs checking
+ else
+ share = false
+ end
+ shared[value] = share
+ end
+ hash[other] = share or nil -- really overload ?
+ end
+ end
+ coverage[index] = hash
+ end
+ return {
+ shared = shared and true or nil,
+ format = "pair",
+ coverage = coverage,
+ }
+ elseif subtype == 2 then
+ local coverage = readushort(f)
+ local format1 = readushort(f)
+ local format2 = readushort(f)
+ local classdef1 = readushort(f)
+ local classdef2 = readushort(f)
+ local nofclasses1 = readushort(f) -- incl class 0
+ local nofclasses2 = readushort(f) -- incl class 0
+ local classlist = readpairclasssets(f,nofclasses1,nofclasses2,format1,format2,tableoffset,getdelta)
+ coverage = readcoverage(f,tableoffset+coverage)
+ classdef1 = readclassdef(f,tableoffset+classdef1,coverage)
+ classdef2 = readclassdef(f,tableoffset+classdef2,nofglyphs)
+ local usedcoverage = { }
+ local shared = { } -- partial sparse, when set also needs to be handled in the packer
+ for g1, c1 in next, classdef1 do
+ if coverage[g1] then
+ local l1 = classlist[c1]
+ if l1 then
+ local hash = { }
+ for paired, class in next, classdef2 do
+ local offsets = l1[class]
+ if offsets then
+ local first = offsets[1]
+ local second = offsets[2]
+ if first or second then
+ local s1 = shared[first]
+ if s1 == nil then
+ s1 = { }
+ shared[first] = s1
+ end
+ local s2 = s1[second]
+ if s2 == nil then
+ s2 = { first, second or nil }
+ s1[second] = s2
+ end
+ hash[paired] = s2
+ end
+ end
+ end
+ usedcoverage[g1] = hash
+ end
+ end
+ end
+ return {
+ shared = shared and true or nil,
+ format = "pair",
+ coverage = usedcoverage,
+ }
+ elseif subtype == 3 then
+ report("yet unsupported subtype %a in %a positioning",subtype,"pair")
+ else
+ report("unsupported subtype %a in %a positioning",subtype,"pair")
+ end
+end
+
+function gposhandlers.cursive(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ local tableoffset = lookupoffset + offset
+ setposition(f,tableoffset)
+ local subtype = readushort(f)
+ local getdelta = fontdata.temporary.getdelta
+ if subtype == 1 then
+ local coverage = tableoffset + readushort(f)
+ local nofrecords = readushort(f)
+ local records = { }
+ for i=1,nofrecords do
+ local entry = readushort(f)
+ local exit = readushort(f)
+ records[i] = {
+ -- entry = entry ~= 0 and (tableoffset + entry) or false,
+ -- exit = exit ~= 0 and (tableoffset + exit ) or nil,
+ entry ~= 0 and (tableoffset + entry) or false,
+ exit ~= 0 and (tableoffset + exit ) or nil,
+ }
+ end
+ -- slot 1 will become hash after loading and it must be unique because we
+ -- pack the tables (packed we turn the cc-* into a zero)
+ local cc = (fontdata.temporary.cursivecount or 0) + 1
+ fontdata.temporary.cursivecount = cc
+ cc = "cc-" .. cc
+ coverage = readcoverage(f,coverage)
+ for i=1,nofrecords do
+ local r = records[i]
+ records[i] = {
+ -- 1,
+ cc,
+ -- readanchor(f,r.entry,getdelta) or false,
+ -- readanchor(f,r.exit, getdelta) or nil,
+ readanchor(f,r[1],getdelta) or false,
+ readanchor(f,r[2],getdelta) or nil,
+ }
+ end
+ for index, newindex in next, coverage do
+ coverage[index] = records[newindex+1]
+ end
+ return {
+ coverage = coverage,
+ }
+ else
+ report("unsupported subtype %a in %a positioning",subtype,"cursive")
+ end
+end
+
+local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,ligature)
+ local tableoffset = lookupoffset + offset
+ setposition(f,tableoffset)
+ local subtype = readushort(f)
+ local getdelta = fontdata.temporary.getdelta
+ if subtype == 1 then
+ -- we are one based, not zero
+ local markcoverage = tableoffset + readushort(f)
+ local basecoverage = tableoffset + readushort(f)
+ local nofclasses = readushort(f)
+ local markoffset = tableoffset + readushort(f)
+ local baseoffset = tableoffset + readushort(f)
+ --
+ local markcoverage = readcoverage(f,markcoverage)
+ local basecoverage = readcoverage(f,basecoverage,true) -- TO BE CHECKED: true
+ --
+ setposition(f,markoffset)
+ local markclasses = { }
+ local nofmarkclasses = readushort(f)
+ --
+ local lastanchor = fontdata.lastanchor or 0
+ local usedanchors = { }
+ --
+ for i=1,nofmarkclasses do
+ local class = readushort(f) + 1
+ local offset = readushort(f)
+ if offset == 0 then
+ markclasses[i] = false
+ else
+ markclasses[i] = { class, markoffset + offset }
+ end
+ usedanchors[class] = true
+ end
+ for i=1,nofmarkclasses do
+ local mc = markclasses[i]
+ if mc then
+ mc[2] = readanchor(f,mc[2],getdelta)
+ end
+ end
+ --
+ setposition(f,baseoffset)
+ local nofbaserecords = readushort(f)
+ local baserecords = { }
+ --
+ if ligature then
+ -- 3 components
+ -- 1 : class .. nofclasses -- NULL when empty
+ -- 2 : class .. nofclasses -- NULL when empty
+ -- 3 : class .. nofclasses -- NULL when empty
+ for i=1,nofbaserecords do -- here i is the class
+ local offset = readushort(f)
+ if offset == 0 then
+ baserecords[i] = false
+ else
+ baserecords[i] = baseoffset + offset
+ end
+ end
+ for i=1,nofbaserecords do
+ local recordoffset = baserecords[i]
+ if recordoffset then
+ setposition(f,recordoffset)
+ local nofcomponents = readushort(f)
+ local components = { }
+ for i=1,nofcomponents do
+ local classes = { }
+ for i=1,nofclasses do
+ local offset = readushort(f)
+ if offset ~= 0 then
+ classes[i] = recordoffset + offset
+ else
+ classes[i] = false
+ end
+ end
+ components[i] = classes
+ end
+ baserecords[i] = components
+ end
+ end
+ local baseclasses = { } -- setmetatableindex("table")
+ for i=1,nofclasses do
+ baseclasses[i] = { }
+ end
+ for i=1,nofbaserecords do
+ local components = baserecords[i]
+ if components then
+ local b = basecoverage[i]
+ for c=1,#components do
+ local classes = components[c]
+ if classes then
+ for i=1,nofclasses do
+ local anchor = readanchor(f,classes[i],getdelta)
+ local bclass = baseclasses[i]
+ local bentry = bclass[b]
+ if bentry then
+ bentry[c] = anchor
+ else
+ bclass[b]= { [c] = anchor }
+ end
+ end
+ end
+ end
+ end
+ end
+ for index, newindex in next, markcoverage do
+ markcoverage[index] = markclasses[newindex+1] or nil
+ end
+ return {
+ format = "ligature",
+ baseclasses = baseclasses,
+ coverage = markcoverage,
+ }
+ else
+ for i=1,nofbaserecords do
+ local r = { }
+ for j=1,nofclasses do
+ local offset = readushort(f)
+ if offset == 0 then
+ r[j] = false
+ else
+ r[j] = baseoffset + offset
+ end
+ end
+ baserecords[i] = r
+ end
+ local baseclasses = { } -- setmetatableindex("table")
+ for i=1,nofclasses do
+ baseclasses[i] = { }
+ end
+ for i=1,nofbaserecords do
+ local r = baserecords[i]
+ local b = basecoverage[i]
+ for j=1,nofclasses do
+ baseclasses[j][b] = readanchor(f,r[j],getdelta)
+ end
+ end
+ for index, newindex in next, markcoverage do
+ markcoverage[index] = markclasses[newindex+1] or nil
+ end
+ -- we could actually already calculate the displacement if we want
+ return {
+ format = "base",
+ baseclasses = baseclasses,
+ coverage = markcoverage,
+ }
+ end
+ else
+ report("unsupported subtype %a in",subtype)
+ end
+
+end
+
+function gposhandlers.marktobase(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ return handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+end
+
+function gposhandlers.marktoligature(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ return handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,true)
+end
+
+function gposhandlers.marktomark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ return handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+end
+
+function gposhandlers.context(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ return unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"positioning"), "context"
+end
+
+function gposhandlers.chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ return chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"positioning"), "chainedcontext"
+end
+
+function gposhandlers.extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+ return extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,gpostypes,gposhandlers,"positioning")
+end
+
+-- main loader
+
+do
+
+ local plugins = { }
+
+ function plugins.size(f,fontdata,tableoffset,feature)
+ if fontdata.designsize then
+ -- yes, there are fonts with multiple size entries ... it probably relates
+ -- to the other two fields (menu entries in some language)
+ else
+ local function check(offset)
+ setposition(f,offset)
+ local designsize = readushort(f)
+ if designsize > 0 then -- we could also have a threshold
+ local fontstyleid = readushort(f)
+ local guimenuid = readushort(f)
+ local minsize = readushort(f)
+ local maxsize = readushort(f)
+ if minsize == 0 and maxsize == 0 and fontstyleid == 0 and guimenuid == 0 then
+ minsize = designsize
+ maxsize = designsize
+ end
+ if designsize >= minsize and designsize <= maxsize then
+ return minsize, maxsize, designsize
+ end
+ end
+ end
+ local minsize, maxsize, designsize = check(tableoffset+feature.offset+feature.parameters)
+ if not designsize then
+ -- some old adobe fonts have: tableoffset+feature.parameters and we could
+ -- use some heuristic but why bother ... this extra check will be removed
+ -- some day and/or when we run into an issue
+ minsize, maxsize, designsize = check(tableoffset+feature.parameters)
+ if designsize then
+ report("bad size feature in %a, falling back to wrong offset",fontdata.filename or "?")
+ else
+ report("bad size feature in %a,",fontdata.filename or "?")
+ end
+ end
+ if designsize then
+ fontdata.minsize = minsize
+ fontdata.maxsize = maxsize
+ fontdata.designsize = designsize
+ end
+ end
+ end
+
+ -- function plugins.rvrn(f,fontdata,tableoffset,feature)
+ -- -- todo, at least a message
+ -- end
+
+ -- feature order needs checking ... as we loop over a hash ... however, in the file
+ -- they are sorted so order is not that relevant
+
+ local function reorderfeatures(fontdata,scripts,features)
+ local scriptlangs = { }
+ local featurehash = { }
+ local featureorder = { }
+ for script, languages in next, scripts do
+ for language, record in next, languages do
+ local hash = { }
+ local list = record.featureindices
+ for k=1,#list do
+ local index = list[k]
+ local feature = features[index]
+ local lookups = feature.lookups
+ local tag = feature.tag
+ if tag then
+ hash[tag] = true
+ end
+ if lookups then
+ for i=1,#lookups do
+ local lookup = lookups[i]
+ local o = featureorder[lookup]
+ if o then
+ local okay = true
+ for i=1,#o do
+ if o[i] == tag then
+ okay = false
+ break
+ end
+ end
+ if okay then
+ o[#o+1] = tag
+ end
+ else
+ featureorder[lookup] = { tag }
+ end
+ local f = featurehash[lookup]
+ if f then
+ local h = f[tag]
+ if h then
+ local s = h[script]
+ if s then
+ s[language] = true
+ else
+ h[script] = { [language] = true }
+ end
+ else
+ f[tag] = { [script] = { [language] = true } }
+ end
+ else
+ featurehash[lookup] = { [tag] = { [script] = { [language] = true } } }
+ end
+ --
+ local h = scriptlangs[tag]
+ if h then
+ local s = h[script]
+ if s then
+ s[language] = true
+ else
+ h[script] = { [language] = true }
+ end
+ else
+ scriptlangs[tag] = { [script] = { [language] = true } }
+ end
+ end
+ end
+ end
+ end
+ end
+ return scriptlangs, featurehash, featureorder
+ end
+
+ local function readscriplan(f,fontdata,scriptoffset)
+ setposition(f,scriptoffset)
+ local nofscripts = readushort(f)
+ local scripts = { }
+ for i=1,nofscripts do
+ scripts[readtag(f)] = scriptoffset + readushort(f)
+ end
+ -- script list -> language system info
+ local languagesystems = setmetatableindex("table")
+ for script, offset in next, scripts do
+ setposition(f,offset)
+ local defaultoffset = readushort(f)
+ local noflanguages = readushort(f)
+ local languages = { }
+ if defaultoffset > 0 then
+ languages.dflt = languagesystems[offset + defaultoffset]
+ end
+ for i=1,noflanguages do
+ local language = readtag(f)
+ local offset = offset + readushort(f)
+ languages[language] = languagesystems[offset]
+ end
+ scripts[script] = languages
+ end
+ -- script list -> language system info -> feature list
+ for offset, usedfeatures in next, languagesystems do
+ if offset > 0 then
+ setposition(f,offset)
+ local featureindices = { }
+ usedfeatures.featureindices = featureindices
+ usedfeatures.lookuporder = readushort(f) -- reserved, not used (yet)
+ usedfeatures.requiredindex = readushort(f) -- relates to required (can be 0xFFFF)
+ local noffeatures = readushort(f)
+ for i=1,noffeatures do
+ featureindices[i] = readushort(f) + 1
+ end
+ end
+ end
+ return scripts
+ end
+
+ local function readfeatures(f,fontdata,featureoffset)
+ setposition(f,featureoffset)
+ local features = { }
+ local noffeatures = readushort(f)
+ for i=1,noffeatures do
+ -- also shared?
+ features[i] = {
+ tag = readtag(f),
+ offset = readushort(f)
+ }
+ end
+ --
+ for i=1,noffeatures do
+ local feature = features[i]
+ local offset = featureoffset+feature.offset
+ setposition(f,offset)
+ local parameters = readushort(f) -- feature.parameters
+ local noflookups = readushort(f)
+ if noflookups > 0 then
+-- local lookups = { }
+-- feature.lookups = lookups
+-- for j=1,noflookups do
+-- lookups[j] = readushort(f) + 1
+-- end
+ local lookups = readcardinaltable(f,noflookups,ushort)
+ feature.lookups = lookups
+ for j=1,noflookups do
+ lookups[j] = lookups[j] + 1
+ end
+ end
+ if parameters > 0 then
+ feature.parameters = parameters
+ local plugin = plugins[feature.tag]
+ if plugin then
+ plugin(f,fontdata,featureoffset,feature)
+ end
+ end
+ end
+ return features
+ end
+
+ local function readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder)
+ setposition(f,lookupoffset)
+ local noflookups = readushort(f)
+ local lookups = readcardinaltable(f,noflookups,ushort)
+ for lookupid=1,noflookups do
+ local offset = lookups[lookupid]
+ setposition(f,lookupoffset+offset)
+ local subtables = { }
+ local typebits = readushort(f)
+ local flagbits = readushort(f)
+ local lookuptype = lookuptypes[typebits]
+ local lookupflags = lookupflags[flagbits]
+ local nofsubtables = readushort(f)
+ for j=1,nofsubtables do
+ subtables[j] = offset + readushort(f) -- we can probably put lookupoffset here
+ end
+ -- which one wins?
+ local markclass = band(flagbits,0x0010) ~= 0 -- usemarkfilteringset
+ if markclass then
+ markclass = readushort(f) -- + 1
+ end
+ local markset = rshift(flagbits,8)
+ if markset > 0 then
+ markclass = markset -- + 1
+ end
+ lookups[lookupid] = {
+ type = lookuptype,
+ -- chain = chaindirections[lookuptype] or nil,
+ flags = lookupflags,
+ name = lookupid,
+ subtables = subtables,
+ markclass = markclass,
+ features = featurehash[lookupid], -- not if extension
+ order = featureorder[lookupid],
+ }
+ end
+ return lookups
+ end
+
+ local f_lookupname = formatters["%s_%s_%s"]
+
+ local function resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what,tableoffset)
+
+ local sequences = fontdata.sequences or { }
+ local sublookuplist = fontdata.sublookups or { }
+ fontdata.sequences = sequences
+ fontdata.sublookups = sublookuplist
+ local nofsublookups = #sublookuplist
+ local nofsequences = #sequences -- 0
+ local lastsublookup = nofsublookups
+ local lastsequence = nofsequences
+ local lookupnames = lookupnames[what]
+ local sublookuphash = { }
+ local sublookupcheck = { }
+ local glyphs = fontdata.glyphs
+ local nofglyphs = fontdata.nofglyphs or #glyphs
+ local noflookups = #lookups
+ local lookupprefix = sub(what,2,2) -- g[s|p][ub|os]
+ --
+ local usedlookups = false -- setmetatableindex("number")
+ --
+ local allsteps = { } -- new per 2022-09-25
+
+ for lookupid=1,noflookups do
+ local lookup = lookups[lookupid]
+ local lookuptype = lookup.type
+ local subtables = lookup.subtables
+ local features = lookup.features
+ local handler = lookuphandlers[lookuptype]
+ if handler then
+ local nofsubtables = #subtables
+ local order = lookup.order
+ local flags = lookup.flags
+ -- this is expected in the font handler (faster checking)
+ if flags[1] then flags[1] = "mark" end
+ if flags[2] then flags[2] = "ligature" end
+ if flags[3] then flags[3] = "base" end
+ --
+ local markclass = lookup.markclass
+ -- local chain = lookup.chain
+ if nofsubtables > 0 then
+ local steps = { }
+ local nofsteps = 0
+ local oldtype = nil
+ for s=1,nofsubtables do
+ local step, lt = handler(f,fontdata,lookupid,lookupoffset,subtables[s],glyphs,nofglyphs)
+ if lt then
+ lookuptype = lt
+ if oldtype and lt ~= oldtype then
+ report("messy %s lookup type %a and %a",what,lookuptype,oldtype)
+ end
+ oldtype = lookuptype
+ end
+ if not step then
+ report("unsupported %s lookup type %a",what,lookuptype)
+ else
+ nofsteps = nofsteps + 1
+ steps[nofsteps] = step
+ local rules = step.rules
+ if rules then
+ allsteps[#allsteps+1] = step -- new per 2022-09-25
+ for i=1,#rules do
+ local rule = rules[i]
+ local before = rule.before
+ local current = rule.current
+ local after = rule.after
+ local replacements = rule.replacements
+ if before then
+ for i=1,#before do
+ before[i] = tohash(before[i])
+ end
+ -- as with original ctx ff loader
+ rule.before = reversed(before)
+ end
+ if current then
+ if replacements then
+ -- We have a reverse lookup and therefore only one current entry. We might need
+ -- to reverse the order in the before and after lists so that needs checking.
+ local first = current[1]
+ local hash = { }
+ local repl = { }
+ for i=1,#first do
+ local c = first[i]
+ hash[c] = true
+ repl[c] = replacements[i]
+ end
+ rule.current = { hash }
+ rule.replacements = repl
+ else
+ for i=1,#current do
+ current[i] = tohash(current[i])
+ end
+ end
+ else
+ -- weird lookup
+ end
+ if after then
+ for i=1,#after do
+ after[i] = tohash(after[i])
+ end
+ end
+ if usedlookups then
+ local lookups = rule.lookups
+ if lookups then
+ for k, v in next, lookups do
+ if v then
+ for k, v in next, v do
+ usedlookups[v] = usedlookups[v] + 1
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ if nofsteps ~= nofsubtables then
+ report("bogus subtables removed in %s lookup type %a",what,lookuptype)
+ end
+ lookuptype = lookupnames[lookuptype] or lookuptype
+ if features then
+ nofsequences = nofsequences + 1
+ -- report("registering %i as sequence step %i",lookupid,nofsequences)
+ local l = {
+ index = nofsequences,
+ name = f_lookupname(lookupprefix,"s",lookupid+lookupidoffset),
+ steps = steps,
+ nofsteps = nofsteps,
+ type = lookuptype,
+ markclass = markclass or nil,
+ flags = flags,
+ -- chain = chain,
+ order = order,
+ features = features,
+ }
+ sequences[nofsequences] = l
+ lookup.done = l
+ else
+ nofsublookups = nofsublookups + 1
+ -- report("registering %i as sublookup %i",lookupid,nofsublookups)
+ local l = {
+ index = nofsublookups,
+ name = f_lookupname(lookupprefix,"l",lookupid+lookupidoffset),
+ steps = steps,
+ nofsteps = nofsteps,
+ type = lookuptype,
+ markclass = markclass or nil,
+ flags = flags,
+ -- chain = chain,
+ }
+ sublookuplist[nofsublookups] = l
+ sublookuphash[lookupid] = nofsublookups
+ sublookupcheck[lookupid] = 0
+ lookup.done = l
+ end
+ else
+ report("no subtables for lookup %a",lookupid)
+ end
+ else
+ report("no handler for lookup %a with type %a",lookupid,lookuptype)
+ end
+ end
+
+ if usedlookups then
+ report("used %s lookups: % t",what,sortedkeys(usedlookups))
+ end
+
+ -- When we have a context, we have sublookups that resolve into lookups for which we need to
+ -- know the type. We split the main lookuptable in two parts: sequences (the main lookups)
+ -- and subtable lookups (simple specs with no features). We could keep them merged and might do
+ -- that once we only use this loader. Then we can also move the simple specs into the sequence.
+ -- After all, we pack afterwards.
+
+ local reported = { }
+
+ local function report_issue(i,what,step,kind)
+-- if not reported[step] then
+ report("rule %i in step %i of %s has %s lookups",i,step,what,kind)
+-- reported[name] = true
+-- end
+ end
+
+ -- for i=lastsequence+1,nofsequences do
+ -- local sequence = sequences[i]
+ -- local steps = sequence.steps
+ -- for i=1,#steps do
+ -- local step = steps[i]
+
+ for s=1,#allsteps do -- new per 2022-09-25
+ local step = allsteps[s] -- new per 2022-09-25
+ local rules = step.rules
+ if rules then
+ for i=1,#rules do
+ local rule = rules[i]
+ local rlookups = rule.lookups
+ if not rlookups then
+ report_issue(i,what,s,"no")
+ elseif not next(rlookups) then
+ -- can be ok as it aborts a chain sequence
+ -- report_issue(i,what,s,"empty")
+ rule.lookups = nil
+ else
+ -- we can have holes in rlookups flagged false and we can have multiple lookups
+ -- applied (first time seen in seguemj)
+ local length = #rlookups
+ for index=1,length do
+ local lookuplist = rlookups[index]
+ if lookuplist then
+ local length = #lookuplist
+ local found = { }
+ local noffound = 0
+ for index=1,length do
+ local lookupid = lookuplist[index]
+ if lookupid then
+ local h = sublookuphash[lookupid]
+ if not h then
+ -- here we have a lookup that is used independent as well
+ -- as in another one
+ local lookup = lookups[lookupid]
+ if lookup then
+ local d = lookup.done
+ if d then
+ nofsublookups = nofsublookups + 1
+ -- report("registering %i as sublookup %i",lookupid,nofsublookups)
+ local l = {
+ index = nofsublookups, -- handy for tracing
+ name = f_lookupname(lookupprefix,"d",lookupid+lookupidoffset),
+ derived = true, -- handy for tracing
+ steps = d.steps,
+ nofsteps = d.nofsteps,
+ type = d.lookuptype or "gsub_single", -- todo: check type
+ markclass = d.markclass or nil,
+ flags = d.flags,
+ -- chain = d.chain,
+ }
+ sublookuplist[nofsublookups] = copy(l) -- we repack later
+ sublookuphash[lookupid] = nofsublookups
+ sublookupcheck[lookupid] = 1
+ h = nofsublookups
+ else
+ report_issue(i,what,s,"missing")
+ rule.lookups = nil
+ break
+ end
+ else
+ report_issue(i,what,s,"bad")
+ rule.lookups = nil
+ break
+ end
+ else
+ sublookupcheck[lookupid] = sublookupcheck[lookupid] + 1
+ end
+ if h then
+ noffound = noffound + 1
+ found[noffound] = h
+ end
+ end
+ end
+ rlookups[index] = noffound > 0 and found or false
+ else
+ rlookups[index] = false
+ end
+ end
+ end
+ end
+ end
+ end
+ -- end -- new per 2022-09-25
+
+ for i, n in sortedhash(sublookupcheck) do
+ local l = lookups[i]
+ local t = l.type
+ if n == 0 and t ~= "extension" then
+ local d = l.done
+ report("%s lookup %s of type %a is not used",what,d and d.name or l.name,t)
+ end
+ end
+
+ end
+
+ local function loadvariations(f,fontdata,variationsoffset,lookuptypes,featurehash,featureorder)
+ setposition(f,variationsoffset)
+ local version = readulong(f) -- two times readushort
+ local nofrecords = readulong(f)
+ local records = { }
+ for i=1,nofrecords do
+ records[i] = {
+ conditions = readulong(f),
+ substitutions = readulong(f),
+ }
+ end
+ for i=1,nofrecords do
+ local record = records[i]
+ local offset = record.conditions
+ if offset == 0 then
+ record.condition = nil
+ record.matchtype = "always"
+ else
+ local offset = variationsoffset+offset
+ setposition(f,offset)
+ local nofconditions = readushort(f)
+ local conditions = { }
+ for i=1,nofconditions do
+ conditions[i] = offset + readulong(f)
+ end
+ record.conditions = conditions
+ record.matchtype = "condition"
+ end
+ end
+ for i=1,nofrecords do
+ local record = records[i]
+ if record.matchtype == "condition" then
+ local conditions = record.conditions
+ for i=1,#conditions do
+ setposition(f,conditions[i])
+ conditions[i] = {
+ format = readushort(f),
+ axis = readushort(f),
+ minvalue = read2dot14(f),
+ maxvalue = read2dot14(f),
+ }
+ end
+ end
+ end
+
+ for i=1,nofrecords do
+ local record = records[i]
+ local offset = record.substitutions
+ if offset == 0 then
+ record.substitutions = { }
+ else
+ setposition(f,variationsoffset + offset)
+ local version = readulong(f)
+ local nofsubstitutions = readushort(f)
+ local substitutions = { }
+ for i=1,nofsubstitutions do
+ substitutions[readushort(f)] = readulong(f)
+ end
+ for index, alternates in sortedhash(substitutions) do
+ if index == 0 then
+ record.substitutions = false
+ else
+ local tableoffset = variationsoffset + offset + alternates
+ setposition(f,tableoffset)
+ local parameters = readulong(f) -- feature parameters
+ local noflookups = readushort(f)
+ local lookups = readcardinaltable(f,noflookups,ushort) -- not sure what to do with these
+ -- todo : resolve to proper lookups
+ record.substitutions = lookups
+ end
+ end
+ end
+ end
+ setvariabledata(fontdata,"features",records)
+ end
+
+ local function readscripts(f,fontdata,what,lookuptypes,lookuphandlers,lookupstoo)
+ local tableoffset = gotodatatable(f,fontdata,what,true)
+ if tableoffset then
+ local version = readulong(f)
+ local scriptoffset = tableoffset + readushort(f)
+ local featureoffset = tableoffset + readushort(f)
+ local lookupoffset = tableoffset + readushort(f)
+ -- MFK : Rubik-Regular.ttf : we need to delay adding the offset
+ -- local variationsoffset = version > 0x00010000 and (tableoffset + readulong(f)) or 0
+ local variationsoffset = version > 0x00010000 and readulong(f) or 0
+ if not scriptoffset then
+ return
+ end
+ local scripts = readscriplan(f,fontdata,scriptoffset)
+ local features = readfeatures(f,fontdata,featureoffset)
+ --
+ local scriptlangs, featurehash, featureorder = reorderfeatures(fontdata,scripts,features)
+ --
+ if fontdata.features then
+ fontdata.features[what] = scriptlangs
+ else
+ fontdata.features = { [what] = scriptlangs }
+ end
+ --
+ if not lookupstoo then
+ return
+ end
+ --
+ local lookups = readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder)
+ --
+ if lookups then
+ resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what,tableoffset)
+ end
+ --
+ if variationsoffset > 0 then
+ -- loadvariations(f,fontdata,variationsoffset,lookuptypes,featurehash,featureorder)
+ loadvariations(f,fontdata,tableoffset + variationsoffset,lookuptypes,featurehash,featureorder)
+ end
+ end
+ end
+
+ local function checkkerns(f,fontdata,specification)
+ local datatable = fontdata.tables.kern
+ if not datatable then
+ return -- no kerns
+ end
+ local features = fontdata.features
+ local gposfeatures = features and features.gpos
+ local name
+ if not gposfeatures or not gposfeatures.kern then
+ name = "kern"
+ elseif specification.globalkerns then
+ name = "globalkern"
+ else
+ report("ignoring global kern table, using gpos kern feature")
+ return
+ end
+ setposition(f,datatable.offset)
+ local version = readushort(f)
+ local noftables = readushort(f)
+ if noftables > 1 then
+ report("adding global kern table as gpos feature %a",name)
+ local kerns = setmetatableindex("table")
+ for i=1,noftables do
+ local version = readushort(f)
+ local length = readushort(f)
+ local coverage = readushort(f)
+ -- bit 8-15 of coverage: format 0 or 2
+ local format = rshift(coverage,8) -- is this ok
+ if format == 0 then
+ local nofpairs = readushort(f)
+ local searchrange = readushort(f)
+ local entryselector = readushort(f)
+ local rangeshift = readushort(f)
+ for i=1,nofpairs do
+ kerns[readushort(f)][readushort(f)] = readfword(f)
+ end
+ elseif format == 2 then
+ -- apple specific so let's ignore it
+ else
+ -- not supported by ms
+ end
+ end
+ local feature = { dflt = { dflt = true } }
+ if not features then
+ fontdata.features = { gpos = { [name] = feature } }
+ elseif not gposfeatures then
+ fontdata.features.gpos = { [name] = feature }
+ else
+ gposfeatures[name] = feature
+ end
+ local sequences = fontdata.sequences
+ if not sequences then
+ sequences = { }
+ fontdata.sequences = sequences
+ end
+ local nofsequences = #sequences + 1
+ sequences[nofsequences] = {
+ index = nofsequences,
+ name = name,
+ steps = {
+ {
+ coverage = kerns,
+ format = "kern",
+ },
+ },
+ nofsteps = 1,
+ type = "gpos_pair",
+ flags = { false, false, false, false },
+ order = { name },
+ features = { [name] = feature },
+ }
+ else
+ report("ignoring empty kern table of feature %a",name)
+ end
+ end
+
+ function readers.gsub(f,fontdata,specification)
+ if specification.details then
+ readscripts(f,fontdata,"gsub",gsubtypes,gsubhandlers,specification.lookups)
+ end
+ end
+
+ function readers.gpos(f,fontdata,specification)
+ if specification.details then
+ readscripts(f,fontdata,"gpos",gpostypes,gposhandlers,specification.lookups)
+ if specification.lookups then
+ checkkerns(f,fontdata,specification)
+ end
+ end
+ end
+
+end
+
+function readers.gdef(f,fontdata,specification)
+ if not specification.glyphs then
+ return
+ end
+ local datatable = fontdata.tables.gdef
+ if datatable then
+ local tableoffset = datatable.offset
+ setposition(f,tableoffset)
+ local version = readulong(f)
+ local classoffset = readushort(f)
+ local attachmentoffset = readushort(f) -- used for bitmaps
+ local ligaturecarets = readushort(f) -- used in editors (maybe nice for tracing)
+ local markclassoffset = readushort(f)
+ local marksetsoffset = version >= 0x00010002 and readushort(f) or 0
+ local varsetsoffset = version >= 0x00010003 and readulong(f) or 0
+ local glyphs = fontdata.glyphs
+ local marks = { }
+ local markclasses = setmetatableindex("table")
+ local marksets = setmetatableindex("table")
+ fontdata.marks = marks
+ fontdata.markclasses = markclasses
+ fontdata.marksets = marksets
+ -- class definitions
+ if classoffset ~= 0 then
+ setposition(f,tableoffset + classoffset)
+ local classformat = readushort(f)
+ if classformat == 1 then
+ local firstindex = readushort(f)
+ local lastindex = firstindex + readushort(f) - 1
+ for index=firstindex,lastindex do
+ local class = classes[readushort(f)]
+ if class == "mark" then
+ marks[index] = true
+ end
+ glyphs[index].class = class
+ end
+ elseif classformat == 2 then
+ local nofranges = readushort(f)
+ for i=1,nofranges do
+ local firstindex = readushort(f)
+ local lastindex = readushort(f)
+ local class = classes[readushort(f)]
+ if class then
+ for index=firstindex,lastindex do
+ glyphs[index].class = class
+ if class == "mark" then
+ marks[index] = true
+ end
+ end
+ end
+ end
+ end
+ end
+ -- mark classes
+ if markclassoffset ~= 0 then
+ setposition(f,tableoffset + markclassoffset)
+ local classformat = readushort(f)
+ if classformat == 1 then
+ local firstindex = readushort(f)
+ local lastindex = firstindex + readushort(f) - 1
+ for index=firstindex,lastindex do
+ markclasses[readushort(f)][index] = true
+ end
+ elseif classformat == 2 then
+ local nofranges = readushort(f)
+ for i=1,nofranges do
+ local firstindex = readushort(f)
+ local lastindex = readushort(f)
+ local class = markclasses[readushort(f)]
+ for index=firstindex,lastindex do
+ class[index] = true
+ end
+ end
+ end
+ end
+ -- mark sets : todo: just make the same as class sets above
+ if marksetsoffset ~= 0 then
+ marksetsoffset = tableoffset + marksetsoffset
+ setposition(f,marksetsoffset)
+ local format = readushort(f)
+ if format == 1 then
+ local nofsets = readushort(f)
+ local sets = readcardinaltable(f,nofsets,ulong)
+ for i=1,nofsets do
+ local offset = sets[i]
+ if offset ~= 0 then
+ marksets[i] = readcoverage(f,marksetsoffset+offset)
+ end
+ end
+ end
+ end
+
+ local factors = specification.factors
+
+ if (specification.variable or factors) and varsetsoffset ~= 0 then
+
+ local regions, deltas = readvariationdata(f,tableoffset+varsetsoffset,factors)
+
+ -- setvariabledata(fontdata,"gregions",regions)
+
+ if factors then
+ fontdata.temporary.getdelta = function(outer,inner)
+ local delta = deltas[outer+1]
+ if delta then
+ local d = delta.deltas[inner+1]
+ if d then
+ local scales = delta.scales
+ local dd = 0
+ for i=1,#scales do
+ local di = d[i]
+ if di then
+ dd = dd + scales[i] * di
+ else
+ break
+ end
+ end
+ return round(dd)
+ end
+ end
+ return 0
+ end
+ end
+
+ end
+ end
+end
+
+-- We keep this code here instead of font-otm.lua because we need coverage
+-- helpers. Okay, these helpers could go to the main reader file some day.
+
+local function readmathvalue(f)
+ local v = readshort(f)
+ skipshort(f,1) -- offset to device table
+ return v
+end
+
+local function readmathconstants(f,fontdata,offset)
+ setposition(f,offset)
+ fontdata.mathconstants = {
+ ScriptPercentScaleDown = readshort(f),
+ ScriptScriptPercentScaleDown = readshort(f),
+ DelimitedSubFormulaMinHeight = readushort(f),
+ DisplayOperatorMinHeight = readushort(f),
+ MathLeading = readmathvalue(f),
+ AxisHeight = readmathvalue(f),
+ AccentBaseHeight = readmathvalue(f),
+ FlattenedAccentBaseHeight = readmathvalue(f),
+ SubscriptShiftDown = readmathvalue(f),
+ SubscriptTopMax = readmathvalue(f),
+ SubscriptBaselineDropMin = readmathvalue(f),
+ SuperscriptShiftUp = readmathvalue(f),
+ SuperscriptShiftUpCramped = readmathvalue(f),
+ SuperscriptBottomMin = readmathvalue(f),
+ SuperscriptBaselineDropMax = readmathvalue(f),
+ SubSuperscriptGapMin = readmathvalue(f),
+ SuperscriptBottomMaxWithSubscript = readmathvalue(f),
+ SpaceAfterScript = readmathvalue(f),
+ UpperLimitGapMin = readmathvalue(f),
+ UpperLimitBaselineRiseMin = readmathvalue(f),
+ LowerLimitGapMin = readmathvalue(f),
+ LowerLimitBaselineDropMin = readmathvalue(f),
+ StackTopShiftUp = readmathvalue(f),
+ StackTopDisplayStyleShiftUp = readmathvalue(f),
+ StackBottomShiftDown = readmathvalue(f),
+ StackBottomDisplayStyleShiftDown = readmathvalue(f),
+ StackGapMin = readmathvalue(f),
+ StackDisplayStyleGapMin = readmathvalue(f),
+ StretchStackTopShiftUp = readmathvalue(f),
+ StretchStackBottomShiftDown = readmathvalue(f),
+ StretchStackGapAboveMin = readmathvalue(f),
+ StretchStackGapBelowMin = readmathvalue(f),
+ FractionNumeratorShiftUp = readmathvalue(f),
+ FractionNumeratorDisplayStyleShiftUp = readmathvalue(f),
+ FractionDenominatorShiftDown = readmathvalue(f),
+ FractionDenominatorDisplayStyleShiftDown = readmathvalue(f),
+ FractionNumeratorGapMin = readmathvalue(f),
+ FractionNumeratorDisplayStyleGapMin = readmathvalue(f),
+ FractionRuleThickness = readmathvalue(f),
+ FractionDenominatorGapMin = readmathvalue(f),
+ FractionDenominatorDisplayStyleGapMin = readmathvalue(f),
+ SkewedFractionHorizontalGap = readmathvalue(f),
+ SkewedFractionVerticalGap = readmathvalue(f),
+ OverbarVerticalGap = readmathvalue(f),
+ OverbarRuleThickness = readmathvalue(f),
+ OverbarExtraAscender = readmathvalue(f),
+ UnderbarVerticalGap = readmathvalue(f),
+ UnderbarRuleThickness = readmathvalue(f),
+ UnderbarExtraDescender = readmathvalue(f),
+ RadicalVerticalGap = readmathvalue(f),
+ RadicalDisplayStyleVerticalGap = readmathvalue(f),
+ RadicalRuleThickness = readmathvalue(f),
+ RadicalExtraAscender = readmathvalue(f),
+ RadicalKernBeforeDegree = readmathvalue(f),
+ RadicalKernAfterDegree = readmathvalue(f),
+ RadicalDegreeBottomRaisePercent = readshort(f),
+ }
+end
+
+local function readmathglyphinfo(f,fontdata,offset)
+ setposition(f,offset)
+ local italics = readushort(f)
+ local accents = readushort(f)
+ local extensions = readushort(f)
+ local kerns = readushort(f)
+ local glyphs = fontdata.glyphs
+ if italics ~= 0 then
+ setposition(f,offset+italics)
+ local coverage = readushort(f)
+ local nofglyphs = readushort(f)
+ coverage = readcoverage(f,offset+italics+coverage,true)
+ setposition(f,offset+italics+4)
+ for i=1,nofglyphs do
+ local italic = readmathvalue(f)
+ if italic ~= 0 then
+ local glyph = glyphs[coverage[i]]
+ local math = glyph.math
+ if not math then
+ glyph.math = { italic = italic }
+ else
+ math.italic = italic
+ end
+ end
+ end
+ fontdata.hasitalics = true
+ end
+ if accents ~= 0 then
+ setposition(f,offset+accents)
+ local coverage = readushort(f)
+ local nofglyphs = readushort(f)
+ coverage = readcoverage(f,offset+accents+coverage,true)
+ setposition(f,offset+accents+4)
+ for i=1,nofglyphs do
+ local accent = readmathvalue(f)
+ if accent ~= 0 then
+ local glyph = glyphs[coverage[i]]
+ local math = glyph.math
+ if not math then
+ glyph.math = { accent = accent }
+ else
+ math.accent = accent -- will become math.topanchor
+ end
+ end
+ end
+ end
+ if extensions ~= 0 then
+ setposition(f,offset+extensions)
+ end
+ if kerns ~= 0 then
+ local kernoffset = offset + kerns
+ setposition(f,kernoffset)
+ local coverage = readushort(f)
+ local nofglyphs = readushort(f)
+ if nofglyphs > 0 then
+ local function get(offset)
+ setposition(f,kernoffset+offset)
+ local n = readushort(f)
+ if n == 0 then
+ local k = readmathvalue(f)
+ if k == 0 then
+ -- no need for it (happens sometimes)
+ else
+ return { { kern = k } }
+ end
+ else
+ local l = { }
+ for i=1,n do
+ l[i] = { height = readmathvalue(f) }
+ end
+ for i=1,n do
+ l[i].kern = readmathvalue(f)
+ end
+ l[n+1] = { kern = readmathvalue(f) }
+ return l
+ end
+ end
+ local kernsets = { }
+ for i=1,nofglyphs do
+ local topright = readushort(f)
+ local topleft = readushort(f)
+ local bottomright = readushort(f)
+ local bottomleft = readushort(f)
+ kernsets[i] = {
+ topright = topright ~= 0 and topright or nil,
+ topleft = topleft ~= 0 and topleft or nil,
+ bottomright = bottomright ~= 0 and bottomright or nil,
+ bottomleft = bottomleft ~= 0 and bottomleft or nil,
+ }
+ end
+ coverage = readcoverage(f,kernoffset+coverage,true)
+ for i=1,nofglyphs do
+ local kernset = kernsets[i]
+ if next(kernset) then
+ local k = kernset.topright if k then kernset.topright = get(k) end
+ local k = kernset.topleft if k then kernset.topleft = get(k) end
+ local k = kernset.bottomright if k then kernset.bottomright = get(k) end
+ local k = kernset.bottomleft if k then kernset.bottomleft = get(k) end
+ if next(kernset) then
+ local glyph = glyphs[coverage[i]]
+ local math = glyph.math
+ if math then
+ math.kerns = kernset
+ else
+ glyph.math = { kerns = kernset }
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+local function readmathvariants(f,fontdata,offset)
+ setposition(f,offset)
+ local glyphs = fontdata.glyphs
+ local minoverlap = readushort(f)
+ local vcoverage = readushort(f)
+ local hcoverage = readushort(f)
+ local vnofglyphs = readushort(f)
+ local hnofglyphs = readushort(f)
+ local vconstruction = readcardinaltable(f,vnofglyphs,ushort)
+ local hconstruction = readcardinaltable(f,hnofglyphs,ushort)
+
+ fontdata.mathconstants.MinConnectorOverlap = minoverlap
+
+ -- variants[i] = {
+ -- glyph = readushort(f),
+ -- advance = readushort(f),
+ -- }
+
+ local function get(offset,coverage,nofglyphs,construction,kvariants,kparts,kitalic,korientation,orientation)
+ if coverage ~= 0 and nofglyphs > 0 then
+ local coverage = readcoverage(f,offset+coverage,true)
+ for i=1,nofglyphs do
+ local c = construction[i]
+ if c ~= 0 then
+ local index = coverage[i]
+ local glyph = glyphs[index]
+ local math = glyph.math
+ setposition(f,offset+c)
+ local assembly = readushort(f)
+ local nofvariants = readushort(f)
+ if nofvariants > 0 then
+ local variants, v = nil, 0
+ for i=1,nofvariants do
+ local variant = readushort(f)
+ if variant == index then
+ -- ignore
+ elseif variants then
+ v = v + 1
+ variants[v] = variant
+ else
+ v = 1
+ variants = { variant }
+ end
+ skipshort(f)
+ end
+ if not variants then
+ -- only self
+ elseif not math then
+ math = { [kvariants] = variants }
+ glyph.math = math
+ else
+ math[kvariants] = variants
+ end
+ end
+ if assembly ~= 0 then
+ setposition(f,offset + c + assembly)
+ local italic = readmathvalue(f)
+ local nofparts = readushort(f)
+ local parts = { }
+ for i=1,nofparts do
+ local p = {
+ glyph = readushort(f),
+ start = readushort(f),
+ ["end"] = readushort(f),
+ advance = readushort(f),
+ }
+ local flags = readushort(f)
+ if band(flags,0x0001) ~= 0 then
+ p.extender = 1 -- true
+ end
+ parts[i] = p
+ end
+ if not math then
+ math = {
+ [kparts] = parts
+ }
+ glyph.math = math
+ else
+ math[kparts] = parts
+ end
+ if italic and italic ~= 0 then
+ math[kitalic] = italic
+ end
+ if orientation then
+ math[korientation] = orientation
+ end
+ end
+ end
+ end
+ end
+ end
+
+ -- if CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 then
+ get(offset,hcoverage,hnofglyphs,hconstruction,"variants","parts","partsitalic","partsorientation","horizontal")
+ get(offset,vcoverage,vnofglyphs,vconstruction,"variants","parts","partsitalic","partsorientation","vertical")
+ -- else
+ -- get(offset,vcoverage,vnofglyphs,vconstruction,"vvariants","vparts","vitalic")
+ -- get(offset,hcoverage,hnofglyphs,hconstruction,"hvariants","hparts","hitalic")
+ -- end
+end
+
+function readers.math(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"math",specification.glyphs)
+ if tableoffset then
+ local version = readulong(f)
+ -- if version ~= 0x00010000 then
+ -- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"math",fontdata.filename)
+ -- return
+ -- end
+ local constants = readushort(f)
+ local glyphinfo = readushort(f)
+ local variants = readushort(f)
+ if constants == 0 then
+ report("the math table of %a has no constants",fontdata.filename)
+ else
+ readmathconstants(f,fontdata,tableoffset+constants)
+ end
+ if glyphinfo ~= 0 then
+ readmathglyphinfo(f,fontdata,tableoffset+glyphinfo)
+ end
+ if variants ~= 0 then
+ readmathvariants(f,fontdata,tableoffset+variants)
+ end
+ end
+end
+
+do
+
+ -- format 1: PaintColrLayers
+ -- for each referenced child paint table, in bottom-up z-order:
+ -- call renderPaint() passing the child paint table
+ -- compose the returned graphic onto the surface using simplealpha blending
+ --
+ -- format 2, 3: PaintSolid
+ -- paint the specified color onto the surface
+ --
+ -- format 4, 5, 6, 7, 8, 9: PaintLinearGradient, PaintRadialGradient, PaintSweepGradient
+ -- paint the gradient onto the surface following the gradient algorithm
+ --
+ -- format 10: PaintGlyph
+ -- apply the outline of the referenced glyph to the clip region
+ -- (take the intersection of clip regions—see Filling shapes)
+ -- call renderPaint() passing the child paint table
+ -- restore the previous clip region
+ --
+ -- format 11: PaintColrGlyph
+ -- call renderPaint() passing the paint table referenced by the base glyph ID
+ --
+ -- format 12 .. 31: Transform Translate Scale
+ -- apply the specified transform, compose the transform with the current transform
+ -- call renderPaint() passing the child paint table
+ -- restore the previous transform state
+ --
+ -- format 32: PaintComposite
+ -- call renderPaint() passing the backdrop child paint table and save the result
+ -- call renderPaint() passing the source child paint table and save the result
+ -- compose the source and backdrop using the specified composite mode
+ -- compose the result of the above composition onto the surface using simple alpha blending
+
+ local paintdata -- for the moment verbose, will be just indexed
+ local linesdata -- for the moment verbose, will be just indexed
+ local affinedata -- for the moment verbose, will be just indexed
+
+ local function getpaintoffset(f,offset)
+ offset = offset + readuoffset(f)
+ return paintdata[offset] and offset or nil
+ end
+
+ local function getlinesoffset(f,offset,var)
+ local offset = offset + readuoffset(f)
+ if linesdata[offset] == nil then
+ linesdata[offset] = var
+ end
+ return offset
+ end
+
+ local function getaffineoffset(f,offset,var)
+ local offset = offset + readuoffset(f)
+ if affinedata[offset] == nil then
+ affinedata[offset] = var
+ end
+ return offset
+ end
+
+ paintreaders = {
+ -- uint8 numLayers Number of offsets to paint tables to read from LayerList.
+ -- uint32 firstLayerIndex Index (base 0) into the LayerList.
+ [1] = function(f,format)
+ return {
+ format = format,
+ name = "PaintColrLayers",
+ count = readuinteger(f),
+ index = readulong(f),
+ list = false,
+ }
+ end,
+ -- uint16 paletteIndex Index for a CPAL palette entry.
+ -- F2DOT14 alpha Alpha value.
+ [2] = function(f,format)
+ return {
+ format = format,
+ name = "Paintsolid",
+ palette = readushort(f),
+ alpha = read2dot14(f),
+ }
+ end,
+ -- uint16 paletteIndex Index for a CPAL palette entry.
+ -- F2DOT14 alpha Alpha value. For variation, use varIndexBase + 0.
+ -- uint32 varIndexBase Base index into DeltaSetIndexMap.
+ [3] = function(f,format)
+ return {
+ format = format,
+ name = "Paintsolid",
+ palette = readushort(f),
+ alpha = read2dot14(f),
+ varbase = readulong(f),
+ }
+ end,
+ -- Offset24 colorLineOffset Offset to VarColorLine table.
+ -- FWORD x0 Start point (p₀) x coordinate. For variation, use varIndexBase + 0.
+ -- FWORD y0 Start point (p₀) y coordinate. For variation, use varIndexBase + 1.
+ -- FWORD x1 End point (p₁) x coordinate. For variation, use varIndexBase + 2.
+ -- FWORD y1 End point (p₁) y coordinate. For variation, use varIndexBase + 3.
+ -- FWORD x2 Rotation point (p₂) x coordinate. For variation, use varIndexBase + 4.
+ -- FWORD y2 Rotation point (p₂) y coordinate. For variation, use varIndexBase + 5.
+ -- uint32 varIndexBase Base index into DeltaSetIndexMap.
+ [4] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintLinearGradient",
+ color = getlinesoffset(f,offset,false),
+ x0 = readfword(f),
+ y0 = readfword(f),
+ x1 = readfword(f),
+ y1 = readfword(f),
+ x2 = readfword(f),
+ y2 = readfword(f),
+ }
+ end,
+ [5] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintLinearGradient",
+ color = getlinesoffset(f,offset,true),
+ x0 = readfword(f),
+ y0 = readfword(f),
+ x1 = readfword(f),
+ y1 = readfword(f),
+ x2 = readfword(f),
+ y2 = readfword(f),
+ varbase = readulong(f),
+ }
+ end,
+ -- Offset24 colorLineOffset Offset to VarColorLine table.
+ -- FWORD x0 Start circle center x coordinate. For variation, use varIndexBase + 0.
+ -- FWORD y0 Start circle center y coordinate. For variation, use varIndexBase + 1.
+ -- UFWORD radius0 Start circle radius. For variation, use varIndexBase + 2.
+ -- FWORD x1 End circle center x coordinate. For variation, use varIndexBase + 3.
+ -- FWORD y1 End circle center y coordinate. For variation, use varIndexBase + 4.
+ -- UFWORD radius1 End circle radius. For variation, use varIndexBase + 5.
+ -- uint32 varIndexBase Base index into DeltaSetIndexMap.
+ [6] = function(f,format)
+ return {
+ format = format,
+ name = "PaintRadialGradient",
+ color = getlinesoffset(f,offset,false),
+ x0 = readfword(f),
+ y0 = readfword(f),
+ radius0 = readfword(f),
+ x1 = readfword(f),
+ y1 = readfword(f),
+ radius1 = readfword(f),
+ }
+ end,
+ [7] = function(f,format)
+ return {
+ format = format,
+ name = "PaintRadialGradient",
+ color = getlinesoffset(f,offset,true),
+ x0 = readfword(f),
+ y0 = readfword(f),
+ radius0 = readfword(f),
+ x1 = readfword(f),
+ y1 = readfword(f),
+ radius1 = readfword(f),
+ varbase = readulong(f),
+ }
+ end,
+ -- Offset24 colorLineOffset Offset to VarColorLine table.
+ -- FWORD centerX Center x coordinate. For variation, use varIndexBase + 0.
+ -- FWORD centerY Center y coordinate. For variation, use varIndexBase + 1.
+ -- F2DOT14 startAngle Start of the angular range of the gradient, 180° in counter-clockwise degrees per 1.0 of value. For variation, use varIndexBase + 2.
+ -- F2DOT14 endAngle End of the angular range of the gradient, 180° in counter-clockwise degrees per 1.0 of value. For variation, use varIndexBase + 3.
+ -- uint32 varIndexBase Base index into DeltaSetIndexMap.
+ [8] = function(f,format)
+ return {
+ format = format,
+ name = "PaintSweepGradient",
+ color = getlinesoffset(f,offset,false),
+ centerx = readfword(f),
+ centery = readfword(f),
+ startangle = read2dot14(f),
+ endangle = read2dot14(f),
+ }
+ end,
+ [9] = function(f,format)
+ return {
+ format = format,
+ name = "PaintSweepGradient",
+ color = getlinesoffset(f,offset,true),
+ centerx = readfword(f),
+ centery = readfword(f),
+ startangle = read2dot14(f),
+ endangle = read2dot14(f),
+ varbase = readulong(f),
+ }
+ end,
+ -- Offset24 paintOffset Offset to a Paint table.
+ -- uint16 glyphID Glyph ID for the source outline.
+ [10] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintGlyph",
+ paint = getpaintoffset(f,offset),
+ glyph = readushort(f),
+ }
+ end,
+ -- uint16 glyphID Glyph ID for a BaseGlyphList base glyph.
+ [11] = function(f,format)
+ return {
+ format = format,
+ name = "PaintColrGlyph",
+ glyph = readushort(f),
+ }
+ end,
+ -- Offset24 paintOffset Offset to a Paint subtable.
+ -- Offset24 transformOffset Offset to an (Var)Affine2x3 table.
+ [12] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintTransform",
+ affine = getaffineoffset(f,offset,false),
+ paint = getpaintoffset(f,offset),
+ }
+ end,
+ [13] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintTransform",
+ affine = getaffineoffset(f,offset,true),
+ paint = getpaintoffset(f,offset),
+ }
+ end,
+ -- Offset24 paintOffset Offset to a Paint subtable.
+ -- FWORD dx Translation in x direction. For variation, use varIndexBase + 0.
+ -- FWORD dy Translation in y direction. For variation, use varIndexBase + 1.
+ -- uint32 varIndexBase Base index into DeltaSetIndexMap.
+ [14] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintTranslate",
+ paint = getpaintoffset(f,offset),
+ dx = readfword(f),
+ dy = readfword(f),
+ }
+ end,
+ [15] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintTranslate",
+ paint = getpaintoffset(f,offset),
+ dx = readfword(f),
+ dy = readfword(f),
+ varbase = readulong(f),
+ }
+ end,
+ -- Offset24 paintOffset Offset to a Paint subtable.
+ -- F2DOT14 scaleX Scale factor in x direction. For variation, use varIndexBase + 0.
+ -- F2DOT14 scaleY Scale factor in y direction. For variation, use varIndexBase + 1.
+ -- uint32 varIndexBase Base index into DeltaSetIndexMap.
+ [16] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintScale",
+ paint = getpaintoffset(f,offset),
+ scalex = read2dot14(f),
+ scaley = read2dot14(f),
+ }
+ end,
+ [17] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintScale",
+ paint = getpaintoffset(f,offset),
+ scalex = read2dot14(f),
+ scaley = read2dot14(f),
+ varbase = readulong(f),
+ }
+ end,
+ -- Offset24 paintOffset Offset to a Paint subtable.
+ -- F2DOT14 scaleX Scale factor in x direction. For variation, use varIndexBase + 0.
+ -- F2DOT14 scaleY Scale factor in y direction. For variation, use varIndexBase + 1.
+ -- FWORD centerX x coordinate for the center of scaling. For variation, use varIndexBase + 2.
+ -- FWORD centerY y coordinate for the center of scaling. For variation, use varIndexBase + 3.
+ -- uint32 varIndexBase Base index into DeltaSetIndexMap.
+ [18] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintScale",
+ paint = getpaintoffset(f,offset),
+ scalex = read2dot14(f),
+ scaley = read2dot14(f),
+ centerx = readfword(f),
+ centery = readfword(f),
+ }
+ end,
+ [19] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintScale",
+ paint = getpaintoffset(f,offset),
+ scalex = read2dot14(f),
+ scaley = read2dot14(f),
+ centerx = readfword(f),
+ centery = readfword(f),
+ varbase = readulong(f),
+ }
+ end,
+ -- Offset24 paintOffset Offset to a Paint subtable.
+ -- F2DOT14 scale Scale factor in x and y directions. For variation, use varIndexBase + 0.
+ -- uint32 varIndexBase Base index into DeltaSetIndexMap.
+ [20] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintScale",
+ paint = getpaintoffset(f,offset),
+ scale = read2dot14(f),
+ }
+ end,
+ [21] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintScale",
+ paint = getpaintoffset(f,offset),
+ scale = read2dot14(f),
+ varbase = readulong(f),
+ }
+ end,
+ -- Offset24 paintOffset Offset to a Paint subtable.
+ -- F2DOT14 scale Scale factor in x and y directions. For variation, use varIndexBase + 0.
+ -- FWORD centerX x coordinate for the center of scaling. For variation, use varIndexBase + 1.
+ -- FWORD centerY y coordinate for the center of scaling. For variation, use varIndexBase + 2.
+ -- uint32 varIndexBase Base index into DeltaSetIndexMap.
+ [22] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintScale",
+ paint = getpaintoffset(f,offset),
+ scale = read2dot14(f),
+ centerx = readfword(f),
+ centery = readfword(f),
+ }
+ end,
+ [23] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintScale",
+ paint = getpaintoffset(f,offset),
+ scale = read2dot14(f),
+ centerx = readfword(f),
+ centery = readfword(f),
+ varbase = readulong(f),
+ }
+ end,
+ -- Offset24 paintOffset Offset to a Paint subtable.
+ -- F2DOT14 angle Rotation angle, 180° in counter-clockwise degrees per 1.0 of value. For variation, use varIndexBase + 0.
+ -- uint32 varIndexBase Base index into DeltaSetIndexMap.
+ [24] = function(f,format,offset)
+ return {
+ format = format,
+ angle = read2dot14(f),
+ paint = getpaintoffset(f,offset),
+ name = "PaintRotate",
+ }
+ end,
+ [25] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintRotate",
+ paint = getpaintoffset(f,offset),
+ angle = read2dot14(f),
+ varbase = readulong(f),
+ }
+ end,
+ -- Offset24 paintOffset Offset to a Paint subtable.
+ -- F2DOT14 angle Rotation angle, 180° in counter-clockwise degrees per 1.0 of value. For variation, use varIndexBase + 0.
+ -- FWORD centerX x coordinate for the center of rotation. For variation, use varIndexBase + 1.
+ -- FWORD centerY y coordinate for the center of rotation. For variation, use varIndexBase + 2.
+ -- uint32 varIndexBase Base index into DeltaSetIndexMap.
+ [26] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintRotate",
+ paint = getpaintoffset(f,offset),
+ centerx = readfword(f),
+ centery = readfword(f),
+ }
+ end,
+ [27] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintRotate",
+ paint = getpaintoffset(f,offset),
+ centerx = read2dot14(f),
+ centery = read2dot14(f),
+ varbase = readulong(f),
+ }
+ end,
+ -- Offset24 paintOffset Offset to a Paint subtable.
+ -- F2DOT14 xSkewAngle Angle of skew in the direction of the x-axis, 180° in counter-clockwise degrees per 1.0 of value. For variation, use varIndexBase + 0.
+ -- F2DOT14 ySkewAngle Angle of skew in the direction of the y-axis, 180° in counter-clockwise degrees per 1.0 of value. For variation, use varIndexBase + 1.
+ -- uint32 varIndexBase Base index into DeltaSetIndexMap.
+ [28] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintSkew",
+ paint = getpaintoffset(f,offset),
+ xangle = read2dot14(f),
+ yangle = read2dot14(f),
+ }
+ end,
+ [29] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintSkew",
+ paint = getpaintoffset(f,offset),
+ xangle = read2dot14(f),
+ yangle = read2dot14(f),
+ varbase = readulong(f),
+ }
+ end,
+ -- Offset24 paintOffset Offset to a Paint subtable.
+ -- F2DOT14 xSkewAngle Angle of skew in the direction of the x-axis, 180° in counter-clockwise degrees per 1.0 of value. For variation, use varIndexBase + 0.
+ -- F2DOT14 ySkewAngle Angle of skew in the direction of the y-axis, 180° in counter-clockwise degrees per 1.0 of value. For variation, use varIndexBase + 1.
+ -- FWORD centerX x coordinate for the center of rotation. For variation, use varIndexBase + 2.
+ -- FWORD centerY y coordinate for the center of rotation. For variation, use varIndexBase + 3.
+ -- uint32 varIndexBase Base index into DeltaSetIndexMap.
+ [30] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintSkew",
+ paint = getpaintoffset(f,offset),
+ xangle = read2dot14(f),
+ yangle = read2dot14(f),
+ centerx = readfword(f),
+ centery = readfword(f),
+ }
+ end,
+ [31] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintSkew",
+ paint = getpaintoffset(f,offset),
+ xangle = read2dot14(f),
+ yangle = read2dot14(f),
+ centerx = readfword(f),
+ centery = readfword(f),
+ varbase = readulong(f),
+ }
+ end,
+ -- Offset24 sourcePaintOffset Offset to a source Paint table.
+ -- uint8 compositeMode A CompositeMode enumeration value.
+ -- Offset24 backdropaintOffset Offset to a backdrop Paint table.
+ [32] = function(f,format,offset)
+ return {
+ format = format,
+ name = "PaintComposite",
+ source = getpaintoffset(f,offset),
+ mode = readuinteger(f),
+ backdrop = getpaintoffset(f,offset),
+ }
+ end,
+ }
+
+ local unsupported = function()
+ return nil
+ end
+
+ setmetatableindex(paintreaders,function(t,format)
+ report("unsupported colr type 2 paint format %i",format)
+ t[format] = unsupported
+ return unsupported
+ end)
+
+ function readers.colr(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"colr",specification.glyphs)
+ if tableoffset then
+ local version = readushort(f)
+ if version == 0 then
+ -- we're okay
+ elseif version == 1 then
+ report("table version %a of %a is %s supported for font %s",version,"colr","partially",fontdata.filename)
+ else
+ report("table version %a of %a is %s supported for font %s",version,"colr","not",fontdata.filename)
+ return
+ end
+ if not fontdata.tables.cpal then
+ report("color table %a in font %a has no mandate %a table","colr",fontdata.filename,"cpal")
+ fontdata.colorpalettes = { }
+ end
+ local glyphs = fontdata.glyphs
+ local nofglyphs = readushort(f)
+ local baseoffset = readulong(f)
+ local layeroffset = readulong(f)
+ local noflayers = readushort(f)
+ local glyphlistoffset = 0
+ local layerlistoffset = 0
+ local cliplistoffset = 0
+ local varindexmapoffset = 0
+ local variationoffset = 0
+ if version == 1 then
+ glyphlistoffset = readulong(f)
+ layerlistoffset = readulong(f)
+ cliplistoffset = readulong(f)
+ varindexmapoffset = readulong(f)
+ variationoffset = readulong(f)
+ end
+ local layerrecords = { }
+ local maxclass = 0
+ -- The special value 0xFFFF is foreground (but we index from 1). It
+ -- more looks like indices into a palette so 'class' is a better name
+ -- than 'palette'.
+ if layeroffset > 0 then
+ setposition(f,tableoffset + layeroffset)
+ for i=1,noflayers do
+ local slot = readushort(f)
+ local class = readushort(f)
+ if class < 0xFFFF then
+ class = class + 1
+ if class > maxclass then
+ maxclass = class
+ end
+ end
+ layerrecords[i] = {
+ slot = slot,
+ class = class,
+ }
+ end
+ end
+ fontdata.maxcolorclass = maxclass
+ if baseoffset > 0 then
+ setposition(f,tableoffset + baseoffset)
+ for i=0,nofglyphs-1 do
+ local glyphindex = readushort(f)
+ local firstlayer = readushort(f)
+ local noflayers = readushort(f)
+ local t = { }
+ for i=1,noflayers do
+ t[i] = layerrecords[firstlayer+i]
+ end
+ glyphs[glyphindex].colors = t
+ end
+ end
+if next(layerrecords) then
+ report("table version %a of %a is %s supported for font %s",version,"colr","partially",fontdata.filename)
+ return
+end
+ -- if not (CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0) then
+ -- return
+ -- end
+ if layerlistoffset > 0 and glyphlistoffset > 0 then
+ local layers = { }
+ local paints = { }
+ local count, offset
+ --
+ setposition(f,tableoffset + layerlistoffset)
+ count = readulong(f)
+ -- layers = readcardinaltable(f,count,uoffset)
+ for i=1,count do -- zero ?
+ layers[i] = readulong(f) -- offsets to painttable
+ end
+ --
+ offset = tableoffset + glyphlistoffset
+ setposition(f,offset)
+ count = readulong(f)
+ for i=1,count do
+ -- glyph index -> paintrecord
+ paints[readushort(f)] = readulong(f) -- paintrecord offset (32 formats)
+ end
+ paintdata = setmetatableindex(function(t,k)
+ setposition(f,k)
+ local format = readuinteger(f)
+ local v = paintreaders[format](f,format,k)
+ t[k] = v
+ return v
+ end)
+ linesdata = { }
+ affinedata = { }
+ for k, v in next, paints do
+ local o = offset + v
+ if paintdata[o] then
+ paints[k] = o -- first paint
+ end
+ end
+ -- expand format 1
+ offset = tableoffset + layerlistoffset
+ for k, v in next, paints do
+ v = paintdata[v]
+ local format = v.format
+ if format == 1 then
+ -- name
+ local count = v.count
+ local index = v.index
+ local list = { }
+ v.count = nil
+ v.index = nil
+ v.list = list
+ for i=1,count do
+ local o = offset + layers[index+i]
+ if paintdata[o] then
+ list[i] = o
+ end
+ end
+ end
+ end
+ --
+ if variationoffset > 0 then
+ local offsettostore = tableoffset + variationoffset
+ local factors = specification.factors
+ if factors then
+ local regions, deltas = readvariationdata(f,offsettostore,factors)
+ report("font %a has a colr variations, check it out",fontdata.filename)
+ -- inspect(regions)
+ -- inspect(deltas)
+ end
+ end
+ --
+ -- It will take while before I finish this, also because there has never
+ -- been much demand for color fonts and there is no real incentive for
+ -- spending too much time on it.
+ --
+ -- todo: cliplist, varbase, affine, deltas etc
+ --
+ -- reindex tables, gives smaller files but optional because of tracing
+ --
+ for k, v in next, linesdata do
+ setposition(f,k)
+ local extend = readuinteger(f)
+ local count = readushort(f)
+ local stops = { }
+ for i=1,count do
+ stops[i] = {
+ stop = read2dot14(f),
+ pallette = readushort(f),
+ alpha = read2dot14(f),
+ varbase = v and readulong(f) or nil,
+ }
+ end
+ linesdata[k] = {
+ extend = readuinteger(f),
+ stops = stops,
+ }
+ end
+ --
+ for k, v in next, affinedata do
+ setposition(f,k)
+ affinedata[k] = {
+ xx = readfixed(f),
+ yx = readfixed(f),
+ xy = readfixed(f),
+ yy = readfixed(f),
+ dx = readfixed(f),
+ dy = readfixed(f),
+ }
+ end
+ --
+ local function rehash(t)
+ local hash = { }
+ local data = { }
+ local n = 0
+ for k, v in table.sortedhash(t) do
+ n = n + 1
+ hash[k] = n
+ data[n] = v
+ end
+ return hash, data
+ end
+ --
+ if true then
+ local phash, pdata = rehash(paintdata)
+ local lhash, ldata = rehash(linesdata)
+ local ahash, adata = rehash(affinedata)
+ for k, v in next, paintdata do
+ local c = v.color
+ if c then
+ v.color = lhash[c]
+ end
+ local a = v.affine
+ if a then
+ v.affine = ahash[a]
+ end
+ local p = v.paint
+ if p then
+ v.paint = phash[p]
+ goto done
+ end
+ local l = v.list
+ if l then
+ for i=1,#l do
+ l[i] = phash[l[i]]
+ end
+ goto done
+ end
+ local s = v.source
+ if s then
+ v.source = phash[s]
+ v.backdrop = phash[v.backdrop]
+ -- goto done
+ end
+ ::done::
+ end
+ paintdata = pdata
+ linesdata = ldata
+ for k, v in next, paints do -- zero indexed
+ paints[k] = phash[v]
+ end
+ end
+ --
+ if not next(layerrecords) then
+ for k, v in next, paints do
+ local paint = paintdata[v]
+ local format = paint.format
+ if format == 1 then
+ local list = paint.list
+ local done = { }
+ for i=1,#list do
+ local p = paintdata[list[i]]
+ local f = p.format
+ if f == 10 or f == 11 then
+ done[i] = {
+ slot = p.glyph,
+ class = i,
+ }
+ end
+ end
+ glyphs[k].colors = done
+ end
+ end
+ end
+-- fontdata.colorpaintdata = paintdata
+-- fontdata.colorpaintlist = paints
+-- fontdata.colorlinesdata = linesdata
+-- fontdata.coloraffinedata = affinedata
+ end
+ end
+ fontdata.hascolor = true
+ end
+
+end
+
+function readers.cpal(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"cpal",specification.glyphs)
+ if tableoffset then
+ local version = readushort(f)
+ -- if version > 1 then
+ -- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"cpal",fontdata.filename)
+ -- return
+ -- end
+ local nofpaletteentries = readushort(f)
+ local nofpalettes = readushort(f)
+ local nofcolorrecords = readushort(f)
+ local firstcoloroffset = readulong(f)
+ local colorrecords = { }
+ local palettes = readcardinaltable(f,nofpalettes,ushort)
+ if version == 1 then
+ -- used for guis
+ local palettettypesoffset = readulong(f)
+ local palettelabelsoffset = readulong(f)
+ local paletteentryoffset = readulong(f)
+ end
+ setposition(f,tableoffset+firstcoloroffset)
+ for i=1,nofcolorrecords do
+ local b, g, r, a = readbytes(f,4)
+ colorrecords[i] = {
+ r, g, b, a ~= 255 and a or nil,
+ }
+ end
+ for i=1,nofpalettes do
+ local p = { }
+ local o = palettes[i]
+ for j=1,nofpaletteentries do
+ p[j] = colorrecords[o+j]
+ end
+ palettes[i] = p
+ end
+ fontdata.colorpalettes = palettes
+ end
+end
+
+local compress = gzip and gzip.compress
+local compressed = compress and gzip.compressed
+
+-- At some point I will delay loading and only store the offsets (in context lmtx
+-- only).
+
+-- compressed = false
+
+function readers.svg(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"svg",specification.glyphs)
+ if tableoffset then
+ local version = readushort(f)
+ -- if version ~= 0 then
+ -- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"svg",fontdata.filename)
+ -- return
+ -- end
+ local glyphs = fontdata.glyphs
+ local indexoffset = tableoffset + readulong(f)
+ local reserved = readulong(f)
+ setposition(f,indexoffset)
+ local nofentries = readushort(f)
+ local entries = { }
+ for i=1,nofentries do
+ entries[i] = {
+ first = readushort(f),
+ last = readushort(f),
+ offset = indexoffset + readulong(f),
+ length = readulong(f),
+ }
+ end
+ for i=1,nofentries do
+ local entry = entries[i]
+ setposition(f,entry.offset)
+ local data = readstring(f,entry.length)
+ if compressed and not compressed(data) then
+ data = compress(data)
+ end
+ entries[i] = {
+ first = entry.first,
+ last = entry.last,
+ data = data
+ }
+ end
+ fontdata.svgshapes = entries
+ end
+ fontdata.hascolor = true
+end
+
+function readers.sbix(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"sbix",specification.glyphs)
+ if tableoffset then
+ local version = readushort(f)
+ local flags = readushort(f)
+ local nofstrikes = readulong(f)
+ local strikes = { }
+ local nofglyphs = fontdata.nofglyphs
+ for i=1,nofstrikes do
+ strikes[i] = readulong(f)
+ end
+ local shapes = { }
+ local done = 0
+ for i=1,nofstrikes do
+ local strikeoffset = strikes[i] + tableoffset
+ setposition(f,strikeoffset)
+ strikes[i] = {
+ ppem = readushort(f),
+ ppi = readushort(f),
+ offset = strikeoffset
+ }
+ end
+ -- highest first
+ sort(strikes,function(a,b)
+ if b.ppem == a.ppem then
+ return b.ppi < a.ppi
+ else
+ return b.ppem < a.ppem
+ end
+ end)
+ local glyphs = { }
+ -- local delayed = CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 or fonts.handlers.typethree
+ for i=1,nofstrikes do
+ local strike = strikes[i]
+ local strikeppem = strike.ppem
+ local strikeppi = strike.ppi
+ local strikeoffset = strike.offset
+ setposition(f,strikeoffset)
+ for i=0,nofglyphs do
+ glyphs[i] = readulong(f)
+ end
+ local glyphoffset = glyphs[0]
+ for i=0,nofglyphs-1 do
+ local nextoffset = glyphs[i+1]
+ if not shapes[i] then
+ local datasize = nextoffset - glyphoffset
+ if datasize > 0 then
+ setposition(f,strikeoffset + glyphoffset)
+ local x = readshort(f)
+ local y = readshort(f)
+ local tag = readtag(f) -- or just skip, we never needed it till now
+ local size = datasize - 8
+ local data = nil
+ local offset = nil
+ -- if delayed then
+ offset = getposition(f)
+ -- else
+ -- data = readstring(f,size)
+ -- size = nil
+ -- end
+ shapes[i] = {
+ x = x,
+ y = y,
+ o = offset,
+ s = size,
+ data = data,
+ -- tag = tag, -- maybe for tracing
+ -- ppem = strikeppem, -- not used, for tracing
+ -- ppi = strikeppi, -- not used, for tracing
+ }
+ done = done + 1
+ if done == nofglyphs then
+ break
+ end
+ end
+ end
+ glyphoffset = nextoffset
+ end
+ end
+ fontdata.pngshapes = shapes
+ end
+end
+
+-- Another bitmap (so not that useful) format. But Luigi found a font that
+-- has them , so ...
+
+do
+
+ local function getmetrics(f)
+ return {
+ ascender = readinteger(f),
+ descender = readinteger(f),
+ widthmax = readuinteger(f),
+ caretslopedumerator = readinteger(f),
+ caretslopedenominator = readinteger(f),
+ caretoffset = readinteger(f),
+ minorigin = readinteger(f),
+ minadvance = readinteger(f),
+ maxbefore = readinteger(f),
+ minafter = readinteger(f),
+ pad1 = readinteger(f),
+ pad2 = readinteger(f),
+ }
+ end
+
+ -- bad names
+
+ local function getbigmetrics(f)
+ -- bigmetrics, maybe just skip 9 bytes
+ return {
+ height = readuinteger(f),
+ width = readuinteger(f),
+ horiBearingX = readinteger(f),
+ horiBearingY = readinteger(f),
+ horiAdvance = readuinteger(f),
+ vertBearingX = readinteger(f),
+ vertBearingY = readinteger(f),
+ vertAdvance = readuinteger(f),
+ }
+ end
+
+ local function getsmallmetrics(f)
+ -- smallmetrics, maybe just skip 5 bytes
+ return {
+ height = readuinteger(f),
+ width = readuinteger(f),
+ bearingX = readinteger(f),
+ bearingY = readinteger(f),
+ advance = readuinteger(f),
+ }
+ end
+
+ function readers.cblc(f,fontdata,specification)
+ -- should we delay this ?
+ local ctdttableoffset = gotodatatable(f,fontdata,"cbdt",specification.glyphs)
+ if not ctdttableoffset then
+ return
+ end
+ local cblctableoffset = gotodatatable(f,fontdata,"cblc",specification.glyphs)
+ if cblctableoffset then
+ local majorversion = readushort(f)
+ local minorversion = readushort(f)
+ local nofsizetables = readulong(f)
+ local sizetables = { }
+ local shapes = { }
+ local subtables = { }
+ for i=1,nofsizetables do
+ sizetables[i] = {
+ subtables = readulong(f),
+ indexsize = readulong(f),
+ nofsubtables = readulong(f),
+ colorref = readulong(f),
+ hormetrics = getmetrics(f),
+ vermetrics = getmetrics(f),
+ firstindex = readushort(f),
+ lastindex = readushort(f),
+ ppemx = readbyte(f),
+ ppemy = readbyte(f),
+ bitdepth = readbyte(f),
+ flags = readbyte(f),
+ }
+ end
+ sort(sizetables,function(a,b)
+ if b.ppemx == a.ppemx then
+ return b.bitdepth < a.bitdepth
+ else
+ return b.ppemx < a.ppemx
+ end
+ end)
+ for i=1,nofsizetables do
+ local s = sizetables[i]
+ local d = false
+ for j=s.firstindex,s.lastindex do
+ if not shapes[j] then
+ shapes[j] = i
+ d = true
+ end
+ end
+ if d then
+ s.used = true
+ end
+ end
+ for i=1,nofsizetables do
+ local s = sizetables[i]
+ if s.used then
+ local offset = s.subtables
+ setposition(f,cblctableoffset+offset)
+ for j=1,s.nofsubtables do
+ local firstindex = readushort(f)
+ local lastindex = readushort(f)
+ local tableoffset = readulong(f) + offset
+ for k=firstindex,lastindex do
+ if shapes[k] == i then
+ local s = subtables[tableoffset]
+ if not s then
+ s = {
+ firstindex = firstindex,
+ lastindex = lastindex,
+ }
+ subtables[tableoffset] = s
+ end
+ shapes[k] = s
+ end
+ end
+ end
+ end
+ end
+
+ -- there is no need to sort in string stream but we have a nicer trace
+ -- if needed
+
+ for offset, subtable in sortedhash(subtables) do
+ local tabletype = readushort(f)
+ subtable.format = readushort(f)
+ local baseoffset = readulong(f) + ctdttableoffset
+ local offsets = { }
+ local metrics = nil
+ if tabletype == 1 then
+ -- we have the usual one more to get the size
+ for i=subtable.firstindex,subtable.lastindex do
+ offsets[i] = readulong(f) + baseoffset
+ end
+ skipbytes(f,4)
+ elseif tabletype == 2 then
+ local size = readulong(f)
+ local done = baseoffset
+ metrics = getbigmetrics(f)
+ for i=subtable.firstindex,subtable.lastindex do
+ offsets[i] = done
+ done = done + size
+ end
+ elseif tabletype == 3 then
+ -- we have the usual one more to get the size
+ local n = subtable.lastindex - subtable.firstindex + 2
+ for i=subtable.firstindex,subtable.lastindex do
+ offsets[i] = readushort(f) + baseoffset
+ end
+ if math.odd(n) then
+ skipbytes(f,4)
+ else
+ skipbytes(f,2)
+ end
+ elseif tabletype == 4 then
+ for i=1,readulong(f) do
+ offsets[readushort(f)] = readushort(f) + baseoffset
+ end
+ elseif tabletype == 5 then
+ local size = readulong(f)
+ local done = baseoffset
+ metrics = getbigmetrics(f)
+ local n = readulong(f)
+ for i=1,n do
+ offsets[readushort(f)] = done
+ done = done + size
+ end
+ if math.odd(n) then
+ skipbytes(f,2)
+ end
+ else
+ return -- unsupported format
+ end
+ subtable.offsets = offsets
+ subtable.metrics = metrics
+ end
+
+ -- we only support a few sensible types ... there are hardly any fonts so
+ -- why are there so many variants ... not the best spec
+
+ local default = { width = 0, height = 0 }
+ local glyphs = fontdata.glyphs
+ -- local delayed = CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 or fonts.handlers.typethree
+
+ for index, subtable in sortedhash(shapes) do
+ if type(subtable) == "table" then
+ local data = nil
+ local size = nil
+ local metrics = default
+ local format = subtable.format
+ local offset = subtable.offsets[index]
+ setposition(f,offset)
+ if format == 17 then
+ metrics = getsmallmetrics(f)
+ size = true
+ elseif format == 18 then
+ metrics = getbigmetrics(f)
+ size = true
+ elseif format == 19 then
+ metrics = subtable.metrics
+ size = true
+ else
+ -- forget about it
+ end
+ if size then
+ size = readulong(f)
+ -- if delayed then
+ offset = getposition(f)
+ data = nil
+ -- else
+ -- offset = nil
+ -- data = readstring(f,size)
+ -- size = nil
+ -- end
+ else
+ offset = nil
+ end
+ local x = metrics.width
+ local y = metrics.height
+ shapes[index] = {
+ x = x,
+ y = y,
+ o = offset,
+ s = size,
+ data = data,
+ }
+ -- I'll look into this in more details when needed
+ -- as we can use the bearings to get better boxes.
+ local glyph = glyphs[index]
+ if not glyph.boundingbox then
+ local width = glyph.width
+ local height = width * y/x
+ glyph.boundingbox = { 0, 0, width, height }
+ end
+ else
+ shapes[index] = {
+ x = 0,
+ y = 0,
+ data = "", -- or just nil
+ }
+ end
+ end
+
+ fontdata.pngshapes = shapes -- we cheat
+ end
+ end
+
+ function readers.cbdt(f,fontdata,specification)
+ -- local tableoffset = gotodatatable(f,fontdata,"ctdt",specification.glyphs)
+ -- if tableoffset then
+ -- local majorversion = readushort(f)
+ -- local minorversion = readushort(f)
+ -- end
+ end
+
+ -- function readers.ebdt(f,fontdata,specification)
+ -- if specification.glyphs then
+ -- end
+ -- end
+
+ -- function readers.ebsc(f,fontdata,specification)
+ -- if specification.glyphs then
+ -- end
+ -- end
+
+ -- function readers.eblc(f,fontdata,specification)
+ -- if specification.glyphs then
+ -- end
+ -- end
+
+end
+
+-- + AVAR : optional
+-- + CFF2 : otf outlines
+-- - CVAR : ttf hinting, not needed
+-- + FVAR : the variations
+-- + GVAR : ttf outline changes
+-- + HVAR : horizontal changes
+-- + MVAR : metric changes
+-- + STAT : relations within fonts
+-- * VVAR : vertical changes
+--
+-- * BASE : extra baseline adjustments
+-- - GASP : not needed
+-- + GDEF : not needed (carets)
+-- + GPOS : adapted device tables (needed?)
+-- + GSUB : new table
+-- + NAME : 25 added
+
+function readers.stat(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"stat",true) -- specification.variable
+ if tableoffset then
+ local extras = fontdata.extras
+ local version = readulong(f) -- 0x00010000
+ local axissize = readushort(f)
+ local nofaxis = readushort(f)
+ local axisoffset = readulong(f)
+ local nofvalues = readushort(f)
+ local valuesoffset = readulong(f)
+ local fallbackname = extras[readushort(f)] -- beta fonts mess up
+ local axis = { }
+ local values = { }
+ setposition(f,tableoffset+axisoffset)
+ for i=1,nofaxis do
+ local tag = readtag(f)
+ axis[i] = {
+ tag = tag,
+ name = lower(extras[readushort(f)] or tag),
+ ordering = readushort(f), -- maybe gaps
+ variants = { }
+ }
+ end
+ -- flags:
+ --
+ -- 0x0001 : OlderSiblingFontAttribute
+ -- 0x0002 : ElidableAxisValueName
+ -- 0xFFFC : reservedFlags
+ --
+ setposition(f,tableoffset+valuesoffset)
+ for i=1,nofvalues do
+ values[i] = readushort(f)
+ end
+ for i=1,nofvalues do
+ setposition(f,tableoffset + valuesoffset + values[i])
+ local format = readushort(f)
+ local index = readushort(f) + 1
+ local flags = readushort(f)
+ local name = lower(extras[readushort(f)] or "no name")
+ local value = readfixed(f)
+ local variant
+ if format == 1 then
+ variant = {
+ flags = flags,
+ name = name,
+ value = value,
+ }
+ elseif format == 2 then
+ variant = {
+ flags = flags,
+ name = name,
+ value = value,
+ minimum = readfixed(f),
+ maximum = readfixed(f),
+ }
+ elseif format == 3 then
+ variant = {
+ flags = flags,
+ name = name,
+ value = value,
+ link = readfixed(f),
+ }
+ end
+ insert(axis[index].variants,variant)
+ end
+ sort(axis,function(a,b)
+ return a.ordering < b.ordering
+ end)
+ for i=1,#axis do
+ local a = axis[i]
+ sort(a.variants,function(a,b)
+ return a.name < b.name
+ end)
+ a.ordering = nil
+ end
+ setvariabledata(fontdata,"designaxis",axis)
+ setvariabledata(fontdata,"fallbackname",fallbackname)
+ end
+end
+
+-- The avar table is optional and used in combination with fvar. Given the
+-- detailed explanation about bad values we expect the worst and do some
+-- checking.
+
+function readers.avar(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"avar",true) -- specification.variable
+ if tableoffset then
+
+ local function collect()
+ local nofvalues = readushort(f)
+ local values = { }
+ local lastfrom = false
+ local lastto = false
+ for i=1,nofvalues do
+ local from = read2dot14(f)
+ local to = read2dot14(f)
+ if lastfrom and from <= lastfrom then
+ -- ignore
+ elseif lastto and to >= lastto then
+ -- ignore
+ else
+ values[#values+1] = { from, to }
+ lastfrom, lastto = from, to
+ end
+ end
+ nofvalues = #values
+ if nofvalues > 2 then
+ local some = values[1]
+ if some[1] == -1 and some[2] == -1 then
+ some = values[nofvalues]
+ if some[1] == 1 and some[2] == 1 then
+ for i=2,nofvalues-1 do
+ some = values[i]
+ if some[1] == 0 and some[2] == 0 then
+ return values
+ end
+ end
+ end
+ end
+ end
+ return false
+ end
+
+ local version = readulong(f) -- 0x00010000
+ local reserved = readushort(f)
+ local nofaxis = readushort(f)
+ local segments = { }
+ for i=1,nofaxis do
+ segments[i] = collect()
+ end
+ setvariabledata(fontdata,"segments",segments)
+ end
+end
+
+function readers.fvar(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"fvar",true) -- specification.variable or specification.instancenames
+ if tableoffset then
+ local version = readulong(f) -- 0x00010000
+ local offsettoaxis = tableoffset + readushort(f)
+ local reserved = skipshort(f)
+ -- pair 1
+ local nofaxis = readushort(f)
+ local sizeofaxis = readushort(f)
+ -- pair 2
+ local nofinstances = readushort(f)
+ local sizeofinstances = readushort(f)
+ --
+ local extras = fontdata.extras
+ local axis = { }
+ local instances = { }
+ --
+ setposition(f,offsettoaxis)
+ --
+ for i=1,nofaxis do
+ axis[i] = {
+ tag = readtag(f), -- ital opsz slnt wdth wght
+ minimum = readfixed(f),
+ default = readfixed(f),
+ maximum = readfixed(f),
+ flags = readushort(f),
+ name = lower(extras[readushort(f)] or "bad name"),
+ }
+ local n = sizeofaxis - 20
+ if n > 0 then
+ skipbytes(f,n)
+ elseif n < 0 then
+ -- error
+ end
+ end
+ --
+ local nofbytes = 2 + 2 + 2 + nofaxis * 4
+ local readpsname = nofbytes <= sizeofinstances
+ local skippable = sizeofinstances - nofbytes
+ for i=1,nofinstances do
+ local subfamid = readushort(f)
+ local flags = readushort(f) -- 0, not used yet
+ local values = { }
+ for i=1,nofaxis do
+ values[i] = {
+ axis = axis[i].tag,
+ value = readfixed(f),
+ }
+ end
+ local psnameid = readpsname and readushort(f) or 0xFFFF
+ if subfamid == 2 or subfamid == 17 then
+ -- okay
+ elseif subfamid == 0xFFFF then
+ subfamid = nil
+ elseif subfamid <= 256 or subfamid >= 32768 then
+ subfamid = nil -- actually an error
+ end
+ if psnameid == 6 then
+ -- okay
+ elseif psnameid == 0xFFFF then
+ psnameid = nil
+ elseif psnameid <= 256 or psnameid >= 32768 then
+ psnameid = nil -- actually an error
+ end
+ instances[i] = {
+ -- flags = flags,
+ subfamily = extras[subfamid],
+ psname = psnameid and extras[psnameid] or nil,
+ values = values,
+ }
+ if skippable > 0 then
+ skipbytes(f,skippable)
+ end
+ end
+ setvariabledata(fontdata,"axis",axis)
+ setvariabledata(fontdata,"instances",instances)
+ end
+end
+
+function readers.hvar(f,fontdata,specification)
+ local factors = specification.factors
+ if not factors then
+ return
+ 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) -- 0x00010000
+ local variationoffset = tableoffset + readulong(f) -- the store
+ local advanceoffset = tableoffset + readulong(f)
+ local lsboffset = tableoffset + readulong(f)
+ local rsboffset = tableoffset + readulong(f)
+
+ local regions = { }
+ local variations = { }
+ local innerindex = { } -- size is mapcount
+ local outerindex = { } -- size is mapcount
+ local deltas = { }
+
+ if variationoffset > 0 then
+ regions, deltas = readvariationdata(f,variationoffset,factors)
+ end
+ if not regions then
+ -- for now .. what to do ?
+ return
+ end
+
+ if advanceoffset > 0 then
+ --
+ -- innerIndexBitCountMask = 0x000F
+ -- mapEntrySizeMask = 0x0030
+ -- reservedFlags = 0xFFC0
+ --
+ -- outerIndex = entry >> ((entryFormat & innerIndexBitCountMask) + 1)
+ -- innerIndex = entry & ((1 << ((entryFormat & innerIndexBitCountMask) + 1)) - 1)
+ --
+ setposition(f,advanceoffset)
+ local format = readushort(f) -- todo: check
+ local mapcount = readushort(f)
+ local entrysize = rshift(band(format,0x0030),4) + 1
+ local nofinnerbits = band(format,0x000F) + 1 -- n of inner bits
+ local innermask = lshift(1,nofinnerbits) - 1
+ local readcardinal = read_cardinal[entrysize] -- 1 upto 4 bytes
+ for i=0,mapcount-1 do
+ local mapdata = readcardinal(f)
+ outerindex[i] = rshift(mapdata,nofinnerbits)
+ innerindex[i] = band(mapdata,innermask)
+ end
+ -- use last entry when no match i
+ setvariabledata(fontdata,"hvarwidths",true)
+ local glyphs = fontdata.glyphs
+ for i=0,fontdata.nofglyphs-1 do
+ local glyph = glyphs[i]
+ local width = glyph.width
+ if width then
+ local outer = outerindex[i] or 0
+ local inner = innerindex[i] or i
+ if outer and inner then -- not needed
+ local delta = deltas[outer+1]
+ if delta then
+ local d = delta.deltas[inner+1]
+ if d then
+ local scales = delta.scales
+ local deltaw = 0
+ for i=1,#scales do
+ local di = d[i]
+ if di then
+ deltaw = deltaw + scales[i] * di
+ else
+ break -- can't happen
+ end
+ end
+-- report("index: %i, outer: %i, inner: %i, deltas: %|t, scales: %|t, width: %i, delta %i",
+-- i,outer,inner,d,scales,width,round(deltaw))
+ glyph.width = width + round(deltaw)
+ end
+ end
+ end
+ end
+ end
+
+ end
+
+ -- if lsboffset > 0 then
+ -- -- we don't use left side bearings
+ -- end
+
+ -- if rsboffset > 0 then
+ -- -- we don't use right side bearings
+ -- end
+
+ -- setvariabledata(fontdata,"hregions",regions)
+
+end
+
+function readers.vvar(f,fontdata,specification)
+ if not specification.variable then
+ return
+ end
+end
+
+function readers.mvar(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"mvar",specification.variable)
+ if tableoffset then
+ local version = readulong(f) -- 0x00010000
+ local reserved = skipshort(f,1)
+ local recordsize = readushort(f)
+ local nofrecords = readushort(f)
+ local offsettostore = tableoffset + readushort(f)
+ local dimensions = { }
+ local factors = specification.factors
+ if factors then
+ local regions, deltas = readvariationdata(f,offsettostore,factors)
+ for i=1,nofrecords do
+ local tag = readtag(f)
+ local var = variabletags[tag]
+ if var then
+ local outer = readushort(f)
+ local inner = readushort(f)
+ local delta = deltas[outer+1]
+ if delta then
+ local d = delta.deltas[inner+1]
+ if d then
+ local scales = delta.scales
+ local dd = 0
+ for i=1,#scales do
+ dd = dd + scales[i] * d[i]
+ end
+ var(fontdata,round(dd))
+ end
+ end
+ else
+ skipshort(f,2)
+ end
+ if recordsize > 8 then -- 4 + 2 + 2
+ skipbytes(recordsize-8)
+ end
+ end
+ end
+ -- setvariabledata(fontdata,"mregions",regions)
+ end
+end
diff --git a/tex/context/base/mkxl/font-imp-text.lmt b/tex/context/base/mkxl/font-imp-text.lmt
index 3ca05eb04..16edb2ef4 100644
--- a/tex/context/base/mkxl/font-imp-text.lmt
+++ b/tex/context/base/mkxl/font-imp-text.lmt
@@ -13,7 +13,7 @@ local registerotffeature = fonts.handlers.otf.features.register
local function initialize(tfmdata,value)
if type(value) == "string" then
- tfmdata.properties.textcontrol = tex.stringtocodesbitmap(value,tex.textcontrolcodes)
+ tfmdata.properties.textcontrol = (tfmdata.properties.textcontrol or 0) | tex.stringtocodesbitmap(value,tex.textcontrolcodes)
end
end
diff --git a/tex/context/base/mkxl/font-lib.mklx b/tex/context/base/mkxl/font-lib.mklx
index bb0eec7e6..d3a18f8b5 100644
--- a/tex/context/base/mkxl/font-lib.mklx
+++ b/tex/context/base/mkxl/font-lib.mklx
@@ -43,7 +43,7 @@
\registerctxluafile{font-web}{} % opentype fontloader
\registerctxluafile{font-cff}{optimize} % quadratic outlines
\registerctxluafile{font-ttf}{optimize} % cubic outlines
-\registerctxluafile{font-dsp}{optimize} % ... for this one
+\registerctxluafile{font-dsp}{autosuffix,optimize}
\registerctxluafile{font-hsh}{autosuffix} % hashes used by context
\registerctxluafile{font-vir}{}
\registerctxluafile{font-vfc}{autosuffix}
diff --git a/tex/context/base/mkxl/lang-mis.mkxl b/tex/context/base/mkxl/lang-mis.mkxl
index 48c2fa1cd..374379a0b 100644
--- a/tex/context/base/mkxl/lang-mis.mkxl
+++ b/tex/context/base/mkxl/lang-mis.mkxl
@@ -119,27 +119,10 @@
%D \installdiscretionary | -
%D \stoptyping
%D
-%D Some alternative definitions are:
-%D
-%D \startbuffer
-%D \installdiscretionary * -
-%D \installdiscretionary + -
-%D \installdiscretionary / -
-%D \installdiscretionary ~ -
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D after which we can say:
-%D
-%D \start \getbuffer
-%D \starttest
-%D \test {test**test**test}
-%D \test {test++test++test}
-%D \test {test//test//test}
-%D \test {test~~test~~test}
-%D \stoptest
-%D \stop
+%D We used to have an installable mechanism but in the perspective of \MKIV\ and
+%D especialy \LMTX\ it no longer makes sense to complicate the code, so from now on
+%D we only deal with the active bar. Older code can be seen in the archives. It also
+%D means that we now just hardcode the bar. We also deal with math differently.
%D \macros
%D {compoundhyphen}
@@ -163,7 +146,6 @@
\ifdefined\postwordbreak\else \permanent\protected\def\postwordbreak {\penalty\zerocount \hskip\zeropoint\relax} \fi
\ifdefined\hspaceamount \else \def\hspaceamount#1#2{.16667\emwidth} \fi % will be overloaded
-%frozen\protected\def\permithyphenation{\ifhmode\prewordbreak\fi} % doesn't remove spaces
\permanent\protected\def\permithyphenation{\ifhmode\wordboundary\fi} % doesn't remove spaces
%D \macros
@@ -173,7 +155,7 @@
%D In the previous macros we provided two hooks which can be used to support nested
%D sub||sentences. In \CONTEXT\ these hooks are used to insert a small space when
%D needed.
-
+%D
%D The following piece of code is a torture test compound handling. The \type
%D {\relax} before the \type {\ifmmode} is needed because of the alignment scanner
%D (in \ETEX\ this problem is not present because there a protected macro is not
@@ -186,22 +168,10 @@
%D \stopformula
\installcorenamespace{discretionaryaction}
-\installcorenamespace{discretionarytext}
-\installcorenamespace{discretionarymath}
-\installcorenamespace{discretionaryboth}
\installcorenamespace{discretionarymode}
-\permanent\protected\def\installdiscretionary#1#2%
- {\edefcsname\??discretionarymath\detokenize{#1}\endcsname{\detokenize{#1}}% ?
- \defcsname \??discretionarytext\detokenize{#1}\endcsname{#2}%
- \defcsname \??discretionaryboth\detokenize{#1}\endcsname{\lang_discretionaries_command#1}%
- \scratchcounter\expandafter`\detokenize{#1}%
- \expandafter\uedcatcodecommand\expandafter\ctxcatcodes\expandafter\scratchcounter\csname\??discretionaryboth\detokenize{#1}\endcsname}
-
-\permanent\protected\def\handlemathmodediscretionary#1{\ifcsname\??discretionarymath\detokenize{#1}\endcsname\lastnamedcs}
-\permanent\protected\def\handletextmodediscretionary#1{\ifcsname\??discretionarytext\detokenize{#1}\endcsname\lastnamedcs}
-
-\permanent\protected\def\installdiscretionaries#1#2{\writestatus\m!system{use \string \installdiscretionary}} % obsolete
+\aliased\let\installdiscretionaries\gobbletwoarguments % this alias will go
+\aliased\let\installdiscretionary \gobbletwoarguments % this alias will go
\setnewconstant\discretionarymode\plusone
@@ -209,22 +179,21 @@
\permanent\protected\def\obeydiscretionaries {\discretionarymode\plusone}
\def\lang_discretionaries_command
- {% if direct if, we need \relax for lookahead in math mode
- \csname\??discretionarymode
+ {\begincsname\??discretionarymode
\ifcase\discretionarymode
n%
- \orelse\ifmmode
- m%
\else
t%
\fi
\endcsname}
-\defcsname\??discretionarymode n\endcsname#1%
- {\detokenize{#1}}
+% \catcode\barasciicode\activecatcode
+% \amcode \barasciicode\othercatcode
+
+\letcatcodecommand\ctxcatcodes\barasciicode\lang_discretionaries_command
-%D The macro \type{\lang_discretionaries_check_before} takes care of loners like
-%D \type{||word}, while it counterpart \type {\lang_discretionaries_check_after} is
+%D The macro \type {\lang_discretionaries_check_before} takes care of loners like
+%D \type {||word}, while it counterpart \type {\lang_discretionaries_check_after} is
%D responsible for handling the comma.
\newconditional\punctafterdiscretionary
@@ -257,73 +226,58 @@
\ifx :\nexttoken \settrue \punctafterdiscretionary \orelse
\ifx ;\nexttoken \settrue \punctafterdiscretionary \fi}
-\letcsname\??discretionarymode m\endcsname\handlemathmodediscretionary
+\edefcsname\??discretionarymode n\endcsname
+ {\detokenize{|}}
-\defcsname\??discretionarymode t\endcsname#1%
+\defcsname\??discretionarymode t\endcsname#1|%
{\bgroup
- \let\nextnextnext\egroup
- \def\next##1#1%
- {\def\next{\activedododotextmodediscretionary#1{##1}}%
- \futurelet\nexttoken\next}%
- \next}
-
-\let\lang_discretionaries_token \relax
-\let\lang_discretionaries_action\relax
+ \def\next{\lang_discretionaries_handle{#1}}%
+ \futurelet\nexttoken\next}%
-\permanent\protected\def\activedododotextmodediscretionary#1#2%
- {\edef\lang_discretionaries_token{\detokenize{#2}}%
- \def\lang_discretionaries_action{\handletextmodediscretionary{#1}}%
+\permanent\protected\def\lang_discretionaries_handle#1%
+ {\edef\lang_discretionaries_token{\detokenize{#1}}%
\lang_discretionaries_check_after
\ifempty\lang_discretionaries_token
- \ifx#1\nexttoken % takes care of ||| and +++ and ......
- \ifcsname\??discretionaryaction\string#1\endcsname
+ \ifx|\nexttoken % takes care of |||
+ \ifcsname\??discretionaryaction\string|\endcsname
\lastnamedcs
\orelse\ifconditional\spaceafterdiscretionary
- %\prewordbreak\hbox{\string#1}\relax
- \wordboundary\hbox{\string#1}\relax
+ \wordboundary\hbox{\letterbar}\relax
\orelse\ifconditional\punctafterdiscretionary
- %\prewordbreak\hbox{\string#1}\relax
- \wordboundary\hbox{\string#1}\wordboundary
+ \wordboundary\hbox{\letterbar}\wordboundary
\else
- %\prewordbreak\hbox{\string#1}\prewordbreak
- \wordboundary\hbox{\string#1}\wordboundary
+ \wordboundary\hbox{\letterbar}\wordboundary
\fi
- \def\nextnextnext{\afterassignment\egroup\let\next=}%
+ \def\next{\afterassignment\egroup\let\next=}%
\else
\lang_discretionaries_check_before
- % the next line has been changed (20050203)
- % \prewordbreak\hbox{\lang_discretionaries_action\nexttoken}\postwordbreak
- % but an hbox blocks a possible \discretionary
\ifcsname\??discretionaryaction\endcsname
\lastnamedcs
\orelse\ifconditional\spaceafterdiscretionary
- %\prewordbreak\lang_discretionaries_action\relax
- \wordboundary\lang_discretionaries_action\relax
+ \wordboundary\defaultdiscretionaryhyphen\relax
\orelse\ifconditional\punctafterdiscretionary
- %\prewordbreak\lang_discretionaries_action\relax
- \wordboundary\lang_discretionaries_action\relax
+ \wordboundary\defaultdiscretionaryhyphen\relax
\else
- %\prewordbreak\lang_discretionaries_action\prewordbreak
- \wordboundary\lang_discretionaries_action\wordboundary
+ \wordboundary\defaultdiscretionaryhyphen\wordboundary
\fi
+ \let\next\egroup
\fi
\orelse\ifcsname\??discretionaryaction\lang_discretionaries_token\endcsname
\lastnamedcs
+ \let\next\egroup
\else
\lang_discretionaries_check_before
\ifconditional\spaceafterdiscretionary
- %\prewordbreak\hbox{#2}\relax
- \wordboundary\hbox{#2}\relax
+ \wordboundary\hbox{#1}\relax
\orelse\ifconditional\punctafterdiscretionary
- %\prewordbreak\hbox{#2}\relax
- \wordboundary\hbox{#2}\relax
+ \wordboundary\hbox{#1}\relax
\else
- %\prewordbreak\discretionary{\hbox{#2}}{}{\hbox{#2}}\postwordbreak
- \wordboundary\discretionary{\hbox{#2}}{}{\hbox{#2}}\wordboundary
- %\discretionary options \plusthree{\hbox{#2}}{}{\hbox{#2}}%
+ \wordboundary\discretionary{\hbox{#1}}{}{\hbox{#1}}\wordboundary
+ %\discretionary options \plusthree{\hbox{#1}}{}{\hbox{#1}}%
\fi
+ \let\next\egroup
\fi
- \nextnextnext}
+ \next}
%D \macros
%D {directdiscretionary}
@@ -332,7 +286,7 @@
%D use the more direct approach:
\permanent\protected\def\directdiscretionary
- {\csname\??discretionarymode
+ {\begincsname\??discretionarymode
\ifcase\discretionarymode
n%
\else
@@ -341,7 +295,7 @@
\endcsname}
\permanent\protected\def\indirectdiscretionary
- {\csname\??discretionarymode
+ {\begincsname\??discretionarymode
\ifcase\discretionarymode
n%
\else
@@ -350,16 +304,13 @@
\endcsname}
\protected\defcsname\??discretionarymode d\endcsname#1%
- {\edef\lang_discretionaries_token{\detokenize{#1}}%
- \let\lang_discretionaries_action\compoundhyphen
- \ifcsname\??discretionaryaction\lang_discretionaries_token\endcsname
+ {\ifcsname\??discretionaryaction\detokenize{#1}\endcsname
\expandafter\lastnamedcs
\else
\expandafter\indirectdiscretionary
\fi{#1}}
\protected\defcsname\??discretionarymode i\endcsname#1%
- %{\prewordbreak\discretionary{\hbox{#1}}{}{\hbox{#1}}\postwordbreak}
{\wordboundary\discretionary{\hbox{#1}}{}{\hbox{#1}}\wordboundary}
%{\discretionary options \plusthree{\hbox{#1}}{}{\hbox{#1}}}
@@ -385,13 +336,10 @@
\def\lang_discretionaries_hyphen_like#1#2%
{\ifconditional\spaceafterdiscretionary
- %prewordbreak\hbox{#1}\relax
\wordboundary\hbox{#1}\relax
\orelse\ifconditional\punctafterdiscretionary
- %prewordbreak\hbox{#1}\relax
\wordboundary\hbox{#1}\relax
\else
- %\prewordbreak#2\postwordbreak % was prewordbreak
\wordboundary#2\wordboundary
\fi}
@@ -409,78 +357,55 @@
\definetextmodediscretionary (
{\ifdim\lastskip>\zeropoint
- %(\prewordbreak
(\wordboundary
\else
- %\prewordbreak\discretionary{}{(-}{(}\prewordbreak
\wordboundary\discretionary{}{(-}{(}\wordboundary
%\discretionary options \plusthree{}{(-}{(}%
\fi}
\definetextmodediscretionary ~
- %{\prewordbreak\discretionary{-}{}{\thinspace}\postwordbreak}
{\wordboundary\discretionary{-}{}{\thinspace}\wordboundary}
%{\discretionary options \plusthree{-}{}{\thinspace}}
\definetextmodediscretionary '
- %{\prewordbreak\discretionary{-}{}{'}\postwordbreak}
{\wordboundary\discretionary{-}{}{'}\wordboundary}
%{\discretionary options \plusthree{-}{}{'}}
\definetextmodediscretionary ^
- %{\prewordbreak\discretionary{\hbox{\normalstartimath|\normalstopimath}}{}{\hbox{\normalstartimath|\normalstopimath}}%
- % \postwordbreak} % bugged
{\wordboundary
\discretionary{\hbox{\normalstartimath|\normalstopimath}}{}{\hbox{\normalstartimath|\normalstopimath}}%
\wordboundary} % bugged
%{\discretionary options \plusthree{\hbox{\normalstartimath|\normalstopimath}}{}{\hbox{\normalstartimath|\normalstopimath}}}
\definetextmodediscretionary <
- %{\beginofsubsentence\prewordbreak\beginofsubsentencespacing
{\beginofsubsentence\wordboundary\beginofsubsentencespacing
\aftergroup\ignorespaces} % tricky, we need to go over the \nextnextnext
\definetextmodediscretionary >
{\removeunwantedspaces
- %\endofsubsentencespacing\prewordbreak\endofsubsentence}
\endofsubsentencespacing\wordboundary\endofsubsentence}
\definetextmodediscretionary =
{\removeunwantedspaces
- %\prewordbreak\midsentence\prewordbreak
\wordboundary\midsentence\wordboundary
\aftergroup\ignorespaces}
% french
-%definetextmodediscretionary : {\removeunwantedspaces\prewordbreak\kern\hspaceamount\empty{:}:}
-%definetextmodediscretionary ; {\removeunwantedspaces\prewordbreak\kern\hspaceamount\empty{;};}
-%definetextmodediscretionary ? {\removeunwantedspaces\prewordbreak\kern\hspaceamount\empty{?}?}
-%definetextmodediscretionary ! {\removeunwantedspaces\prewordbreak\kern\hspaceamount\empty{!}!}
-
\definetextmodediscretionary : {\removeunwantedspaces\wordboundary\kern\hspaceamount\empty{:}:}
\definetextmodediscretionary ; {\removeunwantedspaces\wordboundary\kern\hspaceamount\empty{;};}
\definetextmodediscretionary ? {\removeunwantedspaces\wordboundary\kern\hspaceamount\empty{?}?}
\definetextmodediscretionary ! {\removeunwantedspaces\wordboundary\kern\hspaceamount\empty{!}!}
-%definetextmodediscretionary * {\prewordbreak\discretionary{-}{}{\kern.05\emwidth}\prewordbreak}
\definetextmodediscretionary * {\wordboundary\discretionary{-}{}{\kern.05\emwidth}\wordboundary}
% spanish
-%definetextmodediscretionary ?? {\prewordbreak\questiondown}
-%definetextmodediscretionary !! {\prewordbreak\exclamdown}
-
\definetextmodediscretionary ?? {\wordboundary\questiondown}
\definetextmodediscretionary !! {\wordboundary\exclamdown}
-%D \installdiscretionary | +
-%D \installdiscretionary + =
-
\permanent\protected\def\defaultdiscretionaryhyphen{\compoundhyphen}
-\installdiscretionary | \defaultdiscretionaryhyphen % installs in ctx and prt will fall back on it
-
%D \macros
%D {fakecompoundhyphen}
%D
@@ -547,9 +472,9 @@
%D so test\compound{}test can be used instead of test||test
%D \stoptyping
-\bgroup
-
- \catcode\barasciicode\activecatcode
+% \bgroup
+%
+% \catcode\barasciicode\activecatcode
\permanent\protected\gdef\compound#1{|#1|}
@@ -557,7 +482,7 @@
\enforced\permanent\protected\def|#1|{\ifx#1\empty\empty-\else#1\fi}%
\to \everysimplifycommands
-\egroup
+% \egroup
%D Here we hook some code into the clean up mechanism needed for verbatim data.
@@ -581,4 +506,6 @@
{\ifnum\posthyphenchar>\zerocount\char\posthyphenchar\fi}%
{\ifnum\posthyphenchar>\zerocount\char\posthyphenchar\fi}}
+% \setcatcodetable\prtcatcodes % because we activated the bar
+
\protect \endinput
diff --git a/tex/context/base/mkxl/lang-tra.mkxl b/tex/context/base/mkxl/lang-tra.mkxl
index a44ee4ba9..66a020a14 100644
--- a/tex/context/base/mkxl/lang-tra.mkxl
+++ b/tex/context/base/mkxl/lang-tra.mkxl
@@ -27,8 +27,10 @@
\appendtoks
\disablediscretionaries
- \let~=\lettertilde
+ % \let~=\lettertilde
+ \enforced\letcharcode\tildeasciicode\lettertilde
% \let|=\letterbar
+ % \enforced\letcharcode\barasciicode\letterbar
\to \everytransliterations
\def\lang_transliteration_common
diff --git a/tex/context/base/mkxl/lang-url.mkxl b/tex/context/base/mkxl/lang-url.mkxl
index 6e38c95a1..87e64feaf 100644
--- a/tex/context/base/mkxl/lang-url.mkxl
+++ b/tex/context/base/mkxl/lang-url.mkxl
@@ -57,8 +57,10 @@
\enforced\let\{\letterleftbrace
\enforced\let\}\letterrightbrace
\enforced\let\|\letterbar
- \enforced\let~=\lettertilde
- \enforced\let|=\letterbar
+ % \enforced\let~=\lettertilde
+ % \enforced\let|=\letterbar
+ \enforced\letcharcode\tildeasciicode\lettertilde
+ \enforced\letcharcode\barasciicode \letterbar
\enforced\let\Ux\eUx
\to \everyhyphenatedurl
diff --git a/tex/context/base/mkxl/math-act.lmt b/tex/context/base/mkxl/math-act.lmt
index 2df708806..d4abed0ba 100644
--- a/tex/context/base/mkxl/math-act.lmt
+++ b/tex/context/base/mkxl/math-act.lmt
@@ -84,13 +84,13 @@ function mathematics.initializeparameters(target,original)
mathparameters = mathematics.dimensions(mathparameters)
--
-- if not mathparameters.MinConnectorOverlap then mathparameters.MinConnectorOverlap = undefined end
- -- if not mathparameters.SubscriptShiftDownWithSuperscript then mathparameters.SubscriptShiftDownWithSuperscript = undefined end -- a tex one
+ if not mathparameters.SubscriptShiftDownWithSuperscript then mathparameters.SubscriptShiftDownWithSuperscript = mathparameters.SubscriptShiftDown * 1.5 end
-- if not mathparameters.FractionDelimiterSize then mathparameters.FractionDelimiterSize = undefined end
-- if not mathparameters.FractionDelimiterDisplayStyleSize then mathparameters.FractionDelimiterDisplayStyleSize = undefined end
-- if not mathparameters.SkewedDelimiterTolerance then mathparameters.SkewedDelimiterTolerance = undefined end
-- some more can be undefined:
- if not mathparameters.PrimeRaisePercent then mathparameters.PrimeRaisePercent = 50 end
- if not mathparameters.PrimeRaiseComposedPercent then mathparameters.PrimeRaiseComposedPercent = 25 end
+ if not mathparameters.PrimeRaisePercent then mathparameters.PrimeRaisePercent = 0 end
+ if not mathparameters.PrimeRaiseComposedPercent then mathparameters.PrimeRaiseComposedPercent = 0 end
if not mathparameters.PrimeShiftUp then mathparameters.PrimeShiftUp = mathparameters.SuperscriptShiftUp end
if not mathparameters.PrimeBaselineDropMax then mathparameters.PrimeBaselineDropMax = mathparameters.SuperscriptBaselineDropMax end
if not mathparameters.PrimeShiftUpCramped then mathparameters.PrimeShiftUpCramped = mathparameters.SuperscriptShiftUpCramped end
@@ -216,15 +216,15 @@ function mathematics.overloadparameters(target,original)
local tvalue = type(value)
if tvalue == "string" then
local newvalue = mathparameters[value]
- -- if not newvalue then
- -- local code = loadstring("return " .. value,"","t",mathparameters)
- -- if type(code) == "function" then
- -- local okay, v = pcall(code)
- -- if okay then
- -- newvalue = v
- -- end
- -- end
- -- end
+ if not newvalue then
+ local code = loadstring("return " .. value,"","t",mathparameters)
+ if type(code) == "function" then
+ local okay, v = pcall(code)
+ if okay then
+ newvalue = v
+ end
+ end
+ end
if newvalue then
-- split in number and string
mathparameters[name] = newvalue
@@ -421,6 +421,84 @@ local detail do
end
+-- This temporary tweak was used when we (MS & HH) were fixing the Latin Modern
+-- parameters that relate to script placement. We started from the original cmr
+-- ratios combined with the formal specification and ended up with the following
+-- values. In the end we rejected this tweak and setteled for checking and fixing:
+--
+-- SubscriptShiftDown
+-- SubscriptShiftDownWithSuperscript
+-- SuperscriptShiftUp
+-- SuperscriptShiftUpCramped
+--
+-- because it looks a bit arbitrary what values are set. We keep the code below
+-- as documentation.
+
+-- do
+-- -- modern
+-- --
+-- -- local factors = {
+-- -- scripts = {
+-- -- SubscriptBaselineDropMin = 0.116,
+-- -- SubscriptShiftDown = 0.348,
+-- -- SubscriptShiftDownWithSuperscript = 0.573,
+-- -- SubscriptTopMax = 0.800,
+-- -- SuperscriptBaselineDropMax = 0.896,
+-- -- SuperscriptBottomMaxWithSubscript = 0.800,
+-- -- SuperscriptBottomMin = 0.250,
+-- -- SuperscriptShiftUp = 0.958,
+-- -- SuperscriptShiftUpCramped = 0.958,
+-- -- }
+-- -- }
+--
+-- -- -- cambria
+-- --
+-- -- local factors = {
+-- -- scripts = {
+-- -- SubscriptBaselineDropMin = 0.279,
+-- -- SubscriptShiftDown = 0.364,
+-- -- SubscriptShiftDownWithSuperscript = 0.547,
+-- -- SubscriptTopMax = 0.662,
+-- -- SuperscriptBaselineDropMax = 0.401,
+-- -- SuperscriptBottomMaxWithSubscript = 0.667,
+-- -- SuperscriptBottomMin = 0.208,
+-- -- SuperscriptShiftUp = 0.654,
+-- -- SuperscriptShiftUpCramped = 0.654,
+-- -- }
+-- -- }
+--
+-- -- after some tests and inspection
+-- --
+--
+-- local factors = {
+-- scripts = {
+-- SubscriptBaselineDropMin = 0.100, -- harmless but small (seldom triggered)
+-- SubscriptShiftDown = 0.400, -- by inspection in several files
+-- SubscriptShiftDownWithSuperscript = 0.400, -- as above
+-- SubscriptTopMax = 0.800, -- Microsoft recommendation
+-- SuperscriptBaselineDropMax = 0.100, -- see SubscriptBaselineDropMin
+-- SuperscriptBottomMaxWithSubscript = 0.800, -- Microsoft recommendation
+-- SuperscriptBottomMin = 0.250, -- Microsoft recommendation
+-- SuperscriptShiftUp = 0.650, -- by inspection, but also a bit gamble
+-- SuperscriptShiftUpCramped = 0.650, -- see above, non-TeX
+-- }
+-- }
+--
+-- datasets.fixparameters = factors
+--
+-- function mathtweaks.fixparameters(target,original,parameters)
+-- local mathparameters = target.mathparameters
+-- if mathparameters and next(mathparameters) then
+-- local xheight = target.parameters.xheight
+-- -- todo : options
+-- for k, v in next, factors.scripts do
+-- mathparameters[k] = v * xheight
+-- end
+-- end
+-- end
+--
+-- end
+
do
local stepper = utilities.parsers.stepper
@@ -819,150 +897,110 @@ end
do
- -- see changed hack in math-fbk
-
local nps = fonts.helpers.newprivateslot
local list = {
- { 0x2032, { nps("prime 0x2032 1"), nps("prime 0x2032 2"), nps("prime 0x2032 3") }, 1 },
- { 0x2033, { nps("prime 0x2033 1"), nps("prime 0x2033 2"), nps("prime 0x2033 3") }, 2 },
- { 0x2034, { nps("prime 0x2034 1"), nps("prime 0x2034 2"), nps("prime 0x2034 3") }, 3 },
- { 0x2057, { nps("prime 0x2057 1"), nps("prime 0x2057 2"), nps("prime 0x2057 3") }, 4 },
- { 0x2035, { nps("prime 0x2035 1"), nps("prime 0x2035 2"), nps("prime 0x2035 3") }, 1 },
- { 0x2036, { nps("prime 0x2036 1"), nps("prime 0x2036 2"), nps("prime 0x2036 3") }, 2 },
- { 0x2037, { nps("prime 0x2037 1"), nps("prime 0x2037 2"), nps("prime 0x2037 3") }, 3 },
+ { 0x2032, nps("delimited ghost 0x2032"), 1 },
+ { 0x2033, nps("delimited ghost 0x2033"), 2, 0x2032 },
+ { 0x2034, nps("delimited ghost 0x2034"), 3, 0x2032 },
+ { 0x2057, nps("delimited ghost 0x2057"), 4, 0x2032 },
+ { 0x2035, nps("delimited ghost 0x2035"), 1 },
+ { 0x2036, nps("delimited ghost 0x2036"), 2, 0x2035 },
+ { 0x2037, nps("delimited ghost 0x2037"), 3, 0x2035 },
}
- local function copytable(t)
- return {
- width = t.width,
- height = t.height,
- depth = t.depth,
- index = t.index,
- unicode = t.unicode,
- }
- end
-
- local lastprivate
-
- local function use(target,original,targetcharacters,charcode,private,newheight,scale,fake,keep,count,smaller)
- if count == 1 then
- lastprivate = private
- end
- if keep then
- if trace_tweaking then
- report_tweak("keeping prime %U",target,original,charcode)
- end
- return
- end
- if fake and count > 1 then
- local olddata = targetcharacters[lastprivate]
- if olddata then
- -- todo: when keep
- local oldheight = scale * olddata.height
- local oldwidth = scale * olddata.width
- local yoffset = (newheight - oldheight) / scale
- local xoffset = fake * oldwidth
- local newwidth = oldwidth + (count - 1) * xoffset
- targetcharacters[charcode] = {
- yoffset = yoffset,
- width = newwidth,
- height = newheight,
- smaller = smaller,
- unicode = olddata.unicode,
- commands = {
- { "offset", 0, 0, lastprivate, scale, scale },
- { "offset", xoffset, 0, lastprivate, scale, scale },
- count > 2 and { "offset", 2 * xoffset, 0, lastprivate, scale, scale } or nil,
- count > 3 and { "offset", 3 * xoffset, 0, lastprivate, scale, scale } or nil,
- },
- }
- if trace_tweaking then
- report_tweak("faking %U with %i primes",target,original,charcode,count)
- end
- return
- end
- end
- local olddata = targetcharacters[private]
- if olddata then
- local oldheight = scale * olddata.height
- local oldwidth = scale * olddata.width
- local yoffset = (newheight - oldheight) / scale
- targetcharacters[charcode] = {
- yoffset = yoffset,
- width = oldwidth,
- height = newheight,
- smaller = smaller,
- unicode = olddata.unicode,
- commands = {
- { "offset", 0, 0, private, scale, scale }
- },
- }
- if trace_tweaking then
- report_tweak("fixing prime %U",target,original,charcode)
- end
- return
- end
- if trace_tweaking then
- report_tweak("unable to fix prime %U",target,original,charcode)
- end
- end
+ datasets.fixprimes = list
function mathtweaks.fixprimes(target,original,parameters)
- local targetcharacters = target.characters
- local targetparameters = target.parameters
- local originalcharacters = original.characters
- local factor = parameters.factor or 0.85
- local scale = parameters.scale or 1
- local smaller = parameters.smaller
- local fake = parameters.fake
- local keep = parameters.keep and targetparameters.mathsize == 1
- local newheight = factor * target.mathparameters.AccentBaseHeight
- local compact = targetparameters.textscale and true or false
- --
- lastprivate = false
- -- make virtual copies (just all of them, also for tracing)
+ local targetcharacters = target.characters
+ local factor = parameters.factor or 1
+ local fake = tonumber(parameters.fake)
for i=1,#list do
- local entry = list[i]
- local count = entry[3]
- if not fake or count == 1 then
- local c1 = entry[1]
- local d1 = targetcharacters[c1]
- if d1 then
- local pc = entry[2]
- local c2 = d1.smaller or c1
- local d2 = targetcharacters[c2]
- local c3 = d2.smaller or c2
- local d3 = targetcharacters[c3]
- if smaller then
- d1 = d2
- d2 = d3
+ local entry = list[i]
+ local unicode = entry[1]
+ local count = entry[3]
+ local used = fonts.handlers.otf.getsubstitution(target,unicode,"ssty",true,"math","dflt") or unicode
+ local data = targetcharacters[used]
+ if data then
+ targetcharacters[unicode] = data
+ local oldheight = data.height or 0
+ local newheight = factor * oldheight
+ data.yoffset = newheight - (oldheight or 0)
+ data.height = newheight
+ data.smaller = nil
+ elseif not fake then
+ report_tweak("missing %i prime %U",target,original,count,unicode)
+ end
+ end
+ if fake then
+ for i=1,#list do
+ local entry = list[i]
+ local count = entry[3]
+ if count > 1 then
+ local unicode = entry[1]
+ local original = entry[4]
+ local data = targetcharacters[original]
+ if data then
+ local oldwidth = data.width
+ local xoffset = fake * oldwidth
+ local newwidth = oldwidth + (count - 1) * xoffset
+ targetcharacters[unicode] = {
+ width = newwidth,
+ height = data.height,
+ unicode = unicode,
+ commands = {
+ { "offset", 0, 0, original },
+ { "offset", xoffset, 0, original },
+ count > 2 and { "offset", 2 * xoffset, 0, original } or nil,
+ count > 3 and { "offset", 3 * xoffset, 0, original } or nil,
+ },
+ }
end
- targetcharacters[pc[1]] = copytable(d1)
- targetcharacters[pc[2]] = copytable(d2)
- targetcharacters[pc[3]] = copytable(d3)
end
end
end
- -- replace
+ end
+
+ function mathtweaks.addprimed(target,original,parameters)
+ local characters = target.characters
for i=1,#list do
- local entry = list[i]
- local count = entry[3]
- local c1 = entry[1]
- local pc = entry[2]
- local s1 = pc[1]
- local d1 = targetcharacters[c1]
- if compact and d1 then
- local c2 = d1.smaller or c1
- local d2 = targetcharacters[c2]
- local c3 = d2.smaller or c2
- local s2 = pc[2]
- local s3 = pc[3]
- use(target,original,targetcharacters,c1,s1,newheight,scale,fake,keep, count,c2)
- use(target,original,targetcharacters,c2,s2,newheight,scale,fake,false,count,c3)
- use(target,original,targetcharacters,c3,s3,newheight,scale,fake,false,count)
- else
- use(target,original,targetcharacters,c1,s1,newheight,scale,fake,keep,count)
+ local entry = list[i]
+ local basecode = entry[1]
+ local movecode = entry[2]
+ local basedata = characters[basecode]
+ if basedata then
+ local baseheight = basedata.height or 0
+ local basewidth = basedata.width or 0
+ local used = baseheight
+ local total = baseheight
+ characters[movecode] = { -- todo:share
+ width = basewidth,
+ height = used,
+ unicode = basecode, -- 0xFFFD or space or so
+ -- callback = "devirtualize",
+ commands = {
+ downcommand[used],
+ { "rule", used, 0 },
+ },
+ }
+ basedata.parts = {
+ {
+ advance = used,
+ ["end"] = used,
+ extender = 1,
+ glyph = movecode,
+ start = used,
+ },
+ {
+ advance = total,
+ ["end"] = 0,
+ glyph = basecode,
+ start = total,
+ },
+ }
+ if trace_tweaking then
+ report_tweak("primed %U added",target,original,basecode)
+ end
end
end
end
@@ -1384,7 +1422,7 @@ do
local half = (italic/2) * factor
c.topanchor = width + half
c.bottomanchor = width - half
- c.bottomright = - italic
+ c.bottomright = - italic * (parameters.icfactor or 1)
if trace_tweaking then
-- todo
end
@@ -2698,9 +2736,9 @@ do
local nps = fonts.helpers.newprivateslot
local list = {
- { 0x302, nps("delimited right hat" ), nps("delimited ghost hat" ) },
- { 0x303, nps("delimited right tilde"), nps("delimited ghost tilde") },
- { 0x30C, nps("delimited right check"), nps("delimited ghost check") },
+ { 0x0302, nps("delimited right hat"), nps("delimited ghost hat") },
+ { 0x0303, nps("delimited right tilde"), nps("delimited ghost tilde") },
+ { 0x030C, nps("delimited right check"), nps("delimited ghost check") },
}
function mathtweaks.addfourier(target,original,parameters)
diff --git a/tex/context/base/mkxl/math-ali.mkxl b/tex/context/base/mkxl/math-ali.mkxl
index 8a29f4f9d..a2b09a084 100644
--- a/tex/context/base/mkxl/math-ali.mkxl
+++ b/tex/context/base/mkxl/math-ali.mkxl
@@ -2728,7 +2728,8 @@
\appendtoks
\edef\p_threshold{\mathematicsparameter\c!threshold}%
\maththreshold\ifcsname\??maththreshold\p_threshold\endcsname\lastnamedcs\else\p_threshold\fi\relax
-\to \everymath % \everymathematics
+% \to \everymath % \everymathematics
+\to \everymathematics
%D Here is simple alignment mechanism:
diff --git a/tex/context/base/mkxl/math-def.mkxl b/tex/context/base/mkxl/math-def.mkxl
index 16c65cf55..be33bac86 100644
--- a/tex/context/base/mkxl/math-def.mkxl
+++ b/tex/context/base/mkxl/math-def.mkxl
@@ -24,7 +24,7 @@
\popoverloadmode
-\activatemathcharacters
+% \activatemathcharacters
%D The \mfunction macro is an alternative for \hbox with a controlable font switch.
diff --git a/tex/context/base/mkxl/math-del.mklx b/tex/context/base/mkxl/math-del.mklx
index cfb8dc5d2..0377f3507 100644
--- a/tex/context/base/mkxl/math-del.mklx
+++ b/tex/context/base/mkxl/math-del.mklx
@@ -36,6 +36,7 @@
\c!depth=\zeropoint,
\c!strut=\v!height,
\c!source=\zerocount,
+ \c!size=\zerocount,
\c!left=\zerocount,
\c!right=\zerocount,
\c!leftmargin=\zeropoint,
@@ -67,6 +68,7 @@
\s!depth \dimexpr\mathdelimitedparameter\c!depth+\mathdelimitedparameter\c!bottomoffset\relax
\s!source\numexpr\namedboxanchor{\mathdelimitedparameter\c!source}\relax
\s!style \normalmathstyle
+ \s!size \numexpr\namedboxanchor{\mathdelimitedparameter\c!size}\relax
\zerocount \mathdelimitedparameter\c!left
\zerocount \mathdelimitedparameter\c!right
\relax}
@@ -114,4 +116,12 @@
% $ \autofences \fourier{(z+\frac12)} + \courier{(z+\frac12)} + \xourier{(z+\frac12)} $
+\definemathdelimited [primed] [\c!right="2032,\c!size=1,\c!topoffset=.2\exheight]
+\definemathdelimited [doubleprimed] [primed] [\c!right="2033]
+\definemathdelimited [tripleprimed] [primed] [\c!right="2034]
+\definemathdelimited [quadrupleprimed] [primed] [\c!right="2057]
+\definemathdelimited [reverseprimed] [primed] [\c!right="2035]
+\definemathdelimited [doublereverseprimed] [primed] [\c!right="2036]
+\definemathdelimited [triplereverseprimed] [primed] [\c!right="2037]
+
\protect \endinput
diff --git a/tex/context/base/mkxl/math-dim.lmt b/tex/context/base/mkxl/math-dim.lmt
index 15eeb47b3..8f35b4bbd 100644
--- a/tex/context/base/mkxl/math-dim.lmt
+++ b/tex/context/base/mkxl/math-dim.lmt
@@ -137,7 +137,6 @@ end
function mathematics.dimensions(dimens) -- beware, dimens get spoiled
if dimens.SpaceAfterScript then
- dimens.SubscriptShiftDownWithSuperscript = dimens.SubscriptShiftDown * 1.5 -- move this one
return table.fastcopy(dimens), { }
elseif dimens.AxisHeight or dimens.axisheight then
local t = { }
diff --git a/tex/context/base/mkxl/math-fen.mkxl b/tex/context/base/mkxl/math-fen.mkxl
index d8cbf4e76..1efc6bbe6 100644
--- a/tex/context/base/mkxl/math-fen.mkxl
+++ b/tex/context/base/mkxl/math-fen.mkxl
@@ -569,10 +569,10 @@
\fi
\math_fenced_force_size\bigmathdelimitervariant\c_math_fenced_level\relax}
-\appendtoks
- \enforced\aliased\let|\letterbar
- %\enforced\aliased\let\bar\letterbar
-\to \everymathematics
+% \appendtoks
+% \enforced\aliased\let|\letterbar
+% %\enforced\aliased\let\bar\letterbar
+% \to \everymathematics
\definemathfence [parenthesis] [\c!left="0028,\c!right="0029]
\definemathfence [bracket] [\c!left="005B,\c!right="005D]
@@ -843,9 +843,9 @@
%
% \installmathfencepair ⦗ \Linterval ⦘ \Rinterval
-\appendtoks
- \ignorediscretionaries % so $\mtext{a|b}$ works, this is ok because it's an \hbox
-\to \everymathematics
+% \appendtoks
+% \ignorediscretionaries % so $\mtext{a|b}$ works, this is ok because it's an \hbox
+% \to \everymathematics
% We unofficial support some synonyms as we need them for some fuzzy web related math.
@@ -1215,5 +1215,7 @@
\definemathfence [tupanddownarrows] [\v!text] [\c!left="2191,\c!right="2193]
\definemathfence [tupdownarrows] [\v!text] [\c!left="21C5,\c!right=0]
\definemathfence [tdownuparrows] [\v!text] [\c!middle="21F5]
+\definemathfence [tuparrow] [\v!text] [\c!middle="2191]
+\definemathfence [tdownarrow] [\v!text] [\c!middle="2193]
\protect
diff --git a/tex/context/base/mkxl/math-ini.mkxl b/tex/context/base/mkxl/math-ini.mkxl
index 259fd360e..5fcd232a2 100644
--- a/tex/context/base/mkxl/math-ini.mkxl
+++ b/tex/context/base/mkxl/math-ini.mkxl
@@ -2100,23 +2100,33 @@
%D The result is as expected: the first line typesets ok, while the second one
%D triggers an error message.
-\setnewconstant\activemathcharcode "8000
-
-\newtoks\activatedmathcharacters
-
-\permanent\protected\def\activatemathcharacter#1%
- {\appendtoks
- \global\mathcode#1=\activemathcharcode
- \to \activatedmathcharacters}
-
-\permanent\def\activatemathcharacters
- {\the\activatedmathcharacters}
+% \setnewconstant\activemathcharcode "8000
+%
+% \newtoks\activatedmathcharacters
+%
+% \permanent\protected\def\activatemathcharacter#1%
+% {\appendtoks
+% \global\mathcode#1=\activemathcharcode
+% \to \activatedmathcharacters}
+%
+% \permanent\def\activatemathcharacters
+% {\the\activatedmathcharacters}
+%
+% % beware, not runtime, so has to happen at format generation
+%
+% \activatemathcharacter\circumflexasciicode
+% \activatemathcharacter\underscoreasciicode
+% %activatemathcharacter\ampersandasciicode
-% beware, not runtime, so has to happen at format generation
+% % already done in catc-def.mkxl:
+%
+% \amcode \circumflexasciicode \superscriptcatcode
+% \amcode \underscoreasciicode \subscriptcatcode
+% \amcode \barasciicode \othercatcode
+% \amcode \tildeasciicode \othercatcode
-\activatemathcharacter\circumflexasciicode
-\activatemathcharacter\underscoreasciicode
-%activatemathcharacter\ampersandasciicode
+% \Umathcode\circumflexasciicode="0 "0 \circumflexasciicode
+% \Umathcode\underscoreasciicode="0 "0 \underscoreasciicode
% \permanent\def\normalmathaligntab{&}
%
@@ -2200,27 +2210,24 @@
%D We also dropped the option to let ampersands be alignment tabs. That has never
%D been a \CONTEXT\ feature|/|habit anyway.
-\bgroup
-
- \catcode\underscoreasciicode\activecatcode
- \catcode\circumflexasciicode\activecatcode
- % \catcode\ampersandasciicode \activecatcode
-
- \aliased\glet\specialmathaligntab\normalmathaligntab
-
- \permanent\protected\gdef\obeymathcatcodes{%
- \enforced\let _\normalsubscript
- \enforced\let ^\normalsuperscript
- % \enforced\def &\specialmathaligntab
- }
-
- \doglobal\appendtoks
- \enforced\let _\normalsubscript
- \enforced\let ^\normalsuperscript
- % \enforced\let &\specialmathaligntab
- \to \everymathematics
-
-\egroup
+% \bgroup
+%
+% \catcode\underscoreasciicode\activecatcode
+% \catcode\circumflexasciicode\activecatcode
+%
+% \aliased\glet\specialmathaligntab\normalmathaligntab
+%
+% \permanent\protected\gdef\obeymathcatcodes{%
+% \enforced\let _\normalsubscript
+% \enforced\let ^\normalsuperscript
+% }
+%
+% \doglobal\appendtoks
+% \enforced\let _\normalsubscript
+% \enforced\let ^\normalsuperscript
+% \to \everymathematics
+%
+% \egroup
%D We keep this, just for the fun of it:
@@ -3772,10 +3779,10 @@
\permanent\protected\def\?{\mathtextauto{?}{?}}
\popoverloadmode
-\appendtoks
- \reinstatecatcodecommand\barasciicode
- \obeydiscretionaries
-\to \everymathtext
+% \appendtoks
+% \reinstatecatcodecommand\barasciicode
+% \obeydiscretionaries
+% \to \everymathtext
%D Safeguard against redefinitions:
@@ -4452,19 +4459,47 @@
%D test \im {z + \mathaxisontop x + 2 - a = 1} test
%D \stoptyping
+%D \starttyping
+%D $ x^2 + x_2 + x_2^2\mathaxisbelow\mathscriptbelow$\par
+%D $ x^g + x_g + x_g^g\mathaxisbelow\mathscriptbelow$
+%D \stoptyping
+
\definesystemattribute[mathaxis][public]
-\def\math_axis_inject#1%
- {\mathatom \s!class \mathghostcode \s!unpack {
- \showmakeup[strut]% todo: shortcut
- \scratchdimen.5\Umathfractionrule\mathstyle
- \srule
- \s!height \dimexpr\Umathaxis\mathstyle+\scratchdimen\relax
- \s!depth -\dimexpr\Umathaxis\mathstyle-\scratchdimen\relax
- \s!attr \mathaxisattribute #1%
- \relax}}
-
-\permanent\protected\def\mathaxisbelow{\math_axis_inject\plusone}
-\permanent\protected\def\mathaxisontop{\math_axis_inject\plustwo}
+
+\def\math_axis_inject_indeed#1%
+ {\srule
+ \s!height \dimexpr\scratchdimentwo+\scratchdimenone\relax
+ \s!depth -\dimexpr\scratchdimentwo-\scratchdimenone\relax
+ \s!attr \mathaxisattribute#1%
+ \relax}
+
+\def\math_axis_inject#1#2%
+ {\mathatom \s!class \mathghostcode \s!unpack {
+ \showmakeup[strut]% todo: shortcut
+ \ifcase#1%
+ % nothing
+ \or
+ \scratchdimenone.5\Umathfractionrule\mathstyle
+ \scratchdimentwo\Umathaxis\mathstyle
+ \math_axis_inject_indeed#2%
+ \or
+ \scratchdimenone.25\Umathfractionrule\mathstyle
+ \scratchdimentwo\Umathsupshiftup\mathstyle
+ \math_axis_inject_indeed#2%
+ \scratchdimentwo-\Umathsubshiftdown\mathstyle
+ \math_axis_inject_indeed#2%
+ \scratchdimentwo-\Umathsubsupshiftdown\mathstyle
+ \math_axis_inject_indeed#2%
+ % \scratchdimenone.125\Umathfractionrule\mathstyle
+ \divide\scratchdimenone\plustwo
+ \scratchdimentwo\Umathprimeshiftup\mathstyle
+ \math_axis_inject_indeed#2%
+ \fi}}
+
+\permanent\protected\def\mathaxisbelow {\math_axis_inject\plusone\plusone}
+\permanent\protected\def\mathaxisontop {\math_axis_inject\plusone\plustwo}
+\permanent\protected\def\mathscriptbelow{\math_axis_inject\plustwo\plusone}
+\permanent\protected\def\mathscriptontop{\math_axis_inject\plustwo\plustwo}
\protect \endinput
diff --git a/tex/context/base/mkxl/math-twk.mkxl b/tex/context/base/mkxl/math-twk.mkxl
index 269c855c0..6ffb36818 100644
--- a/tex/context/base/mkxl/math-twk.mkxl
+++ b/tex/context/base/mkxl/math-twk.mkxl
@@ -86,8 +86,11 @@
\immutable\chardef\textminute"2032
\immutable\chardef\textsecond"2033
-\immutable\Umathchardef\mathminute\zerocount\zerocount\privatecharactercode{prime 0x2032 1}
-\immutable\Umathchardef\mathsecond\zerocount\zerocount\privatecharactercode{prime 0x2033 1}
+% \immutable\Umathchardef\mathminute\zerocount\zerocount\privatecharactercode{prime 0x2032 1}
+% \immutable\Umathchardef\mathsecond\zerocount\zerocount\privatecharactercode{prime 0x2033 1}
+
+\immutable\Umathchardef\mathminute\zerocount\zerocount\textminute
+\immutable\Umathchardef\mathsecond\zerocount\zerocount\textsecond
\permanent\protected\def\minute{\iffontchar\font\textminute\textminute\else\mathminute\fi}
\permanent\protected\def\second{\iffontchar\font\textsecond\textsecond\else\mathsecond\fi}
diff --git a/tex/context/base/mkxl/node-fnt.lmt b/tex/context/base/mkxl/node-fnt.lmt
index 26e1fc343..61a20c628 100644
--- a/tex/context/base/mkxl/node-fnt.lmt
+++ b/tex/context/base/mkxl/node-fnt.lmt
@@ -73,6 +73,7 @@ local wordboundary_code = boundarycodes.word
local protectglyphs = nuts.protectglyphs
local unprotectglyphs = nuts.unprotectglyphs
+local protectglyphsnone = nuts.protectglyphsnone
local setmetatableindex = table.setmetatableindex
@@ -168,64 +169,428 @@ local function stop_trace(u,usedfonts,d,dynamicfonts,b,basefonts,r,redundant)
report_fonts()
end
+-- This is the original handler and we keep it around as reference. It served us
+-- well for quite a while.
+
+-- do
+--
+-- local usedfonts
+-- local dynamicfonts
+-- local basefonts -- could be reused
+-- local basefont
+-- local prevfont
+-- local prevdynamic
+-- local variants
+-- local redundant -- could be reused
+-- local firstnone
+-- local lastfont
+-- local lastproc
+-- local lastnone
+--
+-- local d, u, b, r
+--
+-- local function protectnone()
+-- protectglyphs(firstnone,lastnone)
+-- firstnone = nil
+-- end
+--
+-- local function setnone(n)
+-- if firstnone then
+-- protectnone()
+-- end
+-- if basefont then
+-- basefont[2] = getprev(n)
+-- basefont = false
+-- end
+-- if not firstnone then
+-- firstnone = n
+-- end
+-- lastnone = n
+-- end
+--
+-- local function setbase(n)
+-- if firstnone then
+-- protectnone()
+-- end
+-- if force_basepass then
+-- if basefont then
+-- basefont[2] = getprev(n)
+-- end
+-- b = b + 1
+-- basefont = { n, false }
+-- basefonts[b] = basefont
+-- end
+-- end
+--
+-- local function setnode(n,font,dynamic) -- we could use prevfont and prevdynamic when we set then first
+-- if firstnone then
+-- protectnone()
+-- end
+-- if basefont then
+-- basefont[2] = getprev(n)
+-- basefont = false
+-- end
+-- if dynamic > 0 then
+-- local used = dynamicfonts[font]
+-- if not used then
+-- used = { }
+-- dynamicfonts[font] = used
+-- end
+-- if not used[dynamic] then
+-- local fd = setfontdynamics[font]
+-- if fd then
+-- used[dynamic] = fd[dynamic]
+-- d = d + 1
+-- end
+-- end
+-- else
+-- local used = usedfonts[font]
+-- if not used then
+-- lastfont = font
+-- lastproc = fontprocesses[font]
+-- if lastproc then
+-- usedfonts[font] = lastproc
+-- u = u + 1
+-- end
+-- end
+-- end
+-- end
+--
+-- function handlers.characters(head,groupcode,direction)
+-- -- either next or not, but definitely no already processed list
+-- starttiming(nodes)
+--
+-- usedfonts = { }
+-- dynamicfonts = { }
+-- basefonts = { }
+-- basefont = nil
+-- prevfont = nil
+-- prevdynamic = 0
+-- variants = nil
+-- redundant = nil
+-- firstnone = nil
+-- lastfont = nil
+-- lastproc = nil
+-- lastnone = nil
+--
+-- local fontmode = nil -- base none or other
+--
+-- d, u, b, r = 0, 0, 0, 0
+--
+-- if trace_fontrun then
+-- start_trace(head)
+-- end
+--
+-- -- There is no gain in checking for a single glyph and then having a fast path. On the
+-- -- metafun manual (with some 2500 single char lists) the difference is just noise.
+--
+-- for n, char, font, dynamic in nextchar, head do
+--
+-- if font ~= prevfont then
+-- prevfont = font
+-- fontmode = fontmodes[font]
+-- if fontmode == "none" then
+-- prevdynamic = 0
+-- variants = false
+-- setnone(n)
+-- elseif fontmode == "base" then
+-- prevdynamic = 0
+-- variants = false
+-- setbase(n)
+-- else
+-- -- local dynamic = getglyphdata(n) or 0 -- zero dynamic is reserved for fonts in context
+-- prevdynamic = dynamic
+-- variants = fontvariants[font]
+-- setnode(n,font,dynamic)
+-- end
+-- elseif fontmode == "node" then
+-- local dynamic = getglyphdata(n) or 0 -- zero dynamic is reserved for fonts in context
+-- if dynamic ~= prevdynamic then
+-- prevdynamic = dynamic
+-- variants = fontvariants[font]
+-- setnode(n,font,dynamic)
+-- end
+-- elseif firstnone then
+-- lastnone = n
+-- end
+--
+-- if variants then
+-- if (char >= 0xFE00 and char <= 0xFE0F) or (char >= 0xE0100 and char <= 0xE01EF) then
+-- -- if variants and char >= 0xFE00 then
+-- -- if char < 0xFE0F or (char >= 0xE0100 and char <= 0xE01EF) then
+-- local hash = variants[char]
+-- if hash then
+-- local p = getprev(n)
+-- if p then
+-- local char = ischar(p) -- checked
+-- local variant = hash[char]
+-- if variant then
+-- if trace_variants then
+-- report_fonts("replacing %C by %C",char,variant)
+-- end
+-- setchar(p,variant)
+-- if redundant then
+-- r = r + 1
+-- redundant[r] = n
+-- else
+-- r = 1
+-- redundant = { n }
+-- end
+-- end
+-- end
+-- elseif keep_redundant then
+-- -- go on, can be used for tracing
+-- elseif redundant then
+-- r = r + 1
+-- redundant[r] = n
+-- else
+-- r = 1
+-- redundant = { n }
+-- end
+-- end
+-- end
+--
+-- end
+--
+-- if firstnone then
+-- protectnone()
+-- end
+--
+-- if force_boundaryrun then
+--
+-- -- we can inject wordboundaries and then let the hyphenator do its work
+-- -- but we need to get rid of those nodes in order to build ligatures
+-- -- and kern (a rather context thing)
+--
+-- for b, subtype in nextboundary, head do
+-- if subtype == wordboundary_code then
+-- if redundant then
+-- r = r + 1
+-- redundant[r] = b
+-- else
+-- r = 1
+-- redundant = { b }
+-- end
+-- end
+-- end
+--
+-- end
+--
+-- if redundant then
+-- for i=1,r do
+-- local r = redundant[i]
+-- local p, n = getboth(r)
+-- if r == head then
+-- head = n
+-- setprev(n)
+-- else
+-- setlink(p,n)
+-- end
+-- if b > 0 then
+-- for i=1,b do
+-- local bi = basefonts[i]
+-- local b1 = bi[1]
+-- local b2 = bi[2]
+-- if b1 == b2 then
+-- if b1 == r then
+-- bi[1] = false
+-- bi[2] = false
+-- end
+-- elseif b1 == r then
+-- bi[1] = n
+-- elseif b2 == r then
+-- bi[2] = p
+-- end
+-- end
+-- end
+-- flushnode(r)
+-- end
+-- end
+--
+-- if force_discrun then
+-- -- basefont is not supported in disc only runs ... it would mean a lot of
+-- -- ranges .. we could try to run basemode as a separate processor run but not
+-- -- for now (we can consider it when the new node code is tested
+-- for disc in nextdisc, head do
+-- -- doing only replace is good enough because pre and post are normally used
+-- -- for hyphens and these come from fonts that part of the hyphenated word
+-- local r = getreplace(disc)
+-- if r then
+-- local prevfont = nil
+-- local prevdynamic = nil
+-- local none = false
+-- firstnone = nil
+-- basefont = nil
+-- for n, char, font, dynamic in nextchar, r do
+-- -- local dynamic = getglyphdata(n) or 0 -- zero dynamic is reserved for fonts in context
+-- if font ~= prevfont or dynamic ~= prevdynamic then
+-- prevfont = font
+-- prevdynamic = dynamic
+-- local fontmode = fontmodes[font]
+-- if fontmode == "none" then
+-- setnone(n)
+-- elseif fontmode == "base" then
+-- -- so the replace gets an extra treatment ... so be it
+-- setbase(n)
+-- else
+-- setnode(n,font,dynamic)
+-- end
+-- elseif firstnone then
+-- -- lastnone = n
+-- lastnone = nil
+-- end
+-- -- we assume one font for now (and if there are more and we get into issues then
+-- -- we can always remove the break)
+-- break
+-- end
+-- if firstnone then
+-- protectnone()
+-- end
+-- end
+-- end
+--
+-- end
+--
+-- if trace_fontrun then
+-- stop_trace(u,usedfonts,d,dynamicfonts,b,basefonts,r,redundant)
+-- end
+--
+-- -- in context we always have at least 2 processors
+-- if u == 0 then
+-- -- skip
+-- elseif u == 1 then
+-- for i=1,#lastproc do
+-- head = lastproc[i](head,lastfont,0,direction)
+-- end
+-- else
+-- for font, processors in next, usedfonts do -- unordered
+-- for i=1,#processors do
+-- head = processors[i](head,font,0,direction,u) -- u triggers disc optimizer
+-- end
+-- end
+-- end
+--
+-- if d == 0 then
+-- -- skip
+-- elseif d == 1 then
+-- local font, dynamics = next(dynamicfonts)
+-- for dynamic, processors in next, dynamics do -- unordered, dynamic can switch in between
+-- for i=1,#processors do
+-- head = processors[i](head,font,dynamic,direction)
+-- end
+-- end
+-- else
+-- for font, dynamics in next, dynamicfonts do
+-- for dynamic, processors in next, dynamics do -- unordered, dynamic can switch in between
+-- for i=1,#processors do
+-- head = processors[i](head,font,dynamic,direction,d) -- d triggers disc optimizer
+-- end
+-- end
+-- end
+-- end
+-- if b == 0 then
+-- -- skip
+-- elseif b == 1 then
+-- -- only one font
+-- local range = basefonts[1]
+-- local start = range[1]
+-- local stop = range[2]
+-- if (start or stop) and (start ~= stop) then
+-- local front = head == start
+-- if stop then
+-- start = ligaturing(start,stop)
+-- start = kerning(start,stop)
+-- elseif start then -- safeguard
+-- start = ligaturing(start)
+-- start = kerning(start)
+-- end
+-- if front and head ~= start then
+-- head = start
+-- end
+-- end
+-- else
+-- -- multiple fonts
+-- for i=1,b do
+-- local range = basefonts[i]
+-- local start = range[1]
+-- local stop = range[2]
+-- if start then -- and start ~= stop but that seldom happens
+-- local front = head == start
+-- local prev = getprev(start)
+-- local next = getnext(stop)
+-- if stop then
+-- start, stop = ligaturing(start,stop)
+-- start, stop = kerning(start,stop)
+-- else
+-- start = ligaturing(start)
+-- start = kerning(start)
+-- end
+-- -- is done automatically
+-- if prev then
+-- setlink(prev,start)
+-- end
+-- if next then
+-- setlink(stop,next)
+-- end
+-- -- till here
+-- if front and head ~= start then
+-- head = start
+-- end
+-- end
+-- end
+-- end
+--
+-- stoptiming(nodes)
+--
+-- if trace_characters then
+-- nodes.report(head)
+-- end
+--
+-- return head
+-- end
+--
+-- end
+
+
+-- This variant uses less code but relies on the engine checking the textcontrol
+-- flags:
+--
+-- baseligatures : 0x02
+-- basekerns : 0x04
+-- noneprotected : 0x08
+--
+-- This permits one 'base' pass instead of multiple over ranges which is kind of
+-- tricky because we then can have clashes when we process replace fields
+-- independently. We can also protect 'none' in one go. It is actually not that
+-- much faster (and in some cases it might even be slower). We can make the code
+-- a bit leaner (no setbase and setnone).
+
do
local usedfonts
local dynamicfonts
- local basefonts -- could be reused
- local basefont
local prevfont
local prevdynamic
local variants
local redundant -- could be reused
- local firstnone
local lastfont
local lastproc
- local lastnone
+ local basedone
+ local nonedone
local d, u, b, r
- local function protectnone()
- protectglyphs(firstnone,lastnone)
- firstnone = nil
- end
-
local function setnone(n)
- if firstnone then
- protectnone()
- end
- if basefont then
- basefont[2] = getprev(n)
- basefont = false
- end
- if not firstnone then
- firstnone = n
- end
- lastnone = n
+ nonedone = true
end
local function setbase(n)
- if firstnone then
- protectnone()
- end
if force_basepass then
- if basefont then
- basefont[2] = getprev(n)
- end
- b = b + 1
- basefont = { n, false }
- basefonts[b] = basefont
+ basedone = true
end
end
local function setnode(n,font,dynamic) -- we could use prevfont and prevdynamic when we set then first
- if firstnone then
- protectnone()
- end
- if basefont then
- basefont[2] = getprev(n)
- basefont = false
- end
if dynamic > 0 then
local used = dynamicfonts[font]
if not used then
@@ -258,24 +623,22 @@ do
usedfonts = { }
dynamicfonts = { }
- basefonts = { }
- basefont = nil
prevfont = nil
prevdynamic = 0
variants = nil
redundant = nil
- firstnone = nil
lastfont = nil
lastproc = nil
- lastnone = nil
+ nonedone = nil
+ basedone = nil
local fontmode = nil -- base none or other
d, u, b, r = 0, 0, 0, 0
- if trace_fontrun then
- start_trace(head)
- end
+-- if trace_fontrun then
+-- start_trace(head)
+-- end
-- There is no gain in checking for a single glyph and then having a fast path. On the
-- metafun manual (with some 2500 single char lists) the difference is just noise.
@@ -306,8 +669,6 @@ do
variants = fontvariants[font]
setnode(n,font,dynamic)
end
- elseif firstnone then
- lastnone = n
end
if variants then
@@ -348,10 +709,6 @@ do
end
- if firstnone then
- protectnone()
- end
-
if force_boundaryrun then
-- we can inject wordboundaries and then let the hyphenator do its work
@@ -382,31 +739,13 @@ do
else
setlink(p,n)
end
- if b > 0 then
- for i=1,b do
- local bi = basefonts[i]
- local b1 = bi[1]
- local b2 = bi[2]
- if b1 == b2 then
- if b1 == r then
- bi[1] = false
- bi[2] = false
- end
- elseif b1 == r then
- bi[1] = n
- elseif b2 == r then
- bi[2] = p
- end
- end
- end
flushnode(r)
end
end
+ -- todo: make this more clever
+
if force_discrun then
- -- basefont is not supported in disc only runs ... it would mean a lot of
- -- ranges .. we could try to run basemode as a separate processor run but not
- -- for now (we can consider it when the new node code is tested
for disc in nextdisc, head do
-- doing only replace is good enough because pre and post are normally used
-- for hyphens and these come from fonts that part of the hyphenated word
@@ -415,8 +754,6 @@ do
local prevfont = nil
local prevdynamic = nil
local none = false
- firstnone = nil
- basefont = nil
for n, char, font, dynamic in nextchar, r do
-- local dynamic = getglyphdata(n) or 0 -- zero dynamic is reserved for fonts in context
if font ~= prevfont or dynamic ~= prevdynamic then
@@ -426,29 +763,26 @@ do
if fontmode == "none" then
setnone(n)
elseif fontmode == "base" then
- -- so the replace gets an extra treatment ... so be it
setbase(n)
else
setnode(n,font,dynamic)
end
- elseif firstnone then
- -- lastnone = n
- lastnone = nil
end
-- we assume one font for now (and if there are more and we get into issues then
-- we can always remove the break)
break
end
- if firstnone then
- protectnone()
- end
end
end
end
- if trace_fontrun then
- stop_trace(u,usedfonts,d,dynamicfonts,b,basefonts,r,redundant)
+-- if trace_fontrun then
+-- stop_trace(u,usedfonts,d,dynamicfonts,b,basefonts,r,redundant)
+-- end
+
+ if nonedone then
+ protectglyphsnone(head)
end
-- in context we always have at least 2 processors
@@ -465,6 +799,7 @@ do
end
end
end
+
if d == 0 then
-- skip
elseif d == 1 then
@@ -483,55 +818,13 @@ do
end
end
end
- if b == 0 then
- -- skip
- elseif b == 1 then
- -- only one font
- local range = basefonts[1]
- local start = range[1]
- local stop = range[2]
- if (start or stop) and (start ~= stop) then
- local front = head == start
- if stop then
- start = ligaturing(start,stop)
- start = kerning(start,stop)
- elseif start then -- safeguard
- start = ligaturing(start)
- start = kerning(start)
- end
- if front and head ~= start then
- head = start
- end
- end
- else
- -- multiple fonts
- for i=1,b do
- local range = basefonts[i]
- local start = range[1]
- local stop = range[2]
- if start then -- and start ~= stop but that seldom happens
- local front = head == start
- local prev = getprev(start)
- local next = getnext(stop)
- if stop then
- start, stop = ligaturing(start,stop)
- start, stop = kerning(start,stop)
- else
- start = ligaturing(start)
- start = kerning(start)
- end
- -- is done automatically
- if prev then
- setlink(prev,start)
- end
- if next then
- setlink(stop,next)
- end
- -- till here
- if front and head ~= start then
- head = start
- end
- end
+
+ if basedone then
+ local start = head
+ start = ligaturing(start)
+ start = kerning(start)
+ if head ~= start then
+ head = start
end
end
diff --git a/tex/context/base/mkxl/node-nut.lmt b/tex/context/base/mkxl/node-nut.lmt
index 62b733125..38c182f8a 100644
--- a/tex/context/base/mkxl/node-nut.lmt
+++ b/tex/context/base/mkxl/node-nut.lmt
@@ -199,6 +199,7 @@ local nuts = {
prependbeforehead = direct.prependbeforehead,
protectglyph = direct.protectglyph,
protectglyphs = direct.protectglyphs,
+ protectglyphsnone = direct.protectglyphsnone,
protrusionskippable = direct.protrusionskippable,
rangedimensions = direct.rangedimensions,
remove = d_remove_node,
diff --git a/tex/context/base/mkxl/spac-chr.mkxl b/tex/context/base/mkxl/spac-chr.mkxl
index a7d339019..346bc2183 100644
--- a/tex/context/base/mkxl/spac-chr.mkxl
+++ b/tex/context/base/mkxl/spac-chr.mkxl
@@ -73,7 +73,11 @@
% unexpanded as otherwise we need to intercept / cleanup a lot
+\pushoverloadmode
+
\protected\def~{\nobreakspace}
+\popoverloadmode
+
\protect \endinput
diff --git a/tex/context/base/mkxl/spac-hor.mkxl b/tex/context/base/mkxl/spac-hor.mkxl
index 4c153931b..111bdc94c 100644
--- a/tex/context/base/mkxl/spac-hor.mkxl
+++ b/tex/context/base/mkxl/spac-hor.mkxl
@@ -523,10 +523,12 @@
\permanent\protected\def\fixedspaces
{\letcatcodecommand \ctxcatcodes \tildeasciicode\fixedspace
- \enforced\let~\fixedspace} % we need to renew it
+ %\enforced\let~\fixedspace} % we need to renew it
+ \enforced\letcharcode\tildeasciicode\fixedspace} % why this
\appendtoks
- \enforced\let~\space
+ %\enforced\let~\space
+ \enforced\letcharcode\tildeasciicode\space
\enforced\let\ \space
\to \everysimplifycommands
diff --git a/tex/context/base/mkxl/tabl-tab.mkxl b/tex/context/base/mkxl/tabl-tab.mkxl
index ad9bfdd45..815767e18 100644
--- a/tex/context/base/mkxl/tabl-tab.mkxl
+++ b/tex/context/base/mkxl/tabl-tab.mkxl
@@ -57,7 +57,8 @@
\dontcomplain
\tabl_table_restore_lineskips
\normalbaselines
- \enforced\let~\fixedspace
+ % \enforced\let~\fixedspace
+` \enforced\letcharcode\tildeasciicode\fixedspace % why
\inhibitblank % \blank[\v!disable]% % added
\the\everytableparbox}
@@ -835,7 +836,7 @@
\bgroup \catcode\tildeasciicode\activecatcode
\appendtoks
- \catcode\barasciicode\activecatcode
+% \catcode\barasciicode\activecatcode
\enforced\protected\def ~{\kern.5em}%
\enforced\protected\def\\{\ifhmode\space\else\par\fi}%
\to \everytable
@@ -1492,26 +1493,42 @@
% \noalign{\globalpopmacro\simpletableHL}%
}
-\bgroup \catcode\barasciicode\othercatcode
+% \bgroup \catcode\barasciicode\othercatcode
+%
+% \gdef\tabl_table_second_stage[#1]% brr nested mess
+% {\bgroup
+% \tabl_table_use_bar
+% \global\setfalse\tableactionstatepermitted
+% \global\setfalse\hassometablehead
+% \global\setfalse\hassometabletail
+% \expanded{\doifelseinstring{|}{#1}}
+% {\xdef\tabl_table_restart{\noexpand\tabl_table_restart_indeed{\noexpand\tabl_table_third_stage{#1}}}}
+% {\ifcsname\??tabletemplate#1\endcsname
+% \gdef\tabl_table_restart{\csname\??tabletemplate#1\endcsname}%
+% \else
+% \gdef\tabl_table_restart{\tabl_table_restart_indeed{\begincsname#1\endcsname}}%
+% \fi}%
+% \egroup
+% \tabl_table_restart}
+%
+% \egroup
-\gdef\tabl_table_second_stage[#1]% brr nested mess
+\def\tabl_table_second_stage[#1]% brr nested mess
{\bgroup
\tabl_table_use_bar
\global\setfalse\tableactionstatepermitted
\global\setfalse\hassometablehead
\global\setfalse\hassometabletail
- \expanded{\doifelseinstring{|}{#1}}
- {\xdef\tabl_table_restart{\noexpand\tabl_table_restart_indeed{\noexpand\tabl_table_third_stage{#1}}}}
- {\ifcsname\??tabletemplate#1\endcsname
- \gdef\tabl_table_restart{\csname\??tabletemplate#1\endcsname}%
- \else
- \gdef\tabl_table_restart{\tabl_table_restart_indeed{\begincsname#1\endcsname}}%
- \fi}%
+ \normalexpanded{\noexpand\ifhastoks{|}{#1}}%
+ \xdef\tabl_table_restart{\noexpand\tabl_table_restart_indeed{\noexpand\tabl_table_third_stage{#1}}}%
+ \orelse\ifcsname\??tabletemplate#1\endcsname
+ \gdef\tabl_table_restart{\csname\??tabletemplate#1\endcsname}%
+ \else
+ \gdef\tabl_table_restart{\tabl_table_restart_indeed{\begincsname#1\endcsname}}%
+ \fi
\egroup
\tabl_table_restart}
-\egroup
-
%D The third stage involves a lot of (re)sets, which we will explain later.
\appendtoks
@@ -1859,14 +1876,15 @@
\newcount\currenttablecolumn
-% DWhile defining this macro we change the \CATCODE\ of \type{|}. When counting the
-% Dbars, we use a non active representation of the bar, simply because we cannot be
-% Dsure if the bar is active or not.\footnote{Normally it is, but \TABLE\ changes
-% Dthe catcode when needed.}
+%D While defining this macro we change the \CATCODE\ of \type{|}. When counting the
+%D bars, we use a non active representation of the bar, simply because we cannot be
+%D sure if the bar is active or not.\footnote{Normally it is, but \TABLE\ changes
+%D the catcode when needed.}
\bgroup
- \catcode\barasciicode\othercatcode \permanent\gdef\tabl_table_bar{|}
- \catcode\barasciicode\activecatcode\gdef\tabl_table_use_bar{\enforced\let|\tabl_table_bar}
+% \catcode\barasciicode\othercatcode \permanent\gdef\tabl_table_bar{|}
+% \catcode\barasciicode\activecatcode\gdef\tabl_table_use_bar{\enforced\let|\tabl_table_bar}
+\glet\tabl_table_use_bar\relax
\egroup
\bgroup \catcode\barasciicode\othercatcode
@@ -1874,7 +1892,7 @@
\gdef\tabl_tables_get_nofcolumns#1% todo: also divert this to lua as with tabulate
{\bgroup
\cleanupfeatures % needed !
- \tabl_table_use_bar
+ \tabl_table_use_bar % doesn't do anything as we don't treat #1
\egroup}
\egroup
diff --git a/tex/context/base/mkxl/typo-rub.mkxl b/tex/context/base/mkxl/typo-rub.mkxl
index bf48d8fa1..79760c328 100644
--- a/tex/context/base/mkxl/typo-rub.mkxl
+++ b/tex/context/base/mkxl/typo-rub.mkxl
@@ -45,7 +45,8 @@
\enforced\let\ruby\noruby
\edef\currentruby{#1}%
\edef\p_location{\rubyparameter\c!location}%
- \enforced\let|\relax
+ % \enforced\let|\relax
+ \enforced\letcharcode\barasciicode\relax
\ifcsname\??rubyanalyze\p_location\endcsname
\expandafter\lastnamedcs\else\expandafter\typo_ruby_analyze
\fi{#2}{#3}%
diff --git a/tex/context/fonts/mkiv/bonum-math.lfg b/tex/context/fonts/mkiv/bonum-math.lfg
index dfce35d80..736b8a176 100644
--- a/tex/context/fonts/mkiv/bonum-math.lfg
+++ b/tex/context/fonts/mkiv/bonum-math.lfg
@@ -24,11 +24,16 @@ return {
DelimiterPercent = 90,
DelimiterShortfall = 400,
DisplayOperatorMinHeight = 1900, -- 1250 in font
- -- AccentSuperscriptDrop = 100,
- -- AccentSuperscriptPercent = 20,
- -- PrimeRaisePercent = 50,
- PrimeRaiseComposedPercent = 0,
- -- PrimeShiftUp = 0,
+ -- ScriptPercentScaleDown = 65, -- 77 in font
+ -- ScriptScriptPercentScaleDown = 50, -- 60 in font
+ SubscriptShiftDown = 201, -- 231 in font
+ SuperscriptShiftUp = 364, -- 334 in font
+ SubscriptShiftDownWithSuperscript = "1.4*SubscriptShiftDown", -- trial and error
+ -- PrimeRaisePercent = 0, -- set to 0 in math-act
+ -- PrimeRaiseComposedPercent = 0, -- set to 0 in math-act
+ PrimeShiftUp = "1.25*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.25*SuperscriptShiftUp",
+
-- PrimeBaselineDropMax = 0,
},
tweaks = {
@@ -41,7 +46,7 @@ return {
tweak = "fixprimes",
-- scale = 0.8,
-- smaller = true,
- factor = 1,--1.1
+ factor = 0.77,--1.1
},
{
tweak = "addmirrors",
@@ -121,8 +126,8 @@ return {
[0x0029] = { topright = -0.15, bottomright = -0.15 }, -- right parenthesis variants
["0x29.variants.*"] = { topright = -0.15, bottomright = -0.15 }, -- right parenthesis variants
["0x29.parts.top"] = { topright = -0.15, }, -- right parenthesis top
- ["0x29.parts.bottom"] = { bottomright = -0.15 }, -- right parenthesis bottom -- radical
- [0x221A] = { topright = 0.2, bottomright = 0.2 },
+ ["0x29.parts.bottom"] = { bottomright = -0.15 }, -- right parenthesis bottom
+ [0x221A] = { topright = 0.2, bottomright = 0.2 }, -- radical
["0x221A.variants.*"] = { topright = 0.2, bottomright = 0.2 },
["0x221A.parts.top"] = { topright = 0.2, },
["0x221A.parts.bottom"] = { bottomright = 0.2 },
@@ -131,6 +136,8 @@ return {
[0x27EB] = { topright = -0.1, bottomright = -0.1 },
["0x27EB.variants.*"] = { topright = -0.2, bottomright = -0.2 },
--
+ [0x1D465] = { bottomright = -0.05, }, -- italic x (ic is too large)
+ [0x00393] = { bottomright = -0.30, }, -- upright Gamma
-- [0x222B] = integral_variants, ["0x222B.variants.*"] = integral_variants, ["0x222B.parts.top"] = integral_top,
["0x222B.parts.bottom"] = { bottomright = -0.20 }, -- int
["0x222C.parts.bottom"] = { bottomright = -0.15 }, -- iint
@@ -420,6 +427,9 @@ return {
tweak = "addfourier",
variant = 1,
},
+ {
+ tweak = "addprimed",
+ },
-- this is the mkiv section
{
tweak = "emulatelmtx",
diff --git a/tex/context/fonts/mkiv/cambria-math.lfg b/tex/context/fonts/mkiv/cambria-math.lfg
index 97cea6674..e4791fc79 100644
--- a/tex/context/fonts/mkiv/cambria-math.lfg
+++ b/tex/context/fonts/mkiv/cambria-math.lfg
@@ -21,8 +21,10 @@ return {
DelimiterPercent = 90,
DelimiterShortfall = 400,
DisplayOperatorMinHeight = 2800, -- 2500 in font
- PrimeRaisePercent = 75, -- 50 default
- -- PrimeRaiseComposedPercent = 25, -- 25 default
+ -- PrimeRaisePercent = 0, -- set to 0 in math-act
+ -- PrimeRaiseComposedPercent = 25, -- set to 0 in math-act
+ PrimeShiftUp = "1.25*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.25*SuperscriptShiftUp",
},
tweaks = {
aftercopying = {
@@ -46,35 +48,28 @@ return {
{
tweak = "kerns",
list = {
- [0x2F] = {
- topleft = -0.2,
- -- bottomleft = 0,
- -- topright = 0,
- bottomright = -0.2,
- },
- ["0x7D.parts.top"] = {
- topright = -0.1,
- },
- ["0x7D.parts.bottom"] = {
- bottomright = -0.1,
- },
- ["0x29.parts.top"] = {
- topright = -0.2,
- },
- ["0x29.parts.bottom"] = {
- bottomright = -0.2,
- },
- ["0x221A.parts.top"] = {
- topright = 0.2,
- },
- ["0x221A.parts.bottom"] = {
- bottomright = 0.2,
- },
- ["0x221A.variants.*"] = {
- topright = 0.2,
- bottomright = 0.2,
- },
-
+ [0x002F] = { topleft = -0.2, bottomright = -0.2 },
+ ["0x002F.variants.*"] = { topleft = -0.2, bottomright = -0.2 },
+ -- No!
+ -- [0x0028] = { topleft = -0.1, bottomleft = -0.1 }, -- left parenthesis
+ -- [0x0029] = { topright = -0.1, bottomright = -0.1, all = true }, -- right parenthesis
+ --
+ [0x007D] = { topright = -0.05, bottomright = -0.05 }, -- right brace variants
+ ["0x7D.variants.*"] = { topright = -0.10, bottomright = -0.10 }, -- right brace variants
+ ["0x7D.parts.top"] = { topright = -0.10, }, -- right brace top
+ ["0x7D.parts.bottom"] = { bottomright = -0.10 }, -- right brace bottom
+ [0x0029] = { topright = -0.15, bottomright = -0.15 }, -- right parenthesis variants
+ ["0x29.variants.*"] = { topright = -0.15, bottomright = -0.15 }, -- right parenthesis variants
+ ["0x29.parts.top"] = { topright = -0.15, }, -- right parenthesis top
+ ["0x29.parts.bottom"] = { bottomright = -0.15 }, -- right parenthesis bottom
+ [0x221A] = { topright = 0.2, bottomright = 0.2 }, -- radical
+ ["0x221A.variants.*"] = { topright = 0.2, bottomright = 0.2 },
+ ["0x221A.parts.top"] = { topright = 0.2, },
+ ["0x221A.parts.bottom"] = { bottomright = 0.2 },
+ [0x27E9] = { topright = -0.1, bottomright = -0.1 }, -- angle
+ ["0x27E9.variants.*"] = { topright = -0.3, bottomright = -0.3 },
+ [0x27EB] = { topright = -0.1, bottomright = -0.1 },
+ ["0x27EB.variants.*"] = { topright = -0.2, bottomright = -0.2 },
-- Keep as example. not needed in cambria (after all it is the reference):
[0x2A0C] = { bottomright = -0.1 }, -- iiiint does not have any ic
@@ -156,9 +151,10 @@ return {
{
tweak = "fixprimes",
- scale = 0.9,
+ -- scale = 1.0,
-- smaller = true,
- factor = 0.9,
+ factor = 0.83,
+ fake = 0.8,
},
{
tweak = "checkspacing",
@@ -206,6 +202,9 @@ return {
tweak = "addfourier",
variant = 2,
},
+ {
+ tweak = "addprimed",
+ },
-- { -- the ldots are squareshaped and the cdots are circular
-- tweak = "fixellipses",
-- },
diff --git a/tex/context/fonts/mkiv/common-math.lfg b/tex/context/fonts/mkiv/common-math.lfg
index 85915c26a..d2785b3b2 100644
--- a/tex/context/fonts/mkiv/common-math.lfg
+++ b/tex/context/fonts/mkiv/common-math.lfg
@@ -214,6 +214,7 @@ return {
return {
tweak = "movelimits",
factor = parameters.factor or 1,
+ icfactor = parameters.icfactor or 1,
list = mathematics.tweaks.subsets.integrals,
}
end,
diff --git a/tex/context/fonts/mkiv/concrete-math.lfg b/tex/context/fonts/mkiv/concrete-math.lfg
index c107cfdeb..d0fc5749f 100644
--- a/tex/context/fonts/mkiv/concrete-math.lfg
+++ b/tex/context/fonts/mkiv/concrete-math.lfg
@@ -14,12 +14,16 @@ return {
DelimiterPercent = 90,
DelimiterShortfall = 400,
-- DisplayOperatorMinHeight = 1800, -- 1400 in font (one size)
+ -- PrimeRaisePercent = 0, -- set to 0 in math-act
+ -- PrimeRaiseComposedPercent = 25, -- set to 0 in math-act
+ PrimeShiftUp = "1.2*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.2*SuperscriptShiftUp",
},
tweaks = {
aftercopying = {
{
tweak = "fixprimes",
- factor = 0.8,
+ factor = 0.92,
},
-- there are circular variants
-- {
@@ -44,6 +48,43 @@ return {
[0x002F] = { topleft = -0.2, bottomright = -0.2 },
},
},
+ {
+ tweak = "kerns",
+ list = {
+ [0x002F] = { topleft = -0.2, bottomright = -0.2 },
+ ["0x002F.variants.*"] = { topleft = -0.2, bottomright = -0.2 },
+ -- No!
+ -- [0x0028] = { topleft = -0.1, bottomleft = -0.1 }, -- left parenthesis
+ -- [0x0029] = { topright = -0.1, bottomright = -0.1, all = true }, -- right parenthesis
+ --
+ [0x007D] = { topright = -0.05, bottomright = -0.05 }, -- right brace variants
+ ["0x7D.variants.*"] = { topright = -0.25, bottomright = -0.25 }, -- right brace variants
+ ["0x7D.parts.top"] = { topright = -0.25, }, -- right brace top
+ ["0x7D.parts.bottom"] = { bottomright = -0.25 }, -- right brace bottom
+ [0x0029] = { topright = -0.15, bottomright = -0.15 }, -- right parenthesis variants
+ ["0x29.variants.*"] = { topright = -0.15, bottomright = -0.15 }, -- right parenthesis variants
+ ["0x29.parts.top"] = { topright = -0.15, }, -- right parenthesis top
+ ["0x29.parts.bottom"] = { bottomright = -0.15 }, -- right parenthesis bottom
+ [0x221A] = { topright = 0.2, bottomright = 0.2 }, -- radical
+ ["0x221A.variants.*"] = { topright = 0.2, bottomright = 0.2 },
+ ["0x221A.parts.top"] = { topright = 0.2, },
+ ["0x221A.parts.bottom"] = { bottomright = 0.2 },
+ [0x27E9] = { topright = -0.1, bottomright = -0.1 }, -- angle
+ ["0x27E9.variants.*"] = { topright = -0.3, bottomright = -0.3 },
+ [0x27EB] = { topright = -0.1, bottomright = -0.1 },
+ ["0x27EB.variants.*"] = { topright = -0.2, bottomright = -0.2 },
+ --
+ [0x00393] = { bottomright = -0.30, }, -- upright Gamma
+ },
+ },
+
+ {
+ tweak = "dimensions",
+ list = {
+ [0x00393] = { width = 0.875, }, -- upright Gamma
+ },
+ },
+
{
tweak = "radicaldegreeanchors",
@@ -79,6 +120,9 @@ return {
variant = 2,
},
{
+ tweak = "addprimed",
+ },
+ {
tweak = "setoptions",
set = { "ignorekerndimensions" }
},
diff --git a/tex/context/fonts/mkiv/dejavu-math.lfg b/tex/context/fonts/mkiv/dejavu-math.lfg
index 728a5f2fc..af6a4bd55 100644
--- a/tex/context/fonts/mkiv/dejavu-math.lfg
+++ b/tex/context/fonts/mkiv/dejavu-math.lfg
@@ -24,8 +24,15 @@ return {
DelimiterPercent = 90,
DelimiterShortfall = 400,
DisplayOperatorMinHeight = 1800, -- 1333 in font
+ -- ScriptPercentScaleDown = 70, -- 80 in font (set in typescript)
+ -- ScriptScriptPercentScaleDown = 55, -- 65 in font (set in typescript)
+ SubscriptShiftDown = 177, -- 277 in font
+ SuperscriptShiftUp = 428, -- 381 in font
+ SubscriptShiftDownWithSuperscript = "1.3*SubscriptShiftDown", -- trial and error
-- PrimeRaisePercent = 50, -- 50 default
- PrimeRaiseComposedPercent = 10, -- 25 default
+ -- PrimeRaiseComposedPercent = 10, -- 25 default
+ PrimeShiftUp = "1.4*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.4*SuperscriptShiftUp",
},
tweaks = {
aftercopying = {
@@ -33,17 +40,9 @@ return {
tweak = "version",
expected = "Version 1.106",
},
--- {
--- tweak = "fixprimes",
--- scale = 0.85,
--- -- smaller = true,
--- factor = 1,
--- },
{
tweak = "fixprimes",
- scale = 1,
- -- smaller = true,
- factor = 0.8,
+ factor = 0.63,
},
{
tweak = "addmirrors",
@@ -89,7 +88,8 @@ return {
[0x27EB] = { topright = -0.1, bottomright = -0.1 },
["0x27EB.variants.*"] = { topright = -0.2, bottomright = -0.2 },
--
-
+ [0x00393] = { bottomright = -0.30, }, -- upright Gamma
+ --
["0x222B.parts.bottom"] = { bottomright = -0.20 }, -- int
["0x222C.parts.bottom"] = { bottomright = -0.15 }, -- iint
["0x222D.parts.bottom"] = { bottomright = -0.10 }, -- iiint
@@ -197,6 +197,9 @@ return {
tweak = "addfourier",
variant = 1,
},
+ {
+ tweak = "addprimed",
+ },
-- this is the mkiv section
{
tweak = "emulatelmtx",
diff --git a/tex/context/fonts/mkiv/ebgaramond-math.lfg b/tex/context/fonts/mkiv/ebgaramond-math.lfg
index afdd66279..43bafadd1 100644
--- a/tex/context/fonts/mkiv/ebgaramond-math.lfg
+++ b/tex/context/fonts/mkiv/ebgaramond-math.lfg
@@ -22,9 +22,15 @@ return {
-- RadicalRuleThickness = 50, -- 50 in font
DelimiterPercent = 90,
DelimiterShortfall = 400,
+ SubscriptShiftDown = 200, -- 250 in font
+ SuperscriptShiftUp = 400, -- 430 in font
+ SubscriptShiftDownWithSuperscript = "1.25*SubscriptShiftDown", -- trial and error
+ SubSuperscriptGapMin = 200, -- 250 in font
-- DisplayOperatorMinHeight = 1800, -- 1300 in font (only one)
- PrimeRaisePercent = 85, -- 50 default
- -- PrimeRaiseComposedPercent = 25, -- 25 default
+ -- PrimeRaisePercent = 0, -- set to 0 in math-act
+ -- PrimeRaiseComposedPercent = 25, -- set to 0 in math-act
+ PrimeShiftUp = "1.2*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.2*SuperscriptShiftUp",
},
tweaks = {
aftercopying = {
@@ -34,9 +40,9 @@ return {
},
{
tweak = "fixprimes",
- scale = 0.95,
+ -- scale = 1,
-- smaller = true,
- factor = 0.95,
+ factor = 0.73,
-- fake = 0.75,
},
{
@@ -232,6 +238,9 @@ return {
tweak = "addfourier",
variant = 2,
},
+ {
+ tweak = "addprimed",
+ },
-- this is the mkiv section
{
tweak = "emulatelmtx",
diff --git a/tex/context/fonts/mkiv/erewhon-math.lfg b/tex/context/fonts/mkiv/erewhon-math.lfg
index cf2e7f28c..0cb72d149 100644
--- a/tex/context/fonts/mkiv/erewhon-math.lfg
+++ b/tex/context/fonts/mkiv/erewhon-math.lfg
@@ -22,14 +22,19 @@ return {
DelimiterPercent = 90,
DelimiterShortfall = 400,
-- DisplayOperatorMinHeight = 1800, -- 1300 in font (one size)
+ SubscriptShiftDown = 200, -- 220 in font
+ SuperscriptShiftUp = 400, -- 400 in font
+ SubscriptShiftDownWithSuperscript = "1.2*SubscriptShiftDown", -- unclear original value, trial and error
+ PrimeShiftUp = "1.1*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.1*SuperscriptShiftUp",
},
tweaks = {
aftercopying = {
{
tweak = "fixprimes",
-- smaller = true, -- replace multiples
- factor = 0.9,
- scale = 1.0,
+ factor = 0.94 ,
+ -- scale = 1.0,
fake = 0.85, -- replace multiples with this width proportion
},
{
@@ -72,6 +77,7 @@ return {
["0x27E9.variants.*"] = { topright = -0.2, bottomright = -0.2 },
[0x27EB] = { topright = -0.1, bottomright = -0.1 },
["0x27EB.variants.*"] = { topright = -0.2, bottomright = -0.2 },
+ [0x00393] = { bottomright = -0.30, }, -- upright Gamma
},
},
{
@@ -114,6 +120,9 @@ return {
variant = 2,
},
{
+ tweak = "addprimed",
+ },
+ {
tweak = "setoptions",
-- set = { "ignorekerndimensions" }
},
diff --git a/tex/context/fonts/mkiv/kpfonts-math.lfg b/tex/context/fonts/mkiv/kpfonts-math.lfg
index 385170aab..7cb968860 100644
--- a/tex/context/fonts/mkiv/kpfonts-math.lfg
+++ b/tex/context/fonts/mkiv/kpfonts-math.lfg
@@ -21,8 +21,11 @@ return {
DelimiterPercent = 90,
DelimiterShortfall = 400,
-- DisplayOperatorMinHeight = 1800, -- 1500 in font (only one)
- PrimeRaisePercent = 25, -- 50 default
- -- PrimeRaiseComposedPercent = 25, -- 25 default
+ -- PrimeRaisePercent = 25, -- set to 0 in math-act
+ -- PrimeRaiseComposedPercent = 25, -- set to 0 in math-act
+ PrimeShiftUp = "1.15*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.15*SuperscriptShiftUp",
+ SubscriptShiftDownWithSuperscript = "1.2*SubscriptShiftDown", -- unclear original value, trial and error
},
tweaks = {
aftercopying = {
@@ -54,7 +57,7 @@ return {
},
{
tweak = "fixprimes",
- factor = 1.4, -- accent base height
+ factor = 0.86, -- accent base height
smaller = true, -- replace multiples
scale = 1, -- glyph scale
fake = 0.8, -- replace multiples with this width proportion
@@ -142,6 +145,9 @@ return {
variant = 2,
},
{
+ tweak = "addprimed",
+ },
+ {
tweak = "setoptions",
set = { "ignorekerndimensions" }
},
diff --git a/tex/context/fonts/mkiv/libertinus-math.lfg b/tex/context/fonts/mkiv/libertinus-math.lfg
index 71863fb59..30f8f6456 100644
--- a/tex/context/fonts/mkiv/libertinus-math.lfg
+++ b/tex/context/fonts/mkiv/libertinus-math.lfg
@@ -4,7 +4,6 @@
-- fix-feature or just disable ssty, but we have to revert to a runtime fix. Lucky me that I didn't
-- remove that hardly needed 'tweaks' mechanism yet.
--- The italic x has a rectangular piece in its eye (redundant point)
local common = fonts.goodies.load("common-math.lfg")
local presets = common.mathematics.tweaks.presets
@@ -34,8 +33,10 @@ return {
DelimiterPercent = 90,
DelimiterShortfall = 400,
-- DisplayOperatorMinHeight = 1800, -- 1250 in font (only one)
- PrimeRaisePercent = 70, -- 50 default
- PrimeRaiseComposedPercent = 10, -- 25 default
+ -- PrimeRaisePercent = 70, -- set to 0 in math-act
+ -- PrimeRaiseComposedPercent = 10, -- set to 0 in math-act
+ PrimeShiftUp = "1.2*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.2*SuperscriptShiftUp",
},
tweaks = {
aftercopying = {
@@ -88,7 +89,8 @@ return {
["0x27E9.variants.*"] = { topright = -0.2, bottomright = -0.2 },
[0x27EB] = { topright = -0.1, bottomright = -0.1 },
["0x27EB.variants.*"] = { topright = -0.2, bottomright = -0.2 },
-
+ --
+ [0x00393] = { bottomright = -0.30, }, -- upright Gamma
},
},
-- Accents are a mess. We migrate the extensibles from the combiners to the base accent
@@ -157,10 +159,10 @@ return {
{
tweak = "fixprimes",
- scale = 0.9,
+ -- scale = 1,
-- smaller = true,
- factor = 0.9,
- fake = 0.8,
+ factor = 0.92,
+ fake = 0.75,
},
{
tweak = "checkspacing",
@@ -189,6 +191,9 @@ return {
variant = 1,
},
{
+ tweak = "addprimed",
+ },
+ {
-- needed for integrals (bad axis) and (less prominent) fences
tweak = "setoptions",
set = { "ignorekerndimensions" }
diff --git a/tex/context/fonts/mkiv/lucida-math.lfg b/tex/context/fonts/mkiv/lucida-math.lfg
index 6842d505b..f0ab84b8b 100644
--- a/tex/context/fonts/mkiv/lucida-math.lfg
+++ b/tex/context/fonts/mkiv/lucida-math.lfg
@@ -28,9 +28,11 @@ return {
DelimiterPercent = 90,
DelimiterShortfall = 400,
-- DisplayOperatorMinHeight = 1800, -- 1300 in font (only one)
- PrimeRaisePercent = 60, -- 50 default
- PrimeRaiseComposedPercent = 50, -- 25 default
- AxisHeight = 325, -- we keep the old fonts as they are (also for demos)
+ SuperscriptBottomMaxWithSubscript = 325,
+ -- PrimeRaisePercent = 60, -- set to 0 in math-act
+ -- PrimeRaiseComposedPercent = 50, -- set to 0 in math-act
+ PrimeShiftUp = "1.4*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.4*SuperscriptShiftUp",
},
tweaks = {
aftercopying = {
@@ -217,12 +219,13 @@ return {
},
},
{
- tweak = "fixprimes",
- factor = 0.8, -- accent base height
- -- smaller = true, -- replace multiples
- scale = 1.1, -- glyph scale
- fake = 0.65, -- replace multiples with this width proportion
- -- keep = true, -- keep the text size prime (aka minute)
+ tweak = "fixprimes",
+ -- factor = 0.75, -- accent base height
+ factor = 0.7, -- accent base height
+ -- smaller = true, -- replace multiples
+ -- scale = 1.1, -- glyph scale
+ fake = 0.65, -- replace multiples with this width proportion
+ -- keep = true, -- keep the text size prime (aka minute)
},
{
tweak = "checkspacing",
@@ -245,6 +248,9 @@ return {
variant = 1,
},
{
+ tweak = "addprimed",
+ },
+ {
tweak = "addarrows",
left = 0.1,
right = 0.1,
diff --git a/tex/context/fonts/mkiv/minion-math.lfg b/tex/context/fonts/mkiv/minion-math.lfg
index 82b0b0c33..dfc2251ec 100644
--- a/tex/context/fonts/mkiv/minion-math.lfg
+++ b/tex/context/fonts/mkiv/minion-math.lfg
@@ -39,9 +39,12 @@ return {
-- DisplayOperatorMinHeight = 1900, -- 1250 in font
-- AccentSuperscriptDrop = 100,
-- AccentSuperscriptPercent = 20,
- PrimeRaisePercent = 50, -- 50 default
- PrimeRaiseComposedPercent = 25, -- 25 default
- -- PrimeShiftUp = 0,
+ SubscriptShiftDown = 200, -- 250 in font
+ SubscriptShiftDownWithSuperscript = "1.4*SubscriptShiftDown", -- 1.5* in math-act
+ -- PrimeRaisePercent = 50, -- set to 0 in math-act
+ -- PrimeRaiseComposedPercent = 25, -- set to 0 in math-act
+ PrimeShiftUp = "1.15*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.15*SuperscriptShiftUp",
-- PrimeBaselineDropMax = 0,
-- RadicalKernAfterExtensible = 100, -- 0 default
-- RadicalKernBeforeExtensible = 100, -- 0 default
@@ -65,6 +68,38 @@ return {
presets.moveitalics { correct = true, letters = true },
presets.moveintegrals { factor = 1.3 },
presets.wipeitalics { },
+
+ {
+ tweak = "kerns",
+ list = {
+ [0x002F] = { topleft = -0.2, bottomright = -0.2 },
+ ["0x002F.variants.*"] = { topleft = -0.2, bottomright = -0.2 },
+ -- No!
+ -- [0x0028] = { topleft = -0.1, bottomleft = -0.1 }, -- left parenthesis
+ -- [0x0029] = { topright = -0.1, bottomright = -0.1, all = true }, -- right parenthesis
+ --
+ [0x007D] = { topright = -0.05, bottomright = -0.05 }, -- right brace variants
+ ["0x7D.variants.*"] = { topright = -0.10, bottomright = -0.10 }, -- right brace variants
+ ["0x7D.parts.top"] = { topright = -0.10, }, -- right brace top
+ ["0x7D.parts.bottom"] = { bottomright = -0.10 }, -- right brace bottom
+ [0x0029] = { topright = -0.15, bottomright = -0.15 }, -- right parenthesis variants
+ ["0x29.variants.*"] = { topright = -0.15, bottomright = -0.15 }, -- right parenthesis variants
+ ["0x29.parts.top"] = { topright = -0.15, }, -- right parenthesis top
+ ["0x29.parts.bottom"] = { bottomright = -0.15 }, -- right parenthesis bottom
+ [0x221A] = { topright = 0.2, bottomright = 0.2 }, -- radical
+ ["0x221A.variants.*"] = { topright = 0.2, bottomright = 0.2 },
+ ["0x221A.parts.top"] = { topright = 0.2, },
+ ["0x221A.parts.bottom"] = { bottomright = 0.2 },
+ [0x27E9] = { topright = -0.1, bottomright = -0.1 }, -- angle
+ ["0x27E9.variants.*"] = { topright = -0.3, bottomright = -0.3 },
+ [0x27EB] = { topright = -0.1, bottomright = -0.1 },
+ ["0x27EB.variants.*"] = { topright = -0.2, bottomright = -0.2 },
+ -- Keep as example. not needed in cambria (after all it is the reference):
+ [0x2A0C] = { bottomright = -0.1 }, -- iiiint does not have any ic
+ },
+ },
+
+
{
tweak = "simplifykerns",
},
@@ -96,8 +131,8 @@ return {
},
{
tweak = "fixprimes",
- factor = 0.95,
- scale = 0.9,
+ factor = 1,
+ -- scale = 0.9,
},
-- {
-- tweak = "checkspacing",
@@ -115,6 +150,9 @@ return {
tweak = "addfourier",
variant = 1,
},
+ {
+ tweak = "addprimed",
+ },
-- this is the mkiv section
{
tweak = "emulatelmtx",
diff --git a/tex/context/fonts/mkiv/modern-math.lfg b/tex/context/fonts/mkiv/modern-math.lfg
index 509e5a7da..4c433702c 100644
--- a/tex/context/fonts/mkiv/modern-math.lfg
+++ b/tex/context/fonts/mkiv/modern-math.lfg
@@ -26,14 +26,22 @@ return {
DelimiterPercent = 90,
DelimiterShortfall = 400,
-- DisplayOperatorMinHeight = 1800, -- 1300 in font (only one)
- PrimeRaisePercent = 60,
- PrimeRaiseComposedPercent = 15,
- -- SubSuperscriptGapMin = 160, -- 160 in font
- SuperscriptBaselineDropMax = 250, -- 250 in font
- -- SuperscriptBottomMaxWithSubscript = 344, -- 344 in font
- -- SuperscriptBottomMin = 108, -- 108 in font
- SuperscriptShiftUp = 363, -- 363 in font
- SuperscriptShiftUpCramped = 89, -- 289 in font
+ -- SubSuperscriptGapMin = 160, -- 160 in font (4*ruleheight)
+ -- SubscriptBaselineDropMin = 50, -- 200 in font (multiplied by 0.59999/2.39868)
+ SubscriptShiftDown = 150, -- 247 in font (multiplied to be consistent with cm)
+ SubscriptShiftDownWithSuperscript = 247, -- relates to the previous one (see math-act)
+ -- SubscriptTopMax = 344, -- 344 in font .8 exheight
+ -- SuperscriptBaselineDropMax = 386, -- 250 in font (multiplied by 4.6333/2.99 (values in cm/values in lm)) 0 means: align the baseline of the superscript at the (top)
+ SuperscriptBaselineDropMax = 0.6*431, -- 250 in font (multiplied by 4.6333/2.99 (values in cm/values in lm))
+ SubscriptBaselineDropMin = 0.1*431, -- 200 in font
+ -- SuperscriptBottomMaxWithSubscript = 344, -- 344 in font .8 exheight
+ -- SuperscriptBottomMin = 108, -- 108 in font .25 exheight
+ SuperscriptShiftUp = 413, -- 363 in font (multiplied with 4.9547/4.3536, got 413)
+ SuperscriptShiftUpCramped = 413, -- 289 in font (no distinction, old TeX)
+ PrimeShiftUp = "1.1*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.1*SuperscriptShiftUp",
+ -- PrimeRaisePercent = 0,
+ -- PrimeRaiseComposedPercent = 25,
},
tweaks = {
aftercopying = {
@@ -53,7 +61,7 @@ return {
presets.fallbacks { },
presets.moveitalics { correct = true },
presets.moveitalics { correct = true, letters = true },
- presets.moveintegrals { factor = 1.4 },
+ presets.moveintegrals { factor = 1.4, icfactor = 0.8 }, -- the icfactor is due to the very slanted integral.
presets.wipeanchors { },
presets.wipeitalics { },
-- these will become moveanchors
@@ -279,6 +287,8 @@ return {
[0x1D4B4] = { bottomright = -0.18, }, -- script Y
[0x1D4B5] = { bottomright = -0.05, }, -- script Z
--
+ [0x00393] = { bottomright = -0.20, }, -- upright Gamma
+ --
["0x7D.parts.top"] = { topright = -0.25 }, -- right brace top
["0x7D.parts.bottom"] = { bottomright = -0.25 }, -- right brace bottom
["0x7D.variants.*"] = { topright = -0.25, bottomright = -0.25 }, -- right brace variants
@@ -376,9 +386,9 @@ return {
},
{
tweak = "fixprimes",
- factor = 1.05,
+ factor = 0.825,
-- smaller = true,
- scale = 0.9,
+ -- scale = 1,
-- fake = 0.6,
},
{
@@ -411,6 +421,9 @@ return {
variant = 1,
},
{
+ tweak = "addprimed",
+ },
+ {
tweak = "addequals",
},
-- {
diff --git a/tex/context/fonts/mkiv/newcomputermodern-math.lfg b/tex/context/fonts/mkiv/newcomputermodern-math.lfg
index 2e0c3169d..bf818b077 100644
--- a/tex/context/fonts/mkiv/newcomputermodern-math.lfg
+++ b/tex/context/fonts/mkiv/newcomputermodern-math.lfg
@@ -70,6 +70,19 @@ return {
DelimiterPercent = 90,
DelimiterShortfall = 400,
-- DisplayOperatorMinHeight = 1800, -- 1300 in font (only one)
+ -- Borrow values from lm:
+ -- SubSuperscriptGapMin = 160, -- 160 in font (4*ruleheight)
+ SubscriptBaselineDropMin = 50, -- 200 in font (multiplied by 0.59999/2.39868)
+ SubscriptShiftDown = 150, -- 247 in font (multiplied to be consistent with cm)
+ SubscriptShiftDownWithSuperscript = 247, -- relates to the previous one (see math-act)
+ -- SubscriptTopMax = 344, -- 344 in font .8 exheight
+ SuperscriptBaselineDropMax = 386, -- 250 in font (multiplied by 4.6333/2.99 (values in cm/values in lm))
+ -- SuperscriptBottomMaxWithSubscript = 344, -- 344 in font .8 exheight
+ -- SuperscriptBottomMin = 108, -- 108 in font .25 exheight
+ SuperscriptShiftUp = 413, -- 363 in font (multiplied with 4.9547/4.3536, got 413)
+ SuperscriptShiftUpCramped = 413, -- 289 in font (no distinction, old TeX)
+ PrimeShiftUp = "1.1*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.1*SuperscriptShiftUp",
},
tweaks = {
aftercopying = {
@@ -83,13 +96,36 @@ return {
-- nothing yet
},
},
- -- {
- -- tweak = "fixprimes",
- -- factor = 0.85,
- -- smaller = true,
- -- scale = 0.70,
- -- fake = 0.6,
- -- },
+ {
+ tweak = "fixprimes",
+ factor = 0.825,
+ smaller = true,
+ -- scale = 0.70,
+ fake = 0.6,
+ },
+ {
+ tweak = "kerns",
+ list = {
+ [0x0002F] = { topleft = -0.2, bottomright = -0.2 }, -- solidus
+ --
+ [0x00393] = { bottomright = -0.20, }, -- upright Gamma
+ --
+ ["0x7D.parts.top"] = { topright = -0.25 }, -- right brace top
+ ["0x7D.parts.bottom"] = { bottomright = -0.25 }, -- right brace bottom
+ ["0x7D.variants.*"] = { topright = -0.25, bottomright = -0.25 }, -- right brace variants
+ ["0x29.parts.top"] = { topright = -0.3, }, -- right parenthesis top
+ ["0x29.parts.bottom"] = { bottomright = -0.3 }, -- right parenthesis bottom
+ ["0x29.variants.*"] = { topright = -0.25, bottomright = -0.25 }, -- right parenthesis variants
+ ["0x221A.parts.top"] = { topright = 0.2, }, -- right radical top
+ ["0x221A.parts.bottom"] = { bottomright = 0.2 }, -- right radical bottom
+ ["0x221A.variants.*"] = { topright = 0.2, bottomright = 0.2 }, -- right radical variants
+ [0x27E9] = { topright = -0.2, bottomright = -0.2 }, -- angles
+ ["0x27E9.variants.*"] = { topright = -0.3, bottomright = -0.3 },
+ [0x27EB] = { topright = -0.2, bottomright = -0.2 },
+ ["0x27EB.variants.*"] = { topright = -0.3, bottomright = -0.3 },
+
+ },
+ },
{
tweak = "checkspacing",
},
@@ -105,6 +141,13 @@ return {
{
tweak = "addrules",
},
+ {
+ tweak = "addfourier",
+ variant = 1,
+ },
+ {
+ tweak = "addprimed",
+ },
},
},
bigs = {
diff --git a/tex/context/fonts/mkiv/pagella-math.lfg b/tex/context/fonts/mkiv/pagella-math.lfg
index 8c60759ab..4df58ad3b 100644
--- a/tex/context/fonts/mkiv/pagella-math.lfg
+++ b/tex/context/fonts/mkiv/pagella-math.lfg
@@ -28,10 +28,15 @@ return {
DelimiterPercent = 90,
DelimiterShortfall = 400,
DisplayOperatorMinHeight = 1800, -- 1500 in font
- PrimeRaisePercent = 75, -- 50 default
- PrimeRaiseComposedPercent = 10, -- 25 default
-- RadicalKernAfterExtensible = 0, -- 0 default
-- RadicalKernBeforeExtensible = 0, -- 0 default
+ SuperscriptShiftUp = 386, -- 354 in font
+ SubscriptShiftDown = 200, -- 232 in font
+ SubscriptShiftDownWithSuperscript = "1.4*SubscriptShiftDown", -- 1.5* in math-act
+ -- PrimeRaisePercent = 75, -- set to 0 in math-act
+ -- PrimeRaiseComposedPercent = 10, -- set to 0 in math-act
+ PrimeShiftUp = "1.3*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.3*SuperscriptShiftUp",
},
tweaks = {
aftercopying = {
@@ -41,9 +46,10 @@ return {
},
{
tweak = "fixprimes",
- factor = 0.9,
+ -- factor = 0.7,
+ factor = 0.8,
-- smaller = true,
- scale = 0.9,
+ -- scale = 1,
-- fake = 0.65,
},
{
@@ -190,6 +196,8 @@ return {
[0x27EB] = { topright = -0.2, bottomright = -0.2 },
["0x27EB.variants.*"] = { topright = -0.3, bottomright = -0.3 },
--
+ [0x00393] = { bottomright = -0.20, }, -- upright Gamma
+ --
["0x222B.parts.bottom"] = { bottomright = -0.20 }, -- int
["0x222C.parts.bottom"] = { bottomright = -0.15 }, -- iint
["0x222D.parts.bottom"] = { bottomright = -0.10 }, -- iiint
@@ -238,6 +246,9 @@ return {
variant = 1,
},
{
+ tweak = "addprimed",
+ },
+ {
tweak = "kernpairs",
list = {
-- beware: we kept the italic correction in spite of punctuation class
diff --git a/tex/context/fonts/mkiv/schola-math.lfg b/tex/context/fonts/mkiv/schola-math.lfg
index 8666690da..d1711bce0 100644
--- a/tex/context/fonts/mkiv/schola-math.lfg
+++ b/tex/context/fonts/mkiv/schola-math.lfg
@@ -25,8 +25,11 @@ return {
DelimiterPercent = 90,
DelimiterShortfall = 400,
DisplayOperatorMinHeight = 1800, -- 1333 in font
- -- PrimeRaisePercent = 50, -- 50 default
- PrimeRaiseComposedPercent = 10, -- 25 default
+ -- PrimeRaisePercent = 50, -- set to 0 in math-act
+ -- PrimeRaiseComposedPercent = 10, -- set to 0 in math-act
+ PrimeShiftUp = "1.35*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.35*SuperscriptShiftUp",
+ -- Can be improved: Smaller script and scriptscript, modified SuperShiftUp and SubShiftDown, ...
},
tweaks = {
aftercopying = {
@@ -36,9 +39,9 @@ return {
},
{
tweak = "fixprimes",
- scale = 0.85,
+ -- scale = 0.95,
-- smaller = true,
- factor = 1,
+ factor = 0.74,
},
{
tweak = "addmirrors",
@@ -176,6 +179,9 @@ return {
-- scale = 1.25,
variant = 1,
},
+ {
+ tweak = "addprimed",
+ },
-- this is the mkiv section
{
tweak = "emulatelmtx",
diff --git a/tex/context/fonts/mkiv/stixtwo-math.lfg b/tex/context/fonts/mkiv/stixtwo-math.lfg
index 8e5489830..dadc70067 100644
--- a/tex/context/fonts/mkiv/stixtwo-math.lfg
+++ b/tex/context/fonts/mkiv/stixtwo-math.lfg
@@ -42,8 +42,10 @@ return {
DelimiterPercent = 90,
DelimiterShortfall = 400,
DisplayOperatorMinHeight = 1800, -- 1800 in font
- PrimeRaisePercent = 75, -- 50 default
- PrimeRaiseComposedPercent = 10, -- 25 default
+ -- PrimeRaisePercent = 75, -- set to 0 in math-act
+ -- PrimeRaiseComposedPercent = 10, -- set to 0 in math-act
+ PrimeShiftUp = "1.3*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.3*SuperscriptShiftUp",
},
tweaks = {
aftercopying = {
@@ -53,9 +55,7 @@ return {
},
{
tweak = "fixprimes",
- scale = 1,
- -- smaller = true,
- factor = 1,
+ factor = 0.84,
},
{
tweak = "addmirrors",
@@ -82,11 +82,11 @@ return {
presets.moderntocalligraphic { },
presets.eulertocalligraphic { },
presets.xitsarabic { rscale = 0.95 },
- presets.fallbacks { },
+ presets.fallbacks { },
presets.moveitalics { correct = true },
- presets.moveitalics { correct = true, letters = true },
+ presets.moveitalics { correct = true, letters = true },
presets.moveintegrals { },
- presets.wipeitalics { },
+ presets.wipeitalics { },
{
tweak = "simplifykerns",
},
@@ -216,6 +216,9 @@ return {
variant = 1,
},
{
+ tweak = "addprimed",
+ },
+ {
tweak = "addparts",
list = {
[0x21F4] = {
diff --git a/tex/context/fonts/mkiv/termes-math.lfg b/tex/context/fonts/mkiv/termes-math.lfg
index cd4536b55..cff3090a9 100644
--- a/tex/context/fonts/mkiv/termes-math.lfg
+++ b/tex/context/fonts/mkiv/termes-math.lfg
@@ -24,8 +24,15 @@ return {
DelimiterPercent = 90,
DelimiterShortfall = 400,
DisplayOperatorMinHeight = 1800, -- 1300 in font (only one)
- PrimeRaisePercent = 60, -- 50 default
- PrimeRaiseComposedPercent = 10, -- 25 default
+ -- ScriptPercentScaleDown = 70, -- 74 in font (set in typescript)
+ -- ScriptScriptPercentScaleDown = 50, -- 50 in font (set in typescript)
+ SuperscriptShiftUp = 310, -- 339
+ SubscriptShiftDown = 200, -- 222
+ SubscriptShiftDownWithSuperscript = "1.4*SubscriptShiftDown", -- 1.5* in math-act
+ -- PrimeRaisePercent = 60, -- set to 0 in math-act
+ -- PrimeRaiseComposedPercent = 10, -- set to 0 in math-act
+ PrimeShiftUp = "1.35*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.35*SuperscriptShiftUp",
},
tweaks = {
aftercopying = {
@@ -35,9 +42,9 @@ return {
},
{
tweak = "fixprimes",
- scale = 0.85,
+ -- scale = 0.9,
-- smaller = true,
- factor = 0.95,
+ factor = 0.76,
},
{
tweak = "addmirrors",
@@ -71,6 +78,8 @@ return {
[0x27EB] = { topright = -0.1, bottomright = -0.1 },
["0x27EB.variants.*"] = { topright = -0.2, bottomright = -0.2 },
--
+ [0x00393] = { bottomright = -0.20, }, -- upright Gamma
+ --
["0x222B.parts.bottom"] = { bottomright = -0.20 }, -- int
["0x222C.parts.bottom"] = { bottomright = -0.15 }, -- iint
["0x222D.parts.bottom"] = { bottomright = -0.10 }, -- iiint
diff --git a/tex/context/fonts/mkiv/type-imp-dejavu.mkiv b/tex/context/fonts/mkiv/type-imp-dejavu.mkiv
index d6fe406fb..49b788a73 100644
--- a/tex/context/fonts/mkiv/type-imp-dejavu.mkiv
+++ b/tex/context/fonts/mkiv/type-imp-dejavu.mkiv
@@ -45,8 +45,8 @@
\stoptypescript
\starttypescript [\s!math] [dejavu,dejavu-nt,dejavu-condensed]
- \checkedmapfontsize[\typescripttwo][\s!script] [.80]
- \checkedmapfontsize[\typescripttwo][\s!scriptscript][.65]
+ \checkedmapfontsize[\typescripttwo][\s!script] [.70]%.80
+ \checkedmapfontsize[\typescripttwo][\s!scriptscript][.55]%.65
\stoptypescript
\starttypescript [\s!math] [dejavu] [\s!name]
diff --git a/tex/context/fonts/mkiv/type-imp-modernlatin.mkiv b/tex/context/fonts/mkiv/type-imp-modernlatin.mkiv
index f62855a59..c10ffa54e 100644
--- a/tex/context/fonts/mkiv/type-imp-modernlatin.mkiv
+++ b/tex/context/fonts/mkiv/type-imp-modernlatin.mkiv
@@ -83,9 +83,9 @@
\stoptypescript
\starttypescript [\s!math] [modernlatin,modern-latin,lessmodernlatin,less-modern-latin]
- \loadfontgoodies[lm]
- \definefontsynonym [MathRoman] [\v!file:latinmodern-math-regular.otf] [\s!features={\s!math\mathsizesuffix,lm-math,lm-math-regular,mathextra},\s!goodies=lm]
- \definefontsynonym [MathRomanBold] [\v!file:latinmodern-math-regular.otf] [\s!features={\s!math\mathsizesuffix,lm-math,lm-math-bold,mathextra},\s!goodies=lm]
+ \loadfontgoodies[modern-math]
+ \definefontsynonym [MathRoman] [\v!file:latinmodern-math.otf] [\s!features={\s!math\mathsizesuffix,lm-math,lm-math-regular,mathextra},\s!goodies=modern-math]
+ \definefontsynonym [MathRomanBold] [\v!file:latinmodern-math.otf] [\s!features={\s!math\mathsizesuffix,lm-math,lm-math-bold,mathextra},\s!goodies=modern-math]
\stoptypescript
\starttypescript [modern-latin,modernlatin,less-modern-latin,lessmodernlatin]
diff --git a/tex/context/fonts/mkiv/type-imp-newcomputermodern.mkiv b/tex/context/fonts/mkiv/type-imp-newcomputermodern.mkiv
index 73f7c4dbf..65a84ec5f 100644
--- a/tex/context/fonts/mkiv/type-imp-newcomputermodern.mkiv
+++ b/tex/context/fonts/mkiv/type-imp-newcomputermodern.mkiv
@@ -49,8 +49,8 @@
\starttypescript [\s!math][newcomputermodern] [\s!name]
% \loadfontgoodies[newcomputermodern-math] ,\s!goodies=newcomputermodern-math
- \definefontsynonym[\s!MathRoman] [\s!file:newcmmath-regular][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=lm]
- \definefontsynonym[\s!MathRomanBold][\s!file:newcmmath-regular][\s!features={\s!math\mathsizesuffix,newcomputermodern-math-bold,mathextra},\s!goodies=lm]
+ \definefontsynonym[\s!MathRoman] [\s!file:newcmmath-regular][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=newcomputermodern-math]
+ \definefontsynonym[\s!MathRomanBold][\s!file:newcmmath-regular][\s!features={\s!math\mathsizesuffix,newcomputermodern-math-bold,mathextra},\s!goodies=newcomputermodern-math]
\stoptypescript
\starttypescript [\s!serif] [newcomputermodern-book] [\s!name]
@@ -79,8 +79,8 @@
\starttypescript [\s!math][newcomputermodern-book] [\s!name]
% \loadfontgoodies[newcomputermodern-math] ,\s!goodies=newcomputermodern-math
- \definefontsynonym[\s!MathRoman] [\s!file:newcmmath-book][\s!features={\s!math\mathsizesuffix,newcm-mathextra,mathextra},\s!goodies=lm]
- \definefontsynonym[\s!MathRomanBold][\s!file:newcmmath-book][\s!features={\s!math\mathsizesuffix,newcm-mathextra,newcomputermodern-math-bold,mathextra},\s!goodies=lm]
+ \definefontsynonym[\s!MathRoman] [\s!file:newcmmath-book][\s!features={\s!math\mathsizesuffix,newcm-mathextra,mathextra},\s!goodies=newcomputermodern-math]
+ \definefontsynonym[\s!MathRomanBold][\s!file:newcmmath-book][\s!features={\s!math\mathsizesuffix,newcm-mathextra,newcomputermodern-math-bold,mathextra},\s!goodies=newcomputermodern-math]
\stoptypescript
\starttypescript[newcomputermodern,newcomputermodern-book]
diff --git a/tex/context/fonts/mkiv/type-imp-texgyre.mkiv b/tex/context/fonts/mkiv/type-imp-texgyre.mkiv
index 87009f11e..a3f3952c7 100644
--- a/tex/context/fonts/mkiv/type-imp-texgyre.mkiv
+++ b/tex/context/fonts/mkiv/type-imp-texgyre.mkiv
@@ -281,8 +281,8 @@
\starttypescriptcollection[texgyre-math-termes]
\starttypescript [\s!math][termes,termes-nt,times][\s!all]
- \checkedmapfontsize[\typescripttwo][\s!script] [.74]
- \checkedmapfontsize[\typescripttwo][\s!scriptscript][.55]
+ \checkedmapfontsize[\typescripttwo][\s!script] [.70]%.74
+ \checkedmapfontsize[\typescripttwo][\s!scriptscript][.50]%.55
\stoptypescript
\starttypescript [\s!math][termes,times][\s!all]
\definefontsynonym[\s!MathRoman] [file:texgyretermes-math.otf][\s!features={\s!math\mathsizesuffix,termes:mathextra,mathextra},\s!goodies=termes-math]
@@ -335,8 +335,8 @@
\starttypescriptcollection[texgyre-math-bonum]
\starttypescript [\s!math][bonum,bonum-nt,bookman][\s!all]
- \checkedmapfontsize[\typescripttwo][\s!script] [.77]
- \checkedmapfontsize[\typescripttwo][\s!scriptscript][.60]
+ \checkedmapfontsize[\typescripttwo][\s!script] [.70]%.77
+ \checkedmapfontsize[\typescripttwo][\s!scriptscript][.55]%.60
\stoptypescript
\starttypescript [\s!math][bonum,bookman][\s!all]
\definefontsynonym[\s!MathRoman] [file:texgyrebonum-math.otf][\s!features={\s!math\mathsizesuffix,bonum:mathextra,mathextra},\s!goodies=bonum-math]
diff --git a/tex/context/fonts/mkiv/xcharter-math.lfg b/tex/context/fonts/mkiv/xcharter-math.lfg
index be09720d1..c91ea6fa7 100644
--- a/tex/context/fonts/mkiv/xcharter-math.lfg
+++ b/tex/context/fonts/mkiv/xcharter-math.lfg
@@ -22,13 +22,17 @@ return {
-- DelimiterPercent = 90,
-- DelimiterShortfall = 400,
-- DisplayOperatorMinHeight = 1800, -- 1300 in font (one size)
+ SubscriptShiftDown = 200, -- 300 in font
+ SubscriptShiftDownWithSuperscript = "1.3*SubscriptShiftDown", -- 1.5* in math-act
+ PrimeShiftUp = "1.2*SuperscriptShiftUp",
+ PrimeShiftUpCramped = "1.2*SuperscriptShiftUp",
},
tweaks = {
aftercopying = {
{
tweak = "fixprimes",
- factor = 0.8,
- scale = 1,
+ factor = 0.92,
+ -- scale = 1,
},
{
tweak = "addmirrors",
@@ -70,6 +74,8 @@ return {
["0x27E9.variants.*"] = { topright = -0.2, bottomright = -0.2 },
[0x27EB] = { topright = -0.1, bottomright = -0.1 },
["0x27EB.variants.*"] = { topright = -0.2, bottomright = -0.2 },
+ --
+ [0x00393] = { bottomright = -0.20, }, -- upright Gamma
},
},
{
diff --git a/tex/context/modules/mkiv/s-fonts-variable.lua b/tex/context/modules/mkiv/s-fonts-variable.lua
index b84b78ada..e77903665 100644
--- a/tex/context/modules/mkiv/s-fonts-variable.lua
+++ b/tex/context/modules/mkiv/s-fonts-variable.lua
@@ -232,14 +232,16 @@ function moduledata.fonts.variable.showvariations(specification)
end
context.stopsubject()
- local sample = specification.sample
+ local sample = specification.sample
+ local features = specification.features or "default"
for i=1,#collected do
local instance = collected[i]
context.startsubject { title = instance }
+ local fontspecification = "name:" .. instance .. "*" .. features
context.start()
- context.definedfont { "name:" .. instance .. "*default" }
+ context.definedfont { fontspecification }
context.start()
if show_glyphs then
context.showglyphs()
@@ -247,6 +249,7 @@ function moduledata.fonts.variable.showvariations(specification)
if show_kerns then
context.showfontkerns()
end
+-- print("using",fontspecification)
if sample and sample ~= "" then
context(sample)
else
diff --git a/tex/context/modules/mkiv/s-fonts-variable.mkiv b/tex/context/modules/mkiv/s-fonts-variable.mkiv
index 43cb1d32c..d061179eb 100644
--- a/tex/context/modules/mkiv/s-fonts-variable.mkiv
+++ b/tex/context/modules/mkiv/s-fonts-variable.mkiv
@@ -132,4 +132,8 @@
% \showfontvariations[font=file:goldmansanscdvf_wght.ttf]
% \stoptext
+\showfontvariations
+ [font=file:nupuram-vf.otf,features=malayalam-two,sample=test നൂപുരം]
+% [font=file:nupuram-vf.ttf,features=malayalam-two,sample=test നൂപുരം]
+
\stoptext
diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua
index 376fa61db..eee1dc4e2 100644
--- a/tex/generic/context/luatex/luatex-fonts-merged.lua
+++ b/tex/generic/context/luatex/luatex-fonts-merged.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 : 2022-11-18 13:15
+-- merge date : 2022-12-01 12:38
do -- begin closure to overcome local limits and interference
@@ -11306,6 +11306,7 @@ if not modules then modules={} end modules ['font-otr']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
+local number=number
local next,type,tonumber,rawget=next,type,tonumber,rawget
local byte,lower,char,gsub=string.byte,string.lower,string.char,string.gsub
local fullstrip=string.fullstrip
@@ -12389,7 +12390,7 @@ end
function readers.cmap(f,fontdata,specification)
local tableoffset=gotodatatable(f,fontdata,"cmap",specification.glyphs)
if tableoffset then
- local version=readushort(f)
+ local version=readushort(f)
local noftables=readushort(f)
local records={}
local unicodecid=false
@@ -13050,6 +13051,10 @@ function readers.loadfont(filename,n,instance)
cidinfo=fontdata.cidinfo,
mathconstants=fontdata.mathconstants,
colorpalettes=fontdata.colorpalettes,
+ colorpaintdata=fontdata.colorpaintdata,
+ colorpaintlist=fontdata.colorpaintlist,
+ colorlinesdata=fontdata.colorlinesdata,
+ coloraffinedata=fontdata.coloraffinedata,
svgshapes=fontdata.svgshapes,
pngshapes=fontdata.pngshapes,
variabledata=fontdata.variabledata,
@@ -14833,20 +14838,7 @@ end
local n=0
for i=1,top do
if n==48 then
- local zero=encode[0]
- local res3=result[r-3]
- local res2=result[r-2]
- local res1=result[r-1]
- local res0=result[r]
- result[r-3]=zero
- result[r-2]=zero
r=r+1;result[r]=chars[t]
- r=r+1;result[r]=zero
- r=r+1;result[r]=zero
- r=r+1;result[r]=res3
- r=r+1;result[r]=res2
- r=r+1;result[r]=res1
- r=r+1;result[r]=res0
n=1
else
n=n+1
@@ -19275,9 +19267,10 @@ function readers.colr(f,fontdata,specification)
local tableoffset=gotodatatable(f,fontdata,"colr",specification.glyphs)
if tableoffset then
local version=readushort(f)
- if version~=0 then
+ if version==0 or version==1 then
report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"colr",fontdata.filename)
return
+ else
end
if not fontdata.tables.cpal then
report("color table %a in font %a has no mandate %a table","colr",fontdata.filename,"cpal")
@@ -20194,16 +20187,20 @@ local scripts=allocate {
["cari"]="carian",
["cham"]="cham",
["cher"]="cherokee",
+ ["chrs"]="chorasmian",
["copt"]="coptic",
+ ["cpmn"]="cypro-minoan",
["cprt"]="cypriot syllabary",
["cyrl"]="cyrillic",
["dev2"]="devanagari variant 2",
["deva"]="devanagari",
+ ["diak"]="dives akuru",
["dogr"]="dogra",
["dsrt"]="deseret",
["dupl"]="duployan",
["egyp"]="egyptian heiroglyphs",
["elba"]="elbasan",
+ ["elym"]="elymaic",
["ethi"]="ethiopic",
["geor"]="georgian",
["gjr2"]="gujarati variant 2",
@@ -20223,6 +20220,7 @@ local scripts=allocate {
["hebr"]="hebrew",
["hluw"]="anatolian hieroglyphs",
["hmng"]="pahawh hmong",
+ ["hmnp"]="nyiakeng puachue hmong",
["hung"]="old hungarian",
["ital"]="old italic",
["jamo"]="hangul jamo",
@@ -20232,6 +20230,7 @@ local scripts=allocate {
["khar"]="kharosthi",
["khmr"]="khmer",
["khoj"]="khojki",
+ ["kits"]="khitan small script",
["knd2"]="kannada variant 2",
["knda"]="kannada",
["kthi"]="kaithi",
@@ -20265,6 +20264,7 @@ local scripts=allocate {
["musc"]="musical symbols",
["mym2"]="myanmar variant 2",
["mymr"]="myanmar",
+ ["nand"]="nandinagari",
["narb"]="old north arabian",
["nbat"]="nabataean",
["newa"]="newa",
@@ -20274,9 +20274,10 @@ local scripts=allocate {
["olck"]="ol chiki",
["orkh"]="old turkic and orkhon runic",
["ory2"]="odia variant 2",
- ["orya"]="oriya",
+ ["orya"]="odia",
["osge"]="osage",
["osma"]="osmanya",
+ ["ougr"]="old uyghur",
["palm"]="palmyrene",
["pauc"]="pau cin hau",
["perm"]="old permic",
@@ -20308,7 +20309,7 @@ local scripts=allocate {
["tagb"]="tagbanwa",
["takr"]="takri",
["tale"]="tai le",
- ["talu"]="tai lu",
+ ["talu"]="new tai lue",
["taml"]="tamil",
["tang"]="tangut",
["tavt"]="tai viet",
@@ -20320,12 +20321,16 @@ local scripts=allocate {
["thai"]="thai",
["tibt"]="tibetan",
["tirh"]="tirhuta",
+ ["tnsa"]="tangsa",
["tml2"]="tamil variant 2",
+ ["toto"]="toto",
["ugar"]="ugaritic cuneiform",
["vai" ]="vai",
["wara"]="warang citi",
+ ["wcho"]="wancho",
["xpeo"]="old persian cuneiform",
["xsux"]="sumero-akkadian cuneiform",
+ ["yezi"]="yezidi",
["yi" ]="yi",
["zanb"]="zanabazar square",
}
@@ -20340,6 +20345,7 @@ local languages=allocate {
["agw" ]="agaw",
["aio" ]="aiton",
["aka" ]="akan",
+ ["akb" ]="batak angkola",
["als" ]="alsatian",
["alt" ]="altai",
["amh" ]="amharic",
@@ -20352,6 +20358,7 @@ local languages=allocate {
["asm" ]="assamese",
["ast" ]="asturian",
["ath" ]="athapaskan",
+ ["avn" ]="avatime",
["avr" ]="avar",
["awa" ]="awadhi",
["aym" ]="aymara",
@@ -20397,8 +20404,12 @@ local languages=allocate {
["brx" ]="bodo",
["bsh" ]="bashkir",
["bsk" ]="burushaski",
+ ["bta" ]="batak alas kluet",
+ ["btd" ]="batak dairi (pakpak)",
["bti" ]="beti",
+ ["btm" ]="batak mandailing",
["bts" ]="batak simalungun",
+ ["btx" ]="batak karo",
["bug" ]="bugis",
["byv" ]="medumba",
["cak" ]="kaqchikel",
@@ -20433,14 +20444,16 @@ local languages=allocate {
["csl" ]="church slavonic",
["csy" ]="czech",
["ctg" ]="chittagonian",
+ ["ctt" ]="wayanad chetti",
["cuk" ]="san blas kuna",
+ ["dag" ]="dagbani",
["dan" ]="danish",
["dar" ]="dargwa",
["dax" ]="dayi",
["dcr" ]="woods cree",
["deu" ]="german",
- ["dgo" ]="dogri",
- ["dgr" ]="dogri",
+ ["dgo" ]="dogri (individual language)",
+ ["dgr" ]="dogri (macro language)",
["dhg" ]="dhangu",
["dhv" ]="divehi (dhivehi, maldivian)",
["diq" ]="dimli",
@@ -20512,13 +20525,16 @@ local languages=allocate {
["guj" ]="gujarati",
["guz" ]="gusii",
["hai" ]="haitian (haitian creole)",
+ ["hai0"]="haida",
["hal" ]="halam",
["har" ]="harauti",
["hau" ]="hausa",
["haw" ]="hawaiian",
["hay" ]="haya",
["haz" ]="hazaragi",
+ ["hmz" ]="hmong shuat",
["hbn" ]="hammer-banna",
+ ["hei" ]="heiltsuk",
["her" ]="herero",
["hil" ]="hiligaynon",
["hin" ]="hindi",
@@ -20543,10 +20559,12 @@ local languages=allocate {
["ind" ]="indonesian",
["ing" ]="ingush",
["inu" ]="inuktitut",
+ ["inuk"]="nunavik inuktitut",
["ipk" ]="inupiat",
["ipph"]="phonetic transcription—ipa conventions",
["iri" ]="irish",
["irt" ]="irish traditional",
+ ["uri" ]="irula",
["isl" ]="icelandic",
["ism" ]="inari sami",
["ita" ]="italian",
@@ -20566,6 +20584,7 @@ local languages=allocate {
["kan" ]="kannada",
["kar" ]="karachay",
["kat" ]="georgian",
+ ["kaw" ]="kawi (old javanese)",
["kaz" ]="kazakh",
["kde" ]="makonde",
["kea" ]="kabuverdianu (crioulo)",
@@ -20623,6 +20642,7 @@ local languages=allocate {
["kur" ]="kurdish",
["kuu" ]="kurukh",
["kuy" ]="kuy",
+ ["kwk" ]="kwakʼwala",
["kyk" ]="koryak",
["kyu" ]="western kayah",
["lad" ]="ladin",
@@ -20634,6 +20654,7 @@ local languages=allocate {
["laz" ]="laz",
["lcr" ]="l-cree",
["ldk" ]="ladakhi",
+ ["lef" ]="lelemi",
["lez" ]="lezgi",
["lij" ]="ligurian",
["lim" ]="limburgish",
@@ -20646,6 +20667,7 @@ local languages=allocate {
["lmo" ]="lombard",
["lmw" ]="lomwe",
["lom" ]="loma",
+ ["lpo" ]="lipo",
["lrc" ]="luri",
["lsb" ]="lower sorbian",
["lsm" ]="lule sami",
@@ -20662,7 +20684,7 @@ local languages=allocate {
["mah" ]="marshallese",
["maj" ]="majang",
["mak" ]="makhuwa",
- ["mal" ]="malayalam reformed",
+ ["mal" ]="malayalam",
["mam" ]="mam",
["man" ]="mansi",
["map" ]="mapudungun",
@@ -20697,6 +20719,7 @@ local languages=allocate {
["mok" ]="moksha",
["mol" ]="moldavian",
["mon" ]="mon",
+ ["mnw" ]="thailand mon",
["mor" ]="moroccan",
["mos" ]="mossi",
["mri" ]="maori",
@@ -20735,7 +20758,7 @@ local languages=allocate {
["nor" ]="norwegian",
["nov" ]="novial",
["nsm" ]="northern sami",
- ["nso" ]="sotho, northern",
+ ["nso" ]="northern sotho",
["nta" ]="northern tai",
["nto" ]="esperanto",
["nym" ]="nyamwezi",
@@ -20783,6 +20806,7 @@ local languages=allocate {
["rbu" ]="russian buriat",
["rcr" ]="r-cree",
["rej" ]="rejang",
+ ["rhg" ]="rohingya",
["ria" ]="riang",
["rif" ]="tarifit",
["rit" ]="ritarungo",
@@ -20807,6 +20831,7 @@ local languages=allocate {
["scs" ]="north slavey",
["sek" ]="sekota",
["sel" ]="selkup",
+ ["sfm" ]="small flowery miao",
["sga" ]="old irish",
["sgo" ]="sango",
["sgs" ]="samogitian",
@@ -20828,7 +20853,7 @@ local languages=allocate {
["snk" ]="soninke",
["sog" ]="sodo gurage",
["sop" ]="songe",
- ["sot" ]="sotho, southern",
+ ["sot" ]="southern sotho",
["sqi" ]="albanian",
["srb" ]="serbian",
["srd" ]="sardinian",
@@ -20869,7 +20894,9 @@ local languages=allocate {
["tht" ]="tahitian",
["tib" ]="tibetan",
["tiv" ]="tiv",
+ ["tj;" ]="tai laing",
["tkm" ]="turkmen",
+ ["tli" ]="tlingit",
["tmh" ]="tamashek",
["tmn" ]="temne",
["tna" ]="tswana",
@@ -20883,7 +20910,7 @@ local languages=allocate {
["tsj" ]="tshangla",
["tua" ]="turoyo aramaic",
["tul" ]="tulu",
- ["tum" ]="tulu",
+ ["tum" ]="tumbuka",
["tuv" ]="tuvin",
["tvl" ]="tuvalu",
["twi" ]="twi",
@@ -20905,6 +20932,7 @@ local languages=allocate {
["wa" ]="wa",
["wag" ]="wagdi",
["war" ]="waray-waray",
+ ["wci" ]="waci gbe",
["wcr" ]="west-cree",
["wel" ]="welsh",
["wlf" ]="wolof",
@@ -20916,17 +20944,23 @@ local languages=allocate {
["xkf" ]="khengkha",
["xog" ]="soga",
["xpe" ]="kpelle (liberia)",
+ ["xub" ]="bette kuruma",
+ ["xuj" ]="jennu kuruma",
["yak" ]="sakha",
["yao" ]="yao",
["yap" ]="yapese",
["yba" ]="yoruba",
["ycr" ]="y-cree",
+ ["ygp" ]="gepo",
["yic" ]="yi classic",
["yim" ]="yi modern",
+ ["yna" ]="aluo",
+ ["ywq" ]="wuding-luquan",
["zea" ]="zealandic",
["zgh" ]="standard morrocan tamazigh",
["zha" ]="zhuang",
["zhh" ]="chinese, hong kong sar",
+ ["zho" ]="chinese traditional, macao",
["zhp" ]="chinese phonetic",
["zhs" ]="chinese simplified",
["zht" ]="chinese traditional",
@@ -20950,6 +20984,7 @@ local features=allocate {
["case"]="case-sensitive forms",
["ccmp"]="glyph composition/decomposition",
["cfar"]="conjunct form after ro",
+ ["chws"]="contextual half-width spacing",
["cjct"]="conjunct forms",
["clig"]="contextual ligatures",
["cpct"]="centered cjk punctuation",
@@ -21026,8 +21061,8 @@ local features=allocate {
["rtbd"]="right bounds",
["rtla"]="right-to-left alternates",
["rtlm"]="right to left mirrored forms",
- ["rvrn"]="required variation alternates",
["ruby"]="ruby notation forms",
+ ["rvrn"]="required variation alternates",
["salt"]="stylistic alternates",
["sinf"]="scientific inferiors",
["size"]="optical size",
@@ -21047,6 +21082,7 @@ local features=allocate {
["unic"]="unicase",
["valt"]="alternate vertical metrics",
["vatu"]="vattu variants",
+ ["vchw"]="vertical contextual half-width spacing",
["vert"]="vertical writing",
["vhal"]="alternate vertical half metrics",
["vjmo"]="vowel jamo forms",