diff options
Diffstat (limited to 'macros')
92 files changed, 3170 insertions, 2266 deletions
diff --git a/macros/luatex/generic/lualibs/NEWS b/macros/luatex/generic/lualibs/NEWS index 889232dc47..6117812375 100644 --- a/macros/luatex/generic/lualibs/NEWS +++ b/macros/luatex/generic/lualibs/NEWS @@ -1,4 +1,7 @@ History of the lualibs package +2023/07/13 v2.76/ + * sync with Context current as of 2023/07/13. + 2022/10/04 v2.75/ * sync with Context current as of 2022/10/04. * add util-sac diff --git a/macros/luatex/generic/lualibs/README.md b/macros/luatex/generic/lualibs/README.md index 09194115ce..f4f2e7162c 100644 --- a/macros/luatex/generic/lualibs/README.md +++ b/macros/luatex/generic/lualibs/README.md @@ -1,10 +1,10 @@ # The Lualibs Package -VERSION: 2.75 +VERSION: 2.76 -DATE: 2022-10-04 +DATE: 2023-07-13 -FONTLOADERDATE: 2022-10-04 +FONTLOADERDATE: 2023-07-13 Lualibs is a collection of Lua modules useful for general programming. diff --git a/macros/luatex/generic/lualibs/lualibs-basic-merged.lua b/macros/luatex/generic/lualibs/lualibs-basic-merged.lua index 690a3160ac..b201cfab04 100644 --- a/macros/luatex/generic/lualibs/lualibs-basic-merged.lua +++ b/macros/luatex/generic/lualibs/lualibs-basic-merged.lua @@ -1,6 +1,6 @@ -- merged file : lualibs-basic-merged.lua -- parent file : lualibs-basic.lua --- merge date : 2022-10-04 17:16 +-- merge date : 2023-07-13 12:55 do -- begin closure to overcome local limits and interference @@ -1274,7 +1274,7 @@ if not modules then modules={} end modules ['l-string']={ license="see context related readme files" } local string=string -local sub,gmatch,format,char,byte,rep,lower=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower +local sub,gmatch,format,char,byte,rep,lower,find=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower,string.find local lpegmatch,patterns=lpeg.match,lpeg.patterns local P,S,C,Ct,Cc,Cs=lpeg.P,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.Cs local unquoted=patterns.squote*C(patterns.nosquote)*patterns.squote+patterns.dquote*C(patterns.nodquote)*patterns.dquote @@ -1284,10 +1284,18 @@ end function string.quoted(str) return format("%q",str) end -function string.count(str,pattern) +function string.count(str,pattern) local n=0 - for _ in gmatch(str,pattern) do - n=n+1 + local i=1 + local l=#pattern + while true do + i=find(str,pattern,i) + if i then + n=n+1 + i=i+l + else + break + end end return n end @@ -4022,9 +4030,23 @@ function file.withinbase(path) end return true end -local symlinkattributes=lfs.symlinkattributes -function lfs.readlink(name) - return symlinkattributes(name,"target") or nil +do + local symlinktarget=lfs.symlinktarget + local symlinkattributes=lfs.symlinkattributes + if symlinktarget then + function lfs.readlink(name) + local target=symlinktarget(name) + return name~=target and name or nil + end + elseif symlinkattributes then + function lfs.readlink(name) + return symlinkattributes(name,"target") or nil + end + else + function lfs.readlink(name) + return nil + end + end end end -- closure @@ -4136,7 +4158,7 @@ dir=dir or {} local dir=dir local lfs=lfs local attributes=lfs.attributes -local walkdir=lfs.dir +local scandir=lfs.dir local isdir=lfs.isdir local isfile=lfs.isfile local currentdir=lfs.currentdir @@ -4167,6 +4189,15 @@ else lfs.isdir=isdir lfs.isfile=isfile end +local isreadable=file.isreadable +local walkdir=function(p,...) + if isreadable(p.."/.") then + return scandir(p,...) + else + return function() end + end +end +lfs.walkdir=walkdir function dir.current() return (gsub(currentdir(),"\\","/")) end @@ -4582,6 +4613,23 @@ do return str end end + function dir.expandlink(dir,report) + local curdir=currentdir() + local trace=type(report)=="function" + if chdir(dir) then + local newdir=currentdir() + if newdir~=dir and trace then + report("following symlink %a to %a",dir,newdir) + end + chdir(curdir) + return newdir + else + if trace then + report("unable to check path %a",dir) + end + return dir + end + end end file.expandname=dir.expandname local stack={} diff --git a/macros/luatex/generic/lualibs/lualibs-dir.lua b/macros/luatex/generic/lualibs/lualibs-dir.lua index ac8e2f4e8e..3164068505 100644 --- a/macros/luatex/generic/lualibs/lualibs-dir.lua +++ b/macros/luatex/generic/lualibs/lualibs-dir.lua @@ -21,7 +21,8 @@ local dir = dir local lfs = lfs local attributes = lfs.attributes -local walkdir = lfs.dir +----- walkdir = lfs.dir +local scandir = lfs.dir local isdir = lfs.isdir -- not robust, will be overloaded anyway local isfile = lfs.isfile -- not robust, will be overloaded anyway local currentdir = lfs.currentdir @@ -69,6 +70,20 @@ else end +-- safeguard + +local isreadable = file.isreadable + +local walkdir = function(p,...) + if isreadable(p.."/.") then + return scandir(p,...) + else + return function() end + end +end + +lfs.walkdir = walkdir + -- handy function dir.current() @@ -197,7 +212,7 @@ local function collectpattern(path,patt,recurse,result) if not find(path,"/$") then path = path .. '/' end - for name in scanner, first do -- cna be optimized + for name in scanner, first do -- can be optimized if name == "." then -- skip elseif name == ".." then @@ -596,6 +611,27 @@ do end + -- This go there anc check works okay in tricky situation as we encounter + -- on osx, where tex installations use rather complex chains of links. + + function dir.expandlink(dir,report) + local curdir = currentdir() + local trace = type(report) == "function" + if chdir(dir) then + local newdir = currentdir() + if newdir ~= dir and trace then + report("following symlink %a to %a",dir,newdir) + end + chdir(curdir) + return newdir + else + if trace then + report("unable to check path %a",dir) + end + return dir + end + end + end file.expandname = dir.expandname -- for convenience diff --git a/macros/luatex/generic/lualibs/lualibs-extended-merged.lua b/macros/luatex/generic/lualibs/lualibs-extended-merged.lua index 08428c51ac..ceecbf3013 100644 --- a/macros/luatex/generic/lualibs/lualibs-extended-merged.lua +++ b/macros/luatex/generic/lualibs/lualibs-extended-merged.lua @@ -1,6 +1,6 @@ -- merged file : lualibs-extended-merged.lua -- parent file : lualibs-extended.lua --- merge date : 2022-10-04 17:16 +-- merge date : 2023-07-13 12:55 do -- begin closure to overcome local limits and interference @@ -481,13 +481,13 @@ if bit32 and not streams.tocardinal1 then local extract=bit32.extract local char=string.char streams.tocardinal1=char - function streams.tocardinal2(n) return char(extract(8,8),extract(0,8)) end - function streams.tocardinal3(n) return char(extract(16,8),extract(8,8),extract(0,8)) end - function streams.tocardinal4(n) return char(extract(24,8),extract(16,8),extract(8,8),extract(0,8)) end + function streams.tocardinal2(n) return char(extract(n,8,8),extract(n,0,8)) end + function streams.tocardinal3(n) return char(extract(n,16,8),extract(n,8,8),extract(n,0,8)) end + function streams.tocardinal4(n) return char(extract(n,24,8),extract(n,16,8),extract(n,8,8),extract(n,0,8)) end streams.tocardinal1le=char - function streams.tocardinal2le(n) return char(extract(0,8),extract(8,8)) end - function streams.tocardinal3le(n) return char(extract(0,8),extract(8,8),extract(16,8)) end - function streams.tocardinal4le(n) return char(extract(0,8),extract(8,8),extract(16,8),extract(24,8)) end + function streams.tocardinal2le(n) return char(extract(n,0,8),extract(n,8,8)) end + function streams.tocardinal3le(n) return char(extract(n,0,8),extract(n,8,8),extract(n,16,8)) end + function streams.tocardinal4le(n) return char(extract(n,0,8),extract(n,8,8),extract(n,16,8),extract(n,24,8)) end end if not streams.readcstring then local readchar=streams.readchar @@ -701,6 +701,7 @@ local p_prune_intospace=Cs (noleading*(notrailing+intospace+1 )^0 ) local p_retain_normal=Cs ((normalline+normalempty )^0 ) local p_retain_collapse=Cs ((normalline+doubleempty )^0 ) local p_retain_noempty=Cs ((normalline+singleempty )^0 ) +local p_collapse_all=Cs (stripstart*(stripend+((whitespace+newline)^1/" ")+1)^0 ) local striplinepatterns={ ["prune"]=p_prune_normal, ["prune and collapse"]=p_prune_collapse, @@ -709,6 +710,7 @@ local striplinepatterns={ ["retain"]=p_retain_normal, ["retain and collapse"]=p_retain_collapse, ["retain and no empty"]=p_retain_noempty, + ["collapse all"]=p_collapse_all, ["collapse"]=patterns.collapser, } setmetatable(striplinepatterns,{ __index=function(t,k) return p_prune_collapse end }) @@ -2090,7 +2092,7 @@ else local v=t[0] if v then m=m+1 - r[m]="[0]='" + r[m]="[0]=" if type(v)=="table" then fastserialize(v) else @@ -2879,7 +2881,9 @@ function parsers.groupedsplitat(symbol,withaction) if not pattern then local symbols=S(symbol) local separator=space^0*symbols*space^0 - local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0) + local value=lbrace*C((nobrace+nestedbraces)^0) +*(rbrace*(#symbols+P(-1))) ++C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0) if withaction then local withvalue=Carg(1)*value/function(f,s) return f(s) end pattern=spaces*withvalue*(separator*withvalue)^0 @@ -2965,7 +2969,17 @@ hashes.settings_to_set=table.setmetatableindex(function(t,k) t[k]=v return v end) -getmetatable(hashes.settings_to_set).__mode="kv" +function parsers.settings_to_set(str) + return str and lpegmatch(pattern,str) or {} +end +local pattern=Ct((C((1-S(", "))^1)*S(", ")^0)^1) +hashes.settings_to_list=table.setmetatableindex(function(t,k) + local v=k and lpegmatch(pattern,k) or {} + t[k]=v + return v +end) +getmetatable(hashes.settings_to_set ).__mode="kv" +getmetatable(hashes.settings_to_list).__mode="kv" function parsers.simple_hash_to_string(h,separator) local t={} local tn=0 @@ -3298,6 +3312,8 @@ local dimenfactors=allocate { ["pc"]=(1/12)/65536, ["dd"]=(1157/1238)/65536, ["cc"]=(1157/14856)/65536, + ["es"]=(9176/129)/65536, + ["ts"]=(4588/645)/65536, } local f_none=formatters["%s%s"] local f_true=formatters["%0.5F%s"] @@ -3323,12 +3339,13 @@ function number.topoints (n,fmt) return numbertodimen(n,"pt",fmt) end function number.toinches (n,fmt) return numbertodimen(n,"in",fmt) end function number.tocentimeters (n,fmt) return numbertodimen(n,"cm",fmt) end function number.tomillimeters (n,fmt) return numbertodimen(n,"mm",fmt) end -function number.toscaledpoints(n,fmt) return numbertodimen(n,"sp",fmt) end function number.toscaledpoints(n) return n.."sp" end function number.tobasepoints (n,fmt) return numbertodimen(n,"bp",fmt) end function number.topicas (n,fmt) return numbertodimen(n "pc",fmt) end function number.todidots (n,fmt) return numbertodimen(n,"dd",fmt) end function number.tociceros (n,fmt) return numbertodimen(n,"cc",fmt) end +function number.toediths (n,fmt) return numbertodimen(n,"es",fmt) end +function number.totoves (n,fmt) return numbertodimen(n,"ts",fmt) end local amount=(S("+-")^0*R("09")^0*P(".")^0*R("09")^0)+Cc("0") local unit=R("az")^1+P("%") local dimenpair=amount/tonumber*(unit^1/dimenfactors+Cc(1)) @@ -3342,7 +3359,7 @@ setmetatableindex(dimenfactors,function(t,s) end) local stringtodimen local amount=S("+-")^0*R("09")^0*S(".,")^0*R("09")^0 -local unit=P("pt")+P("cm")+P("mm")+P("sp")+P("bp")+P("in")+P("pc")+P("dd")+P("cc")+P("nd")+P("nc") +local unit=P("pt")+P("cm")+P("mm")+P("sp")+P("bp")+P("es")+P("ts")+P("pc")+P("dd")+P("cc")+P("in") local validdimen=amount*unit lpeg.patterns.validdimen=validdimen local dimensions={} @@ -3392,8 +3409,9 @@ function dimensions.__index(tab,key) end return 1/d end - dimenfactors["ex"]=4*1/65536 - dimenfactors["em"]=10*1/65536 + dimenfactors["ex"]=4/65536 + dimenfactors["em"]=10/65536 + dimenfactors["eu"]=(9176/129)/65536 local known={} setmetatable(known,{ __mode="v" }) function dimen(a) if a then @@ -4984,11 +5002,13 @@ end local files=utilities.files local openfile=files.open local closefile=files.close +local getsize=files.size local readstring=files.readstring local readcardinal2=files.readcardinal2le local readcardinal4=files.readcardinal4le local setposition=files.setposition local getposition=files.getposition +local skipbytes=files.skip local band=bit32.band local rshift=bit32.rshift local lshift=bit32.lshift @@ -5011,6 +5031,55 @@ local openzipfile,closezipfile,unzipfile,foundzipfile,getziphash,getziplist do handle=openfile(name,0), } end + local function update(handle,data) + position=data.offset + setposition(handle,position) + local signature=readstring(handle,4) + if signature=="PK\3\4" then + local version=readcardinal2(handle) + local flag=readcardinal2(handle) + local method=readcardinal2(handle) + skipbytes(handle,4) + local crc32=readcardinal4(handle) + local compressed=readcardinal4(handle) + local uncompressed=readcardinal4(handle) + local namelength=readcardinal2(handle) + local extralength=readcardinal2(handle) + local filename=readstring(handle,namelength) + local descriptor=band(flag,8)~=0 + local encrypted=band(flag,1)~=0 + local acceptable=method==0 or method==8 + local skipped=0 + local size=0 + if encrypted then + size=readcardinal2(handle) + skipbytes(handle,size) + skipped=skipped+size+2 + skipbytes(8) + skipped=skipped+8 + size=readcardinal2(handle) + skipbytes(handle,size) + skipped=skipped+size+2 + size=readcardinal4(handle) + skipbytes(handle,size) + skipped=skipped+size+4 + size=readcardinal2(handle) + skipbytes(handle,size) + skipped=skipped+size+2 + end + if acceptable then + if filename~=data.filename then + else + position=position+30+namelength+extralength+skipped + data.position=position + return position + end + else + end + end + data.position=false + return false + end local function collect(z) if not z.list then local list={} @@ -5018,72 +5087,68 @@ local openzipfile,closezipfile,unzipfile,foundzipfile,getziphash,getziplist do local position=0 local index=0 local handle=z.handle - while true do - setposition(handle,position) - local signature=readstring(handle,4) - if signature=="PK\3\4" then - local version=readcardinal2(handle) - local flag=readcardinal2(handle) - local method=readcardinal2(handle) - local filetime=readcardinal2(handle) - local filedate=readcardinal2(handle) - local crc32=readcardinal4(handle) - local compressed=readcardinal4(handle) - local uncompressed=readcardinal4(handle) - local namelength=readcardinal2(handle) - local extralength=readcardinal2(handle) - local filename=readstring(handle,namelength) - local descriptor=band(flag,8)~=0 - local encrypted=band(flag,1)~=0 - local acceptable=method==0 or method==8 - local skipped=0 - local size=0 - if encrypted then - size=readcardinal2(handle) - skipbytes(size) - skipped=skipped+size+2 - skipbytes(8) - skipped=skipped+8 - size=readcardinal2(handle) - skipbytes(size) - skipped=skipped+size+2 - size=readcardinal4(handle) - skipbytes(size) - skipped=skipped+size+4 - size=readcardinal2(handle) - skipbytes(size) - skipped=skipped+size+2 - end - position=position+30+namelength+extralength+skipped - if descriptor then - setposition(handle,position+compressed) - crc32=readcardinal4(handle) - compressed=readcardinal4(handle) - uncompressed=readcardinal4(handle) - end - if acceptable then - index=index+1 - local data={ - filename=filename, - index=index, - position=position, - method=method, - compressed=compressed, - uncompressed=uncompressed, - crc32=crc32, - encrypted=encrypted, - } - hash[filename]=data - list[index]=data - else + local size=getsize(handle) + for i=size-4,size-64*1024,-1 do + setposition(handle,i) + local enddirsignature=readcardinal4(handle) + if enddirsignature==0x06054B50 then + local thisdisknumber=readcardinal2(handle) + local centraldisknumber=readcardinal2(handle) + local thisnofentries=readcardinal2(handle) + local totalnofentries=readcardinal2(handle) + local centralsize=readcardinal4(handle) + local centraloffset=readcardinal4(handle) + local commentlength=readcardinal2(handle) + local comment=readstring(handle,length) + if size-i>=22 then + if thisdisknumber==centraldisknumber then + setposition(handle,centraloffset) + while true do + if readcardinal4(handle)==0x02014B50 then + skipbytes(handle,4) + local flag=readcardinal2(handle) + local method=readcardinal2(handle) + skipbytes(handle,4) + local crc32=readcardinal4(handle) + local compressed=readcardinal4(handle) + local uncompressed=readcardinal4(handle) + local namelength=readcardinal2(handle) + local extralength=readcardinal2(handle) + local commentlength=readcardinal2(handle) + skipbytes(handle,8) + local headeroffset=readcardinal4(handle) + local filename=readstring(handle,namelength) + skipbytes(handle,extralength+commentlength) + local descriptor=band(flag,8)~=0 + local encrypted=band(flag,1)~=0 + local acceptable=method==0 or method==8 + if acceptable then + index=index+1 + local data={ + filename=filename, + index=index, + position=nil, + method=method, + compressed=compressed, + uncompressed=uncompressed, + crc32=crc32, + encrypted=encrypted, + offset=headeroffset, + } + hash[filename]=data + list[index]=data + end + else + break + end + end + end + break end - position=position+compressed - else - break end - z.list=list - z.hash=hash end + z.list=list + z.hash=hash end end function getziplist(z) @@ -5122,7 +5187,10 @@ local openzipfile,closezipfile,unzipfile,foundzipfile,getziphash,getziplist do local handle=z.handle local position=data.position local compressed=data.compressed - if compressed>0 then + if position==nil then + position=update(handle,data) + end + if position and compressed>0 then setposition(handle,position) local result=readstring(handle,compressed) if data.method==8 then @@ -5333,8 +5401,10 @@ if xzip then closezip(zipf) end end - local function unzipdir(zipname,path,verbose) + local function unzipdir(zipname,path,verbose,collect,validate) if type(zipname)=="table" then + validate=zipname.validate + collect=zipname.collect verbose=zipname.verbose path=zipname.path zipname=zipname.zipname @@ -5355,34 +5425,47 @@ if xzip then local done=0 local steps=verbose=="steps" local time=steps and osclock() + if collect then + collect={} + else + collect=false + end for i=1,count do local l=list[i] local n=l.filename - local d=unzipfile(z,n) - if d then - local p=filejoin(path,n) - if mkdirs(dirname(p)) then - if steps then - total=total+#d - done=done+1 - if done>=step then - done=0 - logwriter(format("%4i files of %4i done, %10i bytes, %0.3f seconds",i,count,total,osclock()-time)) + if not validate or validate(n) then + local d=unzipfile(z,n) + if d then + local p=filejoin(path,n) + if mkdirs(dirname(p)) then + if steps then + total=total+#d + done=done+1 + if done>=step then + done=0 + logwriter(format("%4i files of %4i done, %10i bytes, %0.3f seconds",i,count,total,osclock()-time)) + end + elseif verbose then + logwriter(n) + end + savedata(p,d) + if collect then + collect[#collect+1]=p end - elseif verbose then - logwriter(n) end - savedata(p,d) + else + logwriter(format("problem with file %s",n)) end else - logwriter(format("problem with file %s",n)) end end if steps then logwriter(format("%4i files of %4i done, %10i bytes, %0.3f seconds",count,count,total,osclock()-time)) end closezipfile(z) - return true + if collect then + return collect + end else closezipfile(z) end diff --git a/macros/luatex/generic/lualibs/lualibs-file.lua b/macros/luatex/generic/lualibs/lualibs-file.lua index 9f8fd65483..70f8188dc1 100644 --- a/macros/luatex/generic/lualibs/lualibs-file.lua +++ b/macros/luatex/generic/lualibs/lualibs-file.lua @@ -741,8 +741,24 @@ end -- not used in context but was in luatex once: -local symlinkattributes = lfs.symlinkattributes +do + + local symlinktarget = lfs.symlinktarget -- luametatex (always returns string) + local symlinkattributes = lfs.symlinkattributes -- luatex (can return nil) + + if symlinktarget then + function lfs.readlink(name) + local target = symlinktarget(name) + return name ~= target and name or nil + end + elseif symlinkattributes then + function lfs.readlink(name) + return symlinkattributes(name,"target") or nil + end + else + function lfs.readlink(name) + return nil + end + end -function lfs.readlink(name) - return symlinkattributes(name,"target") or nil end diff --git a/macros/luatex/generic/lualibs/lualibs-string.lua b/macros/luatex/generic/lualibs/lualibs-string.lua index 1dee85e289..476820a175 100644 --- a/macros/luatex/generic/lualibs/lualibs-string.lua +++ b/macros/luatex/generic/lualibs/lualibs-string.lua @@ -7,7 +7,7 @@ if not modules then modules = { } end modules ['l-string'] = { } local string = string -local sub, gmatch, format, char, byte, rep, lower = string.sub, string.gmatch, string.format, string.char, string.byte, string.rep, string.lower +local sub, gmatch, format, char, byte, rep, lower, find = string.sub, string.gmatch, string.format, string.char, string.byte, string.rep, string.lower, string.find local lpegmatch, patterns = lpeg.match, lpeg.patterns local P, S, C, Ct, Cc, Cs = lpeg.P, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cs @@ -52,10 +52,26 @@ function string.quoted(str) return format("%q",str) -- always double quote end -function string.count(str,pattern) -- variant 3 +-- function string.count(str,pattern) -- variant 3 +-- local n = 0 +-- for _ in gmatch(str,pattern) do -- not for utf +-- n = n + 1 +-- end +-- return n +-- end + +function string.count(str,pattern) local n = 0 - for _ in gmatch(str,pattern) do -- not for utf - n = n + 1 + local i = 1 + local l = #pattern + while true do + i = find(str,pattern,i) + if i then + n = n + 1 + i = i + l + else + break + end end return n end diff --git a/macros/luatex/generic/lualibs/lualibs-unicode.lua b/macros/luatex/generic/lualibs/lualibs-unicode.lua index 5d9a7149bd..f98686c6b6 100644 --- a/macros/luatex/generic/lualibs/lualibs-unicode.lua +++ b/macros/luatex/generic/lualibs/lualibs-unicode.lua @@ -32,7 +32,6 @@ if not modules then modules = { } end modules ['l-unicode'] = { -- dump, find, format, gfind, gmatch, gsub, lower, match, rep, reverse, upper utf = utf or { } --- unicode = nil if not string.utfcharacters then diff --git a/macros/luatex/generic/lualibs/lualibs-util-dim.lua b/macros/luatex/generic/lualibs/lualibs-util-dim.lua index bb9eca9668..6462f3e492 100644 --- a/macros/luatex/generic/lualibs/lualibs-util-dim.lua +++ b/macros/luatex/generic/lualibs/lualibs-util-dim.lua @@ -6,14 +6,10 @@ if not modules then modules = { } end modules ['util-dim'] = { license = "see context related readme files" } ---[[ldx-- -<p>Internally <l n='luatex'/> work with scaled point, which are -represented by integers. However, in practice, at east at the -<l n='tex'/> end we work with more generic units like points (pt). Going -from scaled points (numbers) to one of those units can be -done by using the conversion factors collected in the following -table.</p> ---ldx]]-- +-- Internally LuaTeX work with scaled point, which are represented by integers. +-- However, in practice, at east at the TeX end we work with more generic units like +-- points (pt). Going from scaled points (numbers) to one of those units can be done +-- by using the conversion factors collected in the following table. local format, match, gsub, type, setmetatable = string.format, string.match, string.gsub, type, setmetatable local P, S, R, Cc, C, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.Cc, lpeg.C, lpeg.match @@ -45,7 +41,9 @@ local dimenfactors = allocate { ["dd"] = ( 1157/ 1238)/65536, ["cc"] = ( 1157/14856)/65536, -- ["nd"] = (20320/21681)/65536, - -- ["nc"] = ( 5080/65043)/65536 + -- ["nc"] = ( 5080/65043)/65536, + ["es"] = ( 9176/ 129)/65536, + ["ts"] = ( 4588/ 645)/65536, } -- print(table.serialize(dimenfactors)) @@ -86,10 +84,8 @@ local dimenfactors = allocate { -- ["sp"]=1, -- } ---[[ldx-- -<p>A conversion function that takes a number, unit (string) and optional -format (string) is implemented using this table.</p> ---ldx]]-- +-- A conversion function that takes a number, unit (string) and optional format +-- (string) is implemented using this table. local f_none = formatters["%s%s"] local f_true = formatters["%0.5F%s"] @@ -110,9 +106,7 @@ local function numbertodimen(n,unit,fmt) -- will be redefined later ! end end ---[[ldx-- -<p>We collect a bunch of converters in the <type>number</type> namespace.</p> ---ldx]]-- +-- We collect a bunch of converters in the 'number' namespace. number.maxdimen = 1073741823 number.todimen = numbertodimen @@ -122,7 +116,7 @@ function number.topoints (n,fmt) return numbertodimen(n,"pt",fmt) end function number.toinches (n,fmt) return numbertodimen(n,"in",fmt) end function number.tocentimeters (n,fmt) return numbertodimen(n,"cm",fmt) end function number.tomillimeters (n,fmt) return numbertodimen(n,"mm",fmt) end -function number.toscaledpoints(n,fmt) return numbertodimen(n,"sp",fmt) end +-------- number.toscaledpoints(n,fmt) return numbertodimen(n,"sp",fmt) end function number.toscaledpoints(n) return n .. "sp" end function number.tobasepoints (n,fmt) return numbertodimen(n,"bp",fmt) end function number.topicas (n,fmt) return numbertodimen(n "pc",fmt) end @@ -130,14 +124,13 @@ function number.todidots (n,fmt) return numbertodimen(n,"dd",fmt) end function number.tociceros (n,fmt) return numbertodimen(n,"cc",fmt) end -------- number.tonewdidots (n,fmt) return numbertodimen(n,"nd",fmt) end -------- number.tonewciceros (n,fmt) return numbertodimen(n,"nc",fmt) end +function number.toediths (n,fmt) return numbertodimen(n,"es",fmt) end +function number.totoves (n,fmt) return numbertodimen(n,"ts",fmt) end ---[[ldx-- -<p>More interesting it to implement a (sort of) dimen datatype, one -that permits calculations too. First we define a function that -converts a string to scaledpoints. We use <l n='lpeg'/>. We capture -a number and optionally a unit. When no unit is given a constant -capture takes place.</p> ---ldx]]-- +-- More interesting it to implement a (sort of) dimen datatype, one that permits +-- calculations too. First we define a function that converts a string to +-- scaledpoints. We use LPEG. We capture a number and optionally a unit. When no +-- unit is given a constant capture takes place. local amount = (S("+-")^0 * R("09")^0 * P(".")^0 * R("09")^0) + Cc("0") local unit = R("az")^1 + P("%") @@ -152,21 +145,16 @@ function number.splitdimen(str) return lpegmatch(splitter,str) end ---[[ldx-- -<p>We use a metatable to intercept errors. When no key is found in -the table with factors, the metatable will be consulted for an -alternative index function.</p> ---ldx]]-- +-- We use a metatable to intercept errors. When no key is found in the table with +-- factors, the metatable will be consulted for an alternative index function. setmetatableindex(dimenfactors, function(t,s) -- error("wrong dimension: " .. (s or "?")) -- better a message return false end) ---[[ldx-- -<p>We redefine the following function later on, so we comment it -here (which saves us bytecodes.</p> ---ldx]]-- +-- We redefine the following function later on, so we comment it here (which saves +-- us bytecodes. -- function string.todimen(str) -- if type(str) == "number" then @@ -182,44 +170,38 @@ here (which saves us bytecodes.</p> local stringtodimen -- assigned later (commenting saves bytecode) local amount = S("+-")^0 * R("09")^0 * S(".,")^0 * R("09")^0 -local unit = P("pt") + P("cm") + P("mm") + P("sp") + P("bp") + P("in") + - P("pc") + P("dd") + P("cc") + P("nd") + P("nc") +local unit = P("pt") + P("cm") + P("mm") + P("sp") + P("bp") + + P("es") + P("ts") + P("pc") + P("dd") + P("cc") + + P("in") + -- + P("nd") + P("nc") local validdimen = amount * unit lpeg.patterns.validdimen = validdimen ---[[ldx-- -<p>This converter accepts calls like:</p> - -<typing> -string.todimen("10") -string.todimen(".10") -string.todimen("10.0") -string.todimen("10.0pt") -string.todimen("10pt") -string.todimen("10.0pt") -</typing> - -<p>With this in place, we can now implement a proper datatype for dimensions, one -that permits us to do this:</p> - -<typing> -s = dimen "10pt" + dimen "20pt" + dimen "200pt" - - dimen "100sp" / 10 + "20pt" + "0pt" -</typing> - -<p>We create a local metatable for this new type:</p> ---ldx]]-- +-- This converter accepts calls like: +-- +-- string.todimen("10") +-- string.todimen(".10") +-- string.todimen("10.0") +-- string.todimen("10.0pt") +-- string.todimen("10pt") +-- string.todimen("10.0pt") +-- +-- With this in place, we can now implement a proper datatype for dimensions, one +-- that permits us to do this: +-- +-- s = dimen "10pt" + dimen "20pt" + dimen "200pt" +-- - dimen "100sp" / 10 + "20pt" + "0pt" +-- +-- We create a local metatable for this new type: local dimensions = { } ---[[ldx-- -<p>The main (and globally) visible representation of a dimen is defined next: it is -a one-element table. The unit that is returned from the match is normally a number -(one of the previously defined factors) but we also accept functions. Later we will -see why. This function is redefined later.</p> ---ldx]]-- +-- The main (and globally) visible representation of a dimen is defined next: it is +-- a one-element table. The unit that is returned from the match is normally a +-- number (one of the previously defined factors) but we also accept functions. +-- Later we will see why. This function is redefined later. -- function dimen(a) -- if a then @@ -241,11 +223,9 @@ see why. This function is redefined later.</p> -- end -- end ---[[ldx-- -<p>This function return a small hash with a metatable attached. It is -through this metatable that we can do the calculations. We could have -shared some of the code but for reasons of speed we don't.</p> ---ldx]]-- +-- This function return a small hash with a metatable attached. It is through this +-- metatable that we can do the calculations. We could have shared some of the code +-- but for reasons of speed we don't. function dimensions.__add(a, b) local ta, tb = type(a), type(b) @@ -281,20 +261,16 @@ function dimensions.__unm(a) return setmetatable({ - a }, dimensions) end ---[[ldx-- -<p>It makes no sense to implement the power and modulo function but -the next two do make sense because they permits is code like:</p> - -<typing> -local a, b = dimen "10pt", dimen "11pt" -... -if a > b then - ... -end -</typing> ---ldx]]-- - --- makes no sense: dimensions.__pow and dimensions.__mod +-- It makes no sense to implement the power and modulo function but +-- the next two do make sense because they permits is code like: +-- +-- local a, b = dimen "10pt", dimen "11pt" +-- ... +-- if a > b then +-- ... +-- end +-- +-- This also makes no sense: dimensions.__pow and dimensions.__mod. function dimensions.__lt(a, b) return a[1] < b[1] @@ -304,24 +280,17 @@ function dimensions.__eq(a, b) return a[1] == b[1] end ---[[ldx-- -<p>We also need to provide a function for conversion to string (so that -we can print dimensions). We print them as points, just like <l n='tex'/>.</p> ---ldx]]-- +-- We also need to provide a function for conversion to string (so that we can print +-- dimensions). We print them as points, just like TeX. function dimensions.__tostring(a) return a[1]/65536 .. "pt" -- instead of todimen(a[1]) end ---[[ldx-- -<p>Since it does not take much code, we also provide a way to access -a few accessors</p> - -<typing> -print(dimen().pt) -print(dimen().sp) -</typing> ---ldx]]-- +-- Since it does not take much code, we also provide a way to access a few accessors +-- +-- print(dimen().pt) +-- print(dimen().sp) function dimensions.__index(tab,key) local d = dimenfactors[key] @@ -332,41 +301,34 @@ function dimensions.__index(tab,key) return 1/d end ---[[ldx-- -<p>In the converter from string to dimension we support functions as -factors. This is because in <l n='tex'/> we have a few more units: -<type>ex</type> and <type>em</type>. These are not constant factors but -depend on the current font. They are not defined by default, but need -an explicit function call. This is because at the moment that this code -is loaded, the relevant tables that hold the functions needed may not -yet be available.</p> ---ldx]]-- - - dimenfactors["ex"] = 4 * 1/65536 -- 4pt - dimenfactors["em"] = 10 * 1/65536 -- 10pt --- dimenfactors["%"] = 4 * 1/65536 -- 400pt/100 - ---[[ldx-- -<p>The previous code is rather efficient (also thanks to <l n='lpeg'/>) but we -can speed it up by caching converted dimensions. On my machine (2008) the following -loop takes about 25.5 seconds.</p> - -<typing> -for i=1,1000000 do - local s = dimen "10pt" + dimen "20pt" + dimen "200pt" - - dimen "100sp" / 10 + "20pt" + "0pt" -end -</typing> - -<p>When we cache converted strings this becomes 16.3 seconds. In order not -to waste too much memory on it, we tag the values of the cache as being -week which mean that the garbage collector will collect them in a next -sweep. This means that in most cases the speed up is mostly affecting the -current couple of calculations and as such the speed penalty is small.</p> - -<p>We redefine two previous defined functions that can benefit from -this:</p> ---ldx]]-- +-- In the converter from string to dimension we support functions as factors. This +-- is because in TeX we have a few more units: 'ex' and 'em'. These are not constant +-- factors but depend on the current font. They are not defined by default, but need +-- an explicit function call. This is because at the moment that this code is +-- loaded, the relevant tables that hold the functions needed may not yet be +-- available. + + dimenfactors["ex"] = 4 /65536 -- 4pt + dimenfactors["em"] = 10 /65536 -- 10pt +-- dimenfactors["%"] = 4 /65536 -- 400pt/100 + dimenfactors["eu"] = (9176/129)/65536 -- 1es + +-- The previous code is rather efficient (also thanks to LPEG) but we can speed it +-- up by caching converted dimensions. On my machine (2008) the following loop takes +-- about 25.5 seconds. +-- +-- for i=1,1000000 do +-- local s = dimen "10pt" + dimen "20pt" + dimen "200pt" +-- - dimen "100sp" / 10 + "20pt" + "0pt" +-- end +-- +-- When we cache converted strings this becomes 16.3 seconds. In order not to waste +-- too much memory on it, we tag the values of the cache as being week which mean +-- that the garbage collector will collect them in a next sweep. This means that in +-- most cases the speed up is mostly affecting the current couple of calculations +-- and as such the speed penalty is small. +-- +-- We redefine two previous defined functions that can benefit from this: local known = { } setmetatable(known, { __mode = "v" }) @@ -436,14 +398,10 @@ function number.toscaled(d) return format("%0.5f",d/0x10000) -- 2^16 end ---[[ldx-- -<p>In a similar fashion we can define a glue datatype. In that case we -probably use a hash instead of a one-element table.</p> ---ldx]]-- - ---[[ldx-- -<p>Goodie:s</p> ---ldx]]-- +-- In a similar fashion we can define a glue datatype. In that case we probably use +-- a hash instead of a one-element table. +-- +-- A goodie: function number.percent(n,d) -- will be cleaned up once luatex 0.30 is out d = d or texget("hsize") diff --git a/macros/luatex/generic/lualibs/lualibs-util-prs.lua b/macros/luatex/generic/lualibs/lualibs-util-prs.lua index 635b610e07..a527555db7 100644 --- a/macros/luatex/generic/lualibs/lualibs-util-prs.lua +++ b/macros/luatex/generic/lualibs/lualibs-util-prs.lua @@ -264,8 +264,13 @@ function parsers.groupedsplitat(symbol,withaction) if not pattern then local symbols = S(symbol) local separator = space^0 * symbols * space^0 - local value = lbrace * C((nobrace + nestedbraces)^0) * rbrace - + C((nestedbraces + (1-(space^0*(symbols+P(-1)))))^0) + local value = + lbrace + * C((nobrace + nestedbraces)^0) + -- * rbrace + * (rbrace * (#symbols + P(-1))) -- new per 2023-03-11 + + + C((nestedbraces + (1-(space^0*(symbols+P(-1)))))^0) if withaction then local withvalue = Carg(1) * value / function(f,s) return f(s) end pattern = spaces * withvalue * (separator*withvalue)^0 @@ -378,9 +383,25 @@ hashes.settings_to_set = table.setmetatableindex(function(t,k) -- experiment, n return v end) +function parsers.settings_to_set(str) + return str and lpegmatch(pattern,str) or { } +end + +local pattern = Ct((C((1-S(", "))^1) * S(", ")^0)^1) + +hashes.settings_to_list = table.setmetatableindex(function(t,k) -- experiment, not public + local v = k and lpegmatch(pattern,k) or { } + t[k] = v + return v +end) + +-- inspect(hashes.settings_to_set["a,b, c, d"]) +-- inspect(hashes.settings_to_list["a,b, c, d"]) + -- as we use a next, we are not sure when the gc kicks in -getmetatable(hashes.settings_to_set).__mode = "kv" -- could be an option (maybe sharing makes sense) +getmetatable(hashes.settings_to_set ).__mode = "kv" -- could be an option (maybe sharing makes sense) +getmetatable(hashes.settings_to_list).__mode = "kv" -- could be an option (maybe sharing makes sense) function parsers.simple_hash_to_string(h, separator) local t = { } diff --git a/macros/luatex/generic/lualibs/lualibs-util-sac.lua b/macros/luatex/generic/lualibs/lualibs-util-sac.lua index 36daef8167..9d2e8356da 100644 --- a/macros/luatex/generic/lualibs/lualibs-util-sac.lua +++ b/macros/luatex/generic/lualibs/lualibs-util-sac.lua @@ -551,14 +551,14 @@ if bit32 and not streams.tocardinal1 then local char = string.char streams.tocardinal1 = char - function streams.tocardinal2(n) return char(extract( 8,8),extract( 0,8)) end - function streams.tocardinal3(n) return char(extract(16,8),extract( 8,8),extract(0,8)) end - function streams.tocardinal4(n) return char(extract(24,8),extract(16,8),extract(8,8),extract(0,8)) end + function streams.tocardinal2(n) return char(extract(n, 8,8),extract(n, 0,8)) end + function streams.tocardinal3(n) return char(extract(n,16,8),extract(n, 8,8),extract(n,0,8)) end + function streams.tocardinal4(n) return char(extract(n,24,8),extract(n,16,8),extract(n,8,8),extract(n,0,8)) end streams.tocardinal1le = char - function streams.tocardinal2le(n) return char(extract(0,8),extract(8,8)) end - function streams.tocardinal3le(n) return char(extract(0,8),extract(8,8),extract(16,8)) end - function streams.tocardinal4le(n) return char(extract(0,8),extract(8,8),extract(16,8),extract(24,8)) end + function streams.tocardinal2le(n) return char(extract(n,0,8),extract(n,8,8)) end + function streams.tocardinal3le(n) return char(extract(n,0,8),extract(n,8,8),extract(n,16,8)) end + function streams.tocardinal4le(n) return char(extract(n,0,8),extract(n,8,8),extract(n,16,8),extract(n,24,8)) end end diff --git a/macros/luatex/generic/lualibs/lualibs-util-str.lua b/macros/luatex/generic/lualibs/lualibs-util-str.lua index b5c721a41d..a9150b886a 100644 --- a/macros/luatex/generic/lualibs/lualibs-util-str.lua +++ b/macros/luatex/generic/lualibs/lualibs-util-str.lua @@ -269,6 +269,7 @@ local p_prune_intospace = Cs ( noleading * ( notrailing + intospace + 1 local p_retain_normal = Cs ( ( normalline + normalempty )^0 ) local p_retain_collapse = Cs ( ( normalline + doubleempty )^0 ) local p_retain_noempty = Cs ( ( normalline + singleempty )^0 ) +local p_collapse_all = Cs ( stripstart * ( stripend + ((whitespace+newline)^1/" ") + 1)^0 ) -- function striplines(str,prune,collapse,noempty) -- if prune then @@ -298,6 +299,7 @@ local striplinepatterns = { ["retain"] = p_retain_normal, ["retain and collapse"] = p_retain_collapse, ["retain and no empty"] = p_retain_noempty, + ["collapse all"] = p_collapse_all, ["collapse"] = patterns.collapser, } @@ -313,6 +315,9 @@ function strings.collapse(str) -- maybe also in strings return str and lpegmatch(p_prune_intospace,str) or str end +-- local s = "\naa\n\naa\na a\n\n" +-- print("["..strings.striplines(s,"collapse all").."]") + -- also see: string.collapsespaces strings.striplong = strings.striplines -- for old times sake diff --git a/macros/luatex/generic/lualibs/lualibs-util-tab.lua b/macros/luatex/generic/lualibs/lualibs-util-tab.lua index 64fa1af4fb..58ca3bcb10 100644 --- a/macros/luatex/generic/lualibs/lualibs-util-tab.lua +++ b/macros/luatex/generic/lualibs/lualibs-util-tab.lua @@ -432,7 +432,7 @@ else local v = t[0] if v then m = m + 1 - r[m] = "[0]='" + r[m] = "[0]=" if type(v) == "table" then fastserialize(v) else diff --git a/macros/luatex/generic/lualibs/lualibs-util-zip.lua b/macros/luatex/generic/lualibs/lualibs-util-zip.lua index bd8fdf287f..194eb56972 100644 --- a/macros/luatex/generic/lualibs/lualibs-util-zip.lua +++ b/macros/luatex/generic/lualibs/lualibs-util-zip.lua @@ -34,11 +34,13 @@ end local files = utilities.files local openfile = files.open local closefile = files.close +local getsize = files.size local readstring = files.readstring local readcardinal2 = files.readcardinal2le local readcardinal4 = files.readcardinal4le local setposition = files.setposition local getposition = files.getposition +local skipbytes = files.skip local band = bit32.band local rshift = bit32.rshift @@ -69,6 +71,158 @@ local openzipfile, closezipfile, unzipfile, foundzipfile, getziphash, getziplist } end + -- https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT + +-- local function collect(z) +-- if not z.list then +-- local list = { } +-- local hash = { } +-- local position = 0 +-- local index = 0 +-- local handle = z.handle +-- while true do +-- setposition(handle,position) +-- local signature = readstring(handle,4) +-- if signature == "PK\3\4" then +-- -- [local file header 1] +-- -- [encryption header 1] +-- -- [file data 1] +-- -- [data descriptor 1] +-- local version = readcardinal2(handle) +-- local flag = readcardinal2(handle) +-- local method = readcardinal2(handle) +-- local filetime = readcardinal2(handle) +-- local filedate = readcardinal2(handle) +-- local crc32 = readcardinal4(handle) +-- local compressed = readcardinal4(handle) +-- local uncompressed = readcardinal4(handle) +-- local namelength = readcardinal2(handle) +-- local extralength = readcardinal2(handle) +-- local filename = readstring(handle,namelength) +-- local descriptor = band(flag,8) ~= 0 +-- local encrypted = band(flag,1) ~= 0 +-- local acceptable = method == 0 or method == 8 +-- -- 30 bytes of header including the signature +-- local skipped = 0 +-- local size = 0 +-- if encrypted then +-- size = readcardinal2(handle) +-- skipbytes(handle,size) +-- skipped = skipped + size + 2 +-- skipbytes(8) +-- skipped = skipped + 8 +-- size = readcardinal2(handle) +-- skipbytes(handle,size) +-- skipped = skipped + size + 2 +-- size = readcardinal4(handle) +-- skipbytes(handle,size) +-- skipped = skipped + size + 4 +-- size = readcardinal2(handle) +-- skipbytes(handle,size) +-- skipped = skipped + size + 2 +-- end +-- position = position + 30 + namelength + extralength + skipped +-- -- if descriptor then +-- -- -- where is this one located +-- -- setposition(handle,position + compressed) +-- -- crc32 = readcardinal4(handle) +-- -- compressed = readcardinal4(handle) +-- -- uncompressed = readcardinal4(handle) +-- -- end +-- if acceptable then +-- index = index + 1 +-- local data = { +-- filename = filename, +-- index = index, +-- position = position, +-- method = method, +-- compressed = compressed, +-- uncompressed = uncompressed, +-- crc32 = crc32, +-- encrypted = encrypted, +-- } +-- hash[filename] = data +-- list[index] = data +-- else +-- -- maybe a warning when encrypted +-- end +-- position = position + compressed +-- else +-- break +-- end +-- z.list = list +-- z.hash = hash +-- end +-- end +-- end +-- end + +-- end +-- end + + local function update(handle,data) + position = data.offset + setposition(handle,position) + local signature = readstring(handle,4) + if signature == "PK\3\4" then -- 0x04034B50 + -- [local file header 1] + -- [encryption header 1] + -- [file data 1] + -- [data descriptor 1] + local version = readcardinal2(handle) + local flag = readcardinal2(handle) + local method = readcardinal2(handle) + skipbytes(handle,4) + ----- filetime = readcardinal2(handle) + ----- filedate = readcardinal2(handle) + local crc32 = readcardinal4(handle) + local compressed = readcardinal4(handle) + local uncompressed = readcardinal4(handle) + local namelength = readcardinal2(handle) + local extralength = readcardinal2(handle) + local filename = readstring(handle,namelength) + local descriptor = band(flag,8) ~= 0 + local encrypted = band(flag,1) ~= 0 + local acceptable = method == 0 or method == 8 + -- 30 bytes of header including the signature + local skipped = 0 + local size = 0 + if encrypted then + size = readcardinal2(handle) + skipbytes(handle,size) + skipped = skipped + size + 2 + skipbytes(8) + skipped = skipped + 8 + size = readcardinal2(handle) + skipbytes(handle,size) + skipped = skipped + size + 2 + size = readcardinal4(handle) + skipbytes(handle,size) + skipped = skipped + size + 4 + size = readcardinal2(handle) + skipbytes(handle,size) + skipped = skipped + size + 2 + end + if acceptable then + if filename ~= data.filename then + -- elseif method ~= data.method then + -- elseif encrypted ~= data.encrypted then + -- elseif crc32 ~= 0 and crc32 ~= data.crc32 then + -- elseif uncompressed ~= 0 and uncompressed ~= data.uncompressed then + -- elseif compressed ~= 0 and compressed ~= data.compressed then + else + position = position + 30 + namelength + extralength + skipped + data.position = position + return position + end + else + -- maybe a warning when encrypted + end + end + data.position = false + return false + end + local function collect(z) if not z.list then local list = { } @@ -76,78 +230,88 @@ local openzipfile, closezipfile, unzipfile, foundzipfile, getziphash, getziplist local position = 0 local index = 0 local handle = z.handle - while true do - setposition(handle,position) - local signature = readstring(handle,4) - if signature == "PK\3\4" then - -- [local file header 1] - -- [encryption header 1] - -- [file data 1] - -- [data descriptor 1] - local version = readcardinal2(handle) - local flag = readcardinal2(handle) - local method = readcardinal2(handle) - local filetime = readcardinal2(handle) - local filedate = readcardinal2(handle) - local crc32 = readcardinal4(handle) - local compressed = readcardinal4(handle) - local uncompressed = readcardinal4(handle) - local namelength = readcardinal2(handle) - local extralength = readcardinal2(handle) - local filename = readstring(handle,namelength) - local descriptor = band(flag,8) ~= 0 - local encrypted = band(flag,1) ~= 0 - local acceptable = method == 0 or method == 8 - -- 30 bytes of header including the signature - local skipped = 0 - local size = 0 - if encrypted then - size = readcardinal2(handle) - skipbytes(size) - skipped = skipped + size + 2 - skipbytes(8) - skipped = skipped + 8 - size = readcardinal2(handle) - skipbytes(size) - skipped = skipped + size + 2 - size = readcardinal4(handle) - skipbytes(size) - skipped = skipped + size + 4 - size = readcardinal2(handle) - skipbytes(size) - skipped = skipped + size + 2 - end - position = position + 30 + namelength + extralength + skipped - if descriptor then - setposition(handle,position + compressed) - crc32 = readcardinal4(handle) - compressed = readcardinal4(handle) - uncompressed = readcardinal4(handle) - end - if acceptable then - index = index + 1 - local data = { - filename = filename, - index = index, - position = position, - method = method, - compressed = compressed, - uncompressed = uncompressed, - crc32 = crc32, - encrypted = encrypted, - } - hash[filename] = data - list[index] = data - else - -- maybe a warning when encrypted + local size = getsize(handle) + -- + -- Not all files have the compressed into set so we need to get the directory + -- first. We only handle single disk zip files. + -- + for i=size-4,size-64*1024,-1 do + setposition(handle,i) + local enddirsignature = readcardinal4(handle) + if enddirsignature == 0x06054B50 then + local thisdisknumber = readcardinal2(handle) + local centraldisknumber = readcardinal2(handle) + local thisnofentries = readcardinal2(handle) + local totalnofentries = readcardinal2(handle) + local centralsize = readcardinal4(handle) + local centraloffset = readcardinal4(handle) + local commentlength = readcardinal2(handle) + local comment = readstring(handle,length) + if size - i >= 22 then + if thisdisknumber == centraldisknumber then + setposition(handle,centraloffset) + while true do + if readcardinal4(handle) == 0x02014B50 then + skipbytes(handle,4) + ----- versionmadeby = readcardinal2(handle) + ----- versionneeded = readcardinal2(handle) + local flag = readcardinal2(handle) + local method = readcardinal2(handle) + skipbytes(handle,4) + ----- filetime = readcardinal2(handle) + ----- filedate = readcardinal2(handle) + local crc32 = readcardinal4(handle) + local compressed = readcardinal4(handle) + local uncompressed = readcardinal4(handle) + local namelength = readcardinal2(handle) + local extralength = readcardinal2(handle) + local commentlength = readcardinal2(handle) + skipbytes(handle,8) + ----- disknumber = readcardinal2(handle) + ----- intattributes = readcardinal2(handle) + ----- extattributes = readcardinal4(handle) + local headeroffset = readcardinal4(handle) + local filename = readstring(handle,namelength) + skipbytes(handle,extralength+commentlength) + ----- extradata = readstring(handle,extralength) + ----- comment = readstring(handle,commentlength) + -- + local descriptor = band(flag,8) ~= 0 + local encrypted = band(flag,1) ~= 0 + local acceptable = method == 0 or method == 8 + if acceptable then + index = index + 1 + local data = { + filename = filename, + index = index, + position = nil, + method = method, + compressed = compressed, + uncompressed = uncompressed, + crc32 = crc32, + encrypted = encrypted, + offset = headeroffset, + } + hash[filename] = data + list[index] = data + end + else + break + end + end + end + break end - position = position + compressed - else - break end - z.list = list - z.hash = hash end + -- for i=1,index do -- delayed + -- local data = list[i] + -- if not data.position then + -- update(handle,list[i]) + -- end + -- end + z.list = list + z.hash = hash end end @@ -156,6 +320,7 @@ local openzipfile, closezipfile, unzipfile, foundzipfile, getziphash, getziplist if not list then collect(z) end + -- inspect(z.list) return z.list end @@ -193,7 +358,10 @@ local openzipfile, closezipfile, unzipfile, foundzipfile, getziphash, getziplist local handle = z.handle local position = data.position local compressed = data.compressed - if compressed > 0 then + if position == nil then + position = update(handle,data) + end + if position and compressed > 0 then setposition(handle,position) local result = readstring(handle,compressed) if data.method == 8 then @@ -451,11 +619,13 @@ if xzip then -- flate then do end end - local function unzipdir(zipname,path,verbose) + local function unzipdir(zipname,path,verbose,collect,validate) if type(zipname) == "table" then - verbose = zipname.verbose - path = zipname.path - zipname = zipname.zipname + validate = zipname.validate + collect = zipname.collect + verbose = zipname.verbose + path = zipname.path + zipname = zipname.zipname end if not zipname or zipname == "" then return @@ -473,34 +643,49 @@ if xzip then -- flate then do local done = 0 local steps = verbose == "steps" local time = steps and osclock() + -- local skip = 0 + if collect then + collect = { } + else + collect = false + end for i=1,count do local l = list[i] local n = l.filename - local d = unzipfile(z,n) -- true for check - if d then - local p = filejoin(path,n) - if mkdirs(dirname(p)) then - if steps then - total = total + #d - done = done + 1 - if done >= step then - done = 0 - logwriter(format("%4i files of %4i done, %10i bytes, %0.3f seconds",i,count,total,osclock()-time)) + if not validate or validate(n) then + local d = unzipfile(z,n) -- true for check + if d then + local p = filejoin(path,n) + if mkdirs(dirname(p)) then + if steps then + total = total + #d + done = done + 1 + if done >= step then + done = 0 + logwriter(format("%4i files of %4i done, %10i bytes, %0.3f seconds",i,count,total,osclock()-time)) + end + elseif verbose then + logwriter(n) + end + savedata(p,d) + if collect then + collect[#collect+1] = p end - elseif verbose then - logwriter(n) end - savedata(p,d) + else + logwriter(format("problem with file %s",n)) end else - logwriter(format("problem with file %s",n)) + -- skip = skip + 1 end end if steps then logwriter(format("%4i files of %4i done, %10i bytes, %0.3f seconds",count,count,total,osclock()-time)) end closezipfile(z) - return true + if collect then + return collect + end else closezipfile(z) end diff --git a/macros/luatex/generic/lualibs/lualibs.dtx b/macros/luatex/generic/lualibs/lualibs.dtx index ebdba58424..d033500527 100644 --- a/macros/luatex/generic/lualibs/lualibs.dtx +++ b/macros/luatex/generic/lualibs/lualibs.dtx @@ -37,7 +37,7 @@ \input docstrip.tex \Msg{************************************************************************} \Msg{* Installation} -\Msg{* Package: lualibs 2022-10-04 v2.75 Lua additional functions.} +\Msg{* Package: lualibs 2023-07-13 v2.76 Lua additional functions.} \Msg{************************************************************************} \keepsilent @@ -107,7 +107,7 @@ and lualibs-extended.lua. %<*driver> \NeedsTeXFormat{LaTeX2e} \ProvidesFile{lualibs.drv} - [2022/10/04 v2.75 Lua Libraries.] + [2023/07/13 v2.76 Lua Libraries.] \documentclass{ltxdoc} \usepackage{fancyvrb,xspace} \usepackage[x11names]{xcolor} @@ -208,7 +208,7 @@ and lualibs-extended.lua. % \GetFileInfo{lualibs.drv} % % \title{The \identifier{lualibs} package} -% \date{2022/10/04 v2.75} +% \date{2023/07/13 v2.76} % \author{Élie Roux · \email{elie.roux@telecom-bretagne.eu}\\ % Philipp Gesang · \email{phg@phi-gamma.net}\\ % The \LaTeX{} Project · \email{https://github.com/latex3/lualibs/}\\ @@ -430,8 +430,8 @@ lualibs = lualibs or { } lualibs.module_info = { name = "lualibs", - version = "2.75", --TAGVERSION - date = "2022-10-04", --TAGDATE + version = "2.76", --TAGVERSION + date = "2023-07-13", --TAGDATE description = "ConTeXt Lua standard libraries.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", @@ -584,8 +584,8 @@ local loadmodule = lualibs.loadmodule local lualibs_basic_module = { name = "lualibs-basic", - version = "2.75", --TAGVERSION - date = "2022-10-04", --TAGDATE + version = "2.76", --TAGVERSION + date = "2023-07-13", --TAGDATE description = "ConTeXt Lua libraries -- basic collection.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", @@ -665,8 +665,8 @@ lualibs = lualibs or { } local lualibs_extended_module = { name = "lualibs-extended", - version = "2.75", --TAGVERSION - date = "2022-10-04", --TAGDATE + version = "2.76", --TAGVERSION + date = "2023-07-13", --TAGDATE description = "ConTeXt Lua libraries -- extended collection.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", diff --git a/macros/luatex/generic/lualibs/lualibs.pdf b/macros/luatex/generic/lualibs/lualibs.pdf Binary files differindex 175e7e9f01..00ef113d5f 100644 --- a/macros/luatex/generic/lualibs/lualibs.pdf +++ b/macros/luatex/generic/lualibs/lualibs.pdf diff --git a/macros/luatex/generic/luaotfload/NEWS b/macros/luatex/generic/luaotfload/NEWS index ab31f8c84c..ffc67f5fe1 100644 --- a/macros/luatex/generic/luaotfload/NEWS +++ b/macros/luatex/generic/luaotfload/NEWS @@ -1,5 +1,15 @@ Change History -------------- +2023-08-19 luaotfload v3.24 + + * Add experimental configuration option to change default font lookup location + precedence. + * Support xdvipsk in DVI mode + * Preserve soft-hyphens when dropping default ignorable characters + * Hash cache keys to better support certain rather unflexible operating + systems + * Various bug fixes + 2022-10-03 luaotfload v3.23 * More reliable ToUnicode mappings in Harf mode diff --git a/macros/luatex/generic/luaotfload/README.md b/macros/luatex/generic/luaotfload/README.md index c325c4171e..3f84eccafc 100644 --- a/macros/luatex/generic/luaotfload/README.md +++ b/macros/luatex/generic/luaotfload/README.md @@ -1,8 +1,8 @@ # The Luaotfload Package -VERSION: 3.23 +VERSION: 3.24 -DATE: 2022-10-03 +DATE: 2023-08-19 ## Description diff --git a/macros/luatex/generic/luaotfload/filegraph.pdf b/macros/luatex/generic/luaotfload/filegraph.pdf Binary files differindex 79a370e2b1..950b5fe6b3 100644 --- a/macros/luatex/generic/luaotfload/filegraph.pdf +++ b/macros/luatex/generic/luaotfload/filegraph.pdf diff --git a/macros/luatex/generic/luaotfload/fontloader-2022-10-03.lua b/macros/luatex/generic/luaotfload/fontloader-2023-08-19.lua index 4df88ec41d..dd457f0221 100644 --- a/macros/luatex/generic/luaotfload/fontloader-2022-10-03.lua +++ b/macros/luatex/generic/luaotfload/fontloader-2023-08-19.lua @@ -1,9 +1,9 @@ --[[info----------------------------------------------------------------------- Luaotfload fontloader package - build 2022-10-03 20:21:57 + build 2023-08-19 22:30:03 ------------------------------------------------------------------------------- - © 2022 PRAGMA ADE / ConTeXt Development Team + © 2023 PRAGMA ADE / ConTeXt Development Team The code in this file is provided under the GPL v2.0 license. See the file COPYING in the Luaotfload repository for details. @@ -63,7 +63,7 @@ --info]]----------------------------------------------------------------------- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “data-con” 23a0f5386d46a1c157ae82a373e35fa0] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “data-con” b4ab51aaeab872d86d827f3e216bf05e] --- if not modules then modules={} end modules ['data-con']={ version=1.100, @@ -101,7 +101,7 @@ local mt={ end, __storage__=true } -function containers.define(category,subcategory,version,enabled) +function containers.define(category,subcategory,version,enabled,reload) if category and subcategory then local c=allocated[category] if not c then @@ -115,6 +115,7 @@ function containers.define(category,subcategory,version,enabled) subcategory=subcategory, storage={}, enabled=enabled, + reload=reload, version=version or math.pi, trace=false, } @@ -137,7 +138,8 @@ function containers.is_valid(container,name) end function containers.read(container,name) local storage=container.storage - local stored=storage[name] + local reload=container.reload + local stored=not reload and storage[name] if not stored and container.enabled and caches and containers.usecache then stored=loaddatafromcache(container.readables,name,container.writable) if stored and stored.cache_version==container.version then @@ -184,10 +186,10 @@ function containers.cleanname(name) return (gsub(lower(name),"[^%w\128-\255]+","-")) end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “data-con”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “data-con”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “basics-nod” 1750af43148def9e7a75c6900a96f9dc] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “basics-nod” 1750af43148def9e7a75c6900a96f9dc] --- if not modules then modules={} end modules ['luatex-fonts-nod']={ version=1.001, @@ -454,10 +456,10 @@ do end end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “basics-nod”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “basics-nod”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “basics-chr” ce4afac7ba19471f3c8f90800839f315] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “basics-chr” ce4afac7ba19471f3c8f90800839f315] --- characters=characters or {} @@ -4291,10 +4293,10 @@ characters.indicgroups={ }, } -end --- [luaotfload, fontloader-2022-10-03.lua scope for “basics-chr”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “basics-chr”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-ini” 5343de60613adb24cdd7a8d2ee1d153c] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-ini” 16b855c98602e4a3e9df39512916a427] --- if not modules then modules={} end modules ['font-ini']={ version=1.001, @@ -4335,10 +4337,10 @@ if node and not tex.getfontoffamily then tex.getfontoffamily=node.family_font end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-ini”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-ini”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “fonts-mis” 17e967c9ec4d001deefd43ddf25e98f7] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “fonts-mis” 17e967c9ec4d001deefd43ddf25e98f7] --- if not modules then modules={} end modules ['luatex-font-mis']={ version=1.001, @@ -4370,10 +4372,10 @@ function font.each() return table.sortedhash(fonts.hashes.identifiers) end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “fonts-mis”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “fonts-mis”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-con” 724e5dd14aec2d4d189f8619898004cf] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-con” bdbaaa361308c9ccc0a7dac0bf6c17ec] --- if not modules then modules={} end modules ['font-con']={ version=1.001, @@ -4660,19 +4662,9 @@ function constructors.scale(tfmdata,specification) target.unscaled=tfmdata local mathsize=tonumber(specification.mathsize) or 0 local textsize=tonumber(specification.textsize) or scaledpoints - local forcedsize=tonumber(parameters.mathsize ) or 0 local extrafactor=tonumber(specification.factor ) or 1 - if (mathsize==2 or forcedsize==2) and parameters.scriptpercentage then - scaledpoints=parameters.scriptpercentage*textsize/100 - elseif (mathsize==3 or forcedsize==3) and parameters.scriptscriptpercentage then - scaledpoints=parameters.scriptscriptpercentage*textsize/100 - elseif forcedsize>1000 then - scaledpoints=forcedsize - else - end targetparameters.mathsize=mathsize - targetparameters.textsize=textsize - targetparameters.forcedsize=forcedsize + targetparameters.textsize=textsize targetparameters.extrafactor=extrafactor local addtounicode=constructors.addtounicode local tounicode=fonts.mappings.tounicode @@ -5741,10 +5733,10 @@ function constructors.addcoreunicodes(unicodes) return unicodes end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-con”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-con”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “fonts-enc” c24fd6b4f34f87b9c4ff5e6193ce2656] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “fonts-enc” c24fd6b4f34f87b9c4ff5e6193ce2656] --- if not modules then modules={} end modules ['luatex-font-enc']={ version=1.001, @@ -5819,10 +5811,10 @@ function encodings.load(filename) return containers.write(encodings.cache,name,data) end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “fonts-enc”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “fonts-enc”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-cid” 22b0367742fb253deef84ef7ccf5e8de] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-cid” 22b0367742fb253deef84ef7ccf5e8de] --- if not modules then modules={} end modules ['font-cid']={ version=1.001, @@ -5973,10 +5965,10 @@ function cid.getmap(specification) return found end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-cid”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-cid”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-map” 27ee748150e56f5f0e5f0fefc864f35e] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-map” 27ee748150e56f5f0e5f0fefc864f35e] --- if not modules then modules={} end modules ['font-map']={ version=1.001, @@ -6384,10 +6376,10 @@ function mappings.addtounicode(data,filename,checklookups,forceligatures) end end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-map”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-map”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-vfc” a81c29eda98cd62cbebdb6c93544b50d] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-vfc” a81c29eda98cd62cbebdb6c93544b50d] --- if not modules then modules={} end modules ['font-vfc']={ version=1.001, @@ -6484,10 +6476,10 @@ helpers.commands=utilities.storage.allocate { dummy=dummy, } -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-vfc”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-vfc”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-otr” 1896ac990a961f6d6fec551ca9b52a83] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-otr” 2958a21bebcf0579f4e11f0646d1b402] --- if not modules then modules={} end modules ['font-otr']={ version=1.001, @@ -6497,6 +6489,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 @@ -7580,7 +7573,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 @@ -8241,6 +8234,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, @@ -8331,10 +8328,10 @@ function readers.extend(fontdata) end end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-otr”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-otr”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-oti” 309a75f9c14b77d87e94eba827dc4e71] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-oti” 309a75f9c14b77d87e94eba827dc4e71] --- if not modules then modules={} end modules ['font-oti']={ version=1.001, @@ -8477,10 +8474,10 @@ function otffeatures.checkeddefaultlanguage(featuretype,autolanguage,languages) end end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-oti”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-oti”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-ott” 3f67b1b1d40bbc222681d8db4aff0f42] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-ott” 427bdc77dd187158eafb79b7193400dc] --- if not modules then modules={} end modules ["font-ott"]={ version=1.001, @@ -8529,16 +8526,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", @@ -8558,6 +8559,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", @@ -8567,6 +8569,7 @@ local scripts=allocate { ["khar"]="kharosthi", ["khmr"]="khmer", ["khoj"]="khojki", + ["kits"]="khitan small script", ["knd2"]="kannada variant 2", ["knda"]="kannada", ["kthi"]="kaithi", @@ -8600,6 +8603,7 @@ local scripts=allocate { ["musc"]="musical symbols", ["mym2"]="myanmar variant 2", ["mymr"]="myanmar", + ["nand"]="nandinagari", ["narb"]="old north arabian", ["nbat"]="nabataean", ["newa"]="newa", @@ -8609,9 +8613,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", @@ -8643,7 +8648,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", @@ -8655,12 +8660,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", } @@ -8675,6 +8684,7 @@ local languages=allocate { ["agw" ]="agaw", ["aio" ]="aiton", ["aka" ]="akan", + ["akb" ]="batak angkola", ["als" ]="alsatian", ["alt" ]="altai", ["amh" ]="amharic", @@ -8687,6 +8697,7 @@ local languages=allocate { ["asm" ]="assamese", ["ast" ]="asturian", ["ath" ]="athapaskan", + ["avn" ]="avatime", ["avr" ]="avar", ["awa" ]="awadhi", ["aym" ]="aymara", @@ -8732,8 +8743,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", @@ -8768,14 +8783,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", @@ -8847,13 +8864,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", @@ -8878,10 +8898,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", @@ -8901,6 +8923,7 @@ local languages=allocate { ["kan" ]="kannada", ["kar" ]="karachay", ["kat" ]="georgian", + ["kaw" ]="kawi (old javanese)", ["kaz" ]="kazakh", ["kde" ]="makonde", ["kea" ]="kabuverdianu (crioulo)", @@ -8958,6 +8981,7 @@ local languages=allocate { ["kur" ]="kurdish", ["kuu" ]="kurukh", ["kuy" ]="kuy", + ["kwk" ]="kwakʼwala", ["kyk" ]="koryak", ["kyu" ]="western kayah", ["lad" ]="ladin", @@ -8969,6 +8993,7 @@ local languages=allocate { ["laz" ]="laz", ["lcr" ]="l-cree", ["ldk" ]="ladakhi", + ["lef" ]="lelemi", ["lez" ]="lezgi", ["lij" ]="ligurian", ["lim" ]="limburgish", @@ -8981,6 +9006,7 @@ local languages=allocate { ["lmo" ]="lombard", ["lmw" ]="lomwe", ["lom" ]="loma", + ["lpo" ]="lipo", ["lrc" ]="luri", ["lsb" ]="lower sorbian", ["lsm" ]="lule sami", @@ -8997,7 +9023,7 @@ local languages=allocate { ["mah" ]="marshallese", ["maj" ]="majang", ["mak" ]="makhuwa", - ["mal" ]="malayalam reformed", + ["mal" ]="malayalam", ["mam" ]="mam", ["man" ]="mansi", ["map" ]="mapudungun", @@ -9032,6 +9058,7 @@ local languages=allocate { ["mok" ]="moksha", ["mol" ]="moldavian", ["mon" ]="mon", + ["mnw" ]="thailand mon", ["mor" ]="moroccan", ["mos" ]="mossi", ["mri" ]="maori", @@ -9070,7 +9097,7 @@ local languages=allocate { ["nor" ]="norwegian", ["nov" ]="novial", ["nsm" ]="northern sami", - ["nso" ]="sotho, northern", + ["nso" ]="northern sotho", ["nta" ]="northern tai", ["nto" ]="esperanto", ["nym" ]="nyamwezi", @@ -9118,6 +9145,7 @@ local languages=allocate { ["rbu" ]="russian buriat", ["rcr" ]="r-cree", ["rej" ]="rejang", + ["rhg" ]="rohingya", ["ria" ]="riang", ["rif" ]="tarifit", ["rit" ]="ritarungo", @@ -9142,6 +9170,7 @@ local languages=allocate { ["scs" ]="north slavey", ["sek" ]="sekota", ["sel" ]="selkup", + ["sfm" ]="small flowery miao", ["sga" ]="old irish", ["sgo" ]="sango", ["sgs" ]="samogitian", @@ -9163,7 +9192,7 @@ local languages=allocate { ["snk" ]="soninke", ["sog" ]="sodo gurage", ["sop" ]="songe", - ["sot" ]="sotho, southern", + ["sot" ]="southern sotho", ["sqi" ]="albanian", ["srb" ]="serbian", ["srd" ]="sardinian", @@ -9204,7 +9233,9 @@ local languages=allocate { ["tht" ]="tahitian", ["tib" ]="tibetan", ["tiv" ]="tiv", + ["tj;" ]="tai laing", ["tkm" ]="turkmen", + ["tli" ]="tlingit", ["tmh" ]="tamashek", ["tmn" ]="temne", ["tna" ]="tswana", @@ -9218,7 +9249,7 @@ local languages=allocate { ["tsj" ]="tshangla", ["tua" ]="turoyo aramaic", ["tul" ]="tulu", - ["tum" ]="tulu", + ["tum" ]="tumbuka", ["tuv" ]="tuvin", ["tvl" ]="tuvalu", ["twi" ]="twi", @@ -9240,6 +9271,7 @@ local languages=allocate { ["wa" ]="wa", ["wag" ]="wagdi", ["war" ]="waray-waray", + ["wci" ]="waci gbe", ["wcr" ]="west-cree", ["wel" ]="welsh", ["wlf" ]="wolof", @@ -9251,17 +9283,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", @@ -9285,6 +9323,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", @@ -9361,8 +9400,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", @@ -9382,6 +9421,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", @@ -9596,10 +9636,10 @@ function otffeatures.normalize(features,wrap) end end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-ott”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-ott”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-cff” 651c74e4804fbb85d31267210298f466] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-cff” 999da544079698ce70178fd84bcdd67a] --- if not modules then modules={} end modules ['font-cff']={ version=1.001, @@ -9865,10 +9905,10 @@ do result.familyotherblues={ unpack(stack,1,top) } top=0 end+P("\10")/function() - result.strhw=stack[top] + result.stdhw=stack[top] top=0 end+P("\11")/function() - result.strvw=stack[top] + result.stdvw=stack[top] top=0 end+P("\13")/function() result.uniqueid=stack[top] @@ -9940,7 +9980,7 @@ do result.bluescale=stack[top] top=0 end+P("\10")/function() - result.bluesnap=stack[top] + result.blueshift=stack[top] top=0 end+P("\11")/function() result.bluefuzz=stack[top] @@ -9994,7 +10034,7 @@ do top=0 end ) - local remap={ + local remap_1={ ["\x00"]="00",["\x01"]="01",["\x02"]="02",["\x03"]="03",["\x04"]="04",["\x05"]="05",["\x06"]="06",["\x07"]="07",["\x08"]="08",["\x09"]="09",["\x0A"]="0.",["\x0B"]="0E",["\x0C"]="0E-",["\x0D"]="0",["\x0E"]="0-",["\x0F"]="0", ["\x10"]="10",["\x11"]="11",["\x12"]="12",["\x13"]="13",["\x14"]="14",["\x15"]="15",["\x16"]="16",["\x17"]="17",["\x18"]="18",["\x19"]="19",["\x1A"]="1.",["\x1B"]="1E",["\x1C"]="1E-",["\x1D"]="1",["\x1E"]="1-",["\x1F"]="1", ["\x20"]="20",["\x21"]="21",["\x22"]="22",["\x23"]="23",["\x24"]="24",["\x25"]="25",["\x26"]="26",["\x27"]="27",["\x28"]="28",["\x29"]="29",["\x2A"]="2.",["\x2B"]="2E",["\x2C"]="2E-",["\x2D"]="2",["\x2E"]="2-",["\x2F"]="2", @@ -10010,8 +10050,13 @@ do ["\xC0"]="E-0",["\xC1"]="E-1",["\xC2"]="E-2",["\xC3"]="E-3",["\xC4"]="E-4",["\xC5"]="E-5",["\xC6"]="E-6",["\xC7"]="E-7",["\xC8"]="E-8",["\xC9"]="E-9",["\xCA"]="E-.",["\xCB"]="E-E",["\xCC"]="E-E-",["\xCD"]="E-",["\xCE"]="E--",["\xCF"]="E-", ["\xD0"]="-0",["\xD1"]="-1",["\xD2"]="-2",["\xD3"]="-3",["\xD4"]="-4",["\xD5"]="-5",["\xD6"]="-6",["\xD7"]="-7",["\xD8"]="-8",["\xD9"]="-9",["\xDA"]="-.",["\xDB"]="-E",["\xDC"]="-E-",["\xDD"]="-",["\xDE"]="--",["\xDF"]="-", } - local p_last=S("\x0F\x1F\x2F\x3F\x4F\x5F\x6F\x7F\x8F\x9F\xAF\xBF")+R("\xF0\xFF") - local p_nibbles=P("\30")*Cs(((1-p_last)/remap)^0*(P(1)/remap))/function(n) + local remap_2={ + ["\x0F"]="0",["\x1F"]="1",["\x2F"]="2",["\x3F"]="3",["\x4F"]="4", + ["\x5F"]="5",["\x6F"]="6",["\x7F"]="7",["\x8F"]="8",["\x9F"]="9", + } + local p_last_1=S("\x0F\x1F\x2F\x3F\x4F\x5F\x6F\x7F\x8F\x9F\xAF\xBF") + local p_last_2=R("\xF0\xFF") + local p_nibbles=P("\30")*Cs(((1-(p_last_1+p_last_2))/remap_1)^0*(p_last_1/remap_2+p_last_2/""))/function(n) top=top+1 stack[top]=tonumber(n) or 0 end @@ -10122,7 +10167,7 @@ do local y=0 local width=false local lsb=0 -local result={} + local result={} local r=0 local stems=0 local globalbias=0 @@ -11015,6 +11060,7 @@ end end) local c_endchar=chars[14] local encode={} + local typeone=false setmetatableindex(encode,function(t,i) for i=-2048,-1130 do t[i]=char(28,band(rshift(i,8),0xFF),band(i,0xFF)) @@ -11140,6 +11186,13 @@ end elseif t<=254 then stack[top]=-t*256+64148-tab[i+1] i=i+2 + elseif typeone then + local n=0x1000000*tab[i+1]+0x10000*tab[i+2]+0x100*tab[i+3]+tab[i+4] + if n>=0x8000000 then + n=n-0xFFFFFFFF-1 + end + stack[top]=n + i=i+5 else local n1=0x100*tab[i+1]+tab[i+2] local n2=0x100*tab[i+3]+tab[i+4] @@ -11285,20 +11338,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 @@ -11345,7 +11385,7 @@ end ((l<1240 and 107) or (l<33900 and 1131) or 32768)+1 end end - local function processshape(tab,index,hack) + local function processshape(glyphs,tab,index,hack) if not tab then glyphs[index]={ boundingbox={ 0,0,0,0 }, @@ -11400,8 +11440,9 @@ end result=nil if glyph then glyph.stream=stream + glyph.width=width else - glyphs[index]={ stream=stream } + glyphs[index]={ stream=stream,width=width } end elseif glyph then glyph.segments=keepcurve~=false and result or nil @@ -11469,23 +11510,24 @@ result=nil end return privatedata.nominalwidthx or 0,privatedata.defaultwidthx or 0 end - parsecharstrings=function(fontdata,data,glphs,doshapes,tversion,streams,nobias) + parsecharstrings=function(fontdata,data,glphs,doshapes,tversion,streams,nobias,istypeone) local dictionary=data.dictionaries[1] local charstrings=dictionary.charstrings keepcurve=doshapes version=tversion + typeone=istypeone or false strings=data.strings globals=data.routines or {} locals=dictionary.subroutines or {} charset=dictionary.charset vsindex=dictionary.vsindex or 0 - glyphs=glphs or {} + local glyphs=glphs or {} globalbias,localbias=setbias(globals,locals,nobias) nominalwidth,defaultwidth=setwidths(dictionary.private) if charstrings then startparsing(fontdata,data,streams) for index=1,#charstrings do - processshape(charstrings[index],index-1) + processshape(glyphs,charstrings[index],index-1) end if justpass and next(seacs) then local charset=data.dictionaries[1].charset @@ -11499,7 +11541,7 @@ result=nil if bglyph and aglyph then local jp=justpass justpass=false - local x,y=processshape(charstrings[bindex+1],bindex,true) + local x,y=processshape(glyphs,charstrings[bindex+1],bindex,true) justpass=jp local base=bglyph.stream local accent=aglyph.stream @@ -11524,12 +11566,13 @@ result=nil locals=dictionary.subroutines or {} charset=false vsindex=dictionary.vsindex or 0 - glyphs=glphs or {} + local glyphs=glphs or {} justpass=streams==true seacs={} globalbias,localbias=setbias(globals,locals,nobias) nominalwidth,defaultwidth=setwidths(dictionary.private) - processshape(tab,index-1) + processshape(glyphs,tab,index-1) + return glyphs[index] end end local function readglobals(f,data,version) @@ -11677,7 +11720,7 @@ local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams) parseprivates(data,data.dictionaries) readlocals(f,data,dictionary,version) startparsing(fontdata,data,streams) - parsecharstrings(fontdata,data,glyphs,doshapes,version,streams) + parsecharstrings(fontdata,data,glyphs,doshapes,version,streams,false) stopparsing(fontdata,data) end local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams) @@ -11825,6 +11868,8 @@ function readers.cff(f,fontdata,specification) cffinfo.bluefuzz=data.bluefuzz cffinfo.stdhw=data.stdhw cffinfo.stdvw=data.stdvw + cffinfo.stemsnaph=data.stemsnaph + cffinfo.stemsnapv=data.stemsnapv end end cleanup(data,dictionaries) @@ -11867,44 +11912,11 @@ function readers.cff2(f,fontdata,specification) cleanup(data,dictionaries) end end -function readers.cffcheck(filename) - local f=io.open(filename,"rb") - if f then - local fontdata={ - glyphs={}, - } - local header=readheader(f) - if header.major~=1 then - report("only version %s is supported for table %a",1,"cff") - return - end - local names=readfontnames(f) - local dictionaries=readtopdictionaries(f) - local strings=readstrings(f) - local glyphs={} - local data={ - header=header, - names=names, - dictionaries=dictionaries, - strings=strings, - glyphs=glyphs, - nofglyphs=0, - } - parsedictionaries(data,dictionaries,"cff") - local cid=data.dictionaries[1].cid - if cid and cid.fdselect then - readfdselect(f,fontdata,data,glyphs,false) - else - readnoselect(f,fontdata,data,glyphs,false) - end - return data - end -end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-cff”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-cff”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-ttf” a3ff07150b3535fd32f68748d53fcd36] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-ttf” ff94e130d7c71edd899c4bae7745b7db] --- if not modules then modules={} end modules ['font-ttf']={ version=1.001, @@ -12070,20 +12082,7 @@ local function applyaxis(glyph,shape,deltas,dowidth) if dowidth then cnt=cnt-4 end - if cnt==1 then - local d=dpoints[1] - local x=xvalues[d]*factor - local y=yvalues[d]*factor - for i=1,nofpoints do - local p=points[i] - if x~=0 then - p[1]=p[1]+x - end - if y~=0 then - p[2]=p[2]+y - end - end - elseif cnt>0 then + if cnt>0 then local contours=shape.contours local nofcontours=#contours local first=1 @@ -12100,8 +12099,11 @@ local function applyaxis(glyph,shape,deltas,dowidth) end if found==last then lastindex=currentindex - break; + break elseif found>last then + while lastindex>1 and dpoints[lastindex]>last do + lastindex=lastindex-1 + end break end end @@ -12109,7 +12111,7 @@ local function applyaxis(glyph,shape,deltas,dowidth) local function find(i) local prv=lastindex for j=firstindex,lastindex do - local nxt=dpoints[j] + local nxt=dpoints[j] if nxt==i then return false,j,false elseif nxt>i then @@ -12557,6 +12559,12 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) end first=last+1 end + xmin=glyph.boundingbox[1] + local dlsb=glyph.dlsb + if dlsb then + xmin=xmin+dlsb + glyph.dlsb=nil + end glyph.boundingbox={ round(xmin),round(ymin),round(xmax),round(ymax) } end end @@ -13164,10 +13172,10 @@ function readers.gvar(f,fontdata,specification,glyphdata,shapedata) end end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-ttf”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-ttf”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-dsp” 23a82ec8fdb9f226427e78904402e48a] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-dsp” 755beef1b31e9dfd050e9d221d4e9ae3] --- if not modules then modules={} end modules ['font-dsp']={ version=1.001, @@ -13332,6 +13340,20 @@ local read_integer={ streamreader.readinteger3, streamreader.readinteger4, } +directives.register("fonts.streamreader",function() + read_cardinal={ + streamreader.readcardinal1, + streamreader.readcardinal2, + streamreader.readcardinal3, + streamreader.readcardinal4, + } + read_integer={ + streamreader.readinteger1, + streamreader.readinteger2, + streamreader.readinteger3, + streamreader.readinteger4, + } +end) local lookupnames={ gsub={ single="gsub_single", @@ -13406,7 +13428,6 @@ local function getaxisscale(segments,minimum,default,maximum,user) 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 @@ -14910,6 +14931,7 @@ do local noflookups=#lookups local lookupprefix=sub(what,2,2) local usedlookups=false + local allsteps={} for lookupid=1,noflookups do local lookup=lookups[lookupid] local lookuptype=lookup.type @@ -14944,6 +14966,7 @@ do steps[nofsteps]=step local rules=step.rules if rules then + allsteps[#allsteps+1]=step for i=1,#rules do local rule=rules[i] local before=rule.before @@ -15042,25 +15065,18 @@ do report("used %s lookups: % t",what,sortedkeys(usedlookups)) end local reported={} - local function report_issue(i,what,sequence,kind) - local name=sequence.name - if not reported[name] then - report("rule %i in %s lookup %a has %s lookups",i,what,name,kind) - reported[name]=true - end + local function report_issue(i,what,step,kind) + report("rule %i in step %i of %s has %s lookups",i,step,what,kind) 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 + local step=allsteps[s] 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,sequence,"no") + report_issue(i,what,s,"no") elseif not next(rlookups) then rule.lookups=nil else @@ -15096,12 +15112,12 @@ do sublookupcheck[lookupid]=1 h=nofsublookups else - report_issue(i,what,sequence,"missing") + report_issue(i,what,s,"missing") rule.lookups=nil break end else - report_issue(i,what,sequence,"bad") + report_issue(i,what,s,"bad") rule.lookups=nil break end @@ -15123,7 +15139,6 @@ do end end end - end for i,n in sortedhash(sublookupcheck) do local l=lookups[i] local t=l.type @@ -15546,7 +15561,7 @@ local function readmathglyphinfo(f,fontdata,offset) if not math then glyph.math={ accent=accent } else - math.accent=accent + math.accent=accent end end end @@ -15627,7 +15642,7 @@ local function readmathvariants(f,fontdata,offset) local vconstruction=readcardinaltable(f,vnofglyphs,ushort) local hconstruction=readcardinaltable(f,hnofglyphs,ushort) fontdata.mathconstants.MinConnectorOverlap=minoverlap - local function get(offset,coverage,nofglyphs,construction,kvariants,kparts,kitalic) + 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 @@ -15690,13 +15705,21 @@ local function readmathvariants(f,fontdata,offset) if italic and italic~=0 then math[kitalic]=italic end + if orientation then + math[korientation]=orientation + end end end end end end - get(offset,vcoverage,vnofglyphs,vconstruction,"vvariants","vparts","vitalic") - get(offset,hcoverage,hnofglyphs,hconstruction,"hvariants","hparts","hitalic") + 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) @@ -15722,9 +15745,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 and 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") @@ -16336,7 +16360,6 @@ function readers.hvar(f,fontdata,specification) end local tableoffset=gotodatatable(f,fontdata,"hvar",specification.variable) if not tableoffset then - report("no hvar table, expect problems due to messy widths") return end local version=readulong(f) @@ -16445,10 +16468,10 @@ function readers.mvar(f,fontdata,specification) end end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-dsp”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-dsp”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-oup” 76dc3379061e5650f772909966b5759e] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-oup” aaff9c28233bbea56e6d27ae50e04ff0] --- if not modules then modules={} end modules ['font-oup']={ version=1.001, @@ -17279,24 +17302,40 @@ local function unifyglyphs(fontdata,usenames) descriptions[unicode]=glyph end end - for index=1,nofglyphs do - local math=glyphs[index].math - if math then - local list=math.vparts - if list then - for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end - end - local list=math.hparts - if list then - for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end - end - local list=math.vvariants - if list then - for i=1,#list do list[i]=indices[list[i]] end + if LUATEXENGINE=="luametatex" then + for index=1,nofglyphs do + local math=glyphs[index].math + if math then + local list=math.parts + if list then + for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end + end + local list=math.variants + if list then + for i=1,#list do list[i]=indices[list[i]] end + end end - local list=math.hvariants - if list then - for i=1,#list do list[i]=indices[list[i]] end + end + else + for index=1,nofglyphs do + local math=glyphs[index].math + if math then + local list=math.vparts + if list then + for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end + end + local list=math.hparts + if list then + for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end + end + local list=math.vvariants + if list then + for i=1,#list do list[i]=indices[list[i]] end + end + local list=math.hvariants + if list then + for i=1,#list do list[i]=indices[list[i]] end + end end end end @@ -17307,7 +17346,9 @@ local function unifyglyphs(fontdata,usenames) if colors then for i=1,#colors do local c=colors[i] - c.slot=indices[c.slot] + if c then + c.slot=indices[c.slot] + end end end end @@ -19286,10 +19327,10 @@ end expandlookups(sublookups,sequences) end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-oup”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-oup”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-otl” 308b1aab04bc131da7eb8e8c3b0471d4] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-otl” 21196d193ce16f3996c9aa75e81e440c] --- if not modules then modules={} end modules ['font-otl']={ version=1.001, @@ -19317,7 +19358,7 @@ local trace_defining=false registertracker("fonts.defining",function(v) trace_d local report_otf=logs.reporter("fonts","otf loading") local fonts=fonts local otf=fonts.handlers.otf -otf.version=3.120 +otf.version=3.133 otf.cache=containers.define("fonts","otl",otf.version,true) otf.svgcache=containers.define("fonts","svg",otf.version,true) otf.pngcache=containers.define("fonts","png",otf.version,true) @@ -19800,24 +19841,6 @@ local function read_from_otf(specification) end return tfmdata end -local function checkmathsize(tfmdata,mathsize) - local mathdata=tfmdata.shared.rawdata.metadata.math - local mathsize=tonumber(mathsize) - if mathdata then - local parameters=tfmdata.parameters - parameters.scriptpercentage=mathdata.ScriptPercentScaleDown - parameters.scriptscriptpercentage=mathdata.ScriptScriptPercentScaleDown - parameters.mathsize=mathsize - end -end -registerotffeature { - name="mathsize", - description="apply mathsize specified in the font", - initializers={ - base=checkmathsize, - node=checkmathsize, - } -} function otf.collectlookups(rawdata,kind,script,language) if not kind then return @@ -20017,10 +20040,10 @@ otf.coverup={ end } -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-otl”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-otl”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-oto” 9febc4d75d17a543cd73fb17918f7307] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-oto” 1cc20f34606fb55d4646a0dd323499ef] --- if not modules then modules={} end modules ['font-oto']={ version=1.001, @@ -20489,10 +20512,10 @@ registerotffeature { } otf.basemodeinitializer=featuresinitializer -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-oto”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-oto”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-otj” b2c165bd6771a57633f992d07384b739] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-otj” b2c165bd6771a57633f992d07384b739] --- if not modules then modules={} end modules ['font-otj']={ version=1.001, @@ -21985,10 +22008,10 @@ function injections.handler(head,where) end end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-otj”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-otj”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-ota” 2bb12d708e35bc05443eba791e2554e7] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-ota” 7407b709ae7b2cdf36f68d5c98d51d12] --- if not modules then modules={} end modules ['font-ota']={ version=1.001, @@ -22482,10 +22505,10 @@ directives.register("otf.analyze.useunicodemarks",function(v) analyzers.useunicodemarks=v end) -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-ota”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-ota”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-ots” 55316a605d11a1d07d38795224c90a63] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-ots” c039b20490b526ec469e41a8584ebe6d] --- if not modules then modules={} end modules ['font-ots']={ version=1.001, @@ -22528,12 +22551,8 @@ local trace_testruns=false registertracker("otf.testruns",function(v) trace_tes local forcediscretionaries=false local forcepairadvance=false local repeatablemultiples=context or false -directives.register("otf.forcediscretionaries",function(v) - forcediscretionaries=v -end) -directives.register("otf.forcepairadvance",function(v) - forcepairadvance=v -end) +directives.register("otf.forcediscretionaries",function(v) forcediscretionaries=v end) +directives.register("otf.forcepairadvance",function(v) forcepairadvance=v end) local report_direct=logs.reporter("fonts","otf direct") local report_subchain=logs.reporter("fonts","otf subchain") local report_chain=logs.reporter("fonts","otf chain") @@ -22555,7 +22574,6 @@ local setboth=nuts.setboth local getid=nuts.getid local getstate=nuts.getstate local getsubtype=nuts.getsubtype -local setsubtype=nuts.setsubtype local getchar=nuts.getchar local setchar=nuts.setchar local getdisc=nuts.getdisc @@ -22575,10 +22593,10 @@ local flushcomponents=components.flush local ischar=nuts.ischar local usesfont=nuts.usesfont local insertnodeafter=nuts.insertafter -local copy_node=nuts.copy -local copy_node_list=nuts.copylist -local remove_node=nuts.remove -local find_node_tail=nuts.tail +local copynode=nuts.copy +local copynodelist=nuts.copylist +local removenode=nuts.remove +local findnodetail=nuts.tail local flushnodelist=nuts.flushlist local flushnode=nuts.flushnode local endofmath=nuts.endofmath @@ -22588,7 +22606,6 @@ local setmetatableindex=table.setmetatableindex local nextnode=nuts.traversers.node local nodecodes=nodes.nodecodes local glyphcodes=nodes.glyphcodes -local disccodes=nodes.disccodes local glyph_code=nodecodes.glyph local glue_code=nodecodes.glue local disc_code=nodecodes.disc @@ -22597,8 +22614,7 @@ local dir_code=nodecodes.dir local par_code=nodecodes.par local lefttoright_code=nodes.dirvalues.lefttoright local righttoleft_code=nodes.dirvalues.righttoleft -local discretionarydisc_code=disccodes.discretionary -local ligatureglyph_code=glyphcodes.ligature +local discretionarydisc_code=nodes.disccodes.discretionary local a_noligature=attributes.private("noligature") local injections=nodes.injections local setmark=injections.setmark @@ -22689,7 +22705,7 @@ local function cref(dataset,sequence,index) return "no valid dataset" end local merged=sequence.merged and "merged " or "" - if index then + if index and index>1 then return formatters["feature %a, type %a, %schain lookup %a, index %a"]( dataset[4],sequence.type,merged,sequence.name,index) else @@ -22746,7 +22762,7 @@ end local function appenddisc(disc,list) local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true) local posthead=list - local replacehead=copy_node_list(list) + local replacehead=copynodelist(list) if post then setlink(posttail,posthead) else @@ -22773,7 +22789,6 @@ local function markstoligature(head,start,stop,char) end resetinjection(base) setchar(base,char) - setsubtype(base,ligatureglyph_code) setcomponents(base,start) setlink(prev,base,next) flushcomponents(start) @@ -22811,7 +22826,6 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou end resetinjection(base) setchar(base,char) - setsubtype(base,ligatureglyph_code) setcomponents(base,comp) setlink(prev,base,next) if not discfound then @@ -22831,7 +22845,7 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou if trace_marks then logwarning("%s: keep ligature mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start)) end - local n=copy_node(start) + local n=copynode(start) copyinjection(n,start) head,current=insertnodeafter(head,current,n) elseif trace_marks then @@ -22895,57 +22909,57 @@ end local function multiple_glyphs(head,start,multiple,skiphash,what,stop) local nofmultiples=#multiple if nofmultiples>0 then + local first=start resetinjection(start) setchar(start,multiple[1]) if nofmultiples>1 then - local sn=getnext(start) - for k=2,nofmultiples do - local n=copy_node(start) + for i=2,nofmultiples do + local n=copynode(start) resetinjection(n) - setchar(n,multiple[k]) + setchar(n,multiple[i]) insertnodeafter(head,start,n) start=n end - if what~=true and repeatablemultiples then - local kind=type(what) - local m,f,l - if kind=="string" then - local what,n=string.match(what,"^repeat(.-)[:=](%d+)$") - if what=="middle" then - m=tonumber(n) - elseif what=="first" then - f=tonumber(n) - elseif what=="last" then - l=tonumber(n) - end - elseif kind=="table" then - m=what.middle - f=what.first - l=what.last - end - if f or m or l then - if m and m>1 and nofmultiples==3 then - local middle=getnext(first) - for i=2,m do - local n=copynode(middle) - resetinjection(n) - insertnodeafter(head,first,n) - end - end - if f and f>1 then - for i=2,f do - local n=copynode(first) - resetinjection(n) - insertnodeafter(head,first,n) - end - end - if l and l>1 then - for i=2,l do - local n=copynode(start) - resetinjection(n) - insertnodeafter(head,start,n) - start=n - end + end + if what~=true and repeatablemultiples then + local kind=type(what) + local m,f,l + if kind=="string" then + local what,n=string.match(what,"^repeat(.-)[:=](%d+)$") + if what=="middle" then + m=tonumber(n) + elseif what=="first" then + f=tonumber(n) + elseif what=="last" then + l=tonumber(n) + end + elseif kind=="table" then + m=what.middle + f=what.first + l=what.last + end + if f or m or l then + if m and m>1 and nofmultiples==3 then + local middle=getnext(first) + for i=2,m do + local n=copynode(middle) + resetinjection(n) + insertnodeafter(head,first,n) + end + end + if f and f>1 then + for i=2,f do + local n=copynode(first) + resetinjection(n) + insertnodeafter(head,first,n) + end + end + if l and l>1 then + for i=2,l do + local n=copynode(start) + resetinjection(n) + insertnodeafter(head,start,n) + start=n end end end @@ -23117,9 +23131,9 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip local prev=getprev(start) if stop then setnext(stop) - local copy=copy_node_list(start) + local copy=copynodelist(start) local tail=stop - local liat=find_node_tail(copy) + local liat=findnodetail(copy) if pre then setlink(liat,pre) end @@ -23130,7 +23144,7 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip replace=start else setnext(start) - local copy=copy_node(start) + local copy=copynode(start) if pre then setlink(copy,pre) end @@ -23507,7 +23521,7 @@ function chainprocs.gsub_remove(head,start,stop,dataset,sequence,currentlookup,r if trace_chains then logprocess("%s: removing character %s",cref(dataset,sequence,chainindex),gref(getchar(start))) end - head,start=remove_node(head,start,true) + head,start=removenode(head,start,true) return head,getprev(start),true end function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) @@ -24020,7 +24034,7 @@ do if not userkern then local thekern=nuts.new("kern",1) local setkern=nuts.setkern userkern=function(k) - local n=copy_node(thekern) + local n=copynode(thekern) setkern(n,k) return n end @@ -24057,26 +24071,33 @@ local function setdiscchecked(d,pre,post,replace) setdisc(d,pre,post,replace) end local noflags={ false,false,false,false } -local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck) +local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck,where) local size=ck[5]-ck[4]+1 local chainlookups=ck[6] local done=false if chainlookups then if size==1 then local chainlookup=chainlookups[1] - for j=1,#chainlookup do - local chainstep=chainlookup[j] - local chainkind=chainstep.type - local chainproc=chainprocs[chainkind] - if chainproc then - local ok - head,start,ok=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,1) - if ok then - done=true + if chainlookup then + for j=1,#chainlookup do + local chainstep=chainlookup[j] + if chainstep then + local chainkind=chainstep.type + local chainproc=chainprocs[chainkind] + if chainproc then + local ok + head,start,ok=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,1) + if ok then + done=true + end + else + logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind) + end + else + logprocess("%s: has an issue (1)",cref(dataset,sequence)) end - else - logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind) end + else end else local i=1 @@ -24101,20 +24122,24 @@ local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck) if chainlookup then for j=1,#chainlookup do local chainstep=chainlookup[j] - local chainkind=chainstep.type - local chainproc=chainprocs[chainkind] - if chainproc then - local ok,n - head,start,ok,n=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,i) - if ok then - done=true - if n and n>1 and i+n>nofchainlookups then - i=size - break + if chainstep then + local chainkind=chainstep.type + local chainproc=chainprocs[chainkind] + if chainproc then + local ok,n + head,start,ok,n=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,i) + if ok then + done=true + if n and n>1 and i+n>nofchainlookups then + i=size + break + end end + else + logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind) end else - logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind) + logprocess("%s: has an issue (2)",cref(dataset,sequence)) end end else @@ -24138,7 +24163,7 @@ local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck) else done=true if trace_contexts then - logprocess("%s: skipping match",cref(dataset,sequence)) + logprocess("%s: skipping match @ %i",cref(dataset,sequence),where) end end end @@ -24165,6 +24190,8 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) local last=start local prev=getprev(start) local hasglue=false + local useddisc=nil + local usedstart=start local i=f while i<=l do local id=getid(current) @@ -24227,7 +24254,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) tail=prev setprev(current,sweepnode) else - tail=find_node_tail(head) + tail=findnodetail(head) end setnext(sweepnode,current) setprev(head) @@ -24338,13 +24365,13 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) head=lookaheaddisc end local pre,post,replace=getdisc(lookaheaddisc) - local new=copy_node_list(cf) + local new=copynodelist(cf) local cnew=new if pre then - setlink(find_node_tail(cf),pre) + setlink(findnodetail(cf),pre) end if replace then - local tail=find_node_tail(new) + local tail=findnodetail(new) setlink(tail,replace) end for i=1,insertedmarks do @@ -24358,14 +24385,14 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) end if not notmatchpre[lookaheaddisc] then local ok=false - cf,start,ok=chainrun(cf,start,cl,dataset,sequence,rlmode,skiphash,ck) + cf,start,ok=chainrun(cf,start,cl,dataset,sequence,rlmode,skiphash,ck,1) if ok then done=true end end if not notmatchreplace[lookaheaddisc] then local ok=false - new,cnew,ok=chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck) + new,cnew,ok=chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck,2) if ok then done=true end @@ -24376,6 +24403,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) setdisc(lookaheaddisc,cf,post,new) end start=getprev(lookaheaddisc) + useddisc=lookaheaddisc sweephead[cf]=getnext(clast) or false sweephead[new]=getnext(cl) or false elseif backtrackdisc then @@ -24397,8 +24425,8 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) setprev(cf) setnext(cl) local pre,post,replace,pretail,posttail,replacetail=getdisc(backtrackdisc,true) - local new=copy_node_list(cf) - local cnew=find_node_tail(new) + local new=copynodelist(cf) + local cnew=findnodetail(new) for i=1,insertedmarks do cnew=getprev(cnew) end @@ -24408,14 +24436,14 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) end if not notmatchpost[backtrackdisc] then local ok=false - cf,start,ok=chainrun(cf,start,last,dataset,sequence,rlmode,skiphash,ck) + cf,start,ok=chainrun(cf,start,last,dataset,sequence,rlmode,skiphash,ck,3) if ok then done=true end end if not notmatchreplace[backtrackdisc] then local ok=false - new,cnew,ok=chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck) + new,cnew,ok=chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck,4) if ok then done=true end @@ -24436,30 +24464,55 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) setdisc(backtrackdisc,pre,post,replace) end start=getprev(backtrackdisc) + useddisc=backtrackdisc sweephead[post]=getnext(clast) or false sweephead[replace]=getnext(last) or false else local ok=false - head,start,ok=chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck) + head,start,ok=chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck,5) if ok then done=true end end - return head,start,done -end -local function chaintrac(head,start,dataset,sequence,rlmode,skiphash,ck,match,discseen,sweepnode) - local rule=ck[1] - local lookuptype=ck[8] or ck[2] - local nofseq=#ck[3] - local first=ck[4] - local last=ck[5] - local char=getchar(start) - logwarning("%s: rule %s %s at char %s for (%s,%s,%s) chars, lookuptype %a, %sdisc seen, %ssweeping", - cref(dataset,sequence),rule,match and "matches" or "nomatch", - gref(char),first-1,last-first+1,nofseq-last,lookuptype, - discseen and "" or "no ",sweepnode and "" or "not ") + if useddisc and start~=usedstart then + start=getnext(start) + end + return head,start,done,useddisc +end +local chaintrac do + local level=0 + local last={} + chaintrac=function(head,start,dataset,sequence,rlmode,skiphash,ck,match,discseen,sweepnode) + if dataset then + level=level+1 + last[level]=start + local rule=ck[1] + local lookuptype=ck[8] or ck[2] + local nofseq=#ck[3] + local first=ck[4] + local last=ck[5] + local char=getchar(start) + logwarning("+ %i : %s: rule %s %s at char %s for (%s,%s,%s) chars, lookuptype %a, %sdisc seen, %ssweeping", + level,cref(dataset,sequence),rule,match and "matches" or "nomatch", + gref(char),first-1,last-first+1,nofseq-last,lookuptype, + discseen and "" or "no ",sweepnode and "" or "not ") + else + local what=start and "done" or "continue" + local where=head==last[level] and "same" or "different" + local char=getchar(head) + if char then + logwarning("- %i : %s at char %s, %s node",level,what,gref(char),where) + else + logwarning("- %i : %s, %s node",level,what,where) + end + level=level-1 + end + end end local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,skiphash) + if not contexts then + return head,start,false + end local sweepnode=sweepnode local sweeptype=sweeptype local postreplace @@ -24487,7 +24540,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s local ck=contexts[k] local seq=ck[3] local f=ck[4] -local last=start + local last=start if not startchar or not seq[f][startchar] then goto next end @@ -24598,7 +24651,6 @@ local last=start end end if f>1 then - if startprev then local prev=startprev if prereplace and prev==checkdisc then prev=getprev(sweepnode) @@ -24713,9 +24765,6 @@ local last=start else goto next end - else - goto next - end end if s>l then local current=last and getnext(last) @@ -24839,12 +24888,15 @@ local last=start if discseen or sweepnode then head,start,done=chaindisk(head,start,dataset,sequence,rlmode,skipped and skiphash,ck) else - head,start,done=chainrun(head,start,last,dataset,sequence,rlmode,skipped and skiphash,ck) + head,start,done=chainrun(head,start,last,dataset,sequence,rlmode,skipped and skiphash,ck,6) + end + if trace_contexts then + chaintrac(start,done) end if done then break end - ::next:: + ::next:: end if discseen then notmatchpre={} @@ -24861,15 +24913,26 @@ handlers.gpos_context=handle_contextchain local function chained_contextchain(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash) local steps=currentlookup.steps local nofsteps=currentlookup.nofsteps - if nofsteps>1 then - reportmoresteps(dataset,sequence) - end - local l=steps[1].coverage[getchar(start)] - if l then - return handle_contextchain(head,start,dataset,sequence,l,rlmode,skiphash) + local char=getchar(start) + if nofsteps==1 then + local s=steps[1] + local l=s.coverage[char] + if l then + return handle_contextchain(head,start,dataset,sequence,l,rlmode,skiphash) + end else - return head,start,false + for i=1,nofsteps do + local s=steps[i] + local l=s.coverage[char] + if l then + local h,s,d=handle_contextchain(head,start,dataset,sequence,l,rlmode,skiphash) + if d then + return h,s,d + end + end + end end + return head,start,false end chainprocs.gsub_context=chained_contextchain chainprocs.gsub_contextchain=chained_contextchain @@ -25052,7 +25115,7 @@ local function kernrun(disc,k_run,font,attr,...) if done and trace_testruns then report_disc("done",disc) end - return nextstart,done + return nextstart end local function comprun(disc,c_run,...) if trace_compruns then @@ -25095,8 +25158,12 @@ local function comprun(disc,c_run,...) end setdisc(disc,pre,post,replace) end - return getnext(disc),renewed + return getnext(disc) end +local test_flatten_start=2 +directives.register("otf.testrun.forceflatten",function(v) + test_flatten_start=v and 1 or 2 +end) local function testrun(disc,t_run,c_run,...) if trace_testruns then report_disc("test",disc) @@ -25124,7 +25191,7 @@ local function testrun(disc,t_run,c_run,...) local d=d_replace>d_post and d_replace or d_post local head=getnext(disc) local tail=head - for i=2,d do + for i=test_flatten_start,d do local nx=getnext(tail) local id=getid(nx) if id==disc_code then @@ -25138,7 +25205,7 @@ local function testrun(disc,t_run,c_run,...) next=getnext(tail) setnext(tail) setprev(head) - local new=copy_node_list(head) + local new=copynodelist(head) if posttail then setlink(posttail,head) else @@ -25201,7 +25268,7 @@ local function testrun(disc,t_run,c_run,...) report_disc("done",disc) end end - return getnext(disc),renewed + return getnext(disc) end local nesting=0 local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) @@ -25619,7 +25686,7 @@ do head=h end elseif typ=="gsub_reversecontextchain" then - local start=find_node_tail(head) + local start=findnodetail(head) local rlmode=0 local merged=steps.merged while start do @@ -25697,13 +25764,12 @@ do start=getnext(start) elseif id==disc_code then if not discs or discs[start]==true then - local ok if gpossing then - start,ok=kernrun(start,k_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) + start=kernrun(start,k_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) elseif forcetestrun then - start,ok=testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) + start=testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) else - start,ok=comprun(start,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) + start=comprun(start,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) end else start=getnext(start) @@ -25767,13 +25833,12 @@ do start=getnext(start) elseif id==disc_code then if not discs or discs[start]==true then - local ok if gpossing then - start,ok=kernrun(start,k_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) + start=kernrun(start,k_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) elseif forcetestrun then - start,ok=testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) + start=testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) else - start,ok=comprun(start,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) + start=comprun(start,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) end else start=getnext(start) @@ -26145,10 +26210,10 @@ registerotffeature { }, } -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-ots”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-ots”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-osd” 1716513d8fe5f28e0e88daad2be0e05b] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-osd” c38c14c118680202c6f4b09734542c49] --- if not modules then modules={} end modules ['font-osd']={ version=1.001, @@ -27686,7 +27751,7 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) local subpos=nil local postpos=nil reorderreph.coverage={} - rephbase[font]={} + rephbase[font]={} for i=1,#seqsubset do local subset=seqsubset[i] local kind=subset[1] @@ -27807,7 +27872,7 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) end end end - local current,base,firstcons=start,nil,nil + local current,base,firstcons,subnotafterbase,postnotafterbase=start,nil,nil,nil,nil if getstate(start,s_rphf) then current=getnext(getnext(start)) end @@ -27863,10 +27928,16 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) logprocess("reorder two, handle nbsp") end end - else + else local last=getnext(stop) while current~=last do local next=getnext(current) + if current==subpos then + subnotafterbase=current + end + if current==postpos then + postnotafterbase=current + end if consonant[getchar(current)] then if not (current~=stop and next~=stop and halant[getchar(next)] and getchar(getnext(next))==c_zwj) then if not firstcons then @@ -27875,6 +27946,12 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) local a=getstate(current) if not (a==s_blwf or a==s_pstf or (a~=s_rphf and a~=s_blwf and ra[getchar(current)])) then base=current + if subnotafterbase then + subpos=base + end + if postnotafterbase then + postpos=base + end end end end @@ -27926,7 +28003,7 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) logprocess("reorder two, handle matra") end end - if dependent_vowel[char] then + if not moved[current] and dependent_vowel[char] then if pre_mark[char] then moved[current]=true local prev,next=getboth(current) @@ -27969,14 +28046,11 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) logprocess("reorder two, handle pre mark") end elseif above_mark[char] then - target=basepos - if subpos==basepos then - subpos=current - end - if postpos==basepos then + target=subpos + if postpos==subpos then postpos=current end - basepos=current + subpos=current elseif below_mark[char] then target=subpos if postpos==subpos then @@ -28196,11 +28270,7 @@ local function analyze_next_chars_one(c,font,variant) if pre_mark[v] and not already_pre_mark then already_pre_mark=true elseif post_mark[v] and not already_post_mark then - if devanagarihash[font].conjuncts=="mixed" then - return c - else already_post_mark=true - end elseif below_mark[v] and not already_below_mark then already_below_mark=true elseif above_mark[v] and not already_above_mark then @@ -28401,11 +28471,7 @@ local function analyze_next_chars_two(c,font) if pre_mark[v] and not already_pre_mark then already_pre_mark=true elseif post_mark[v] and not already_post_mark then - if devanagarihash[font].conjuncts=="mixed" then - return c - else - already_post_mark=true - end + already_post_mark=true elseif below_mark[v] and not already_below_mark then already_below_mark=true elseif above_mark[v] and not already_above_mark then @@ -28781,10 +28847,10 @@ for i=1,nofscripts do methods[scripts_two[i]]=method_two end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-osd”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-osd”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-ocl” 2a377351ae23c339764ec8ce2e8e9164] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-ocl” 2a377351ae23c339764ec8ce2e8e9164] --- if not modules then modules={} end modules ['font-ocl']={ version=1.001, @@ -29332,10 +29398,10 @@ if context then } end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-ocl”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-ocl”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-otc” 57f5270b894e40efa93149c7d3fb0209] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-otc” 0ad931eec679ebeceed5d4f02f4ba31b] --- if not modules then modules={} end modules ['font-otc']={ version=1.001, @@ -29459,6 +29525,10 @@ local function addfeature(data,feature,specifications,prepareonly) end local descriptions=data.descriptions local resources=data.resources + if not descriptions or not resources then + report_otf("missing specification") + return + end local features=resources.features local sequences=resources.sequences if not features or not sequences then @@ -30036,7 +30106,11 @@ local function addfeature(data,feature,specifications,prepareonly) local list=askedsteps[i] local coverage=nil local format=nil - if featuretype=="substitution" then +if type(list)=="function" then + list=list(data,specification,list,i) +end + if not list then + elseif featuretype=="substitution" then category="gsub" coverage=(mapping and list) or prepare_substitution(list,featuretype,nocheck) elseif featuretype=="ligature" then @@ -30159,10 +30233,10 @@ end otf.enhancers.enhance=enhance otf.enhancers.register("check extra features",enhance) -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-otc”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-otc”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-onr” 6d161533f3437435e12a0ad64866df44] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-onr” a3f85c886cf22fb27760d98603d51ffd] --- if not modules then modules={} end modules ['font-onr']={ version=1.001, @@ -30535,10 +30609,10 @@ function readers.getinfo(filename) end end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-onr”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-onr”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-one” bd39d42055a44ca2002f8ddbbbbf27c3] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-one” b7fb0389462a49bc1f41bebd2da85401] --- if not modules then modules={} end modules ['font-one']={ version=1.001, @@ -31253,10 +31327,10 @@ registerafmenhancer("normalize features",enhance_normalize_features) registerafmenhancer("check extra features",otfenhancers.enhance) registerafmenhancer("fix names",enhance_fix_names) -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-one”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-one”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-afk” 9da14e0fb22129c053acc599d1312544] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-afk” b7bef80aa4c18357cbfa0ae4df4d4046] --- if not modules then modules={} end modules ['font-afk']={ version=1.001, @@ -31423,10 +31497,10 @@ fonts.handlers.afm.helpdata={ } } -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-afk”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-afk”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “fonts-tfm” f0eb5e2a8068b17ad401bb7efdba1630] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “fonts-tfm” f0eb5e2a8068b17ad401bb7efdba1630] --- if not modules then modules={} end modules ['luatex-fonts-tfm']={ version=1.001, @@ -31941,10 +32015,10 @@ registertfmfeature { } } -end --- [luaotfload, fontloader-2022-10-03.lua scope for “fonts-tfm”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “fonts-tfm”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-lua” 1fbfdf7b689b2bdfd0e3bb9bf74ce136] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-lua” 1fbfdf7b689b2bdfd0e3bb9bf74ce136] --- if not modules then modules={} end modules ['font-lua']={ version=1.001, @@ -31984,10 +32058,10 @@ function readers.lua(specification) return check_lua(specification,fullname) end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-lua”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-lua”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-def” b9d908c2338b7dc443ce9d1e9fcb7139] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-def” cec0e49aee881c4cbd36d541f0162c6f] --- if not modules then modules={} end modules ['font-def']={ version=1.001, @@ -32387,10 +32461,10 @@ if not context then callbacks.register('define_font',definers.read,"definition of fonts (tfmdata preparation)") end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-def”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-def”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-shp” a40862fe382d26c1f3753431254bcfdd] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-shp” a174ac26390bd0828805747500df0077] --- if not modules then modules={} end modules ['font-shp']={ version=1.001, @@ -32407,7 +32481,7 @@ local afm=fonts.handlers.afm local pfb=fonts.handlers.pfb local hashes=fonts.hashes local identifiers=hashes.identifiers -local version=otf.version or 0.011 +local version=otf.version or 0.015 local shapescache=containers.define("fonts","shapes",version,true) local streamscache=containers.define("fonts","streams",version,true) local compact_streams=false @@ -32633,7 +32707,8 @@ local function loadstreams(cache,filename,sub,instance) if streams then local fontbbox=metadata.fontbbox or { 0,0,0,0 } for i=0,#streams do - streams[i]=streams[i].stream or "\14" + local s=streams[i] + streams[i]=s.stream or "\14" end data={ filename=filename, @@ -32715,7 +32790,8 @@ local function getstreamhash(fontid) local fontdata=identifiers[fontid] if fontdata then local properties=fontdata.properties - return makehash(properties.filename,properties.subfont,properties.instance),fontdata + local fonthash=makehash(properties.filename,properties.subfont,properties.instance) + return fonthash,fontdata end end local function loadstreamdata(fontdata) @@ -32755,10 +32831,10 @@ callback.register("glyph_stream_provider",function(id,index,mode) return "" end) -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-shp”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-shp”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “fonts-def” f435e0875f203f343157baeff876ec9c] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “fonts-def” f435e0875f203f343157baeff876ec9c] --- if not modules then modules={} end modules ['luatex-fonts-def']={ version=1.001, @@ -32839,10 +32915,10 @@ function fonts.definers.applypostprocessors(tfmdata) return tfmdata end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “fonts-def”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “fonts-def”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “fonts-ext” 32013cbc5d5d336be8b1d1e5879d86c4] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “fonts-ext” 32013cbc5d5d336be8b1d1e5879d86c4] --- if not modules then modules={} end modules ['luatex-fonts-ext']={ version=1.001, @@ -33028,10 +33104,10 @@ registerotffeature { } } -end --- [luaotfload, fontloader-2022-10-03.lua scope for “fonts-ext”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “fonts-ext”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-imp-tex” ceb087ef6fa2f89aed7179f60ddf8f35] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-imp-tex” 9882d382700e714cace08b7f09820958] --- if not modules then modules={} end modules ['font-imp-tex']={ version=1.001, @@ -33045,7 +33121,7 @@ local fonts=fonts local otf=fonts.handlers.otf local registerotffeature=otf.features.register local addotffeature=otf.addfeature -local specification={ +local tlig={ type="ligature", order={ "tlig" }, prepend=true, @@ -33054,12 +33130,17 @@ local specification={ [0x2014]={ 0x002D,0x002D,0x002D }, }, } -addotffeature("tlig",specification) -registerotffeature { - name="tlig", - description="tex ligatures", +local tquo={ + type="ligature", + order={ "tquo" }, + prepend=true, + data={ + [0x201C]={ 0x0060,0x0060 }, + [0x201D]={ 0x0027,0x0027 }, + [0x201E]={ 0x002C,0x002C }, + }, } -local specification={ +local trep={ type="substitution", order={ "trep" }, prepend=true, @@ -33067,11 +33148,12 @@ local specification={ [0x0027]=0x2019, }, } -addotffeature("trep",specification) -registerotffeature { - name="trep", - description="tex replacements", -} +addotffeature("trep",trep) +addotffeature("tlig",tlig) +addotffeature("tquo",tquo) +registerotffeature { name="tlig",description="tex ligatures" } +registerotffeature { name="tquo",description="tex quotes" } +registerotffeature { name="trep",description="tex replacements" } local anum_arabic={ [0x0030]=0x0660, [0x0031]=0x0661, @@ -33130,10 +33212,10 @@ registerotffeature { description="arabic digits", } -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-imp-tex”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-imp-tex”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-imp-ligatures” 250f6f4488ee770c23177afb2ff75676] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-imp-ligatures” 250f6f4488ee770c23177afb2ff75676] --- if not modules then modules={} end modules ['font-imp-ligatures']={ version=1.001, @@ -33247,10 +33329,10 @@ if context then } end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-imp-ligatures”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-imp-ligatures”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-imp-italics” defcb415bc1e0a0999b27773902adc18] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-imp-italics” 3cc555a1fe00dc45449f1e4a47a5c990] --- if not modules then modules={} end modules ['font-imp-italics']={ version=1.001, @@ -33259,30 +33341,11 @@ if not modules then modules={} end modules ['font-imp-italics']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local next=next +local next,tonumber=next,tonumber local fonts=fonts local handlers=fonts.handlers local registerotffeature=handlers.otf.features.register local registerafmfeature=handlers.afm.features.register -local function initialize(tfmdata,key,value) - for unicode,character in next,tfmdata.characters do - local olditalic=character.italic - if olditalic and olditalic~=0 then - character.width=character.width+olditalic - character.italic=0 - end - end -end -local specification={ - name="italicwidths", - description="add italic to width", - manipulators={ - base=initialize, - node=initialize, - } -} -registerotffeature(specification) -registerafmfeature(specification) local function initialize(tfmdata,value) if value then local parameters=tfmdata.parameters @@ -33354,10 +33417,10 @@ if context then registerafmfeature(dimensions_specification) end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-imp-italics”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-imp-italics”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “font-imp-effects” d05997c1826355548ec9aec1346f9f23] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “font-imp-effects” d05997c1826355548ec9aec1346f9f23] --- if not modules then modules={} end modules ['font-imp-effects']={ version=1.001, @@ -33714,10 +33777,10 @@ local specification={ registerotffeature(specification) registerafmfeature(specification) -end --- [luaotfload, fontloader-2022-10-03.lua scope for “font-imp-effects”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “font-imp-effects”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “fonts-lig” fbd251eea3810a43a8d5542319361d68] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “fonts-lig” fbd251eea3810a43a8d5542319361d68] --- fonts.handlers.otf.addfeature { @@ -35786,10 +35849,10 @@ fonts.handlers.otf.addfeature { ["type"]="ligature", } -end --- [luaotfload, fontloader-2022-10-03.lua scope for “fonts-lig”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “fonts-lig”] --- -do --- [luaotfload, fontloader-2022-10-03.lua scope for “fonts-gbn” 34e4543a02f6fbc8c2ade896cb6dc7df] --- +do --- [luaotfload, fontloader-2023-08-19.lua scope for “fonts-gbn” 34e4543a02f6fbc8c2ade896cb6dc7df] --- if not modules then modules={} end modules ['luatex-fonts-gbn']={ version=1.001, @@ -36054,7 +36117,7 @@ function nodes.simple_font_handler(head,groupcode,size,packtype,direction) return head end -end --- [luaotfload, fontloader-2022-10-03.lua scope for “fonts-gbn”] --- +end --- [luaotfload, fontloader-2023-08-19.lua scope for “fonts-gbn”] --- --- vim:ft=lua:sw=2:ts=8:et:tw=79 diff --git a/macros/luatex/generic/luaotfload/fontloader-data-con.lua b/macros/luatex/generic/luaotfload/fontloader-data-con.lua index ec2251b353..d7d3c7d461 100644 --- a/macros/luatex/generic/luaotfload/fontloader-data-con.lua +++ b/macros/luatex/generic/luaotfload/fontloader-data-con.lua @@ -13,19 +13,17 @@ local trace_cache = false trackers.register("resolvers.cache", functi local trace_containers = false trackers.register("resolvers.containers", function(v) trace_containers = v end) local trace_storage = false trackers.register("resolvers.storage", function(v) trace_storage = v end) ---[[ldx-- -<p>Once we found ourselves defining similar cache constructs several times, -containers were introduced. Containers are used to collect tables in memory and -reuse them when possible based on (unique) hashes (to be provided by the calling -function).</p> - -<p>Caching to disk is disabled by default. Version numbers are stored in the -saved table which makes it possible to change the table structures without -bothering about the disk cache.</p> - -<p>Examples of usage can be found in the font related code. This code is not -ideal but we need it in generic too so we compromise.</p> ---ldx]]-- +-- Once we found ourselves defining similar cache constructs several times, +-- containers were introduced. Containers are used to collect tables in memory and +-- reuse them when possible based on (unique) hashes (to be provided by the calling +-- function). +-- +-- Caching to disk is disabled by default. Version numbers are stored in the saved +-- table which makes it possible to change the table structures without bothering +-- about the disk cache. +-- +-- Examples of usage can be found in the font related code. This code is not ideal +-- but we need it in generic too so we compromise. containers = containers or { } local containers = containers @@ -56,7 +54,7 @@ local mt = { __storage__ = true } -function containers.define(category, subcategory, version, enabled) +function containers.define(category, subcategory, version, enabled, reload) if category and subcategory then local c = allocated[category] if not c then @@ -70,6 +68,7 @@ function containers.define(category, subcategory, version, enabled) subcategory = subcategory, storage = { }, enabled = enabled, + reload = reload, version = version or math.pi, -- after all, this is TeX trace = false, -- writable = getwritablepath and getwritablepath (category,subcategory) or { "." }, @@ -97,7 +96,8 @@ end function containers.read(container,name) local storage = container.storage - local stored = storage[name] + local reload = container.reload + local stored = not reload and storage[name] if not stored and container.enabled and caches and containers.usecache then stored = loaddatafromcache(container.readables,name,container.writable) if stored and stored.cache_version == container.version then diff --git a/macros/luatex/generic/luaotfload/fontloader-font-afk.lua b/macros/luatex/generic/luaotfload/fontloader-font-afk.lua index 761016d348..250c17e776 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-afk.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-afk.lua @@ -7,11 +7,9 @@ if not modules then modules = { } end modules ['font-afk'] = { dataonly = true, } ---[[ldx-- -<p>For ligatures, only characters with a code smaller than 128 make sense, -anything larger is encoding dependent. An interesting complication is that a -character can be in an encoding twice but is hashed once.</p> ---ldx]]-- +-- For ligatures, only characters with a code smaller than 128 make sense, anything +-- larger is encoding dependent. An interesting complication is that a character can +-- be in an encoding twice but is hashed once. local allocate = utilities.storage.allocate diff --git a/macros/luatex/generic/luaotfload/fontloader-font-cff.lua b/macros/luatex/generic/luaotfload/fontloader-font-cff.lua index 114d7dd079..c71c3aef33 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-cff.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-cff.lua @@ -348,11 +348,11 @@ do top = 0 end + P("\10") / function() - result.strhw = stack[top] + result.stdhw = stack[top] top = 0 end + P("\11") / function() - result.strvw = stack[top] + result.stdvw = stack[top] top = 0 end + P("\13") / function() @@ -453,7 +453,7 @@ do top = 0 end + P("\10") / function() - result.bluesnap = stack[top] + result.blueshift = stack[top] top = 0 end + P("\11") / function() @@ -528,7 +528,7 @@ do -- the second variant is much faster. Not that it matters much as we don't see -- such numbers often. - local remap = { + local remap_1 = { ["\x00"] = "00", ["\x01"] = "01", ["\x02"] = "02", ["\x03"] = "03", ["\x04"] = "04", ["\x05"] = "05", ["\x06"] = "06", ["\x07"] = "07", ["\x08"] = "08", ["\x09"] = "09", ["\x0A"] = "0.", ["\x0B"] = "0E", ["\x0C"] = "0E-", ["\x0D"] = "0", ["\x0E"] = "0-", ["\x0F"] = "0", ["\x10"] = "10", ["\x11"] = "11", ["\x12"] = "12", ["\x13"] = "13", ["\x14"] = "14", ["\x15"] = "15", ["\x16"] = "16", ["\x17"] = "17", ["\x18"] = "18", ["\x19"] = "19", ["\x1A"] = "1.", ["\x1B"] = "1E", ["\x1C"] = "1E-", ["\x1D"] = "1", ["\x1E"] = "1-", ["\x1F"] = "1", ["\x20"] = "20", ["\x21"] = "21", ["\x22"] = "22", ["\x23"] = "23", ["\x24"] = "24", ["\x25"] = "25", ["\x26"] = "26", ["\x27"] = "27", ["\x28"] = "28", ["\x29"] = "29", ["\x2A"] = "2.", ["\x2B"] = "2E", ["\x2C"] = "2E-", ["\x2D"] = "2", ["\x2E"] = "2-", ["\x2F"] = "2", @@ -544,11 +544,18 @@ do ["\xC0"] = "E-0", ["\xC1"] = "E-1", ["\xC2"] = "E-2", ["\xC3"] = "E-3", ["\xC4"] = "E-4", ["\xC5"] = "E-5", ["\xC6"] = "E-6", ["\xC7"] = "E-7", ["\xC8"] = "E-8", ["\xC9"] = "E-9", ["\xCA"] = "E-.", ["\xCB"] = "E-E", ["\xCC"] = "E-E-", ["\xCD"] = "E-", ["\xCE"] = "E--", ["\xCF"] = "E-", ["\xD0"] = "-0", ["\xD1"] = "-1", ["\xD2"] = "-2", ["\xD3"] = "-3", ["\xD4"] = "-4", ["\xD5"] = "-5", ["\xD6"] = "-6", ["\xD7"] = "-7", ["\xD8"] = "-8", ["\xD9"] = "-9", ["\xDA"] = "-.", ["\xDB"] = "-E", ["\xDC"] = "-E-", ["\xDD"] = "-", ["\xDE"] = "--", ["\xDF"] = "-", } + local remap_2 = { + ["\x0F"] = "0", ["\x1F"] = "1", ["\x2F"] = "2", ["\x3F"] = "3", ["\x4F"] = "4", + ["\x5F"] = "5", ["\x6F"] = "6", ["\x7F"] = "7", ["\x8F"] = "8", ["\x9F"] = "9", + } + + local p_last_1 = S("\x0F\x1F\x2F\x3F\x4F\x5F\x6F\x7F\x8F\x9F\xAF\xBF") + local p_last_2 = R("\xF0\xFF") - local p_last = S("\x0F\x1F\x2F\x3F\x4F\x5F\x6F\x7F\x8F\x9F\xAF\xBF") - + R("\xF0\xFF") + -- tricky, we don't want to append last - local p_nibbles = P("\30") * Cs(((1-p_last)/remap)^0 * (P(1)/remap)) / function(n) + -- local p_nibbles = P("\30") * Cs(((1-p_last)/remap)^0 * (P(1)/remap)) / function(n) + local p_nibbles = P("\30") * Cs(((1-(p_last_1+p_last_2))/remap_1)^0 * (p_last_1/remap_2 + p_last_2/"")) / function(n) -- 0-9=digit a=. b=E c=E- d=reserved e=- f=finish top = top + 1 stack[top] = tonumber(n) or 0 @@ -707,7 +714,7 @@ do local y = 0 local width = false local lsb = 0 -local result = { } + local result = { } local r = 0 local stems = 0 local globalbias = 0 @@ -1707,7 +1714,8 @@ end -- todo: round in blend - local encode = { } + local encode = { } + local typeone = false -- this eventually can become a helper @@ -1724,15 +1732,13 @@ end end for i=108,1131 do local v = 0xF700 + i - 108 --- t[i] = char(band(rshift(v,8),0xFF),band(v,0xFF)) t[i] = char(extract(v,8,8),extract(v,0,8)) end for i=1132,2048 do t[i] = char(28,band(rshift(i,8),0xFF),band(i,0xFF)) end - -- we could inline some ... setmetatableindex(encode,function(t,k) - -- 16.16-bit signed fixed value + -- as we're cff2 we write 16.16-bit signed fixed value local r = round(k) local v = rawget(t,r) if v then @@ -1837,42 +1843,6 @@ end -- precompiling and reuse is much slower than redoing the calls - -- local function decode(str) - -- local a, b, c, d, e = byte(str,1,5) - -- if a == 28 then - -- if c then - -- local n = 0x100 * b + c - -- if n >= 0x8000 then - -- return n - 0x10000 - -- else - -- return n - -- end - -- end - -- elseif a < 32 then - -- return false - -- elseif a <= 246 then - -- return a - 139 - -- elseif a <= 250 then - -- if b then - -- return a*256 - 63124 + b - -- end - -- elseif a <= 254 then - -- if b then - -- return -a*256 + 64148 - b - -- end - -- else - -- if e then - -- local n = 0x100 * b + c - -- if n >= 0x8000 then - -- return n - 0x10000 + (0x100 * d + e)/0xFFFF - -- else - -- return n + (0x100 * d + e)/0xFFFF - -- end - -- end - -- end - -- return false - -- end - process = function(tab) local i = 1 local n = #tab @@ -1896,8 +1866,14 @@ end -- stack[top] = -t*256 + 251*256 - tab[i+1] - 108 stack[top] = -t*256 + 64148 - tab[i+1] i = i + 2 + elseif typeone then + local n = 0x1000000 * tab[i+1] + 0x10000 * tab[i+2] + 0x100 * tab[i+3] + tab[i+4] + if n >= 0x8000000 then + n = n - 0xFFFFFFFF - 1 + end + stack[top] = n + i = i + 5 else - -- a 16.16 float (used for italic but pretty unreliable) local n1 = 0x100 * tab[i+1] + tab[i+2] local n2 = 0x100 * tab[i+3] + tab[i+4] if n1 >= 0x8000 then @@ -2054,24 +2030,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 @@ -2158,7 +2136,7 @@ end end end - local function processshape(tab,index,hack) + local function processshape(glyphs,tab,index,hack) if not tab then glyphs[index] = { @@ -2224,9 +2202,10 @@ result = nil -- report("vdata: %s",stream) -- end if glyph then - glyph.stream = stream + glyph.stream = stream + glyph.width = width else - glyphs[index] = { stream = stream } + glyphs[index] = { stream = stream, width = width } end elseif glyph then glyph.segments = keepcurve ~= false and result or nil @@ -2254,7 +2233,6 @@ result = nil name = charset and charset[index] or nil, } end - if trace_charstrings then report("width : %s",tostring(width)) report("boundingbox: % t",boundingbox) @@ -2305,19 +2283,21 @@ result = nil return privatedata.nominalwidthx or 0, privatedata.defaultwidthx or 0 end - parsecharstrings = function(fontdata,data,glphs,doshapes,tversion,streams,nobias) + parsecharstrings = function(fontdata,data,glphs,doshapes,tversion,streams,nobias,istypeone) local dictionary = data.dictionaries[1] local charstrings = dictionary.charstrings keepcurve = doshapes version = tversion + typeone = istypeone or false strings = data.strings globals = data.routines or { } locals = dictionary.subroutines or { } charset = dictionary.charset vsindex = dictionary.vsindex or 0 - glyphs = glphs or { } + + local glyphs = glphs or { } globalbias, localbias = setbias(globals,locals,nobias) nominalwidth, defaultwidth = setwidths(dictionary.private) @@ -2325,7 +2305,7 @@ result = nil if charstrings then startparsing(fontdata,data,streams) for index=1,#charstrings do - processshape(charstrings[index],index-1) + processshape(glyphs,charstrings[index],index-1) end if justpass and next(seacs) then -- old type 1 stuff ... seacs @@ -2341,7 +2321,7 @@ result = nil -- this is a real ugly hack but we seldom enter this branch (e.g. old lbr) local jp = justpass justpass = false - local x, y = processshape(charstrings[bindex+1],bindex,true) + local x, y = processshape(glyphs,charstrings[bindex+1],bindex,true) justpass = jp -- local base = bglyph.stream @@ -2372,7 +2352,8 @@ result = nil locals = dictionary.subroutines or { } charset = false vsindex = dictionary.vsindex or 0 - glyphs = glphs or { } + + local glyphs = glphs or { } justpass = streams == true seacs = { } @@ -2380,9 +2361,9 @@ result = nil globalbias, localbias = setbias(globals,locals,nobias) nominalwidth, defaultwidth = setwidths(dictionary.private) - processshape(tab,index-1) + processshape(glyphs,tab,index-1) - -- return glyphs[index] + return glyphs[index] end end @@ -2547,7 +2528,7 @@ local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams) parseprivates(data,data.dictionaries) readlocals(f,data,dictionary,version) startparsing(fontdata,data,streams) - parsecharstrings(fontdata,data,glyphs,doshapes,version,streams) + parsecharstrings(fontdata,data,glyphs,doshapes,version,streams,false) stopparsing(fontdata,data) end @@ -2715,6 +2696,8 @@ function readers.cff(f,fontdata,specification) cffinfo.bluefuzz = data.bluefuzz cffinfo.stdhw = data.stdhw cffinfo.stdvw = data.stdvw + cffinfo.stemsnaph = data.stemsnaph + cffinfo.stemsnapv = data.stemsnapv end end cleanup(data,dictionaries) @@ -2765,38 +2748,38 @@ end -- temporary helper needed for checking backend patches -function readers.cffcheck(filename) - local f = io.open(filename,"rb") - if f then - local fontdata = { - glyphs = { }, - } - local header = readheader(f) - if header.major ~= 1 then - report("only version %s is supported for table %a",1,"cff") - return - end - local names = readfontnames(f) - local dictionaries = readtopdictionaries(f) - local strings = readstrings(f) - local glyphs = { } - local data = { - header = header, - names = names, - dictionaries = dictionaries, - strings = strings, - glyphs = glyphs, - nofglyphs = 0, - } - -- - parsedictionaries(data,dictionaries,"cff") - -- - local cid = data.dictionaries[1].cid - if cid and cid.fdselect then - readfdselect(f,fontdata,data,glyphs,false) - else - readnoselect(f,fontdata,data,glyphs,false) - end - return data - end -end +-- function readers.cffcheck(filename) +-- local f = io.open(filename,"rb") +-- if f then +-- local fontdata = { +-- glyphs = { }, +-- } +-- local header = readheader(f) +-- if header.major ~= 1 then +-- report("only version %s is supported for table %a",1,"cff") +-- return +-- end +-- local names = readfontnames(f) +-- local dictionaries = readtopdictionaries(f) +-- local strings = readstrings(f) +-- local glyphs = { } +-- local data = { +-- header = header, +-- names = names, +-- dictionaries = dictionaries, +-- strings = strings, +-- glyphs = glyphs, +-- nofglyphs = 0, +-- } +-- -- +-- parsedictionaries(data,dictionaries,"cff") +-- -- +-- local cid = data.dictionaries[1].cid +-- if cid and cid.fdselect then +-- readfdselect(f,fontdata,data,glyphs,false) +-- else +-- readnoselect(f,fontdata,data,glyphs,false) +-- end +-- return data +-- end +-- end diff --git a/macros/luatex/generic/luaotfload/fontloader-font-con.lua b/macros/luatex/generic/luaotfload/fontloader-font-con.lua index f650e5b03d..10f98ca120 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-con.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-con.lua @@ -6,6 +6,9 @@ if not modules then modules = { } end modules ['font-con'] = { license = "see context related readme files" } +-- Todo: Enable fixes from the lmt to here. Also in font-oto.lua wrt the changed +-- assignments. (Around texlive 2024 in order not to disturb generic.) + -- some names of table entries will be changed (no _) local next, tostring, tonumber, rawget = next, tostring, tonumber, rawget @@ -22,11 +25,9 @@ local trace_scaling = false trackers.register("fonts.scaling", function(v) local report_defining = logs.reporter("fonts","defining") --- watch out: no negative depths and negative eights permitted in regular fonts - ---[[ldx-- -<p>Here we only implement a few helper functions.</p> ---ldx]]-- +-- Watch out: no negative depths and negative heights are permitted in regular +-- fonts. Also, the code in LMTX is a bit different. Here we only implement a +-- few helper functions. local fonts = fonts local constructors = fonts.constructors or { } @@ -59,11 +60,9 @@ constructors.designsizes = designsizes local loadedfonts = allocate() constructors.loadedfonts = loadedfonts ---[[ldx-- -<p>We need to normalize the scale factor (in scaled points). This has to -do with the fact that <l n='tex'/> uses a negative multiple of 1000 as -a signal for a font scaled based on the design size.</p> ---ldx]]-- +-- We need to normalize the scale factor (in scaled points). This has to do with the +-- fact that TeX uses a negative multiple of 1000 as a signal for a font scaled +-- based on the design size. local factors = { pt = 65536.0, @@ -118,22 +117,18 @@ function constructors.getmathparameter(tfmdata,name) end end ---[[ldx-- -<p>Beware, the boundingbox is passed as reference so we may not overwrite it -in the process; numbers are of course copies. Here 65536 equals 1pt. (Due to -excessive memory usage in CJK fonts, we no longer pass the boundingbox.)</p> ---ldx]]-- - --- The scaler is only used for otf and afm and virtual fonts. If a virtual font has italic --- correction make sure to set the hasitalics flag. Some more flags will be added in the --- future. - ---[[ldx-- -<p>The reason why the scaler was originally split, is that for a while we experimented -with a helper function. However, in practice the <l n='api'/> calls are too slow to -make this profitable and the <l n='lua'/> based variant was just faster. A days -wasted day but an experience richer.</p> ---ldx]]-- +-- Beware, the boundingbox is passed as reference so we may not overwrite it in the +-- process; numbers are of course copies. Here 65536 equals 1pt. (Due to excessive +-- memory usage in CJK fonts, we no longer pass the boundingbox.) +-- +-- The scaler is only used for OTF and AFM and virtual fonts. If a virtual font has +-- italic correction make sure to set the hasitalics flag. Some more flags will be +-- added in the future. +-- +-- The reason why the scaler was originally split, is that for a while we +-- experimented with a helper function. However, in practice the API calls are too +-- slow to make this profitable and the Lua based variant was just faster. A days +-- wasted day but an experience richer. function constructors.cleanuptable(tfmdata) -- This no longer makes sense because the addition of font.getcopy and its @@ -388,20 +383,20 @@ function constructors.scale(tfmdata,specification) -- local mathsize = tonumber(specification.mathsize) or 0 local textsize = tonumber(specification.textsize) or scaledpoints - local forcedsize = tonumber(parameters.mathsize ) or 0 -- can be set by the feature "mathsize" + -- local forcedsize = tonumber(parameters.mathsize ) or 0 -- can be set by the feature "mathsize" local extrafactor = tonumber(specification.factor ) or 1 - if (mathsize == 2 or forcedsize == 2) and parameters.scriptpercentage then - scaledpoints = parameters.scriptpercentage * textsize / 100 - elseif (mathsize == 3 or forcedsize == 3) and parameters.scriptscriptpercentage then - scaledpoints = parameters.scriptscriptpercentage * textsize / 100 - elseif forcedsize > 1000 then -- safeguard - scaledpoints = forcedsize - else - -- in context x and xx also use mathsize - end + -- if context then + -- -- do nothing, as we moved this upstream + -- elseif (mathsize == 2 or forcedsize == 2) and parameters.scriptpercentage then + -- scaledpoints = parameters.scriptpercentage * textsize / 100 + -- elseif (mathsize == 3 or forcedsize == 3) and parameters.scriptscriptpercentage then + -- scaledpoints = parameters.scriptscriptpercentage * textsize / 100 + -- elseif forcedsize > 1000 then -- safeguard + -- scaledpoints = forcedsize + -- end targetparameters.mathsize = mathsize -- context specific targetparameters.textsize = textsize -- context specific - targetparameters.forcedsize = forcedsize -- context specific + -- targetparameters.forcedsize = forcedsize -- context specific targetparameters.extrafactor = extrafactor -- context specific -- local addtounicode = constructors.addtounicode @@ -534,7 +529,6 @@ function constructors.scale(tfmdata,specification) local realdimensions = properties.realdimensions local writingmode = properties.writingmode or "horizontal" local identity = properties.identity or "horizontal" - -- local vfonts = target.fonts if vfonts and #vfonts > 0 then target.fonts = fastcopy(vfonts) -- maybe we virtualize more afterwards @@ -657,6 +651,14 @@ function constructors.scale(tfmdata,specification) if changed then local c = changed[unicode] if c and c ~= unicode then + -- local cc = changed[c] + -- if cc then + -- while cc do + -- c = cc + -- cc = changed[c] + -- end + -- end + -- check not needed: if c then description = descriptions[c] or descriptions[unicode] or character character = characters[c] or character @@ -1094,9 +1096,7 @@ function constructors.finalize(tfmdata) return tfmdata end ---[[ldx-- -<p>A unique hash value is generated by:</p> ---ldx]]-- +-- A unique hash value is generated by: local hashmethods = { } constructors.hashmethods = hashmethods @@ -1155,13 +1155,11 @@ hashmethods.normal = function(list) end end ---[[ldx-- -<p>In principle we can share tfm tables when we are in need for a font, but then -we need to define a font switch as an id/attr switch which is no fun, so in that -case users can best use dynamic features ... so, we will not use that speedup. Okay, -when we get rid of base mode we can optimize even further by sharing, but then we -loose our testcases for <l n='luatex'/>.</p> ---ldx]]-- +-- In principle we can share tfm tables when we are in need for a font, but then we +-- need to define a font switch as an id/attr switch which is no fun, so in that +-- case users can best use dynamic features ... so, we will not use that speedup. +-- Okay, when we get rid of base mode we can optimize even further by sharing, but +-- then we loose our testcases for LuaTeX. function constructors.hashinstance(specification,force) local hash = specification.hash @@ -1517,10 +1515,7 @@ do end ---[[ldx-- -<p>We need to check for default features. For this we provide -a helper function.</p> ---ldx]]-- +-- We need to check for default features. For this we provide a helper function. function constructors.checkedfeatures(what,features) local defaults = handlers[what].features.defaults diff --git a/macros/luatex/generic/luaotfload/fontloader-font-def.lua b/macros/luatex/generic/luaotfload/fontloader-font-def.lua index b752b3258c..01bced6d16 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-def.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-def.lua @@ -24,10 +24,9 @@ trackers.register("fonts.loading", "fonts.defining", "otf.loading", "afm.loading local report_defining = logs.reporter("fonts","defining") ---[[ldx-- -<p>Here we deal with defining fonts. We do so by intercepting the -default loader that only handles <l n='tfm'/>.</p> ---ldx]]-- +-- Here we deal with defining fonts. We do so by intercepting the default loader +-- that only handles TFM files. Although, we started out that way but in the +-- meantime we can hardly speak of TFM any more. local fonts = fonts local fontdata = fonts.hashes.identifiers @@ -53,25 +52,18 @@ local designsizes = constructors.designsizes local resolvefile = fontgoodies and fontgoodies.filenames and fontgoodies.filenames.resolve or function(s) return s end ---[[ldx-- -<p>We hardly gain anything when we cache the final (pre scaled) -<l n='tfm'/> table. But it can be handy for debugging, so we no -longer carry this code along. Also, we now have quite some reference -to other tables so we would end up with lots of catches.</p> ---ldx]]-- - ---[[ldx-- -<p>We can prefix a font specification by <type>name:</type> or -<type>file:</type>. The first case will result in a lookup in the -synonym table.</p> - -<typing> -[ name: | file: ] identifier [ separator [ specification ] ] -</typing> - -<p>The following function split the font specification into components -and prepares a table that will move along as we proceed.</p> ---ldx]]-- +-- We hardly gain anything when we cache the final (pre scaled) TFM table. But it +-- can be handy for debugging, so we no longer carry this code along. Also, we now +-- have quite some reference to other tables so we would end up with lots of +-- catches. +-- +-- We can prefix a font specification by "name:" or "file:". The first case will +-- result in a lookup in the synonym table. +-- +-- [ name: | file: ] identifier [ separator [ specification ] ] +-- +-- The following function split the font specification into components and prepares +-- a table that will move along as we proceed. -- beware, we discard additional specs -- @@ -164,9 +156,7 @@ if context then end ---[[ldx-- -<p>We can resolve the filename using the next function:</p> ---ldx]]-- +-- We can resolve the filename using the next function: definers.resolvers = definers.resolvers or { } local resolvers = definers.resolvers @@ -258,23 +248,17 @@ function definers.resolve(specification) return specification end ---[[ldx-- -<p>The main read function either uses a forced reader (as determined by -a lookup) or tries to resolve the name using the list of readers.</p> - -<p>We need to cache when possible. We do cache raw tfm data (from <l -n='tfm'/>, <l n='afm'/> or <l n='otf'/>). After that we can cache based -on specificstion (name) and size, that is, <l n='tex'/> only needs a number -for an already loaded fonts. However, it may make sense to cache fonts -before they're scaled as well (store <l n='tfm'/>'s with applied methods -and features). However, there may be a relation between the size and -features (esp in virtual fonts) so let's not do that now.</p> - -<p>Watch out, here we do load a font, but we don't prepare the -specification yet.</p> ---ldx]]-- - --- very experimental: +-- The main read function either uses a forced reader (as determined by a lookup) or +-- tries to resolve the name using the list of readers. +-- +-- We need to cache when possible. We do cache raw tfm data (from TFM, AFM or OTF). +-- After that we can cache based on specificstion (name) and size, that is, TeX only +-- needs a number for an already loaded fonts. However, it may make sense to cache +-- fonts before they're scaled as well (store TFM's with applied methods and +-- features). However, there may be a relation between the size and features (esp in +-- virtual fonts) so let's not do that now. +-- +-- Watch out, here we do load a font, but we don't prepare the specification yet. function definers.applypostprocessors(tfmdata) local postprocessors = tfmdata.postprocessors @@ -439,17 +423,13 @@ function constructors.readanddefine(name,size) -- no id -- maybe a dummy first return fontdata[id], id end ---[[ldx-- -<p>So far the specifiers. Now comes the real definer. Here we cache -based on id's. Here we also intercept the virtual font handler. Since -it evolved stepwise I may rewrite this bit (combine code).</p> - -In the previously defined reader (the one resulting in a <l n='tfm'/> -table) we cached the (scaled) instances. Here we cache them again, but -this time based on id. We could combine this in one cache but this does -not gain much. By the way, passing id's back to in the callback was -introduced later in the development.</p> ---ldx]]-- +-- So far the specifiers. Now comes the real definer. Here we cache based on id's. +-- Here we also intercept the virtual font handler. +-- +-- In the previously defined reader (the one resulting in a TFM table) we cached the +-- (scaled) instances. Here we cache them again, but this time based on id. We could +-- combine this in one cache but this does not gain much. By the way, passing id's +-- back to in the callback was introduced later in the development. function definers.registered(hash) local id = internalized[hash] @@ -522,9 +502,7 @@ function font.getfont(id) return fontdata[id] -- otherwise issues end ---[[ldx-- -<p>We overload the <l n='tfm'/> reader.</p> ---ldx]]-- +-- We overload the <l n='tfm'/> reader. if not context then callbacks.register('define_font', definers.read, "definition of fonts (tfmdata preparation)") diff --git a/macros/luatex/generic/luaotfload/fontloader-font-dsp.lua b/macros/luatex/generic/luaotfload/fontloader-font-dsp.lua index 8f65ed9d94..5f9cf1a62e 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-dsp.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-dsp.lua @@ -234,6 +234,24 @@ local read_integer = { streamreader.readinteger4, } +directives.register("fonts.streamreader",function() + + read_cardinal = { + streamreader.readcardinal1, + streamreader.readcardinal2, + streamreader.readcardinal3, + streamreader.readcardinal4, + } + + read_integer = { + streamreader.readinteger1, + streamreader.readinteger2, + streamreader.readinteger3, + streamreader.readinteger4, + } + +end) + -- 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. @@ -360,7 +378,7 @@ local function getaxisscale(segments,minimum,default,maximum,user) for i=1,#segments do local s = segments[i] if type(s) ~= "number" then - report("using default axis scale") + -- report("using default axis scale") return default elseif s[1] >= default then if s[2] == default then @@ -2177,6 +2195,8 @@ do -- 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 @@ -2214,6 +2234,7 @@ do 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 @@ -2329,29 +2350,31 @@ do local reported = { } - local function report_issue(i,what,sequence,kind) - local name = sequence.name - if not reported[name] then - report("rule %i in %s lookup %a has %s lookups",i,what,name,kind) - reported[name] = true - end + 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 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,sequence,"no") + report_issue(i,what,s,"no") elseif not next(rlookups) then -- can be ok as it aborts a chain sequence - -- report_issue(i,what,sequence,"empty") + -- report_issue(i,what,s,"empty") rule.lookups = nil else -- we can have holes in rlookups flagged false and we can have multiple lookups @@ -2392,12 +2415,12 @@ do sublookupcheck[lookupid] = 1 h = nofsublookups else - report_issue(i,what,sequence,"missing") + report_issue(i,what,s,"missing") rule.lookups = nil break end else - report_issue(i,what,sequence,"bad") + report_issue(i,what,s,"bad") rule.lookups = nil break end @@ -2419,7 +2442,7 @@ do end end end - end + -- end -- new per 2022-09-25 for i, n in sortedhash(sublookupcheck) do local l = lookups[i] @@ -2881,7 +2904,7 @@ local function readmathglyphinfo(f,fontdata,offset) if not math then glyph.math = { accent = accent } else - math.accent = accent + math.accent = accent -- will become math.topanchor end end end @@ -2971,7 +2994,7 @@ local function readmathvariants(f,fontdata,offset) -- advance = readushort(f), -- } - local function get(offset,coverage,nofglyphs,construction,kvariants,kparts,kitalic) + 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 @@ -3036,14 +3059,23 @@ local function readmathvariants(f,fontdata,offset) if italic and italic ~= 0 then math[kitalic] = italic end + if orientation then + math[korientation] = orientation + end end end end end end - get(offset,vcoverage,vnofglyphs,vconstruction,"vvariants","vparts","vitalic") - get(offset,hcoverage,hnofglyphs,hconstruction,"hvariants","hparts","hitalic") + -- if LUATEXENGINE == "luametatex" then + 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) @@ -3075,9 +3107,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 and 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") @@ -3809,7 +3843,7 @@ function readers.hvar(f,fontdata,specification) end local tableoffset = gotodatatable(f,fontdata,"hvar",specification.variable) if not tableoffset then - report("no hvar table, expect problems due to messy widths") + -- report("no hvar table, expect problems due to messy widths") return end diff --git a/macros/luatex/generic/luaotfload/fontloader-font-imp-italics.lua b/macros/luatex/generic/luaotfload/fontloader-font-imp-italics.lua index 6c432d7cf4..8b38c5893b 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-imp-italics.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-imp-italics.lua @@ -6,34 +6,39 @@ if not modules then modules = { } end modules ['font-imp-italics'] = { license = "see context related readme files" } -local next = next +local next, tonumber = next, tonumber local fonts = fonts local handlers = fonts.handlers local registerotffeature = handlers.otf.features.register local registerafmfeature = handlers.afm.features.register -local function initialize(tfmdata,key,value) - for unicode, character in next, tfmdata.characters do - local olditalic = character.italic - if olditalic and olditalic ~= 0 then - character.width = character.width + olditalic - character.italic = 0 - end - end -end - -local specification = { - name = "italicwidths", - description = "add italic to width", - manipulators = { - base = initialize, - node = initialize, -- only makes sense for math - } -} - -registerotffeature(specification) -registerafmfeature(specification) +-- This is a precursor to what we do in lmtx now via tweaks but at some point I +-- might make this a mkiv features too using staircase kerns. + +-- local function initialize(tfmdata,key,value) +-- local factor = tonumber(value) or 1 +-- for unicode, character in next, tfmdata.characters do +-- local olditalic = character.italic +-- if olditalic and olditalic ~= 0 then +-- character.width = character.width + olditalic +-- character.italic = 0 +-- character.bottomright = -factor * olditalic -- lmtx only +-- end +-- end +-- end +-- +-- local specification = { +-- name = "italicwidths", +-- description = "add italic to width", +-- manipulators = { +-- base = initialize, +-- node = initialize, -- only makes sense for math +-- } +-- } +-- +-- registerotffeature(specification) +-- registerafmfeature(specification) local function initialize(tfmdata,value) -- hm, always value if value then diff --git a/macros/luatex/generic/luaotfload/fontloader-font-imp-tex.lua b/macros/luatex/generic/luaotfload/fontloader-font-imp-tex.lua index b4b9a7b694..87a1ae3aa2 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-imp-tex.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-imp-tex.lua @@ -13,36 +13,31 @@ local otf = fonts.handlers.otf local registerotffeature = otf.features.register local addotffeature = otf.addfeature --- tlig (we need numbers for some fonts so ...) +-- We provide a few old and obsolete compatibility input features. We need numbers +-- for some fonts so no names here. Do we also need them for afm fonts? -local specification = { +local tlig = { type = "ligature", order = { "tlig" }, prepend = true, data = { - -- endash = "hyphen hyphen", - -- emdash = "hyphen hyphen hyphen", - [0x2013] = { 0x002D, 0x002D }, - [0x2014] = { 0x002D, 0x002D, 0x002D }, - -- quotedblleft = "quoteleft quoteleft", - -- quotedblright = "quoteright quoteright", - -- quotedblleft = "grave grave", - -- quotedblright = "quotesingle quotesingle", - -- quotedblbase = "comma comma", + [0x2013] = { 0x002D, 0x002D }, + [0x2014] = { 0x002D, 0x002D, 0x002D }, }, } -addotffeature("tlig",specification) - -registerotffeature { - -- this makes it a known feature (in tables) - name = "tlig", - description = "tex ligatures", +local tquo = { + type = "ligature", + order = { "tquo" }, + prepend = true, + data = { + [0x201C] = { 0x0060, 0x0060 }, + [0x201D] = { 0x0027, 0x0027 }, + [0x201E] = { 0x002C, 0x002C }, + }, } --- trep - -local specification = { +local trep = { type = "substitution", order = { "trep" }, prepend = true, @@ -53,13 +48,13 @@ local specification = { }, } -addotffeature("trep",specification) +addotffeature("trep",trep) -- last +addotffeature("tlig",tlig) +addotffeature("tquo",tquo) -- first -registerotffeature { - -- this makes it a known feature (in tables) - name = "trep", - description = "tex replacements", -} +registerotffeature { name = "tlig", description = "tex ligatures" } +registerotffeature { name = "tquo", description = "tex quotes" } +registerotffeature { name = "trep", description = "tex replacements" } -- some day this will be moved to font-imp-scripts.lua diff --git a/macros/luatex/generic/luaotfload/fontloader-font-ini.lua b/macros/luatex/generic/luaotfload/fontloader-font-ini.lua index 8bab6d9029..201cc69f48 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-ini.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-ini.lua @@ -6,9 +6,7 @@ if not modules then modules = { } end modules ['font-ini'] = { license = "see context related readme files" } ---[[ldx-- -<p>Not much is happening here.</p> ---ldx]]-- +-- Not much is happening here. local allocate = utilities.storage.allocate local sortedhash = table.sortedhash diff --git a/macros/luatex/generic/luaotfload/fontloader-font-one.lua b/macros/luatex/generic/luaotfload/fontloader-font-one.lua index 829f52ea04..25efc2a046 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-one.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-one.lua @@ -7,18 +7,16 @@ if not modules then modules = { } end modules ['font-one'] = { license = "see context related readme files" } ---[[ldx-- -<p>Some code may look a bit obscure but this has to do with the fact that we also use -this code for testing and much code evolved in the transition from <l n='tfm'/> to -<l n='afm'/> to <l n='otf'/>.</p> - -<p>The following code still has traces of intermediate font support where we handles -font encodings. Eventually font encoding went away but we kept some code around in -other modules.</p> - -<p>This version implements a node mode approach so that users can also more easily -add features.</p> ---ldx]]-- +-- Some code may look a bit obscure but this has to do with the fact that we also +-- use this code for testing and much code evolved in the transition from TFM to AFM +-- to OTF. +-- +-- The following code still has traces of intermediate font support where we handles +-- font encodings. Eventually font encoding went away but we kept some code around +-- in other modules. +-- +-- This version implements a node mode approach so that users can also more easily +-- add features. local fonts, logs, trackers, containers, resolvers = fonts, logs, trackers, containers, resolvers @@ -71,15 +69,13 @@ local overloads = fonts.mappings.overloads local applyruntimefixes = fonts.treatments and fonts.treatments.applyfixes ---[[ldx-- -<p>We cache files. Caching is taken care of in the loader. We cheat a bit by adding -ligatures and kern information to the afm derived data. That way we can set them faster -when defining a font.</p> - -<p>We still keep the loading two phased: first we load the data in a traditional -fashion and later we transform it to sequences. Then we apply some methods also -used in opentype fonts (like <t>tlig</t>).</p> ---ldx]]-- +-- We cache files. Caching is taken care of in the loader. We cheat a bit by adding +-- ligatures and kern information to the afm derived data. That way we can set them +-- faster when defining a font. +-- +-- We still keep the loading two phased: first we load the data in a traditional +-- fashion and later we transform it to sequences. Then we apply some methods also +-- used in opentype fonts (like tlig). function afm.load(filename) filename = resolvers.findfile(filename,'afm') or "" @@ -312,10 +308,8 @@ local function enhance_fix_names(data) end end ---[[ldx-- -<p>These helpers extend the basic table with extra ligatures, texligatures -and extra kerns. This saves quite some lookups later.</p> ---ldx]]-- +-- These helpers extend the basic table with extra ligatures, texligatures and extra +-- kerns. This saves quite some lookups later. local addthem = function(rawdata,ligatures) if ligatures then @@ -349,17 +343,14 @@ local function enhance_add_ligatures(rawdata) addthem(rawdata,afm.helpdata.ligatures) end ---[[ldx-- -<p>We keep the extra kerns in separate kerning tables so that we can use -them selectively.</p> ---ldx]]-- - --- This is rather old code (from the beginning when we had only tfm). If --- we unify the afm data (now we have names all over the place) then --- we can use shcodes but there will be many more looping then. But we --- could get rid of the tables in char-cmp then. Als, in the generic version --- we don't use the character database. (Ok, we can have a context specific --- variant). +-- We keep the extra kerns in separate kerning tables so that we can use them +-- selectively. +-- +-- This is rather old code (from the beginning when we had only tfm). If we unify +-- the afm data (now we have names all over the place) then we can use shcodes but +-- there will be many more looping then. But we could get rid of the tables in +-- char-cmp then. Als, in the generic version we don't use the character database. +-- (Ok, we can have a context specific variant). local function enhance_add_extra_kerns(rawdata) -- using shcodes is not robust here local descriptions = rawdata.descriptions @@ -440,9 +431,7 @@ local function enhance_add_extra_kerns(rawdata) -- using shcodes is not robust h do_it_copy(afm.helpdata.rightkerned) end ---[[ldx-- -<p>The copying routine looks messy (and is indeed a bit messy).</p> ---ldx]]-- +-- The copying routine looks messy (and is indeed a bit messy). local function adddimensions(data) -- we need to normalize afm to otf i.e. indexed table instead of name if data then @@ -619,11 +608,9 @@ end return nil end ---[[ldx-- -<p>Originally we had features kind of hard coded for <l n='afm'/> files but since I -expect to support more font formats, I decided to treat this fontformat like any -other and handle features in a more configurable way.</p> ---ldx]]-- +-- Originally we had features kind of hard coded for AFM files but since I expect to +-- support more font formats, I decided to treat this fontformat like any other and +-- handle features in a more configurable way. function afm.setfeatures(tfmdata,features) local okay = constructors.initializefeatures("afm",tfmdata,features,trace_features,report_afm) @@ -715,13 +702,10 @@ local function afmtotfm(specification) end end ---[[ldx-- -<p>As soon as we could intercept the <l n='tfm'/> reader, I implemented an -<l n='afm'/> reader. Since traditional <l n='pdftex'/> could use <l n='opentype'/> -fonts with <l n='afm'/> companions, the following method also could handle -those cases, but now that we can handle <l n='opentype'/> directly we no longer -need this features.</p> ---ldx]]-- +-- As soon as we could intercept the TFM reader, I implemented an AFM reader. Since +-- traditional pdfTeX could use OpenType fonts with AFM companions, the following +-- method also could handle those cases, but now that we can handle OpenType +-- directly we no longer need this features. local function read_from_afm(specification) local tfmdata = afmtotfm(specification) @@ -736,9 +720,7 @@ local function read_from_afm(specification) return tfmdata end ---[[ldx-- -<p>We have the usual two modes and related features initializers and processors.</p> ---ldx]]-- +-- We have the usual two modes and related features initializers and processors. registerafmfeature { name = "mode", diff --git a/macros/luatex/generic/luaotfload/fontloader-font-onr.lua b/macros/luatex/generic/luaotfload/fontloader-font-onr.lua index c33b09f9e2..6234742a3d 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-onr.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-onr.lua @@ -7,18 +7,16 @@ if not modules then modules = { } end modules ['font-onr'] = { license = "see context related readme files" } ---[[ldx-- -<p>Some code may look a bit obscure but this has to do with the fact that we also use -this code for testing and much code evolved in the transition from <l n='tfm'/> to -<l n='afm'/> to <l n='otf'/>.</p> - -<p>The following code still has traces of intermediate font support where we handles -font encodings. Eventually font encoding went away but we kept some code around in -other modules.</p> - -<p>This version implements a node mode approach so that users can also more easily -add features.</p> ---ldx]]-- +-- Some code may look a bit obscure but this has to do with the fact that we also +-- use this code for testing and much code evolved in the transition from TFM to AFM +-- to OTF. +-- +-- The following code still has traces of intermediate font support where we handles +-- font encodings. Eventually font encoding went away but we kept some code around +-- in other modules. +-- +-- This version implements a node mode approach so that users can also more easily +-- add features. local fonts, logs, trackers, resolvers = fonts, logs, trackers, resolvers @@ -44,12 +42,9 @@ afm.readers = readers afm.version = 1.513 -- incrementing this number one up will force a re-cache ---[[ldx-- -<p>We start with the basic reader which we give a name similar to the built in <l n='tfm'/> -and <l n='otf'/> reader.</p> -<p>We use a new (unfinished) pfb loader but I see no differences between the old -and new vectors (we actually had one bad vector with the old loader).</p> ---ldx]]-- +-- We start with the basic reader which we give a name similar to the built in TFM +-- and OTF reader. We use a PFB loader but I see no differences between the old and +-- new vectors (we actually had one bad vector with the old loader). local get_indexes, get_shapes @@ -211,6 +206,8 @@ do + P(1) )^0 * Carg(1) + -- cache this? + local function loadpfbvector(filename,shapestoo,streams) -- for the moment limited to encoding only @@ -303,11 +300,10 @@ do end ---[[ldx-- -<p>We start with the basic reader which we give a name similar to the built in <l n='tfm'/> -and <l n='otf'/> reader. We only need data that is relevant for our use. We don't support -more complex arrangements like multiple master (obsolete), direction specific kerning, etc.</p> ---ldx]]-- +-- We start with the basic reader which we give a name similar to the built in TFM +-- and OTF reader. We only need data that is relevant for our use. We don't support +-- more complex arrangements like multiple master (obsolete), direction specific +-- kerning, etc. local spacer = patterns.spacer local whitespace = patterns.whitespace diff --git a/macros/luatex/generic/luaotfload/fontloader-font-osd.lua b/macros/luatex/generic/luaotfload/fontloader-font-osd.lua index ecf8009f91..4177e3035a 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-osd.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-osd.lua @@ -6,16 +6,6 @@ if not modules then modules = { } end modules ['font-osd'] = { -- script devanag license = "see context related readme files" } --- local experiment1 = false --- local experiment2 = false --- local experiment2b1 = false --- local experiment2b2 = false - --- experiments.register("fonts.indic.experiment1", function(v) experiment1 = v end) --- experiments.register("fonts.indic.experiment2", function(v) experiment2 = v end) --- experiments.register("fonts.indic.experiment2b1", function(v) experiment2b1 = v end) --- experiments.register("fonts.indic.experiment2b2", function(v) experiment2b2 = v end) - -- we need to check nbsphash (context only) -- A few remarks: @@ -70,6 +60,10 @@ if not modules then modules = { } end modules ['font-osd'] = { -- script devanag -- conjuncts options that can deal with fuzzy fonts. The machinery does what it has -- to do but some fonts expect more magic to be applied. -- +-- Some changes have been reverted because they interfere with proper fonts. We just +-- don't support bad fonts with heuristics any longer. If needed one can use the +-- translitaration filters that come with ConTeXt. +-- -- Hans Hagen, PRAGMA-ADE, Hasselt NL -- Todo: @@ -1392,16 +1386,13 @@ local function reorder_one(head,start,stop,font,attr,nbspaces) end if reph or vattu then --- print(">>> has reph or vattu") local current = start local cns = nil local done = false while current ~= stop do --- print("\t>>> current ~= stop yet") local c = current local n = getnext(current) if ra[getchar(current)] and halant[getchar(n)] then --- print("\t\t>>> current ra; next halant") c = n n = getnext(n) local b, bn = base, base @@ -1415,7 +1406,6 @@ local function reorder_one(head,start,stop,font,attr,nbspaces) if getstate(current,s_rphf) then -- position Reph (Ra + H) after post-base 'matra' (if any) since these -- become marks on the 'matra', not on the base glyph --- print("\t\t\t>>> ra + halant form → reph") if b ~= current then if current == start then if head == start then @@ -1435,7 +1425,6 @@ local function reorder_one(head,start,stop,font,attr,nbspaces) end elseif cns and getnext(cns) ~= current then -- todo: optimize next -- position below-base Ra (vattu) following the consonants on which it is placed (either the base consonant or one of the pre-base consonants) --- print("\t\t\t>>> ra below base (vattu) → rkrf") local cp = getprev(current) local cnsn = getnext(cns) setlink(cp,n) @@ -1449,17 +1438,14 @@ local function reorder_one(head,start,stop,font,attr,nbspaces) current = getprev(n) end else --- print("\t\t>>> NOT! current ra; next halant") local char = getchar(current) if consonant[char] then --- print("\t\t\t>>> is consonant") cns = current local next = getnext(cns) if halant[getchar(next)] then cns = next end if not vatucache[char] then --- print("\t\t\t\t>>> is in vatucache") next = getnext(cns) while dependent_vowel[getchar(next)] do cns = next @@ -1467,7 +1453,6 @@ local function reorder_one(head,start,stop,font,attr,nbspaces) end end elseif char == c_nbsp then --- print("\t\t\t>>> is nbsp") nbspaces = nbspaces + 1 cns = current local next = getnext(cns) @@ -1936,8 +1921,6 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas reorderreph.coverage = { } -- use local rephbase[font] = { } -- use local --- print("!!!!!! reorder two ") - for i=1,#seqsubset do -- this can be done more efficient, the last test and less getnext @@ -2064,7 +2047,7 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas end end - local current, base, firstcons = start, nil, nil + local current, base, firstcons, subnotafterbase, postnotafterbase = start, nil, nil, nil, nil if getstate(start,s_rphf) then -- if syllable starts with Ra + H and script has 'Reph' then exclude Reph from candidates for base consonants @@ -2125,10 +2108,15 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas end end else -- not Stand Alone cluster --- print("!!!! not standalone cluster") local last = getnext(stop) while current ~= last do -- find base consonant local next = getnext(current) + if current == subpos then + subnotafterbase = current + end + if current == postpos then + postnotafterbase = current + end if consonant[getchar(current)] then if not (current ~= stop and next ~= stop and halant[getchar(next)] and getchar(getnext(next)) == c_zwj) then if not firstcons then @@ -2138,6 +2126,12 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas local a = getstate(current) if not (a == s_blwf or a == s_pstf or (a ~= s_rphf and a ~= s_blwf and ra[getchar(current)])) then base = current + if subnotafterbase then + subpos = base + end + if postnotafterbase then + postpos = base + end end end end @@ -2195,10 +2189,7 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas end end -- --- print("char: " .. char) --- if not moved[current] and dependent_vowel[char] then - if dependent_vowel[char] then --- print(">>!! dependent vowel") + if not moved[current] and dependent_vowel[char] then if pre_mark[char] then -- or: if before_main or before_half moved[current] = true -- can be helper to remove one node @@ -2251,14 +2242,11 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas end elseif above_mark[char] then -- after main consonant - target = basepos - if subpos == basepos then - subpos = current - end - if postpos == basepos then + target = subpos + if postpos == subpos then postpos = current end - basepos = current + subpos = current elseif below_mark[char] then -- after subjoined consonants target = subpos @@ -2502,12 +2490,7 @@ local function analyze_next_chars_one(c,font,variant) -- skip one dependent vowe if pre_mark[v] and not already_pre_mark then already_pre_mark = true elseif post_mark[v] and not already_post_mark then - if devanagarihash[font].conjuncts == "mixed" then - -- for messy fonts - return c - else - already_post_mark = true - end + already_post_mark = true elseif below_mark[v] and not already_below_mark then already_below_mark = true elseif above_mark[v] and not already_above_mark then @@ -2710,10 +2693,6 @@ local function analyze_next_chars_two(c,font) for k=1,#vowels do local v = vowels[k] if pre_mark[v] and not already_pre_mark then --- print(">>> pre_mark") --- if dependent_vowel[v] then --- print(">>>> dependent vowel") --- end already_pre_mark = true elseif above_mark[v] and not already_above_mark then already_above_mark = true @@ -2731,12 +2710,7 @@ local function analyze_next_chars_two(c,font) if pre_mark[v] and not already_pre_mark then already_pre_mark = true elseif post_mark[v] and not already_post_mark then - if devanagarihash[font].conjuncts == "mixed" then - -- for messy fonts - return c - else - already_post_mark = true - end + already_post_mark = true elseif below_mark[v] and not already_below_mark then already_below_mark = true elseif above_mark[v] and not already_above_mark then @@ -3068,15 +3042,12 @@ local function method_two(head,font,attr) end end if independent_vowel[char] then --- print("!!>>> independent_vowel") -- vowel-based syllable: [Ra+H]+V+[N]+[<[<ZWJ|ZWNJ>]+H+C|ZWJ+C>]+[{M}+[N]+[H]]+[SM]+[(VD)] current = analyze_next_chars_one(c,font,1) syllableend = current else --- print("!!>>> dependent vowel") local standalone = char == c_nbsp if standalone then --- print("!!>>> standalone") nbspaces = nbspaces + 1 local p = getprev(current) if not p then @@ -3090,12 +3061,10 @@ local function method_two(head,font,attr) end end if standalone then --- print("!!>>>>>>> next standalone") -- Stand Alone cluster (at the start of the word only): #[Ra+H]+NBSP+[N]+[<[<ZWJ|ZWNJ>]+H+C>]+[{M}+[N]+[H]]+[SM]+[(VD)] current = analyze_next_chars_one(c,font,2) syllableend = current elseif consonant[getchar(current)] then --- print("!!>>>>>>> a consonant") -- WHY current INSTEAD OF c ? -- Consonant syllable: {C+[N]+<H+[<ZWNJ|ZWJ>]|<ZWNJ|ZWJ>+H>} + C+[N]+[A] + [< H+[<ZWNJ|ZWJ>] | {M}+[N]+[H]>]+[SM]+[(VD)] current = analyze_next_chars_two(current,font) -- not c ! @@ -3104,7 +3073,6 @@ local function method_two(head,font,attr) end end if syllableend then --- print("!!!>>> syllable end") syllabe = syllabe + 1 local c = syllablestart local n = getnext(syllableend) diff --git a/macros/luatex/generic/luaotfload/fontloader-font-ota.lua b/macros/luatex/generic/luaotfload/fontloader-font-ota.lua index a8f9f0047c..160d0d0edb 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-ota.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-ota.lua @@ -54,10 +54,8 @@ local chardata = characters and characters.data local otffeatures = fonts.constructors.features.otf local registerotffeature = otffeatures.register ---[[ldx-- -<p>Analyzers run per script and/or language and are needed in order to -process features right.</p> ---ldx]]-- +-- Analyzers run per script and/or language and are needed in order to process +-- features right. local setstate = nuts.setstate local getstate = nuts.getstate diff --git a/macros/luatex/generic/luaotfload/fontloader-font-otc.lua b/macros/luatex/generic/luaotfload/fontloader-font-otc.lua index 67b77b1113..0787a20359 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-otc.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-otc.lua @@ -142,6 +142,12 @@ local function addfeature(data,feature,specifications,prepareonly) local descriptions = data.descriptions local resources = data.resources + + if not descriptions or not resources then + report_otf("missing specification") + return + end + local features = resources.features local sequences = resources.sequences @@ -780,7 +786,12 @@ local function addfeature(data,feature,specifications,prepareonly) local list = askedsteps[i] local coverage = nil local format = nil - if featuretype == "substitution" then +if type(list) == "function" then + list = list(data,specification,list,i) +end + if not list then + -- see ebgaramond hack + elseif featuretype == "substitution" then -- see font-imp-tweaks: we directly pass a mapping so no checks done category = "gsub" coverage = (mapping and list) or prepare_substitution(list,featuretype,nocheck) diff --git a/macros/luatex/generic/luaotfload/fontloader-font-otl.lua b/macros/luatex/generic/luaotfload/fontloader-font-otl.lua index f36e533ca0..0825077b3f 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-otl.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-otl.lua @@ -52,7 +52,7 @@ local report_otf = logs.reporter("fonts","otf loading") local fonts = fonts local otf = fonts.handlers.otf -otf.version = 3.120 -- beware: also sync font-mis.lua and in mtx-fonts +otf.version = 3.133 -- beware: also sync font-mis.lua and in mtx-fonts otf.cache = containers.define("fonts", "otl", otf.version, true) otf.svgcache = containers.define("fonts", "svg", otf.version, true) otf.pngcache = containers.define("fonts", "png", otf.version, true) @@ -643,25 +643,33 @@ local function read_from_otf(specification) return tfmdata end -local function checkmathsize(tfmdata,mathsize) - local mathdata = tfmdata.shared.rawdata.metadata.math - local mathsize = tonumber(mathsize) - if mathdata then -- we cannot use mathparameters as luatex will complain - local parameters = tfmdata.parameters - parameters.scriptpercentage = mathdata.ScriptPercentScaleDown - parameters.scriptscriptpercentage = mathdata.ScriptScriptPercentScaleDown - parameters.mathsize = mathsize -- only when a number ! - end -end - -registerotffeature { - name = "mathsize", - description = "apply mathsize specified in the font", - initializers = { - base = checkmathsize, - node = checkmathsize, - } -} +-- if context then +-- +-- -- so the next will go to some generic module instead +-- +-- else +-- +-- local function checkmathsize(tfmdata,mathsize) +-- local mathdata = tfmdata.shared.rawdata.metadata.math +-- local mathsize = tonumber(mathsize) +-- if mathdata then -- we cannot use mathparameters as luatex will complain +-- local parameters = tfmdata.parameters +-- parameters.scriptpercentage = mathdata.ScriptPercentScaleDown +-- parameters.scriptscriptpercentage = mathdata.ScriptScriptPercentScaleDown +-- parameters.mathsize = mathsize -- only when a number ! +-- end +-- end +-- +-- registerotffeature { +-- name = "mathsize", +-- description = "apply mathsize specified in the font", +-- initializers = { +-- base = checkmathsize, +-- node = checkmathsize, +-- } +-- } +-- +-- end -- readers diff --git a/macros/luatex/generic/luaotfload/fontloader-font-oto.lua b/macros/luatex/generic/luaotfload/fontloader-font-oto.lua index 1475fcf678..0689f4dfb5 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-oto.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-oto.lua @@ -6,6 +6,9 @@ if not modules then modules = { } end modules ['font-oto'] = { -- original tex license = "see context related readme files" } +-- Todo: Enable fixes from the lmt to here. Also in font-con.lua wrt the changed +-- assignments. (Around texlive 2024 in order not to disturb generic.) + local concat, unpack = table.concat, table.unpack local insert, remove = table.insert, table.remove local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip @@ -260,7 +263,9 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis for i=1,#steps do for unicode, data in next, steps[i].coverage do if unicode ~= data then +-- if not changed[unicode] then changed[unicode] = data +-- end end if trace_singles then report_substitution(feature,sequence,descriptions,unicode,data) @@ -273,7 +278,9 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local replacement = data[alternate] if replacement then if unicode ~= replacement then +-- if not changed[unicode] then changed[unicode] = replacement +-- end end if trace_alternatives then report_alternate(feature,sequence,descriptions,unicode,replacement,value,"normal") @@ -281,7 +288,9 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis elseif defaultalt == "first" then replacement = data[1] if unicode ~= replacement then +-- if not changed[unicode] then changed[unicode] = replacement +-- end end if trace_alternatives then report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt) @@ -289,7 +298,9 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis elseif defaultalt == "last" then replacement = data[#data] if unicode ~= replacement then +-- if not changed[unicode] then changed[unicode] = replacement +-- end end if trace_alternatives then report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt) @@ -504,6 +515,9 @@ local function featuresinitializer(tfmdata,value) local value = features[feature] if value then local validlookups, lookuplist = collectlookups(rawdata,feature,script,language) +-- if not validlookups and not lookuplist and script == "math" then +-- validlookups, lookuplist = collectlookups(rawdata,feature,"dflt","dflt") +-- end if not validlookups then -- skip elseif basesubstitutions and basesubstitutions[feature] then diff --git a/macros/luatex/generic/luaotfload/fontloader-font-otr.lua b/macros/luatex/generic/luaotfload/fontloader-font-otr.lua index 339de109f8..1e6f94e455 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-otr.lua +++ b/macros/luatex/generic/luaotfload/fontloader-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 @@ -1189,6 +1190,9 @@ readers.hmtx = function(f,fontdata,specification) -- if leftsidebearing ~= 0 then -- glyph.lsb = leftsidebearing -- end +-- if leftsidebearing ~= 0 then +-- glyph.lsb = leftsidebearing +-- end end -- The next can happen in for instance a monospace font or in a cjk font -- with fixed widths. @@ -1683,7 +1687,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 +2429,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/macros/luatex/generic/luaotfload/fontloader-font-ots.lua b/macros/luatex/generic/luaotfload/fontloader-font-ots.lua index 7de108d4c8..48f85c3658 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-ots.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-ots.lua @@ -7,87 +7,90 @@ if not modules then modules = { } end modules ['font-ots'] = { -- sequences license = "see context related readme files", } ---[[ldx-- -<p>This module is a bit more split up that I'd like but since we also want to test -with plain <l n='tex'/> it has to be so. This module is part of <l n='context'/> -and discussion about improvements and functionality mostly happens on the -<l n='context'/> mailing list.</p> - -<p>The specification of OpenType is (or at least decades ago was) kind of vague. -Apart from a lack of a proper free specifications there's also the problem that -Microsoft and Adobe may have their own interpretation of how and in what order to -apply features. In general the Microsoft website has more detailed specifications -and is a better reference. There is also some information in the FontForge help -files. In the end we rely most on the Microsoft specification.</p> - -<p>Because there is so much possible, fonts might contain bugs and/or be made to -work with certain rederers. These may evolve over time which may have the side -effect that suddenly fonts behave differently. We don't want to catch all font -issues.</p> - -<p>After a lot of experiments (mostly by Taco, me and Idris) the first implementation -was already quite useful. When it did most of what we wanted, a more optimized version -evolved. Of course all errors are mine and of course the code can be improved. There -are quite some optimizations going on here and processing speed is currently quite -acceptable and has been improved over time. Many complex scripts are not yet supported -yet, but I will look into them as soon as <l n='context'/> users ask for it.</p> - -<p>The specification leaves room for interpretation. In case of doubt the Microsoft -implementation is the reference as it is the most complete one. As they deal with -lots of scripts and fonts, Kai and Ivo did a lot of testing of the generic code and -their suggestions help improve the code. I'm aware that not all border cases can be -taken care of, unless we accept excessive runtime, and even then the interference -with other mechanisms (like hyphenation) are not trivial.</p> - -<p>Especially discretionary handling has been improved much by Kai Eigner who uses complex -(latin) fonts. The current implementation is a compromis between his patches and my code -and in the meantime performance is quite ok. We cannot check all border cases without -compromising speed but so far we're okay. Given good test cases we can probably improve -it here and there. Especially chain lookups are non trivial with discretionaries but -things got much better over time thanks to Kai.</p> - -<p>Glyphs are indexed not by unicode but in their own way. This is because there is no -relationship with unicode at all, apart from the fact that a font might cover certain -ranges of characters. One character can have multiple shapes. However, at the -<l n='tex'/> end we use unicode so and all extra glyphs are mapped into a private -space. This is needed because we need to access them and <l n='tex'/> has to include -then in the output eventually.</p> - -<p>The initial data table is rather close to the open type specification and also not -that different from the one produced by <l n='fontforge'/> but we uses hashes instead. -In <l n='context'/> that table is packed (similar tables are shared) and cached on disk -so that successive runs can use the optimized table (after loading the table is -unpacked).</p> - -<p>This module is sparsely documented because it is has been a moving target. The -table format of the reader changed a bit over time and we experiment a lot with -different methods for supporting features. By now the structures are quite stable</p> - -<p>Incrementing the version number will force a re-cache. We jump the number by one -when there's a fix in the reader or processing code that can result in different -results.</p> - -<p>This code is also used outside context but in context it has to work with other -mechanisms. Both put some constraints on the code here.</p> - ---ldx]]-- - --- Remark: We assume that cursives don't cross discretionaries which is okay because it --- is only used in semitic scripts. +-- I need to check the description at the microsoft site ... it has been improved so +-- maybe there are some interesting details there. Most below is based on old and +-- incomplete documentation and involved quite a bit of guesswork (checking with the +-- abstract uniscribe of those days. But changing things is tricky! +-- +-- This module is a bit more split up that I'd like but since we also want to test +-- with plain TeX it has to be so. This module is part of ConTeXt and discussion +-- about improvements and functionality mostly happens on the ConTeXt mailing list. +-- +-- The specification of OpenType is (or at least decades ago was) kind of vague. +-- Apart from a lack of a proper free specifications there's also the problem that +-- Microsoft and Adobe may have their own interpretation of how and in what order to +-- apply features. In general the Microsoft website has more detailed specifications +-- and is a better reference. There is also some information in the FontForge help +-- files. In the end we rely most on the Microsoft specification. +-- +-- Because there is so much possible, fonts might contain bugs and/or be made to +-- work with certain rederers. These may evolve over time which may have the side +-- effect that suddenly fonts behave differently. We don't want to catch all font +-- issues. +-- +-- After a lot of experiments (mostly by Taco, me and Idris) the first +-- implementation was already quite useful. When it did most of what we wanted, a +-- more optimized version evolved. Of course all errors are mine and of course the +-- code can be improved. There are quite some optimizations going on here and +-- processing speed is currently quite acceptable and has been improved over time. +-- Many complex scripts are not yet supported yet, but I will look into them as soon +-- as ConTeXt users ask for it. +-- +-- The specification leaves room for interpretation. In case of doubt the Microsoft +-- implementation is the reference as it is the most complete one. As they deal with +-- lots of scripts and fonts, Kai and Ivo did a lot of testing of the generic code +-- and their suggestions help improve the code. I'm aware that not all border cases +-- can be taken care of, unless we accept excessive runtime, and even then the +-- interference with other mechanisms (like hyphenation) are not trivial. +-- +-- Especially discretionary handling has been improved much by Kai Eigner who uses +-- complex (latin) fonts. The current implementation is a compromis between his +-- patches and my code and in the meantime performance is quite ok. We cannot check +-- all border cases without compromising speed but so far we're okay. Given good +-- test cases we can probably improve it here and there. Especially chain lookups +-- are non trivial with discretionaries but things got much better over time thanks +-- to Kai. +-- +-- Glyphs are indexed not by unicode but in their own way. This is because there is +-- no relationship with unicode at all, apart from the fact that a font might cover +-- certain ranges of characters. One character can have multiple shapes. However, at +-- the TeX end we use unicode so and all extra glyphs are mapped into a private +-- space. This is needed because we need to access them and TeX has to include then +-- in the output eventually. +-- +-- The initial data table is rather close to the open type specification and also +-- not that different from the one produced by Fontforge but we uses hashes instead. +-- In ConTeXt that table is packed (similar tables are shared) and cached on disk so +-- that successive runs can use the optimized table (after loading the table is +-- unpacked). +-- +-- This module is sparsely documented because it is has been a moving target. The +-- table format of the reader changed a bit over time and we experiment a lot with +-- different methods for supporting features. By now the structures are quite stable +-- +-- Incrementing the version number will force a re-cache. We jump the number by one +-- when there's a fix in the reader or processing code that can result in different +-- results. +-- +-- This code is also used outside ConTeXt but in ConTeXt it has to work with other +-- mechanisms. Both put some constraints on the code here. +-- +-- Remark: We assume that cursives don't cross discretionaries which is okay because +-- it is only used in semitic scripts. -- -- Remark: We assume that marks precede base characters. -- --- Remark: When complex ligatures extend into discs nodes we can get side effects. Normally --- this doesn't happen; ff\d{l}{l}{l} in lm works but ff\d{f}{f}{f}. +-- Remark: When complex ligatures extend into discs nodes we can get side effects. +-- Normally this doesn't happen; ff\d{l}{l}{l} in lm works but ff\d{f}{f}{f}. -- -- Todo: check if we copy attributes to disc nodes if needed. -- --- Todo: it would be nice if we could get rid of components. In other places we can use --- the unicode properties. We can just keep a lua table. +-- Todo: it would be nice if we could get rid of components. In other places we can +-- use the unicode properties. We can just keep a lua table. -- --- Remark: We do some disc juggling where we need to keep in mind that the pre, post and --- replace fields can have prev pointers to a nesting node ... I wonder if that is still --- needed. +-- Remark: We do some disc juggling where we need to keep in mind that the pre, post +-- and replace fields can have prev pointers to a nesting node ... I wonder if that +-- is still needed. -- -- Remark: This is not possible: -- @@ -165,13 +168,8 @@ local forcepairadvance = false -- for testing local repeatablemultiples = context or false -directives.register("otf.forcediscretionaries",function(v) - forcediscretionaries = v -end) - -directives.register("otf.forcepairadvance",function(v) - forcepairadvance = v -end) +directives.register("otf.forcediscretionaries", function(v) forcediscretionaries = v end) +directives.register("otf.forcepairadvance", function(v) forcepairadvance = v end) local report_direct = logs.reporter("fonts","otf direct") local report_subchain = logs.reporter("fonts","otf subchain") @@ -197,7 +195,6 @@ local setboth = nuts.setboth local getid = nuts.getid local getstate = nuts.getstate local getsubtype = nuts.getsubtype -local setsubtype = nuts.setsubtype local getchar = nuts.getchar local setchar = nuts.setchar local getdisc = nuts.getdisc @@ -229,10 +226,10 @@ local ischar = nuts.ischar local usesfont = nuts.usesfont local insertnodeafter = nuts.insertafter -local copy_node = nuts.copy -local copy_node_list = nuts.copylist -local remove_node = nuts.remove -local find_node_tail = nuts.tail +local copynode = nuts.copy +local copynodelist = nuts.copylist +local removenode = nuts.remove +local findnodetail = nuts.tail local flushnodelist = nuts.flushlist local flushnode = nuts.flushnode local endofmath = nuts.endofmath @@ -244,12 +241,8 @@ local setmetatableindex = table.setmetatableindex local nextnode = nuts.traversers.node ------ zwnj = 0x200C ------ zwj = 0x200D - local nodecodes = nodes.nodecodes local glyphcodes = nodes.glyphcodes -local disccodes = nodes.disccodes local glyph_code = nodecodes.glyph local glue_code = nodecodes.glue @@ -261,8 +254,7 @@ local par_code = nodecodes.par local lefttoright_code = nodes.dirvalues.lefttoright local righttoleft_code = nodes.dirvalues.righttoleft -local discretionarydisc_code = disccodes.discretionary -local ligatureglyph_code = glyphcodes.ligature +local discretionarydisc_code = nodes.disccodes.discretionary local a_noligature = attributes.private("noligature") @@ -377,7 +369,7 @@ local function cref(dataset,sequence,index) return "no valid dataset" end local merged = sequence.merged and "merged " or "" - if index then + if index and index > 1 then return formatters["feature %a, type %a, %schain lookup %a, index %a"]( dataset[4],sequence.type,merged,sequence.name,index) else @@ -455,7 +447,7 @@ end local function appenddisc(disc,list) local pre, post, replace, pretail, posttail, replacetail = getdisc(disc,true) local posthead = list - local replacehead = copy_node_list(list) + local replacehead = copynodelist(list) if post then setlink(posttail,posthead) else @@ -483,7 +475,6 @@ local function markstoligature(head,start,stop,char) end resetinjection(base) setchar(base,char) - setsubtype(base,ligatureglyph_code) setcomponents(base,start) setlink(prev,base,next) flushcomponents(start) @@ -536,7 +527,6 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou end resetinjection(base) setchar(base,char) - setsubtype(base,ligatureglyph_code) setcomponents(base,comp) setlink(prev,base,next) if not discfound then @@ -560,7 +550,7 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou if trace_marks then logwarning("%s: keep ligature mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start)) end - local n = copy_node(start) + local n = copynode(start) copyinjection(n,start) -- is this ok ? we position later anyway head, current = insertnodeafter(head,current,n) -- unlikely that mark has components elseif trace_marks then @@ -634,67 +624,68 @@ end local function multiple_glyphs(head,start,multiple,skiphash,what,stop) -- what to do with skiphash matches here local nofmultiples = #multiple if nofmultiples > 0 then + local first = start resetinjection(start) setchar(start,multiple[1]) if nofmultiples > 1 then - local sn = getnext(start) - for k=2,nofmultiples do + -- local sn = getnext(start) + for i=2,nofmultiples do -- untested: -- -- while ignoremarks and marks[getchar(sn)] then -- local sn = getnext(sn) -- end - local n = copy_node(start) -- ignore components + local n = copynode(start) -- ignore components resetinjection(n) - setchar(n,multiple[k]) + setchar(n,multiple[i]) insertnodeafter(head,start,n) start = n end - if what ~= true and repeatablemultiples then - -- This is just some experimental code; we might introduce gsub_extensible - -- some day instead. Beware: when we have a feature that mixes alternates and - -- multiples we need to make sure we don't handle the alternate string values - -- here. This might eventually become an lmtx only feature. - local kind = type(what) - local m, f, l - if kind == "string" then - local what, n = string.match(what,"^repeat(.-)[:=](%d+)$") - if what == "middle" then - m = tonumber(n) - elseif what == "first" then - f = tonumber(n) - elseif what == "last" then - l = tonumber(n) - end - elseif kind == "table" then - -- won't happen because currently we don't split these values - m = what.middle - f = what.first - l = what.last + end + if what ~= true and repeatablemultiples then + -- This is just some experimental code; we might introduce gsub_extensible + -- some day instead. Beware: when we have a feature that mixes alternates and + -- multiples we need to make sure we don't handle the alternate string values + -- here. + local kind = type(what) + local m, f, l + if kind == "string" then + local what, n = string.match(what,"^repeat(.-)[:=](%d+)$") + if what == "middle" then + m = tonumber(n) + elseif what == "first" then + f = tonumber(n) + elseif what == "last" then + l = tonumber(n) end - if f or m or l then - if m and m > 1 and nofmultiples == 3 then - local middle = getnext(first) - for i=2,m do - local n = copynode(middle) -- ignore components - resetinjection(n) - insertnodeafter(head,first,n) - end + elseif kind == "table" then + -- won't happen because currently we don't split these values + m = what.middle + f = what.first + l = what.last + end + if f or m or l then + if m and m > 1 and nofmultiples == 3 then + local middle = getnext(first) + for i=2,m do + local n = copynode(middle) -- ignore components + resetinjection(n) + insertnodeafter(head,first,n) end - if f and f > 1 then - for i=2,f do - local n = copynode(first) -- ignore components - resetinjection(n) - insertnodeafter(head,first,n) - end + end + if f and f > 1 then + for i=2,f do + local n = copynode(first) -- ignore components + resetinjection(n) + insertnodeafter(head,first,n) end - if l and l > 1 then - for i=2,l do - local n = copynode(start) -- ignore components - resetinjection(n) - insertnodeafter(head,start,n) - start = n - end + end + if l and l > 1 then + for i=2,l do + local n = copynode(start) -- ignore components + resetinjection(n) + insertnodeafter(head,start,n) + start = n end end end @@ -894,9 +885,9 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip local prev = getprev(start) if stop then setnext(stop) - local copy = copy_node_list(start) + local copy = copynodelist(start) local tail = stop -- was: getprev(stop) -- Kai: needs checking on your samples - local liat = find_node_tail(copy) + local liat = findnodetail(copy) if pre then setlink(liat,pre) end @@ -907,7 +898,7 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip replace = start else setnext(start) - local copy = copy_node(start) + local copy = copynode(start) if pre then setlink(copy,pre) end @@ -1045,10 +1036,8 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,skiphash,st end end ---[[ldx-- -<p>We get hits on a mark, but we're not sure if the it has to be applied so -we need to explicitly test for basechar, baselig and basemark entries.</p> ---ldx]]-- +-- We get hits on a mark, but we're not sure if the it has to be applied so we need +-- to explicitly test for basechar, baselig and basemark entries. function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode,skiphash) local markchar = getchar(start) @@ -1243,10 +1232,8 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,sk return head, start, false end ---[[ldx-- -<p>I will implement multiple chain replacements once I run into a font that uses -it. It's not that complex to handle.</p> ---ldx]]-- +-- I will implement multiple chain replacements once I run into a font that uses it. +-- It's not that complex to handle. local chainprocs = { } @@ -1299,29 +1286,22 @@ end chainprocs.reversesub = reversesub ---[[ldx-- -<p>This chain stuff is somewhat tricky since we can have a sequence of actions to be -applied: single, alternate, multiple or ligature where ligature can be an invalid -one in the sense that it will replace multiple by one but not neccessary one that -looks like the combination (i.e. it is the counterpart of multiple then). For -example, the following is valid:</p> - -<typing> -<line>xxxabcdexxx [single a->A][multiple b->BCD][ligature cde->E] xxxABCDExxx</line> -</typing> - -<p>Therefore we we don't really do the replacement here already unless we have the -single lookup case. The efficiency of the replacements can be improved by deleting -as less as needed but that would also make the code even more messy.</p> ---ldx]]-- - ---[[ldx-- -<p>Here we replace start by a single variant.</p> ---ldx]]-- - --- To be done (example needed): what if > 1 steps - --- this is messy: do we need this disc checking also in alternaties? +-- This chain stuff is somewhat tricky since we can have a sequence of actions to be +-- applied: single, alternate, multiple or ligature where ligature can be an invalid +-- one in the sense that it will replace multiple by one but not neccessary one that +-- looks like the combination (i.e. it is the counterpart of multiple then). For +-- example, the following is valid: +-- +-- xxxabcdexxx [single a->A][multiple b->BCD][ligature cde->E] xxxABCDExxx +-- +-- Therefore we we don't really do the replacement here already unless we have the +-- single lookup case. The efficiency of the replacements can be improved by +-- deleting as less as needed but that would also make the code even more messy. +-- +-- Here we replace start by a single variant. +-- +-- To be done : what if > 1 steps (example needed) +-- This is messy: do we need this disc checking also in alternates? local function reportzerosteps(dataset,sequence) logwarning("%s: no steps",cref(dataset,sequence)) @@ -1357,7 +1337,7 @@ function chainprocs.gsub_remove(head,start,stop,dataset,sequence,currentlookup,r if trace_chains then logprocess("%s: removing character %s",cref(dataset,sequence,chainindex),gref(getchar(start))) end - head, start = remove_node(head,start,true) + head, start = removenode(head,start,true) return head, getprev(start), true end @@ -1397,9 +1377,7 @@ function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,r return head, start, false end ---[[ldx-- -<p>Here we replace start by new glyph. First we delete the rest of the match.</p> ---ldx]]-- +-- Here we replace start by new glyph. First we delete the rest of the match. -- char_1 mark_1 -> char_x mark_1 (ignore marks) -- char_1 mark_1 -> char_x @@ -1451,9 +1429,7 @@ function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlooku return head, start, false end ---[[ldx-- -<p>Here we replace start by a sequence of new glyphs.</p> ---ldx]]-- +-- Here we replace start by a sequence of new glyphs. function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) local mapping = currentlookup.mapping @@ -1477,11 +1453,9 @@ function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup return head, start, false end ---[[ldx-- -<p>When we replace ligatures we use a helper that handles the marks. I might change -this function (move code inline and handle the marks by a separate function). We -assume rather stupid ligatures (no complex disc nodes).</p> ---ldx]]-- +-- When we replace ligatures we use a helper that handles the marks. I might change +-- this function (move code inline and handle the marks by a separate function). We +-- assume rather stupid ligatures (no complex disc nodes). -- compare to handlers.gsub_ligature which is more complex ... why @@ -1952,7 +1926,7 @@ do if not userkern then -- generic local setkern = nuts.setkern -- not injections.setkern userkern = function(k) - local n = copy_node(thekern) + local n = copynode(thekern) setkern(n,k) return n end @@ -1994,12 +1968,11 @@ end local noflags = { false, false, false, false } -local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck) +local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck,where) local size = ck[5] - ck[4] + 1 local chainlookups = ck[6] local done = false - -- current match if chainlookups then -- Lookups can be like { 1, false, 3 } or { false, 2 } or basically anything and @@ -2010,23 +1983,30 @@ local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck) -- if nofchainlookups > size then -- -- bad rules -- end - local chainlookup = chainlookups[1] - for j=1,#chainlookup do - local chainstep = chainlookup[j] - local chainkind = chainstep.type - local chainproc = chainprocs[chainkind] - if chainproc then - local ok - -- HH: chainindex 1 added here (for KAI to check too), there are weird ligatures e.g. - -- char + mark -> char where mark has to disappear - head, start, ok = chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,1) - if ok then - done = true + if chainlookup then + for j=1,#chainlookup do + local chainstep = chainlookup[j] + if chainstep then + local chainkind = chainstep.type + local chainproc = chainprocs[chainkind] + if chainproc then + local ok + -- HH: chainindex 1 added here (for KAI to check too), there are weird ligatures e.g. + -- char + mark -> char where mark has to disappear + head, start, ok = chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,1) + if ok then + done = true + end + else + logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind) + end + else + logprocess("%s: has an issue (1)",cref(dataset,sequence)) end - else - logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind) end + else + -- whatever end else @@ -2067,23 +2047,28 @@ local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck) if chainlookup then for j=1,#chainlookup do local chainstep = chainlookup[j] - local chainkind = chainstep.type - local chainproc = chainprocs[chainkind] - if chainproc then - local ok, n - head, start, ok, n = chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,i) - -- messy since last can be changed ! - if ok then - done = true - if n and n > 1 and i + n > nofchainlookups then - -- this is a safeguard, we just ignore the rest of the lookups - i = size -- prevents an advance - break + if chainstep then + local chainkind = chainstep.type + local chainproc = chainprocs[chainkind] + if chainproc then + local ok, n + head, start, ok, n = chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,i) + -- messy since last can be changed ! + if ok then + done = true + if n and n > 1 and i + n > nofchainlookups then + -- this is a safeguard, we just ignore the rest of the lookups + i = size -- prevents an advance + break + end end + else + -- actually an error + logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind) end else -- actually an error - logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind) + logprocess("%s: has an issue (2)",cref(dataset,sequence)) end end else @@ -2111,7 +2096,7 @@ local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck) else done = true if trace_contexts then - logprocess("%s: skipping match",cref(dataset,sequence)) + logprocess("%s: skipping match @ %i",cref(dataset,sequence),where) end end end @@ -2141,6 +2126,8 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) local last = start local prev = getprev(start) local hasglue = false + local useddisc = nil -- new 2022-09-25 + local usedstart = start -- new 2022-09-25 -- fishy: so we can overflow and then go on in the sweep? -- todo : id can also be glue_code as we checked spaces @@ -2211,7 +2198,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) tail = prev setprev(current,sweepnode) else - tail = find_node_tail(head) + tail = findnodetail(head) end setnext(sweepnode,current) setprev(head) @@ -2302,15 +2289,14 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) end end end + local done = false if lookaheaddisc then - local cf = start local cl = getprev(lookaheaddisc) local cprev = getprev(start) local insertedmarks = 0 - while cprev do local char = ischar(cf,currentfont) if char and marks[char] then @@ -2329,13 +2315,13 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) head = lookaheaddisc end local pre, post, replace = getdisc(lookaheaddisc) - local new = copy_node_list(cf) -- br, how often does that happen + local new = copynodelist(cf) -- br, how often does that happen local cnew = new if pre then - setlink(find_node_tail(cf),pre) + setlink(findnodetail(cf),pre) end if replace then - local tail = find_node_tail(new) + local tail = findnodetail(new) setlink(tail,replace) end for i=1,insertedmarks do @@ -2349,14 +2335,14 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) end if not notmatchpre[lookaheaddisc] then local ok = false - cf, start, ok = chainrun(cf,start,cl,dataset,sequence,rlmode,skiphash,ck) + cf, start, ok = chainrun(cf,start,cl,dataset,sequence,rlmode,skiphash,ck,1) if ok then done = true end end if not notmatchreplace[lookaheaddisc] then local ok = false - new, cnew, ok = chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck) + new, cnew, ok = chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck,2) if ok then done = true end @@ -2367,16 +2353,14 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) setdisc(lookaheaddisc,cf,post,new) end start = getprev(lookaheaddisc) + useddisc = lookaheaddisc -- new 2022-09-25 sweephead[cf] = getnext(clast) or false sweephead[new] = getnext(cl) or false - elseif backtrackdisc then - local cf = getnext(backtrackdisc) local cl = start local cnext = getnext(start) local insertedmarks = 0 - while cnext do local char = ischar(cnext,currentfont) if char and marks[char] then @@ -2391,8 +2375,8 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) setprev(cf) setnext(cl) local pre, post, replace, pretail, posttail, replacetail = getdisc(backtrackdisc,true) - local new = copy_node_list(cf) - local cnew = find_node_tail(new) + local new = copynodelist(cf) + local cnew = findnodetail(new) for i=1,insertedmarks do cnew = getprev(cnew) end @@ -2402,14 +2386,14 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) end if not notmatchpost[backtrackdisc] then local ok = false - cf, start, ok = chainrun(cf,start,last,dataset,sequence,rlmode,skiphash,ck) + cf, start, ok = chainrun(cf,start,last,dataset,sequence,rlmode,skiphash,ck,3) if ok then done = true end end if not notmatchreplace[backtrackdisc] then local ok = false - new, cnew, ok = chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck) + new, cnew, ok = chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck,4) if ok then done = true end @@ -2430,33 +2414,57 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) setdisc(backtrackdisc,pre,post,replace) end start = getprev(backtrackdisc) + useddisc = backtrackdisc -- new 2022-09-25 sweephead[post] = getnext(clast) or false sweephead[replace] = getnext(last) or false - else local ok = false - head, start, ok = chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck) + head, start, ok = chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck,5) if ok then done = true end end - - return head, start, done + if useddisc and start ~= usedstart then -- make this option per font -- new 2022-09-25 + start = getnext(start) -- new 2022-09-25 + end -- new 2022-09-25 + return head, start, done, useddisc -- new 2022-09-25 end -local function chaintrac(head,start,dataset,sequence,rlmode,skiphash,ck,match,discseen,sweepnode) - local rule = ck[1] - local lookuptype = ck[8] or ck[2] - local nofseq = #ck[3] - local first = ck[4] - local last = ck[5] - local char = getchar(start) - logwarning("%s: rule %s %s at char %s for (%s,%s,%s) chars, lookuptype %a, %sdisc seen, %ssweeping", - cref(dataset,sequence),rule,match and "matches" or "nomatch", - gref(char),first-1,last-first+1,nofseq-last,lookuptype, - discseen and "" or "no ", sweepnode and "" or "not ") +local chaintrac do + + local level = 0 + local last = { } + + chaintrac = function(head,start,dataset,sequence,rlmode,skiphash,ck,match,discseen,sweepnode) + if dataset then + level = level + 1 + last[level] = start + local rule = ck[1] + local lookuptype = ck[8] or ck[2] + local nofseq = #ck[3] -- ck[3].n + local first = ck[4] + local last = ck[5] + local char = getchar(start) + logwarning("+ %i : %s: rule %s %s at char %s for (%s,%s,%s) chars, lookuptype %a, %sdisc seen, %ssweeping", + level,cref(dataset,sequence),rule,match and "matches" or "nomatch", + gref(char),first-1,last-first+1,nofseq-last,lookuptype, + discseen and "" or "no ", sweepnode and "" or "not ") + else + -- (start,done) + local what = start and "done" or "continue" + local where = head == last[level] and "same" or "different" + local char = getchar(head) + if char then + logwarning("- %i : %s at char %s, %s node",level,what,gref(char),where) + else + logwarning("- %i : %s, %s node",level,what,where) + end + level = level - 1 + end + end + end -- The next one is quite optimized but still somewhat slow, fonts like ebgaramond @@ -2470,6 +2478,9 @@ end -- the previous disc .. such be it (<before><disc><current=fl><after> with only f done) local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,skiphash) + if not contexts then + return head, start, false + end -- optimizing for rlmode gains nothing local sweepnode = sweepnode local sweeptype = sweeptype @@ -2502,7 +2513,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s -- fonts can have many steps (each doing one check) or many contexts -- todo: make a per-char cache so that we have small contexts (when we have a context - -- n == 1 and otherwise it can be more so we can even distingish n == 1 or more) + -- n == 1 and otherwise it can be more so we can even distinguish n == 1 or more) local nofcontexts = contexts.n -- #contexts @@ -2510,10 +2521,10 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s for k=1,nofcontexts do -- does this disc mess work well with n > 1 - local ck = contexts[k] - local seq = ck[3] - local f = ck[4] -- first current -local last = start + local ck = contexts[k] + local seq = ck[3] + local f = ck[4] -- first current + local last = start if not startchar or not seq[f][startchar] then -- report("no hit in %a at %i of %i contexts",sequence.type,k,nofcontexts) goto next @@ -2524,7 +2535,7 @@ local last = start else local l = ck[5] -- last current local current = start --- local last = start + -- local last = start -- current match @@ -2638,7 +2649,7 @@ local last = start -- before if f > 1 then - if startprev then + -- if startprev then -- new 2022-09-25 local prev = startprev if prereplace and prev == checkdisc then prev = getprev(sweepnode) @@ -2762,9 +2773,9 @@ local last = start else goto next end - else - goto next - end + -- else -- new 2022-09-25 + -- goto next -- new 2022-09-25 + -- end -- new 2022-09-25 end -- after @@ -2888,24 +2899,25 @@ local last = start end end end - if trace_contexts then chaintrac(head,start,dataset,sequence,rlmode,skipped and skiphash,ck,true,discseen,sweepnode) end if discseen or sweepnode then + -- When we process a disc we can collapse and therefore we backtrack one node (start) and + -- reprocess. This is needed because there might be more in the collapsed list. head, start, done = chaindisk(head,start,dataset,sequence,rlmode,skipped and skiphash,ck) else - head, start, done = chainrun(head,start,last,dataset,sequence,rlmode,skipped and skiphash,ck) + head, start, done = chainrun(head,start,last,dataset,sequence,rlmode,skipped and skiphash,ck,6) + end + if trace_contexts then + chaintrac(start,done) end if done then break -- else -- next context end - ::next:: - -- if trace_chains then - -- chaintrac(head,start,dataset,sequence,rlmode,skipped and skiphash,ck,false,discseen,sweepnode) - -- end + ::next:: end if discseen then notmatchpre = { } @@ -2924,21 +2936,46 @@ handlers.gsub_reversecontextchain = handle_contextchain handlers.gpos_contextchain = handle_contextchain handlers.gpos_context = handle_contextchain --- this needs testing +-- local function chained_contextchain(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash) +-- local steps = currentlookup.steps +-- local nofsteps = currentlookup.nofsteps +-- if nofsteps > 1 then +-- reportmoresteps(dataset,sequence) +-- end +-- -- probably wrong +-- local l = steps[1].coverage[getchar(start)] +-- if l then +-- return handle_contextchain(head,start,dataset,sequence,l,rlmode,skiphash) +-- else +-- return head, start, false +-- end +-- end + +-- new 2022-09-25 local function chained_contextchain(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash) local steps = currentlookup.steps local nofsteps = currentlookup.nofsteps - if nofsteps > 1 then - reportmoresteps(dataset,sequence) - end - -- probably wrong - local l = steps[1].coverage[getchar(start)] - if l then - return handle_contextchain(head,start,dataset,sequence,l,rlmode,skiphash) + local char = getchar(start) + if nofsteps == 1 then + local s = steps[1] + local l = s.coverage[char] + if l then + return handle_contextchain(head,start,dataset,sequence,l,rlmode,skiphash) + end else - return head, start, false + for i=1,nofsteps do + local s = steps[i] + local l = s.coverage[char] + if l then + local h, s, d = handle_contextchain(head,start,dataset,sequence,l,rlmode,skiphash) + if d then + return h, s, d + end + end + end end + return head, start, false end chainprocs.gsub_context = chained_contextchain @@ -3077,7 +3114,7 @@ do -- overcome local limit end -- Functions like kernrun, comprun etc evolved over time and in the end look rather --- complex. It's a bit of a compromis between extensive copying and creating subruns. +-- complex. It's a bit of a compromise between extensive copying and creating subruns. -- The logic has been improved a lot by Kai and Ivo who use complex fonts which -- really helped to identify border cases on the one hand and get insight in the diverse -- ways fonts implement features (not always that consistent and efficient). At the same @@ -3184,7 +3221,8 @@ local function kernrun(disc,k_run,font,attr,...) if done and trace_testruns then report_disc("done",disc) end - return nextstart, done + -- return nextstart, done + return nextstart end -- fonts like ebgaramond do ligatures this way (less efficient than e.g. dejavu which @@ -3237,12 +3275,19 @@ local function comprun(disc,c_run,...) -- vararg faster than the whole list setdisc(disc,pre,post,replace) end -- - return getnext(disc), renewed + -- return getnext(disc), renewed + return getnext(disc) end -- if we can hyphenate in a lig then unlikely a lig so we -- could have a option here to ignore lig +local test_flatten_start = 2 -- must start at 2 according to Kai + +directives.register("otf.testrun.forceflatten", function(v) + test_flatten_start = v and 1 or 2 +end) + local function testrun(disc,t_run,c_run,...) if trace_testruns then report_disc("test",disc) @@ -3271,7 +3316,7 @@ local function testrun(disc,t_run,c_run,...) local d = d_replace > d_post and d_replace or d_post local head = getnext(disc) -- is: next local tail = head - for i=2,d do -- must start at 2 according to Kai + for i=test_flatten_start,d do local nx = getnext(tail) local id = getid(nx) if id == disc_code then @@ -3286,7 +3331,7 @@ local function testrun(disc,t_run,c_run,...) next = getnext(tail) setnext(tail) setprev(head) - local new = copy_node_list(head) + local new = copynodelist(head) if posttail then setlink(posttail,head) else @@ -3359,7 +3404,8 @@ local function testrun(disc,t_run,c_run,...) end end -- next can have changed (copied list) - return getnext(disc), renewed + -- return getnext(disc), renewed + return getnext(disc) end -- 1{2{\oldstyle\discretionary{3}{4}{5}}6}7\par @@ -3882,7 +3928,7 @@ do -- the before and after lists in the loader. But first I need to see a font that uses multiple -- matches. -- - local start = find_node_tail(head) + local start = findnodetail(head) local rlmode = 0 -- how important is this .. do we need to check for dir? local merged = steps.merged while start do @@ -3968,17 +4014,13 @@ do start = getnext(start) elseif id == disc_code then if not discs or discs[start] == true then - local ok if gpossing then - start, ok = kernrun(start,k_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) + start = kernrun(start,k_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) elseif forcetestrun then - start, ok = testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) + start = testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) else - start, ok = comprun(start,c_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) + start = comprun(start,c_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) end - -- if ok then - -- done = true - -- end else start = getnext(start) end @@ -4052,17 +4094,13 @@ do start = getnext(start) elseif id == disc_code then if not discs or discs[start] == true then - local ok if gpossing then - start, ok = kernrun(start,k_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) + start = kernrun(start,k_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) elseif forcetestrun then - start, ok = testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) + start = testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) else - start, ok = comprun(start,c_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) + start = comprun(start,c_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) end - -- if ok then - -- done = true - -- end else start = getnext(start) end @@ -4184,7 +4222,7 @@ do start = getnext(start) -- elseif id == par_code and startofpar(start) then -- rlparmode, rlmode = pardirstate(start) - -- start = getnext(start) + -- start = nxt else start = getnext(start) end @@ -4274,8 +4312,8 @@ registerotffeature { } } --- Moved here (up) a bit. This doesn't really belong in generic so it will --- move to a context module some day. +-- Moved here (up) a bit. This doesn't really belong in generic so it will move to a +-- context module some day. local function markinitializer(tfmdata,value) local properties = tfmdata.properties diff --git a/macros/luatex/generic/luaotfload/fontloader-font-ott.lua b/macros/luatex/generic/luaotfload/fontloader-font-ott.lua index aa1defd6a1..74fd583758 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-ott.lua +++ b/macros/luatex/generic/luaotfload/fontloader-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/macros/luatex/generic/luaotfload/fontloader-font-oup.lua b/macros/luatex/generic/luaotfload/fontloader-font-oup.lua index 248aad04d2..0d1f9d6a61 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-oup.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-oup.lua @@ -898,26 +898,42 @@ local function unifyglyphs(fontdata,usenames) end end -- - for index=1,nofglyphs do - local math = glyphs[index].math - if math then - local list = math.vparts - if list then - for i=1,#list do local l = list[i] l.glyph = indices[l.glyph] end - end - local list = math.hparts - if list then - for i=1,#list do local l = list[i] l.glyph = indices[l.glyph] end - end - local list = math.vvariants - if list then - -- for i=1,#list do local l = list[i] l.glyph = indices[l.glyph] end - for i=1,#list do list[i] = indices[list[i]] end + if LUATEXENGINE == "luametatex" then + for index=1,nofglyphs do + local math = glyphs[index].math + if math then + local list = math.parts + if list then + for i=1,#list do local l = list[i] l.glyph = indices[l.glyph] end + end + local list = math.variants + if list then + for i=1,#list do list[i] = indices[list[i]] end + end end - local list = math.hvariants - if list then - -- for i=1,#list do local l = list[i] l.glyph = indices[l.glyph] end - for i=1,#list do list[i] = indices[list[i]] end + end + else + for index=1,nofglyphs do + local math = glyphs[index].math + if math then + local list = math.vparts + if list then + for i=1,#list do local l = list[i] l.glyph = indices[l.glyph] end + end + local list = math.hparts + if list then + for i=1,#list do local l = list[i] l.glyph = indices[l.glyph] end + end + local list = math.vvariants + if list then + -- for i=1,#list do local l = list[i] l.glyph = indices[l.glyph] end + for i=1,#list do list[i] = indices[list[i]] end + end + local list = math.hvariants + if list then + -- for i=1,#list do local l = list[i] l.glyph = indices[l.glyph] end + for i=1,#list do list[i] = indices[list[i]] end + end end end end @@ -929,7 +945,9 @@ local function unifyglyphs(fontdata,usenames) if colors then for i=1,#colors do local c = colors[i] - c.slot = indices[c.slot] + if c then -- safeguard + c.slot = indices[c.slot] + end end end end @@ -947,7 +965,6 @@ end local stripredundant do - local p_hex = R("af","AF","09") local p_digit = R("09") local p_done = S("._-")^0 + P(-1) diff --git a/macros/luatex/generic/luaotfload/fontloader-font-shp.lua b/macros/luatex/generic/luaotfload/fontloader-font-shp.lua index 2ca3011a5b..197a3f1ccb 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-shp.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-shp.lua @@ -17,7 +17,7 @@ local pfb = fonts.handlers.pfb local hashes = fonts.hashes local identifiers = hashes.identifiers -local version = otf.version or 0.011 +local version = otf.version or 0.015 local shapescache = containers.define("fonts", "shapes", version, true) local streamscache = containers.define("fonts", "streams", version, true) @@ -150,6 +150,8 @@ end local readers = otf.readers local cleanname = otf.readers.helpers.cleanname +-- todo: shared hash for this but not accessed often + local function makehash(filename,sub,instance) local name = cleanname(file.basename(filename)) if instance then @@ -234,17 +236,21 @@ local function loadstreams(cache,filename,sub,instance) if data then local glyphs = data.glyphs local streams = { } + -- local widths = { } if glyphs then for i=0,#glyphs do local glyph = glyphs[i] if glyph then streams[i] = glyph.stream or "" + -- widths [i] = glyph.width or 0 else streams[i] = "" + -- widths [i] = 0 end end end data.streams = streams + -- data.widths = widths -- maybe more reliable! data.glyphs = nil data.size = size data.format = data.format or (kind == "otf" and "opentype") or "truetype" @@ -259,8 +265,11 @@ local function loadstreams(cache,filename,sub,instance) local names, encoding, streams, metadata = pfb.loadvector(filename,false,true) if streams then local fontbbox = metadata.fontbbox or { 0, 0, 0, 0 } + -- local widths = { } for i=0,#streams do - streams[i] = streams[i].stream or "\14" + local s = streams[i] + streams[i] = s.stream or "\14" + -- widths [i] = s.width or 0 end data = { filename = filename, @@ -268,6 +277,7 @@ local function loadstreams(cache,filename,sub,instance) time = time, format = "type1", streams = streams, + -- widths = widths, fontheader = { fontversion = metadata.version, units = 1000, -- can this be different? @@ -346,7 +356,8 @@ local function getstreamhash(fontid) local fontdata = identifiers[fontid] if fontdata then local properties = fontdata.properties - return makehash(properties.filename,properties.subfont,properties.instance), fontdata + local fonthash = makehash(properties.filename,properties.subfont,properties.instance) + return fonthash, fontdata end end diff --git a/macros/luatex/generic/luaotfload/fontloader-font-ttf.lua b/macros/luatex/generic/luaotfload/fontloader-font-ttf.lua index d1a3972b2c..1fee9fa88d 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-ttf.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-ttf.lua @@ -230,20 +230,7 @@ local function applyaxis(glyph,shape,deltas,dowidth) if dowidth then cnt = cnt - 4 end - if cnt == 1 then - local d = dpoints[1] - local x = xvalues[d] * factor - local y = yvalues[d] * factor - for i=1,nofpoints do - local p = points[i] - if x ~= 0 then - p[1] = p[1] + x - end - if y ~= 0 then - p[2] = p[2] + y - end - end - elseif cnt > 0 then + if cnt > 0 then -- Not the most efficient solution but we seldom do this. We -- actually need to avoid the extra points here but I'll deal -- with that when needed. @@ -263,20 +250,27 @@ local function applyaxis(glyph,shape,deltas,dowidth) end if found == last then lastindex = currentindex - break; + break elseif found > last then + -- \definefontfeature[book][default][axis={weight=800}] + -- \definefont[testfont][file:Commissioner-vf-test.ttf*book] + -- \testfont EΘÄΞ + while lastindex > 1 and dpoints[lastindex] > last do + lastindex = lastindex - 1 + end + -- break end end end - -- print("unicode: ",glyph.unicode or "?") - -- print("contour: ",first,contour,last) - -- print("index : ",firstindex,lastindex,cnt) - -- print("points : ",dpoints[firstindex],dpoints[lastindex]) + -- print("unicode: ",glyph.unicode or "?") + -- print("contour: ",first,contour,last) + -- print("index : ",firstindex,lastindex,cnt) + -- print("points : ",dpoints[firstindex],dpoints[lastindex]) local function find(i) local prv = lastindex for j=firstindex,lastindex do - local nxt = dpoints[j] + local nxt = dpoints[j] -- we could save this lookup when we return it if nxt == i then return false, j, false elseif nxt > i then @@ -343,6 +337,7 @@ local function applyaxis(glyph,shape,deltas,dowidth) end else fx = (p2x - p1x)/(p3x - p1x) +-- fx = round(fx) fx = (1 - fx) * x1 + fx * x3 end -- @@ -366,6 +361,7 @@ local function applyaxis(glyph,shape,deltas,dowidth) end else fy = (p2y - p1y)/(p3y - p1y) +-- fy = round(fy) fy = (1 - fy) * y1 + fy * y3 end -- -- maybe: @@ -769,6 +765,18 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) end first = last + 1 end + -- See readers.hvar where we set the delta lsb as well as the adapted + -- width. At this point we do know the boundingbox's llx. The xmax is + -- not that relevant. It needs more testing! + -- + xmin = glyph.boundingbox[1] + -- + local dlsb = glyph.dlsb + if dlsb then + xmin = xmin + dlsb + glyph.dlsb = nil -- save space + end + -- glyph.boundingbox = { round(xmin), round(ymin), round(xmax), round(ymax) } end end @@ -980,8 +988,8 @@ local function readglyph(f,nofcontours) -- read deltas here, saves space local x = 0 for i=1,nofpoints do local flag = flags[i] - -- local short = band(flag,0x04) ~= 0 - -- local same = band(flag,0x20) ~= 0 + -- local short = band(flag,0x02) ~= 0 + -- local same = band(flag,0x10) ~= 0 if band(flag,0x02) ~= 0 then if band(flag,0x10) ~= 0 then x = x + readbyte(f) diff --git a/macros/luatex/generic/luaotfload/fontloader-l-file.lua b/macros/luatex/generic/luaotfload/fontloader-l-file.lua index 9f8fd65483..70f8188dc1 100644 --- a/macros/luatex/generic/luaotfload/fontloader-l-file.lua +++ b/macros/luatex/generic/luaotfload/fontloader-l-file.lua @@ -741,8 +741,24 @@ end -- not used in context but was in luatex once: -local symlinkattributes = lfs.symlinkattributes +do + + local symlinktarget = lfs.symlinktarget -- luametatex (always returns string) + local symlinkattributes = lfs.symlinkattributes -- luatex (can return nil) + + if symlinktarget then + function lfs.readlink(name) + local target = symlinktarget(name) + return name ~= target and name or nil + end + elseif symlinkattributes then + function lfs.readlink(name) + return symlinkattributes(name,"target") or nil + end + else + function lfs.readlink(name) + return nil + end + end -function lfs.readlink(name) - return symlinkattributes(name,"target") or nil end diff --git a/macros/luatex/generic/luaotfload/fontloader-l-string.lua b/macros/luatex/generic/luaotfload/fontloader-l-string.lua index 1dee85e289..476820a175 100644 --- a/macros/luatex/generic/luaotfload/fontloader-l-string.lua +++ b/macros/luatex/generic/luaotfload/fontloader-l-string.lua @@ -7,7 +7,7 @@ if not modules then modules = { } end modules ['l-string'] = { } local string = string -local sub, gmatch, format, char, byte, rep, lower = string.sub, string.gmatch, string.format, string.char, string.byte, string.rep, string.lower +local sub, gmatch, format, char, byte, rep, lower, find = string.sub, string.gmatch, string.format, string.char, string.byte, string.rep, string.lower, string.find local lpegmatch, patterns = lpeg.match, lpeg.patterns local P, S, C, Ct, Cc, Cs = lpeg.P, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cs @@ -52,10 +52,26 @@ function string.quoted(str) return format("%q",str) -- always double quote end -function string.count(str,pattern) -- variant 3 +-- function string.count(str,pattern) -- variant 3 +-- local n = 0 +-- for _ in gmatch(str,pattern) do -- not for utf +-- n = n + 1 +-- end +-- return n +-- end + +function string.count(str,pattern) local n = 0 - for _ in gmatch(str,pattern) do -- not for utf - n = n + 1 + local i = 1 + local l = #pattern + while true do + i = find(str,pattern,i) + if i then + n = n + 1 + i = i + l + else + break + end end return n end diff --git a/macros/luatex/generic/luaotfload/fontloader-l-table.lua b/macros/luatex/generic/luaotfload/fontloader-l-table.lua index c20bd4733c..b6c3744b8b 100644 --- a/macros/luatex/generic/luaotfload/fontloader-l-table.lua +++ b/macros/luatex/generic/luaotfload/fontloader-l-table.lua @@ -711,7 +711,11 @@ local function do_serialize(root,name,depth,level,indexed) elseif tv == "number" then if tk == "number" then if hexify then - handle(format("%s [0x%X]=0x%X,",depth,k,v)) + if accurate then + handle(format("%s [0x%X]=%q,",depth,k,v)) + else + handle(format("%s [0x%X]=%s,",depth,k,v)) + end elseif accurate then handle(format("%s [%s]=%q,",depth,k,v)) else @@ -719,7 +723,11 @@ local function do_serialize(root,name,depth,level,indexed) end elseif tk == "boolean" then if hexify then - handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v)) + if accurate then + handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) + else + handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) + end elseif accurate then handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) else @@ -729,7 +737,11 @@ local function do_serialize(root,name,depth,level,indexed) -- ignore elseif noquotes and not reserved[k] and lpegmatch(propername,k) then if hexify then - handle(format("%s %s=0x%X,",depth,k,v)) + if accurate then + handle(format("%s %s=%q,",depth,k,v)) + else + handle(format("%s %s=%s,",depth,k,v)) + end elseif accurate then handle(format("%s %s=%q,",depth,k,v)) else @@ -737,7 +749,11 @@ local function do_serialize(root,name,depth,level,indexed) end else if hexify then - handle(format("%s [%q]=0x%X,",depth,k,v)) + if accurate then + handle(format("%s [%q]=%q,",depth,k,v)) + else + handle(format("%s [%q]=%s,",depth,k,v)) + end elseif accurate then handle(format("%s [%q]=%q,",depth,k,v)) else diff --git a/macros/luatex/generic/luaotfload/fontloader-reference.lua b/macros/luatex/generic/luaotfload/fontloader-reference.lua index c539d886cc..6997a417a7 100644 --- a/macros/luatex/generic/luaotfload/fontloader-reference.lua +++ b/macros/luatex/generic/luaotfload/fontloader-reference.lua @@ -1,6 +1,6 @@ -- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua -- parent file : c:/data/develop/context/sources/luatex-fonts.lua --- merge date : 2022-09-16 14:39 +-- merge date : 2023-08-16 19:31 do -- begin closure to overcome local limits and interference @@ -927,7 +927,7 @@ if not modules then modules={} end modules ['l-string']={ license="see context related readme files" } local string=string -local sub,gmatch,format,char,byte,rep,lower=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower +local sub,gmatch,format,char,byte,rep,lower,find=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower,string.find local lpegmatch,patterns=lpeg.match,lpeg.patterns local P,S,C,Ct,Cc,Cs=lpeg.P,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.Cs local unquoted=patterns.squote*C(patterns.nosquote)*patterns.squote+patterns.dquote*C(patterns.nodquote)*patterns.dquote @@ -937,10 +937,18 @@ end function string.quoted(str) return format("%q",str) end -function string.count(str,pattern) +function string.count(str,pattern) local n=0 - for _ in gmatch(str,pattern) do - n=n+1 + local i=1 + local l=#pattern + while true do + i=find(str,pattern,i) + if i then + n=n+1 + i=i+l + else + break + end end return n end @@ -1542,7 +1550,11 @@ local function do_serialize(root,name,depth,level,indexed) elseif tv=="number" then if tk=="number" then if hexify then - handle(format("%s [0x%X]=0x%X,",depth,k,v)) + if accurate then + handle(format("%s [0x%X]=%q,",depth,k,v)) + else + handle(format("%s [0x%X]=%s,",depth,k,v)) + end elseif accurate then handle(format("%s [%s]=%q,",depth,k,v)) else @@ -1550,7 +1562,11 @@ local function do_serialize(root,name,depth,level,indexed) end elseif tk=="boolean" then if hexify then - handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v)) + if accurate then + handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) + else + handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) + end elseif accurate then handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) else @@ -1559,7 +1575,11 @@ local function do_serialize(root,name,depth,level,indexed) elseif tk~="string" then elseif noquotes and not reserved[k] and lpegmatch(propername,k) then if hexify then - handle(format("%s %s=0x%X,",depth,k,v)) + if accurate then + handle(format("%s %s=%q,",depth,k,v)) + else + handle(format("%s %s=%s,",depth,k,v)) + end elseif accurate then handle(format("%s %s=%q,",depth,k,v)) else @@ -1567,7 +1587,11 @@ local function do_serialize(root,name,depth,level,indexed) end else if hexify then - handle(format("%s [%q]=0x%X,",depth,k,v)) + if accurate then + handle(format("%s [%q]=%q,",depth,k,v)) + else + handle(format("%s [%q]=%s,",depth,k,v)) + end elseif accurate then handle(format("%s [%q]=%q,",depth,k,v)) else @@ -2944,9 +2968,23 @@ function file.withinbase(path) end return true end -local symlinkattributes=lfs.symlinkattributes -function lfs.readlink(name) - return symlinkattributes(name,"target") or nil +do + local symlinktarget=lfs.symlinktarget + local symlinkattributes=lfs.symlinkattributes + if symlinktarget then + function lfs.readlink(name) + local target=symlinktarget(name) + return name~=target and name or nil + end + elseif symlinkattributes then + function lfs.readlink(name) + return symlinkattributes(name,"target") or nil + end + else + function lfs.readlink(name) + return nil + end + end end end -- closure @@ -3309,6 +3347,7 @@ local p_prune_intospace=Cs (noleading*(notrailing+intospace+1 )^0 ) local p_retain_normal=Cs ((normalline+normalempty )^0 ) local p_retain_collapse=Cs ((normalline+doubleempty )^0 ) local p_retain_noempty=Cs ((normalline+singleempty )^0 ) +local p_collapse_all=Cs (stripstart*(stripend+((whitespace+newline)^1/" ")+1)^0 ) local striplinepatterns={ ["prune"]=p_prune_normal, ["prune and collapse"]=p_prune_collapse, @@ -3317,6 +3356,7 @@ local striplinepatterns={ ["retain"]=p_retain_normal, ["retain and collapse"]=p_retain_collapse, ["retain and no empty"]=p_retain_noempty, + ["collapse all"]=p_collapse_all, ["collapse"]=patterns.collapser, } setmetatable(striplinepatterns,{ __index=function(t,k) return p_prune_collapse end }) @@ -4852,7 +4892,7 @@ local mt={ end, __storage__=true } -function containers.define(category,subcategory,version,enabled) +function containers.define(category,subcategory,version,enabled,reload) if category and subcategory then local c=allocated[category] if not c then @@ -4866,6 +4906,7 @@ function containers.define(category,subcategory,version,enabled) subcategory=subcategory, storage={}, enabled=enabled, + reload=reload, version=version or math.pi, trace=false, } @@ -4888,7 +4929,8 @@ function containers.is_valid(container,name) end function containers.read(container,name) local storage=container.storage - local stored=storage[name] + local reload=container.reload + local stored=not reload and storage[name] if not stored and container.enabled and caches and containers.usecache then stored=loaddatafromcache(container.readables,name,container.writable) if stored and stored.cache_version==container.version then @@ -9406,19 +9448,9 @@ function constructors.scale(tfmdata,specification) target.unscaled=tfmdata local mathsize=tonumber(specification.mathsize) or 0 local textsize=tonumber(specification.textsize) or scaledpoints - local forcedsize=tonumber(parameters.mathsize ) or 0 local extrafactor=tonumber(specification.factor ) or 1 - if (mathsize==2 or forcedsize==2) and parameters.scriptpercentage then - scaledpoints=parameters.scriptpercentage*textsize/100 - elseif (mathsize==3 or forcedsize==3) and parameters.scriptscriptpercentage then - scaledpoints=parameters.scriptscriptpercentage*textsize/100 - elseif forcedsize>1000 then - scaledpoints=forcedsize - else - end targetparameters.mathsize=mathsize - targetparameters.textsize=textsize - targetparameters.forcedsize=forcedsize + targetparameters.textsize=textsize targetparameters.extrafactor=extrafactor local addtounicode=constructors.addtounicode local tounicode=fonts.mappings.tounicode @@ -11316,6 +11348,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 @@ -12399,7 +12432,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 @@ -13060,6 +13093,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, @@ -13418,10 +13455,10 @@ do result.familyotherblues={ unpack(stack,1,top) } top=0 end+P("\10")/function() - result.strhw=stack[top] + result.stdhw=stack[top] top=0 end+P("\11")/function() - result.strvw=stack[top] + result.stdvw=stack[top] top=0 end+P("\13")/function() result.uniqueid=stack[top] @@ -13493,7 +13530,7 @@ do result.bluescale=stack[top] top=0 end+P("\10")/function() - result.bluesnap=stack[top] + result.blueshift=stack[top] top=0 end+P("\11")/function() result.bluefuzz=stack[top] @@ -13547,7 +13584,7 @@ do top=0 end ) - local remap={ + local remap_1={ ["\x00"]="00",["\x01"]="01",["\x02"]="02",["\x03"]="03",["\x04"]="04",["\x05"]="05",["\x06"]="06",["\x07"]="07",["\x08"]="08",["\x09"]="09",["\x0A"]="0.",["\x0B"]="0E",["\x0C"]="0E-",["\x0D"]="0",["\x0E"]="0-",["\x0F"]="0", ["\x10"]="10",["\x11"]="11",["\x12"]="12",["\x13"]="13",["\x14"]="14",["\x15"]="15",["\x16"]="16",["\x17"]="17",["\x18"]="18",["\x19"]="19",["\x1A"]="1.",["\x1B"]="1E",["\x1C"]="1E-",["\x1D"]="1",["\x1E"]="1-",["\x1F"]="1", ["\x20"]="20",["\x21"]="21",["\x22"]="22",["\x23"]="23",["\x24"]="24",["\x25"]="25",["\x26"]="26",["\x27"]="27",["\x28"]="28",["\x29"]="29",["\x2A"]="2.",["\x2B"]="2E",["\x2C"]="2E-",["\x2D"]="2",["\x2E"]="2-",["\x2F"]="2", @@ -13563,8 +13600,13 @@ do ["\xC0"]="E-0",["\xC1"]="E-1",["\xC2"]="E-2",["\xC3"]="E-3",["\xC4"]="E-4",["\xC5"]="E-5",["\xC6"]="E-6",["\xC7"]="E-7",["\xC8"]="E-8",["\xC9"]="E-9",["\xCA"]="E-.",["\xCB"]="E-E",["\xCC"]="E-E-",["\xCD"]="E-",["\xCE"]="E--",["\xCF"]="E-", ["\xD0"]="-0",["\xD1"]="-1",["\xD2"]="-2",["\xD3"]="-3",["\xD4"]="-4",["\xD5"]="-5",["\xD6"]="-6",["\xD7"]="-7",["\xD8"]="-8",["\xD9"]="-9",["\xDA"]="-.",["\xDB"]="-E",["\xDC"]="-E-",["\xDD"]="-",["\xDE"]="--",["\xDF"]="-", } - local p_last=S("\x0F\x1F\x2F\x3F\x4F\x5F\x6F\x7F\x8F\x9F\xAF\xBF")+R("\xF0\xFF") - local p_nibbles=P("\30")*Cs(((1-p_last)/remap)^0*(P(1)/remap))/function(n) + local remap_2={ + ["\x0F"]="0",["\x1F"]="1",["\x2F"]="2",["\x3F"]="3",["\x4F"]="4", + ["\x5F"]="5",["\x6F"]="6",["\x7F"]="7",["\x8F"]="8",["\x9F"]="9", + } + local p_last_1=S("\x0F\x1F\x2F\x3F\x4F\x5F\x6F\x7F\x8F\x9F\xAF\xBF") + local p_last_2=R("\xF0\xFF") + local p_nibbles=P("\30")*Cs(((1-(p_last_1+p_last_2))/remap_1)^0*(p_last_1/remap_2+p_last_2/""))/function(n) top=top+1 stack[top]=tonumber(n) or 0 end @@ -13675,7 +13717,7 @@ do local y=0 local width=false local lsb=0 -local result={} + local result={} local r=0 local stems=0 local globalbias=0 @@ -14568,6 +14610,7 @@ end end) local c_endchar=chars[14] local encode={} + local typeone=false setmetatableindex(encode,function(t,i) for i=-2048,-1130 do t[i]=char(28,band(rshift(i,8),0xFF),band(i,0xFF)) @@ -14693,6 +14736,13 @@ end elseif t<=254 then stack[top]=-t*256+64148-tab[i+1] i=i+2 + elseif typeone then + local n=0x1000000*tab[i+1]+0x10000*tab[i+2]+0x100*tab[i+3]+tab[i+4] + if n>=0x8000000 then + n=n-0xFFFFFFFF-1 + end + stack[top]=n + i=i+5 else local n1=0x100*tab[i+1]+tab[i+2] local n2=0x100*tab[i+3]+tab[i+4] @@ -14838,20 +14888,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 @@ -14898,7 +14935,7 @@ end ((l<1240 and 107) or (l<33900 and 1131) or 32768)+1 end end - local function processshape(tab,index,hack) + local function processshape(glyphs,tab,index,hack) if not tab then glyphs[index]={ boundingbox={ 0,0,0,0 }, @@ -14953,8 +14990,9 @@ end result=nil if glyph then glyph.stream=stream + glyph.width=width else - glyphs[index]={ stream=stream } + glyphs[index]={ stream=stream,width=width } end elseif glyph then glyph.segments=keepcurve~=false and result or nil @@ -15022,23 +15060,24 @@ result=nil end return privatedata.nominalwidthx or 0,privatedata.defaultwidthx or 0 end - parsecharstrings=function(fontdata,data,glphs,doshapes,tversion,streams,nobias) + parsecharstrings=function(fontdata,data,glphs,doshapes,tversion,streams,nobias,istypeone) local dictionary=data.dictionaries[1] local charstrings=dictionary.charstrings keepcurve=doshapes version=tversion + typeone=istypeone or false strings=data.strings globals=data.routines or {} locals=dictionary.subroutines or {} charset=dictionary.charset vsindex=dictionary.vsindex or 0 - glyphs=glphs or {} + local glyphs=glphs or {} globalbias,localbias=setbias(globals,locals,nobias) nominalwidth,defaultwidth=setwidths(dictionary.private) if charstrings then startparsing(fontdata,data,streams) for index=1,#charstrings do - processshape(charstrings[index],index-1) + processshape(glyphs,charstrings[index],index-1) end if justpass and next(seacs) then local charset=data.dictionaries[1].charset @@ -15052,7 +15091,7 @@ result=nil if bglyph and aglyph then local jp=justpass justpass=false - local x,y=processshape(charstrings[bindex+1],bindex,true) + local x,y=processshape(glyphs,charstrings[bindex+1],bindex,true) justpass=jp local base=bglyph.stream local accent=aglyph.stream @@ -15077,12 +15116,13 @@ result=nil locals=dictionary.subroutines or {} charset=false vsindex=dictionary.vsindex or 0 - glyphs=glphs or {} + local glyphs=glphs or {} justpass=streams==true seacs={} globalbias,localbias=setbias(globals,locals,nobias) nominalwidth,defaultwidth=setwidths(dictionary.private) - processshape(tab,index-1) + processshape(glyphs,tab,index-1) + return glyphs[index] end end local function readglobals(f,data,version) @@ -15230,7 +15270,7 @@ local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams) parseprivates(data,data.dictionaries) readlocals(f,data,dictionary,version) startparsing(fontdata,data,streams) - parsecharstrings(fontdata,data,glyphs,doshapes,version,streams) + parsecharstrings(fontdata,data,glyphs,doshapes,version,streams,false) stopparsing(fontdata,data) end local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams) @@ -15378,6 +15418,8 @@ function readers.cff(f,fontdata,specification) cffinfo.bluefuzz=data.bluefuzz cffinfo.stdhw=data.stdhw cffinfo.stdvw=data.stdvw + cffinfo.stemsnaph=data.stemsnaph + cffinfo.stemsnapv=data.stemsnapv end end cleanup(data,dictionaries) @@ -15420,39 +15462,6 @@ function readers.cff2(f,fontdata,specification) cleanup(data,dictionaries) end end -function readers.cffcheck(filename) - local f=io.open(filename,"rb") - if f then - local fontdata={ - glyphs={}, - } - local header=readheader(f) - if header.major~=1 then - report("only version %s is supported for table %a",1,"cff") - return - end - local names=readfontnames(f) - local dictionaries=readtopdictionaries(f) - local strings=readstrings(f) - local glyphs={} - local data={ - header=header, - names=names, - dictionaries=dictionaries, - strings=strings, - glyphs=glyphs, - nofglyphs=0, - } - parsedictionaries(data,dictionaries,"cff") - local cid=data.dictionaries[1].cid - if cid and cid.fdselect then - readfdselect(f,fontdata,data,glyphs,false) - else - readnoselect(f,fontdata,data,glyphs,false) - end - return data - end -end end -- closure @@ -15622,20 +15631,7 @@ local function applyaxis(glyph,shape,deltas,dowidth) if dowidth then cnt=cnt-4 end - if cnt==1 then - local d=dpoints[1] - local x=xvalues[d]*factor - local y=yvalues[d]*factor - for i=1,nofpoints do - local p=points[i] - if x~=0 then - p[1]=p[1]+x - end - if y~=0 then - p[2]=p[2]+y - end - end - elseif cnt>0 then + if cnt>0 then local contours=shape.contours local nofcontours=#contours local first=1 @@ -15652,8 +15648,11 @@ local function applyaxis(glyph,shape,deltas,dowidth) end if found==last then lastindex=currentindex - break; + break elseif found>last then + while lastindex>1 and dpoints[lastindex]>last do + lastindex=lastindex-1 + end break end end @@ -15661,7 +15660,7 @@ local function applyaxis(glyph,shape,deltas,dowidth) local function find(i) local prv=lastindex for j=firstindex,lastindex do - local nxt=dpoints[j] + local nxt=dpoints[j] if nxt==i then return false,j,false elseif nxt>i then @@ -16109,6 +16108,12 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) end first=last+1 end + xmin=glyph.boundingbox[1] + local dlsb=glyph.dlsb + if dlsb then + xmin=xmin+dlsb + glyph.dlsb=nil + end glyph.boundingbox={ round(xmin),round(ymin),round(xmax),round(ymax) } end end @@ -16883,6 +16888,20 @@ local read_integer={ streamreader.readinteger3, streamreader.readinteger4, } +directives.register("fonts.streamreader",function() + read_cardinal={ + streamreader.readcardinal1, + streamreader.readcardinal2, + streamreader.readcardinal3, + streamreader.readcardinal4, + } + read_integer={ + streamreader.readinteger1, + streamreader.readinteger2, + streamreader.readinteger3, + streamreader.readinteger4, + } +end) local lookupnames={ gsub={ single="gsub_single", @@ -16957,7 +16976,6 @@ local function getaxisscale(segments,minimum,default,maximum,user) 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 @@ -18461,6 +18479,7 @@ do local noflookups=#lookups local lookupprefix=sub(what,2,2) local usedlookups=false + local allsteps={} for lookupid=1,noflookups do local lookup=lookups[lookupid] local lookuptype=lookup.type @@ -18495,6 +18514,7 @@ do steps[nofsteps]=step local rules=step.rules if rules then + allsteps[#allsteps+1]=step for i=1,#rules do local rule=rules[i] local before=rule.before @@ -18593,25 +18613,18 @@ do report("used %s lookups: % t",what,sortedkeys(usedlookups)) end local reported={} - local function report_issue(i,what,sequence,kind) - local name=sequence.name - if not reported[name] then - report("rule %i in %s lookup %a has %s lookups",i,what,name,kind) - reported[name]=true - end + local function report_issue(i,what,step,kind) + report("rule %i in step %i of %s has %s lookups",i,step,what,kind) 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 + local step=allsteps[s] 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,sequence,"no") + report_issue(i,what,s,"no") elseif not next(rlookups) then rule.lookups=nil else @@ -18647,12 +18660,12 @@ do sublookupcheck[lookupid]=1 h=nofsublookups else - report_issue(i,what,sequence,"missing") + report_issue(i,what,s,"missing") rule.lookups=nil break end else - report_issue(i,what,sequence,"bad") + report_issue(i,what,s,"bad") rule.lookups=nil break end @@ -18674,7 +18687,6 @@ do end end end - end for i,n in sortedhash(sublookupcheck) do local l=lookups[i] local t=l.type @@ -19097,7 +19109,7 @@ local function readmathglyphinfo(f,fontdata,offset) if not math then glyph.math={ accent=accent } else - math.accent=accent + math.accent=accent end end end @@ -19178,7 +19190,7 @@ local function readmathvariants(f,fontdata,offset) local vconstruction=readcardinaltable(f,vnofglyphs,ushort) local hconstruction=readcardinaltable(f,hnofglyphs,ushort) fontdata.mathconstants.MinConnectorOverlap=minoverlap - local function get(offset,coverage,nofglyphs,construction,kvariants,kparts,kitalic) + 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 @@ -19241,13 +19253,21 @@ local function readmathvariants(f,fontdata,offset) if italic and italic~=0 then math[kitalic]=italic end + if orientation then + math[korientation]=orientation + end end end end end end - get(offset,vcoverage,vnofglyphs,vconstruction,"vvariants","vparts","vitalic") - get(offset,hcoverage,hnofglyphs,hconstruction,"hvariants","hparts","hitalic") + 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) @@ -19273,9 +19293,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 and 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") @@ -19887,7 +19908,6 @@ function readers.hvar(f,fontdata,specification) end local tableoffset=gotodatatable(f,fontdata,"hvar",specification.variable) if not tableoffset then - report("no hvar table, expect problems due to messy widths") return end local version=readulong(f) @@ -20192,16 +20212,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", @@ -20221,6 +20245,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", @@ -20230,6 +20255,7 @@ local scripts=allocate { ["khar"]="kharosthi", ["khmr"]="khmer", ["khoj"]="khojki", + ["kits"]="khitan small script", ["knd2"]="kannada variant 2", ["knda"]="kannada", ["kthi"]="kaithi", @@ -20263,6 +20289,7 @@ local scripts=allocate { ["musc"]="musical symbols", ["mym2"]="myanmar variant 2", ["mymr"]="myanmar", + ["nand"]="nandinagari", ["narb"]="old north arabian", ["nbat"]="nabataean", ["newa"]="newa", @@ -20272,9 +20299,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", @@ -20306,7 +20334,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", @@ -20318,12 +20346,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", } @@ -20338,6 +20370,7 @@ local languages=allocate { ["agw" ]="agaw", ["aio" ]="aiton", ["aka" ]="akan", + ["akb" ]="batak angkola", ["als" ]="alsatian", ["alt" ]="altai", ["amh" ]="amharic", @@ -20350,6 +20383,7 @@ local languages=allocate { ["asm" ]="assamese", ["ast" ]="asturian", ["ath" ]="athapaskan", + ["avn" ]="avatime", ["avr" ]="avar", ["awa" ]="awadhi", ["aym" ]="aymara", @@ -20395,8 +20429,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", @@ -20431,14 +20469,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", @@ -20510,13 +20550,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", @@ -20541,10 +20584,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", @@ -20564,6 +20609,7 @@ local languages=allocate { ["kan" ]="kannada", ["kar" ]="karachay", ["kat" ]="georgian", + ["kaw" ]="kawi (old javanese)", ["kaz" ]="kazakh", ["kde" ]="makonde", ["kea" ]="kabuverdianu (crioulo)", @@ -20621,6 +20667,7 @@ local languages=allocate { ["kur" ]="kurdish", ["kuu" ]="kurukh", ["kuy" ]="kuy", + ["kwk" ]="kwakʼwala", ["kyk" ]="koryak", ["kyu" ]="western kayah", ["lad" ]="ladin", @@ -20632,6 +20679,7 @@ local languages=allocate { ["laz" ]="laz", ["lcr" ]="l-cree", ["ldk" ]="ladakhi", + ["lef" ]="lelemi", ["lez" ]="lezgi", ["lij" ]="ligurian", ["lim" ]="limburgish", @@ -20644,6 +20692,7 @@ local languages=allocate { ["lmo" ]="lombard", ["lmw" ]="lomwe", ["lom" ]="loma", + ["lpo" ]="lipo", ["lrc" ]="luri", ["lsb" ]="lower sorbian", ["lsm" ]="lule sami", @@ -20660,7 +20709,7 @@ local languages=allocate { ["mah" ]="marshallese", ["maj" ]="majang", ["mak" ]="makhuwa", - ["mal" ]="malayalam reformed", + ["mal" ]="malayalam", ["mam" ]="mam", ["man" ]="mansi", ["map" ]="mapudungun", @@ -20695,6 +20744,7 @@ local languages=allocate { ["mok" ]="moksha", ["mol" ]="moldavian", ["mon" ]="mon", + ["mnw" ]="thailand mon", ["mor" ]="moroccan", ["mos" ]="mossi", ["mri" ]="maori", @@ -20733,7 +20783,7 @@ local languages=allocate { ["nor" ]="norwegian", ["nov" ]="novial", ["nsm" ]="northern sami", - ["nso" ]="sotho, northern", + ["nso" ]="northern sotho", ["nta" ]="northern tai", ["nto" ]="esperanto", ["nym" ]="nyamwezi", @@ -20781,6 +20831,7 @@ local languages=allocate { ["rbu" ]="russian buriat", ["rcr" ]="r-cree", ["rej" ]="rejang", + ["rhg" ]="rohingya", ["ria" ]="riang", ["rif" ]="tarifit", ["rit" ]="ritarungo", @@ -20805,6 +20856,7 @@ local languages=allocate { ["scs" ]="north slavey", ["sek" ]="sekota", ["sel" ]="selkup", + ["sfm" ]="small flowery miao", ["sga" ]="old irish", ["sgo" ]="sango", ["sgs" ]="samogitian", @@ -20826,7 +20878,7 @@ local languages=allocate { ["snk" ]="soninke", ["sog" ]="sodo gurage", ["sop" ]="songe", - ["sot" ]="sotho, southern", + ["sot" ]="southern sotho", ["sqi" ]="albanian", ["srb" ]="serbian", ["srd" ]="sardinian", @@ -20867,7 +20919,9 @@ local languages=allocate { ["tht" ]="tahitian", ["tib" ]="tibetan", ["tiv" ]="tiv", + ["tj;" ]="tai laing", ["tkm" ]="turkmen", + ["tli" ]="tlingit", ["tmh" ]="tamashek", ["tmn" ]="temne", ["tna" ]="tswana", @@ -20881,7 +20935,7 @@ local languages=allocate { ["tsj" ]="tshangla", ["tua" ]="turoyo aramaic", ["tul" ]="tulu", - ["tum" ]="tulu", + ["tum" ]="tumbuka", ["tuv" ]="tuvin", ["tvl" ]="tuvalu", ["twi" ]="twi", @@ -20903,6 +20957,7 @@ local languages=allocate { ["wa" ]="wa", ["wag" ]="wagdi", ["war" ]="waray-waray", + ["wci" ]="waci gbe", ["wcr" ]="west-cree", ["wel" ]="welsh", ["wlf" ]="wolof", @@ -20914,17 +20969,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", @@ -20948,6 +21009,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", @@ -21024,8 +21086,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", @@ -21045,6 +21107,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", @@ -21289,7 +21352,7 @@ local trace_defining=false registertracker("fonts.defining",function(v) trace_d local report_otf=logs.reporter("fonts","otf loading") local fonts=fonts local otf=fonts.handlers.otf -otf.version=3.120 +otf.version=3.133 otf.cache=containers.define("fonts","otl",otf.version,true) otf.svgcache=containers.define("fonts","svg",otf.version,true) otf.pngcache=containers.define("fonts","png",otf.version,true) @@ -21772,24 +21835,6 @@ local function read_from_otf(specification) end return tfmdata end -local function checkmathsize(tfmdata,mathsize) - local mathdata=tfmdata.shared.rawdata.metadata.math - local mathsize=tonumber(mathsize) - if mathdata then - local parameters=tfmdata.parameters - parameters.scriptpercentage=mathdata.ScriptPercentScaleDown - parameters.scriptscriptpercentage=mathdata.ScriptScriptPercentScaleDown - parameters.mathsize=mathsize - end -end -registerotffeature { - name="mathsize", - description="apply mathsize specified in the font", - initializers={ - base=checkmathsize, - node=checkmathsize, - } -} function otf.collectlookups(rawdata,kind,script,language) if not kind then return @@ -24781,24 +24826,40 @@ local function unifyglyphs(fontdata,usenames) descriptions[unicode]=glyph end end - for index=1,nofglyphs do - local math=glyphs[index].math - if math then - local list=math.vparts - if list then - for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end - end - local list=math.hparts - if list then - for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end - end - local list=math.vvariants - if list then - for i=1,#list do list[i]=indices[list[i]] end + if LUATEXENGINE=="luametatex" then + for index=1,nofglyphs do + local math=glyphs[index].math + if math then + local list=math.parts + if list then + for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end + end + local list=math.variants + if list then + for i=1,#list do list[i]=indices[list[i]] end + end end - local list=math.hvariants - if list then - for i=1,#list do list[i]=indices[list[i]] end + end + else + for index=1,nofglyphs do + local math=glyphs[index].math + if math then + local list=math.vparts + if list then + for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end + end + local list=math.hparts + if list then + for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end + end + local list=math.vvariants + if list then + for i=1,#list do list[i]=indices[list[i]] end + end + local list=math.hvariants + if list then + for i=1,#list do list[i]=indices[list[i]] end + end end end end @@ -24809,7 +24870,9 @@ local function unifyglyphs(fontdata,usenames) if colors then for i=1,#colors do local c=colors[i] - c.slot=indices[c.slot] + if c then + c.slot=indices[c.slot] + end end end end @@ -27329,12 +27392,8 @@ local trace_testruns=false registertracker("otf.testruns",function(v) trace_tes local forcediscretionaries=false local forcepairadvance=false local repeatablemultiples=context or false -directives.register("otf.forcediscretionaries",function(v) - forcediscretionaries=v -end) -directives.register("otf.forcepairadvance",function(v) - forcepairadvance=v -end) +directives.register("otf.forcediscretionaries",function(v) forcediscretionaries=v end) +directives.register("otf.forcepairadvance",function(v) forcepairadvance=v end) local report_direct=logs.reporter("fonts","otf direct") local report_subchain=logs.reporter("fonts","otf subchain") local report_chain=logs.reporter("fonts","otf chain") @@ -27356,7 +27415,6 @@ local setboth=nuts.setboth local getid=nuts.getid local getstate=nuts.getstate local getsubtype=nuts.getsubtype -local setsubtype=nuts.setsubtype local getchar=nuts.getchar local setchar=nuts.setchar local getdisc=nuts.getdisc @@ -27376,10 +27434,10 @@ local flushcomponents=components.flush local ischar=nuts.ischar local usesfont=nuts.usesfont local insertnodeafter=nuts.insertafter -local copy_node=nuts.copy -local copy_node_list=nuts.copylist -local remove_node=nuts.remove -local find_node_tail=nuts.tail +local copynode=nuts.copy +local copynodelist=nuts.copylist +local removenode=nuts.remove +local findnodetail=nuts.tail local flushnodelist=nuts.flushlist local flushnode=nuts.flushnode local endofmath=nuts.endofmath @@ -27389,7 +27447,6 @@ local setmetatableindex=table.setmetatableindex local nextnode=nuts.traversers.node local nodecodes=nodes.nodecodes local glyphcodes=nodes.glyphcodes -local disccodes=nodes.disccodes local glyph_code=nodecodes.glyph local glue_code=nodecodes.glue local disc_code=nodecodes.disc @@ -27398,8 +27455,7 @@ local dir_code=nodecodes.dir local par_code=nodecodes.par local lefttoright_code=nodes.dirvalues.lefttoright local righttoleft_code=nodes.dirvalues.righttoleft -local discretionarydisc_code=disccodes.discretionary -local ligatureglyph_code=glyphcodes.ligature +local discretionarydisc_code=nodes.disccodes.discretionary local a_noligature=attributes.private("noligature") local injections=nodes.injections local setmark=injections.setmark @@ -27490,7 +27546,7 @@ local function cref(dataset,sequence,index) return "no valid dataset" end local merged=sequence.merged and "merged " or "" - if index then + if index and index>1 then return formatters["feature %a, type %a, %schain lookup %a, index %a"]( dataset[4],sequence.type,merged,sequence.name,index) else @@ -27547,7 +27603,7 @@ end local function appenddisc(disc,list) local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true) local posthead=list - local replacehead=copy_node_list(list) + local replacehead=copynodelist(list) if post then setlink(posttail,posthead) else @@ -27574,7 +27630,6 @@ local function markstoligature(head,start,stop,char) end resetinjection(base) setchar(base,char) - setsubtype(base,ligatureglyph_code) setcomponents(base,start) setlink(prev,base,next) flushcomponents(start) @@ -27612,7 +27667,6 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou end resetinjection(base) setchar(base,char) - setsubtype(base,ligatureglyph_code) setcomponents(base,comp) setlink(prev,base,next) if not discfound then @@ -27632,7 +27686,7 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou if trace_marks then logwarning("%s: keep ligature mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start)) end - local n=copy_node(start) + local n=copynode(start) copyinjection(n,start) head,current=insertnodeafter(head,current,n) elseif trace_marks then @@ -27696,57 +27750,57 @@ end local function multiple_glyphs(head,start,multiple,skiphash,what,stop) local nofmultiples=#multiple if nofmultiples>0 then + local first=start resetinjection(start) setchar(start,multiple[1]) if nofmultiples>1 then - local sn=getnext(start) - for k=2,nofmultiples do - local n=copy_node(start) + for i=2,nofmultiples do + local n=copynode(start) resetinjection(n) - setchar(n,multiple[k]) + setchar(n,multiple[i]) insertnodeafter(head,start,n) start=n end - if what~=true and repeatablemultiples then - local kind=type(what) - local m,f,l - if kind=="string" then - local what,n=string.match(what,"^repeat(.-)[:=](%d+)$") - if what=="middle" then - m=tonumber(n) - elseif what=="first" then - f=tonumber(n) - elseif what=="last" then - l=tonumber(n) - end - elseif kind=="table" then - m=what.middle - f=what.first - l=what.last - end - if f or m or l then - if m and m>1 and nofmultiples==3 then - local middle=getnext(first) - for i=2,m do - local n=copynode(middle) - resetinjection(n) - insertnodeafter(head,first,n) - end - end - if f and f>1 then - for i=2,f do - local n=copynode(first) - resetinjection(n) - insertnodeafter(head,first,n) - end - end - if l and l>1 then - for i=2,l do - local n=copynode(start) - resetinjection(n) - insertnodeafter(head,start,n) - start=n - end + end + if what~=true and repeatablemultiples then + local kind=type(what) + local m,f,l + if kind=="string" then + local what,n=string.match(what,"^repeat(.-)[:=](%d+)$") + if what=="middle" then + m=tonumber(n) + elseif what=="first" then + f=tonumber(n) + elseif what=="last" then + l=tonumber(n) + end + elseif kind=="table" then + m=what.middle + f=what.first + l=what.last + end + if f or m or l then + if m and m>1 and nofmultiples==3 then + local middle=getnext(first) + for i=2,m do + local n=copynode(middle) + resetinjection(n) + insertnodeafter(head,first,n) + end + end + if f and f>1 then + for i=2,f do + local n=copynode(first) + resetinjection(n) + insertnodeafter(head,first,n) + end + end + if l and l>1 then + for i=2,l do + local n=copynode(start) + resetinjection(n) + insertnodeafter(head,start,n) + start=n end end end @@ -27918,9 +27972,9 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip local prev=getprev(start) if stop then setnext(stop) - local copy=copy_node_list(start) + local copy=copynodelist(start) local tail=stop - local liat=find_node_tail(copy) + local liat=findnodetail(copy) if pre then setlink(liat,pre) end @@ -27931,7 +27985,7 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip replace=start else setnext(start) - local copy=copy_node(start) + local copy=copynode(start) if pre then setlink(copy,pre) end @@ -28308,7 +28362,7 @@ function chainprocs.gsub_remove(head,start,stop,dataset,sequence,currentlookup,r if trace_chains then logprocess("%s: removing character %s",cref(dataset,sequence,chainindex),gref(getchar(start))) end - head,start=remove_node(head,start,true) + head,start=removenode(head,start,true) return head,getprev(start),true end function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) @@ -28821,7 +28875,7 @@ do if not userkern then local thekern=nuts.new("kern",1) local setkern=nuts.setkern userkern=function(k) - local n=copy_node(thekern) + local n=copynode(thekern) setkern(n,k) return n end @@ -28858,26 +28912,33 @@ local function setdiscchecked(d,pre,post,replace) setdisc(d,pre,post,replace) end local noflags={ false,false,false,false } -local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck) +local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck,where) local size=ck[5]-ck[4]+1 local chainlookups=ck[6] local done=false if chainlookups then if size==1 then local chainlookup=chainlookups[1] - for j=1,#chainlookup do - local chainstep=chainlookup[j] - local chainkind=chainstep.type - local chainproc=chainprocs[chainkind] - if chainproc then - local ok - head,start,ok=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,1) - if ok then - done=true + if chainlookup then + for j=1,#chainlookup do + local chainstep=chainlookup[j] + if chainstep then + local chainkind=chainstep.type + local chainproc=chainprocs[chainkind] + if chainproc then + local ok + head,start,ok=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,1) + if ok then + done=true + end + else + logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind) + end + else + logprocess("%s: has an issue (1)",cref(dataset,sequence)) end - else - logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind) end + else end else local i=1 @@ -28902,20 +28963,24 @@ local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck) if chainlookup then for j=1,#chainlookup do local chainstep=chainlookup[j] - local chainkind=chainstep.type - local chainproc=chainprocs[chainkind] - if chainproc then - local ok,n - head,start,ok,n=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,i) - if ok then - done=true - if n and n>1 and i+n>nofchainlookups then - i=size - break + if chainstep then + local chainkind=chainstep.type + local chainproc=chainprocs[chainkind] + if chainproc then + local ok,n + head,start,ok,n=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,i) + if ok then + done=true + if n and n>1 and i+n>nofchainlookups then + i=size + break + end end + else + logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind) end else - logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind) + logprocess("%s: has an issue (2)",cref(dataset,sequence)) end end else @@ -28939,7 +29004,7 @@ local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck) else done=true if trace_contexts then - logprocess("%s: skipping match",cref(dataset,sequence)) + logprocess("%s: skipping match @ %i",cref(dataset,sequence),where) end end end @@ -28966,6 +29031,8 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) local last=start local prev=getprev(start) local hasglue=false + local useddisc=nil + local usedstart=start local i=f while i<=l do local id=getid(current) @@ -29028,7 +29095,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) tail=prev setprev(current,sweepnode) else - tail=find_node_tail(head) + tail=findnodetail(head) end setnext(sweepnode,current) setprev(head) @@ -29139,13 +29206,13 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) head=lookaheaddisc end local pre,post,replace=getdisc(lookaheaddisc) - local new=copy_node_list(cf) + local new=copynodelist(cf) local cnew=new if pre then - setlink(find_node_tail(cf),pre) + setlink(findnodetail(cf),pre) end if replace then - local tail=find_node_tail(new) + local tail=findnodetail(new) setlink(tail,replace) end for i=1,insertedmarks do @@ -29159,14 +29226,14 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) end if not notmatchpre[lookaheaddisc] then local ok=false - cf,start,ok=chainrun(cf,start,cl,dataset,sequence,rlmode,skiphash,ck) + cf,start,ok=chainrun(cf,start,cl,dataset,sequence,rlmode,skiphash,ck,1) if ok then done=true end end if not notmatchreplace[lookaheaddisc] then local ok=false - new,cnew,ok=chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck) + new,cnew,ok=chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck,2) if ok then done=true end @@ -29177,6 +29244,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) setdisc(lookaheaddisc,cf,post,new) end start=getprev(lookaheaddisc) + useddisc=lookaheaddisc sweephead[cf]=getnext(clast) or false sweephead[new]=getnext(cl) or false elseif backtrackdisc then @@ -29198,8 +29266,8 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) setprev(cf) setnext(cl) local pre,post,replace,pretail,posttail,replacetail=getdisc(backtrackdisc,true) - local new=copy_node_list(cf) - local cnew=find_node_tail(new) + local new=copynodelist(cf) + local cnew=findnodetail(new) for i=1,insertedmarks do cnew=getprev(cnew) end @@ -29209,14 +29277,14 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) end if not notmatchpost[backtrackdisc] then local ok=false - cf,start,ok=chainrun(cf,start,last,dataset,sequence,rlmode,skiphash,ck) + cf,start,ok=chainrun(cf,start,last,dataset,sequence,rlmode,skiphash,ck,3) if ok then done=true end end if not notmatchreplace[backtrackdisc] then local ok=false - new,cnew,ok=chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck) + new,cnew,ok=chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck,4) if ok then done=true end @@ -29237,30 +29305,55 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) setdisc(backtrackdisc,pre,post,replace) end start=getprev(backtrackdisc) + useddisc=backtrackdisc sweephead[post]=getnext(clast) or false sweephead[replace]=getnext(last) or false else local ok=false - head,start,ok=chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck) + head,start,ok=chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck,5) if ok then done=true end end - return head,start,done -end -local function chaintrac(head,start,dataset,sequence,rlmode,skiphash,ck,match,discseen,sweepnode) - local rule=ck[1] - local lookuptype=ck[8] or ck[2] - local nofseq=#ck[3] - local first=ck[4] - local last=ck[5] - local char=getchar(start) - logwarning("%s: rule %s %s at char %s for (%s,%s,%s) chars, lookuptype %a, %sdisc seen, %ssweeping", - cref(dataset,sequence),rule,match and "matches" or "nomatch", - gref(char),first-1,last-first+1,nofseq-last,lookuptype, - discseen and "" or "no ",sweepnode and "" or "not ") + if useddisc and start~=usedstart then + start=getnext(start) + end + return head,start,done,useddisc +end +local chaintrac do + local level=0 + local last={} + chaintrac=function(head,start,dataset,sequence,rlmode,skiphash,ck,match,discseen,sweepnode) + if dataset then + level=level+1 + last[level]=start + local rule=ck[1] + local lookuptype=ck[8] or ck[2] + local nofseq=#ck[3] + local first=ck[4] + local last=ck[5] + local char=getchar(start) + logwarning("+ %i : %s: rule %s %s at char %s for (%s,%s,%s) chars, lookuptype %a, %sdisc seen, %ssweeping", + level,cref(dataset,sequence),rule,match and "matches" or "nomatch", + gref(char),first-1,last-first+1,nofseq-last,lookuptype, + discseen and "" or "no ",sweepnode and "" or "not ") + else + local what=start and "done" or "continue" + local where=head==last[level] and "same" or "different" + local char=getchar(head) + if char then + logwarning("- %i : %s at char %s, %s node",level,what,gref(char),where) + else + logwarning("- %i : %s, %s node",level,what,where) + end + level=level-1 + end + end end local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,skiphash) + if not contexts then + return head,start,false + end local sweepnode=sweepnode local sweeptype=sweeptype local postreplace @@ -29288,7 +29381,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s local ck=contexts[k] local seq=ck[3] local f=ck[4] -local last=start + local last=start if not startchar or not seq[f][startchar] then goto next end @@ -29399,7 +29492,6 @@ local last=start end end if f>1 then - if startprev then local prev=startprev if prereplace and prev==checkdisc then prev=getprev(sweepnode) @@ -29514,9 +29606,6 @@ local last=start else goto next end - else - goto next - end end if s>l then local current=last and getnext(last) @@ -29640,12 +29729,15 @@ local last=start if discseen or sweepnode then head,start,done=chaindisk(head,start,dataset,sequence,rlmode,skipped and skiphash,ck) else - head,start,done=chainrun(head,start,last,dataset,sequence,rlmode,skipped and skiphash,ck) + head,start,done=chainrun(head,start,last,dataset,sequence,rlmode,skipped and skiphash,ck,6) + end + if trace_contexts then + chaintrac(start,done) end if done then break end - ::next:: + ::next:: end if discseen then notmatchpre={} @@ -29662,15 +29754,26 @@ handlers.gpos_context=handle_contextchain local function chained_contextchain(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash) local steps=currentlookup.steps local nofsteps=currentlookup.nofsteps - if nofsteps>1 then - reportmoresteps(dataset,sequence) - end - local l=steps[1].coverage[getchar(start)] - if l then - return handle_contextchain(head,start,dataset,sequence,l,rlmode,skiphash) + local char=getchar(start) + if nofsteps==1 then + local s=steps[1] + local l=s.coverage[char] + if l then + return handle_contextchain(head,start,dataset,sequence,l,rlmode,skiphash) + end else - return head,start,false + for i=1,nofsteps do + local s=steps[i] + local l=s.coverage[char] + if l then + local h,s,d=handle_contextchain(head,start,dataset,sequence,l,rlmode,skiphash) + if d then + return h,s,d + end + end + end end + return head,start,false end chainprocs.gsub_context=chained_contextchain chainprocs.gsub_contextchain=chained_contextchain @@ -29853,7 +29956,7 @@ local function kernrun(disc,k_run,font,attr,...) if done and trace_testruns then report_disc("done",disc) end - return nextstart,done + return nextstart end local function comprun(disc,c_run,...) if trace_compruns then @@ -29896,8 +29999,12 @@ local function comprun(disc,c_run,...) end setdisc(disc,pre,post,replace) end - return getnext(disc),renewed + return getnext(disc) end +local test_flatten_start=2 +directives.register("otf.testrun.forceflatten",function(v) + test_flatten_start=v and 1 or 2 +end) local function testrun(disc,t_run,c_run,...) if trace_testruns then report_disc("test",disc) @@ -29925,7 +30032,7 @@ local function testrun(disc,t_run,c_run,...) local d=d_replace>d_post and d_replace or d_post local head=getnext(disc) local tail=head - for i=2,d do + for i=test_flatten_start,d do local nx=getnext(tail) local id=getid(nx) if id==disc_code then @@ -29939,7 +30046,7 @@ local function testrun(disc,t_run,c_run,...) next=getnext(tail) setnext(tail) setprev(head) - local new=copy_node_list(head) + local new=copynodelist(head) if posttail then setlink(posttail,head) else @@ -30002,7 +30109,7 @@ local function testrun(disc,t_run,c_run,...) report_disc("done",disc) end end - return getnext(disc),renewed + return getnext(disc) end local nesting=0 local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) @@ -30420,7 +30527,7 @@ do head=h end elseif typ=="gsub_reversecontextchain" then - local start=find_node_tail(head) + local start=findnodetail(head) local rlmode=0 local merged=steps.merged while start do @@ -30498,13 +30605,12 @@ do start=getnext(start) elseif id==disc_code then if not discs or discs[start]==true then - local ok if gpossing then - start,ok=kernrun(start,k_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) + start=kernrun(start,k_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) elseif forcetestrun then - start,ok=testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) + start=testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) else - start,ok=comprun(start,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) + start=comprun(start,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) end else start=getnext(start) @@ -30568,13 +30674,12 @@ do start=getnext(start) elseif id==disc_code then if not discs or discs[start]==true then - local ok if gpossing then - start,ok=kernrun(start,k_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) + start=kernrun(start,k_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) elseif forcetestrun then - start,ok=testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) + start=testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) else - start,ok=comprun(start,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) + start=comprun(start,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) end else start=getnext(start) @@ -31074,6 +31179,10 @@ local function addfeature(data,feature,specifications,prepareonly) end local descriptions=data.descriptions local resources=data.resources + if not descriptions or not resources then + report_otf("missing specification") + return + end local features=resources.features local sequences=resources.sequences if not features or not sequences then @@ -31651,7 +31760,11 @@ local function addfeature(data,feature,specifications,prepareonly) local list=askedsteps[i] local coverage=nil local format=nil - if featuretype=="substitution" then +if type(list)=="function" then + list=list(data,specification,list,i) +end + if not list then + elseif featuretype=="substitution" then category="gsub" coverage=(mapping and list) or prepare_substitution(list,featuretype,nocheck) elseif featuretype=="ligature" then @@ -33297,7 +33410,7 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) local subpos=nil local postpos=nil reorderreph.coverage={} - rephbase[font]={} + rephbase[font]={} for i=1,#seqsubset do local subset=seqsubset[i] local kind=subset[1] @@ -33418,7 +33531,7 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) end end end - local current,base,firstcons=start,nil,nil + local current,base,firstcons,subnotafterbase,postnotafterbase=start,nil,nil,nil,nil if getstate(start,s_rphf) then current=getnext(getnext(start)) end @@ -33474,10 +33587,16 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) logprocess("reorder two, handle nbsp") end end - else + else local last=getnext(stop) while current~=last do local next=getnext(current) + if current==subpos then + subnotafterbase=current + end + if current==postpos then + postnotafterbase=current + end if consonant[getchar(current)] then if not (current~=stop and next~=stop and halant[getchar(next)] and getchar(getnext(next))==c_zwj) then if not firstcons then @@ -33486,6 +33605,12 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) local a=getstate(current) if not (a==s_blwf or a==s_pstf or (a~=s_rphf and a~=s_blwf and ra[getchar(current)])) then base=current + if subnotafterbase then + subpos=base + end + if postnotafterbase then + postpos=base + end end end end @@ -33537,7 +33662,7 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) logprocess("reorder two, handle matra") end end - if dependent_vowel[char] then + if not moved[current] and dependent_vowel[char] then if pre_mark[char] then moved[current]=true local prev,next=getboth(current) @@ -33580,14 +33705,11 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) logprocess("reorder two, handle pre mark") end elseif above_mark[char] then - target=basepos - if subpos==basepos then - subpos=current - end - if postpos==basepos then + target=subpos + if postpos==subpos then postpos=current end - basepos=current + subpos=current elseif below_mark[char] then target=subpos if postpos==subpos then @@ -33807,11 +33929,7 @@ local function analyze_next_chars_one(c,font,variant) if pre_mark[v] and not already_pre_mark then already_pre_mark=true elseif post_mark[v] and not already_post_mark then - if devanagarihash[font].conjuncts=="mixed" then - return c - else already_post_mark=true - end elseif below_mark[v] and not already_below_mark then already_below_mark=true elseif above_mark[v] and not already_above_mark then @@ -34012,11 +34130,7 @@ local function analyze_next_chars_two(c,font) if pre_mark[v] and not already_pre_mark then already_pre_mark=true elseif post_mark[v] and not already_post_mark then - if devanagarihash[font].conjuncts=="mixed" then - return c - else - already_post_mark=true - end + already_post_mark=true elseif below_mark[v] and not already_below_mark then already_below_mark=true elseif above_mark[v] and not already_above_mark then @@ -37079,7 +37193,7 @@ local afm=fonts.handlers.afm local pfb=fonts.handlers.pfb local hashes=fonts.hashes local identifiers=hashes.identifiers -local version=otf.version or 0.011 +local version=otf.version or 0.015 local shapescache=containers.define("fonts","shapes",version,true) local streamscache=containers.define("fonts","streams",version,true) local compact_streams=false @@ -37305,7 +37419,8 @@ local function loadstreams(cache,filename,sub,instance) if streams then local fontbbox=metadata.fontbbox or { 0,0,0,0 } for i=0,#streams do - streams[i]=streams[i].stream or "\14" + local s=streams[i] + streams[i]=s.stream or "\14" end data={ filename=filename, @@ -37387,7 +37502,8 @@ local function getstreamhash(fontid) local fontdata=identifiers[fontid] if fontdata then local properties=fontdata.properties - return makehash(properties.filename,properties.subfont,properties.instance),fontdata + local fonthash=makehash(properties.filename,properties.subfont,properties.instance) + return fonthash,fontdata end end local function loadstreamdata(fontdata) @@ -37716,7 +37832,7 @@ local fonts=fonts local otf=fonts.handlers.otf local registerotffeature=otf.features.register local addotffeature=otf.addfeature -local specification={ +local tlig={ type="ligature", order={ "tlig" }, prepend=true, @@ -37725,12 +37841,17 @@ local specification={ [0x2014]={ 0x002D,0x002D,0x002D }, }, } -addotffeature("tlig",specification) -registerotffeature { - name="tlig", - description="tex ligatures", +local tquo={ + type="ligature", + order={ "tquo" }, + prepend=true, + data={ + [0x201C]={ 0x0060,0x0060 }, + [0x201D]={ 0x0027,0x0027 }, + [0x201E]={ 0x002C,0x002C }, + }, } -local specification={ +local trep={ type="substitution", order={ "trep" }, prepend=true, @@ -37738,11 +37859,12 @@ local specification={ [0x0027]=0x2019, }, } -addotffeature("trep",specification) -registerotffeature { - name="trep", - description="tex replacements", -} +addotffeature("trep",trep) +addotffeature("tlig",tlig) +addotffeature("tquo",tquo) +registerotffeature { name="tlig",description="tex ligatures" } +registerotffeature { name="tquo",description="tex quotes" } +registerotffeature { name="trep",description="tex replacements" } local anum_arabic={ [0x0030]=0x0660, [0x0031]=0x0661, @@ -37926,30 +38048,11 @@ if not modules then modules={} end modules ['font-imp-italics']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local next=next +local next,tonumber=next,tonumber local fonts=fonts local handlers=fonts.handlers local registerotffeature=handlers.otf.features.register local registerafmfeature=handlers.afm.features.register -local function initialize(tfmdata,key,value) - for unicode,character in next,tfmdata.characters do - local olditalic=character.italic - if olditalic and olditalic~=0 then - character.width=character.width+olditalic - character.italic=0 - end - end -end -local specification={ - name="italicwidths", - description="add italic to width", - manipulators={ - base=initialize, - node=initialize, - } -} -registerotffeature(specification) -registerafmfeature(specification) local function initialize(tfmdata,value) if value then local parameters=tfmdata.parameters diff --git a/macros/luatex/generic/luaotfload/fontloader-util-str.lua b/macros/luatex/generic/luaotfload/fontloader-util-str.lua index b5c721a41d..a9150b886a 100644 --- a/macros/luatex/generic/luaotfload/fontloader-util-str.lua +++ b/macros/luatex/generic/luaotfload/fontloader-util-str.lua @@ -269,6 +269,7 @@ local p_prune_intospace = Cs ( noleading * ( notrailing + intospace + 1 local p_retain_normal = Cs ( ( normalline + normalempty )^0 ) local p_retain_collapse = Cs ( ( normalline + doubleempty )^0 ) local p_retain_noempty = Cs ( ( normalline + singleempty )^0 ) +local p_collapse_all = Cs ( stripstart * ( stripend + ((whitespace+newline)^1/" ") + 1)^0 ) -- function striplines(str,prune,collapse,noempty) -- if prune then @@ -298,6 +299,7 @@ local striplinepatterns = { ["retain"] = p_retain_normal, ["retain and collapse"] = p_retain_collapse, ["retain and no empty"] = p_retain_noempty, + ["collapse all"] = p_collapse_all, ["collapse"] = patterns.collapser, } @@ -313,6 +315,9 @@ function strings.collapse(str) -- maybe also in strings return str and lpegmatch(p_prune_intospace,str) or str end +-- local s = "\naa\n\naa\na a\n\n" +-- print("["..strings.striplines(s,"collapse all").."]") + -- also see: string.collapsespaces strings.striplong = strings.striplines -- for old times sake diff --git a/macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua b/macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua index bcbdd74b2a..6325ba19d2 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua @@ -6,8 +6,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-auxiliary", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / auxiliary functions", license = "GPL v2.0" } diff --git a/macros/luatex/generic/luaotfload/luaotfload-colors.lua b/macros/luatex/generic/luaotfload/luaotfload-colors.lua index 378b0f62b6..35962ee074 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-colors.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-colors.lua @@ -5,8 +5,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-colors", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / color", license = "GPL v2.0", author = "Khaled Hosny, Elie Roux, Philipp Gesang, Dohyun Kim, David Carlisle", diff --git a/macros/luatex/generic/luaotfload/luaotfload-conf.pdf b/macros/luatex/generic/luaotfload/luaotfload-conf.pdf Binary files differindex c735e60a99..9a1cbab1a8 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-conf.pdf +++ b/macros/luatex/generic/luaotfload/luaotfload-conf.pdf diff --git a/macros/luatex/generic/luaotfload/luaotfload-configuration.lua b/macros/luatex/generic/luaotfload/luaotfload-configuration.lua index 9ed614b17e..fda9b4dbff 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-configuration.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-configuration.lua @@ -7,8 +7,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-configuration", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / config file reader", license = "GPL v2.0" } @@ -91,6 +91,13 @@ local valid_formats = tabletohash { "otf", "ttc", "ttf", "afm", "pfb" } +local default_location_precedence = { + "system", "texmf", "local" +} +local valid_locations = tabletohash { + "system", "texmf", "local" +} + local default_anon_sequence = { "tex", "path", "name" } @@ -189,6 +196,10 @@ local permissible_color_callbacks = { pre_output_filter = "pre_output_filter", } +local known_dvi_drivers = { + xdvipsk = 'xdvipsk', + dvisvgm = 'dvisvgm', +} ------------------------------------------------------------------------------- --- DEFAULTS @@ -196,22 +207,24 @@ local permissible_color_callbacks = { local default_config = { db = { - formats = "otf,ttf,ttc", - scan_local = false, - skip_read = false, - strip = true, - update_live = true, - compress = true, - max_fonts = 2^51, - designsize_dimen= "bp", + location_precedence = default_location_precedence, + formats = "otf,ttf,ttc", + scan_local = false, + skip_read = false, + strip = true, + update_live = true, + compress = true, + max_fonts = 2^51, + designsize_dimen = "bp", }, run = { - anon_sequence = default_anon_sequence, - resolver = "cached", - definer = "patch", - log_level = 0, - color_callback = "post_linebreak_filter", - fontloader = default_fontloader (), + anon_sequence = default_anon_sequence, + resolver = "cached", + definer = "patch", + log_level = 0, + color_callback = "post_linebreak_filter", + fontloader = default_fontloader (), + default_dvi_driver = "dvisvgm" }, misc = { bisect = false, @@ -313,6 +326,18 @@ local function set_font_filter () return true end +local function set_location_precedence_list () + local names = fonts.names + if names and names.set_location_precedence then + local locations = config.luaotfload.db.location_precedence + if not locations or locations == "" then + locations = default_config.db.location_precedence + end + fonts.names.set_location_precedence (locations) + end + return true +end + local function set_size_dimension () local names = fonts.names if names and names.set_size_dimension then @@ -396,6 +421,7 @@ reconf_tasks = { { "Set design size dimension" , set_size_dimension }, { "Install font name resolver", set_name_resolver }, { "Set default features" , set_default_features }, + { "Set location precedence" , set_location_precedence_list }, } ------------------------------------------------------------------------------- @@ -484,6 +510,44 @@ local option_spec = { return tableconcat (result, ",") end }, + location_precedence = { + in_t = string_t, + out_t = table_t, + transform = function (s) + local bits = { lpegmatch (commasplitter, s) } + if next (bits) then + local seq = { } + local done = { } + for i = 1, #bits do + local bit = bits [i] + if valid_locations [bit] then + if not done [bit] then + done [bit] = true + seq [#seq + 1] = bit + else + logreport ("both", 0, "conf", + "ignoring duplicate location %s at position %d \z + in precedence list", + bit, i) + end + else + logreport ("both", 0, "conf", + "location precedence list contains invalid item %s \z + at position %d.", + bit, i) + end + end + if next (seq) then + logreport ("both", 2, "conf", + "overriding anon lookup sequence %s.", + tableconcat (seq, ",")) + return seq + end + end + logreport ("both", 0, "conf", "no lookup locations enabled, falling back to default precedence list") + return default_location_precedence + end + }, scan_local = { in_t = boolean_t, }, skip_read = { in_t = boolean_t, }, strip = { in_t = boolean_t, }, @@ -596,6 +660,24 @@ local option_spec = { return permissible_color_callbacks.default end, }, + default_dvi_driver = { + in_t = string_t, + out_t = string_t, + transform = function (driver) + local mapped = known_dvi_drivers[driver] + if mapped then + logreport ("log", 5, "conf", + "Using default DVI driver %q if used in DVI mode.", + mapped) + return mapped + end + logreport ("log", 0, "conf", + "Requested default DVI driver %q invalid, " + .. "falling back to dvisvgm.", + driver) + return known_dvi_drivers.dvisvgm + end, + }, }, misc = { bisect = { in_t = boolean_t, }, --- doesn’t make sense in a config file @@ -740,12 +822,13 @@ local formatters = { lookups_file = { false, format_string }, }, run = { - anon_sequence = { false, format_list }, - color_callback = { false, format_string }, - definer = { false, format_string }, - fontloader = { true, format_string }, - log_level = { false, format_integer }, - resolver = { false, format_string }, + anon_sequence = { false, format_list }, + color_callback = { false, format_string }, + definer = { false, format_string }, + fontloader = { true, format_string }, + log_level = { false, format_integer }, + resolver = { false, format_string }, + default_dvi_driver = { false, format_string }, }, } diff --git a/macros/luatex/generic/luaotfload/luaotfload-database.lua b/macros/luatex/generic/luaotfload/luaotfload-database.lua index e71e923ff6..3a2d87ead9 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-database.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-database.lua @@ -5,8 +5,8 @@ do -- block to avoid to many local variables error assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-database", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / database", license = "GPL v2.0", author = "Khaled Hosny, Elie Roux, Philipp Gesang, Marcel Krüger", @@ -220,9 +220,20 @@ local format_precedence = { local location_precedence = { "local", "system", "texmf", } +local enabled_locations = { + ['local'] = true, + system = true, + texmf = true, +} local function set_location_precedence (precedence) location_precedence = precedence + for location in next, enabled_locations do + enabled_locations[location] = nil + end + for _, location in ipairs(location_precedence) do + enabled_locations[location] = location ~= 'local' or config.luaotfload.db.scan_local == true + end end --[[doc-- @@ -852,23 +863,25 @@ Also, the fields “resolved”, “sub”, “force” etc. influence the outco --doc]]-- -local concat_char = "#" -local hash_fields = { - --- order is important - "specification", "style", "sub", "optsize", "size", -} -local n_hash_fields = #hash_fields - ---- spec -> string -local function hash_request (specification) - local key = { } --- segments of the hash - for i=1, n_hash_fields do - local field = specification[hash_fields[i]] - if field then - key[#key+1] = field +local hash_request do + local concat_char = "#" + local hash_fields = { + --- order is important + "specification", "style", "sub", "optsize", "size", + } + local n_hash_fields = #hash_fields + + --- spec -> string + function hash_request (specification) + local key = { } --- segments of the hash + for i=1, n_hash_fields do + local field = specification[hash_fields[i]] + if field then + key[#key+1] = field + end end + return tableconcat(key, concat_char) end - return tableconcat(key, concat_char) end --- 'a -> 'a -> table -> (string * int|boolean * boolean) @@ -3119,10 +3132,17 @@ local function collect_font_filenames () local bisect = config.luaotfload.misc.bisect local max_fonts = config.luaotfload.db.max_fonts --- XXX revisit for lua 5.3 wrt integers - tableappend (filenames, collect_font_filenames_texmf ()) - tableappend (filenames, collect_font_filenames_system ()) - local scan_local = config.luaotfload.db.scan_local == true - if scan_local then + -- We can't just scan in the order of location_precedence here since + -- the order is important. In the common situation of having texmf + -- added to the system font path, scanning system first would + -- classify all texmf fonts as system fonts. + if enabled_locations.texmf then + tableappend (filenames, collect_font_filenames_texmf ()) + end + if enabled_locations.system then + tableappend (filenames, collect_font_filenames_system ()) + end + if enabled_locations['local'] then local localfonts, found = collect_font_filenames_local() if found then tableappend (filenames, localfonts) @@ -3138,7 +3158,7 @@ local function collect_font_filenames () if bisect then return { unpack (filenames, bisect[1], bisect[2]) } end - return filenames, scan_local + return filenames end --[[doc-- @@ -3409,8 +3429,8 @@ function update_names (currentnames, force, dry_run) read_blacklist () --- pass 1: Collect the names of all fonts we are going to process. - local font_filenames, local_fonts = collect_font_filenames () - if local_fonts then + local font_filenames = collect_font_filenames () + if enabled_locations['local'] then targetnames.meta['local'] = true end @@ -3804,6 +3824,7 @@ return function () names.data = nil --- contains the loaded database names.lookups = nil --- contains the lookup cache + enabled_locations['local'] = enabled_locations['local'] and config.luaotfload.db.scan_local == true for sym, ref in next, export do names[sym] = ref end for sym, ref in next, api do names[sym] = names[sym] or ref end return true diff --git a/macros/luatex/generic/luaotfload/luaotfload-diagnostics.lua b/macros/luatex/generic/luaotfload/luaotfload-diagnostics.lua index 093c171409..9bde02fc1f 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-diagnostics.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-diagnostics.lua @@ -7,8 +7,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-diagnostics", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload-tool submodule / diagnostics", license = "GPL v2.0" } diff --git a/macros/luatex/generic/luaotfload/luaotfload-dvi.lua b/macros/luatex/generic/luaotfload/luaotfload-dvi.lua index eeac1c71d0..e2ea8c82ed 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-dvi.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-dvi.lua @@ -6,8 +6,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-dvi", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / DVI", license = "GPL v2.0", author = "Marcel Krüger", @@ -31,6 +31,9 @@ local vlist_t = node.id'vlist' local disc_t = node.id'disc' local glyph_t = node.id'glyph' +require'luaotfload-configuration' +local configuration = config.luaotfload + -- DVI output support -- -- When writing DVI files, we can't assume that the DVI reader has access to our @@ -48,7 +51,6 @@ local glyph_t = node.id'glyph' -- mapped_fonts maps fontids from the user to fontids used in the DVI file local mapped_fonts = setmetatable({}, {__index = function(t, fid) local font = getfont(fid) - print(fid, font and font.fullname) local mapped = font and font.backend_font or false t[fid] = mapped return mapped @@ -94,7 +96,6 @@ function full_hprocess(head) end if last_mapping then local mapped = last_mapping[c] - print(c, f, mapped) if mapped then setfont(n, last_mapped_font, mapped) end end end @@ -134,7 +135,11 @@ local function process(head, font) end end end local function manipulate(tfmdata, _, dvi_kind) - if dvi_kind ~= 'dvisvgm' then + if dvi_kind == 'xdvipsk' then + -- xdvipsk wants to read tea leaves instead of using reasonable interfaces. + -- They will have to make sense of whatever output this produces. + return + elseif dvi_kind ~= 'dvisvgm' then texio.write_nl(string.format('WARNING (luaotfload): Unsupported DVI backend %q, falling back to dvisvgm.', dvi_kind)) end -- Legacy fonts can be written to the DVI file directly @@ -180,13 +185,14 @@ end fonts.constructors.features.otf.register { name = "dvifont", - default = "dvisvgm", + default = configuration.run.default_dvi_driver, manipulators = { node = manipulate, base = manipulate, }, - processors = { - node = process, - base = process, - }, + -- Processors are not needed since we are using pre_shipout_filter + -- processors = { + -- node = process, + -- base = process, + -- }, } diff --git a/macros/luatex/generic/luaotfload/luaotfload-embolden.lua b/macros/luatex/generic/luaotfload/luaotfload-embolden.lua index 6070b1a9ba..66c4b1c2d6 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-embolden.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-embolden.lua @@ -5,8 +5,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-embolden", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / embolden", license = "GPL v2.0", author = "Marcel Krüger" diff --git a/macros/luatex/generic/luaotfload/luaotfload-fallback.lua b/macros/luatex/generic/luaotfload/luaotfload-fallback.lua index 2f010c11d0..4b257455fb 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-fallback.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-fallback.lua @@ -5,8 +5,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-fallback", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / fallback", license = "GPL v2.0", author = "Marcel Krüger" diff --git a/macros/luatex/generic/luaotfload/luaotfload-features.lua b/macros/luatex/generic/luaotfload/luaotfload-features.lua index 4b3c1a0859..9b753aac82 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-features.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-features.lua @@ -5,8 +5,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-features", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / features", license = "GPL v2.0", author = "Hans Hagen, Khaled Hosny, Elie Roux, Philipp Gesang, Marcel Krüger", @@ -614,6 +614,13 @@ local tlig_specification = { }, } +-- "substitution" features allow to replace individual characters with other +-- characters. This is often used inside of fonts to e.g. implement stylistic +-- sets. +-- As an example how such features can be added in the fontloader, we have a +-- simple implementation of the ROT13 cipher as a font feature. It can be +-- used by enabling the `rot13` font feature in a font, but we are not aware of +-- any practical usecase for this. local rot13_specification = { type = "substitution", features = everywhere, diff --git a/macros/luatex/generic/luaotfload/luaotfload-filelist.lua b/macros/luatex/generic/luaotfload/luaotfload-filelist.lua index c7bfc4e43f..c428e08be9 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-filelist.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-filelist.lua @@ -6,8 +6,8 @@ if luaotfload_module then luaotfload_module { name = "luaotfload-filelist", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / filelist", license = "GPL v2.0" } end diff --git a/macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua b/macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua index 428872e8d3..484b0e63b0 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua @@ -1,8 +1,8 @@ if luaotfload_module then luaotfload_module { name = "luaotfload-glyphlist", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / autogenerated glyphlist", copyright = "derived from https://raw.githubusercontent.com/adobe-type-tools/agl-aglfn/master/glyphlist.txt", original = "Adobe Glyph List, version 2.0, September 20, 2002", diff --git a/macros/luatex/generic/luaotfload/luaotfload-harf-define.lua b/macros/luatex/generic/luaotfload/luaotfload-harf-define.lua index a5923b773c..069513bc5a 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-harf-define.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-harf-define.lua @@ -5,8 +5,8 @@ do -- block to avoid to many local variables error assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-harf-define", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / HarfBuzz font loading", license = "GPL v2.0", author = "Khaled Hosny, Marcel Krüger", @@ -76,6 +76,18 @@ local get_designsize do end end +local keyhash do + local formatstring = string.rep('%02x', 256/8) + local sha256 = sha2.digest256 + local format = string.format + local byte = string.byte + keyhash = setmetatable({}, {__index = function(t, k) + local h = format(formatstring, byte(sha256(k), 1, -1)) + t[k] = h + return h + end}) +end + local containers = luaotfload.fontloader.containers local hbcacheversion = 1.4 local fontcache = containers.define("fonts", "hb", hbcacheversion, true) @@ -93,7 +105,7 @@ end local function loadfont(spec) local path, sub = spec.resolved, spec.sub or 1 - local key = gsub(string.format("%s:%d:%s", path, sub, instance), "[/\\]", ":") + local key = string.format("%s:%d:%s", path, sub, instance) local attributes = lfs.attributes(path) if not attributes then return end @@ -183,6 +195,10 @@ local function loadfont(spec) varkey = '' end + -- Paths get get rather long and contain many characters which can not appear in filenames. + -- Therefore we hash the key to get it into a more regular form + key = keyhash[key] + local cached = containers.read(fontcache, key) local iscached = cached and cached.date == date and cached.size == size diff --git a/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua b/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua index 5b93356b6b..296a99c9b6 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua @@ -4,8 +4,8 @@ ----------------------------------------------------------------------- assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-harf-plug", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / HarfBuzz shaping", license = "GPL v2.0", author = "Khaled Hosny, Marcel Krüger", diff --git a/macros/luatex/generic/luaotfload/luaotfload-harf-var-cff2.lua b/macros/luatex/generic/luaotfload/luaotfload-harf-var-cff2.lua index 467faa8893..3cf3aec64f 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-harf-var-cff2.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-harf-var-cff2.lua @@ -5,8 +5,8 @@ do assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-harf-var-cff2", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / CFF2 table processing", license = "GPL v2.0", author = "Marcel Krüger", @@ -51,9 +51,6 @@ local function parse_real(cs, offset) end local function get_number(result) - if #result ~= 1 then - print(require'inspect'(result)) - end assert(#result == 1) local num = result[1] result[1] = nil @@ -231,23 +228,19 @@ local function parse_charstring(buf, start, after, globalsubrs, subrs, result) for i = before + n + 1, #lastresult do lastresult[i] = nil end - elseif cmd == 12 then - start = start+1 - cmd = buf:byte(start) - lastresult[1] = -cmd-1 - lastresult = {false} - result[#result+1] = lastresult - elseif cmd == 19 or cmd == 20 then - if #result == 1 then - lastresult = {} - result[#result+1] = lastresult - end - lastresult[1] = cmd - local newi = start+(result.stemcount+7)//8 - lastresult[2] = buf:sub(start+1, newi) - start = newi else - if cmd == 21 and #result == 1 then + if cmd == 12 then + start = start+1 + cmd = -buf:byte(start)-1 + elseif cmd == 19 or cmd == 20 then + if #result == 1 then + lastresult = {} + result[#result+1] = lastresult + end + local newi = start+(result.stemcount+7)//8 + lastresult[2] = buf:sub(start+1, newi) + start = newi + elseif cmd == 21 and #result == 1 then table.insert(result, 1, {false}) if #lastresult == 4 then result[1][2] = lastresult[2] diff --git a/macros/luatex/generic/luaotfload/luaotfload-harf-var-t2-writer.lua b/macros/luatex/generic/luaotfload/luaotfload-harf-var-t2-writer.lua index 75a3804ea2..52feadf7f7 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-harf-var-t2-writer.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-harf-var-t2-writer.lua @@ -5,8 +5,8 @@ do assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-harf-var-t2-writer", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / Type 2 charstring writer", license = "GPL v2.0", author = "Marcel Krüger", diff --git a/macros/luatex/generic/luaotfload/luaotfload-harf-var-ttf.lua b/macros/luatex/generic/luaotfload/luaotfload-harf-var-ttf.lua index 0e9b83cd60..1fb8555f6d 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-harf-var-ttf.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-harf-var-ttf.lua @@ -5,8 +5,8 @@ do assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-harf-var-ttf", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / gvar table processing", license = "GPL v2.0", author = "Marcel Krüger", @@ -350,7 +350,7 @@ local function read_points(gvar_data, offset) return true, offset end if point_count & 0x80 ~= 0 then - point_count = ((point_count & 0x7F) << 8) | sio.readcardinal1(gvar_data, suboffset) + point_count = ((point_count & 0x7F) << 8) | sio.readcardinal1(gvar_data, offset) offset = offset + 1 end local points = lua.newtable(point_count, 0) diff --git a/macros/luatex/generic/luaotfload/luaotfload-init.lua b/macros/luatex/generic/luaotfload/luaotfload-init.lua index 77cb1c54de..2796fff22a 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-init.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-init.lua @@ -7,8 +7,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-init", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / initialization", license = "GPL v2.0" } diff --git a/macros/luatex/generic/luaotfload/luaotfload-latex.pdf b/macros/luatex/generic/luaotfload/luaotfload-latex.pdf Binary files differindex c9fde7abfa..0005cba543 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-latex.pdf +++ b/macros/luatex/generic/luaotfload/luaotfload-latex.pdf diff --git a/macros/luatex/generic/luaotfload/luaotfload-letterspace.lua b/macros/luatex/generic/luaotfload/luaotfload-letterspace.lua index 505e0a8186..8942e9234c 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-letterspace.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-letterspace.lua @@ -5,8 +5,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-letterspace", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / letterspacing", license = "GPL v2.0", copyright = "PRAGMA ADE / ConTeXt Development Team", diff --git a/macros/luatex/generic/luaotfload/luaotfload-loaders.lua b/macros/luatex/generic/luaotfload/luaotfload-loaders.lua index 2aec2fb15d..e2ca0c38c8 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-loaders.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-loaders.lua @@ -8,8 +8,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-loaders", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / callback handling", license = "GPL v2.0" } diff --git a/macros/luatex/generic/luaotfload/luaotfload-log.lua b/macros/luatex/generic/luaotfload/luaotfload-log.lua index 03a3d7bbce..24e2dbfbbe 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-log.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-log.lua @@ -6,8 +6,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-log", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / logging", license = "GPL v2.0", author = "Khaled Hosny, Elie Roux, Philipp Gesang", diff --git a/macros/luatex/generic/luaotfload/luaotfload-main.tex b/macros/luatex/generic/luaotfload/luaotfload-main.tex index b9e25919ca..cb94e854c6 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-main.tex +++ b/macros/luatex/generic/luaotfload/luaotfload-main.tex @@ -32,7 +32,7 @@ \beginfrontmatter \setdocumenttitle {The \identifier{luaotfload} package} - \setdocumentdate {2022-10-03 v3.23} + \setdocumentdate {2023-08-19 v3.24} \setdocumentauthor {LaTeX3 Project\\ Elie Roux · Khaled Hosny · Philipp Gesang · Ulrike Fischer · Marcel Krüger\\ Home: \hyperlink {https://github.com/latex3/luaotfload}} @@ -62,6 +62,18 @@ Supported is the \identifier{luatex} versions of a current TeXLive 2019 (and a c \endsection \beginsection{Changes} +\beginsubsection{New in version 3.24} +\begin{itemize} + \item Add experimental configuration option to change default font lookup location + precedence. + \item Support xdvipsk in DVI mode + \item Preserve soft-hyphens when dropping default ignorable characters + \item Hash cache keys to better support certain rather unflexible operating + systems + \item Various bug fixes +\end{itemize} +\endsubsection + \beginsubsection{New in version 3.23} \begin{itemize} \item More reliable ToUnicode mappings in Harf mode @@ -2278,6 +2290,27 @@ By inspecting the output you can get a first impression of how a font is structured in \LuaTeX’s memory, what elements it is composed of, and in what ways it can be rearranged. +The \luaident{pre_shaping_filter} and \luaident{post_shaping_filter} +callbacks is a pair of \identifier{(reverse)list} callbacks running +immediately before and after \identifier{luaotfload} shapes the text. +They both use the interface +\beginlisting + function(head, groupcode, direction) +\endlisting +where \luaident{head} is the head of the to be shaped list, +\luaident{groupcode} is the groupcode as documented for +\luaident{pre_linebreak_filter} and \luaident{hpack_filter} and +\luaident{direction} is the current direction. + +Since most font processing happens during shaping, \LuaTeX's +\luaident{ligaturing} and \luaident{kerning} callbacks are not involved +in most ligature generation and kerning decisions ans should therefore not be +relied upon. Font processing for fonts loaded with \luaident{mode=base} might +happen in any of these places. + +The specific time when extended features are applied is unspecified and might +not be consistent. + \beginsubsubsection {Compatibility with Earlier Versions} As has been touched on in the preface to this section, the structure diff --git a/macros/luatex/generic/luaotfload/luaotfload-multiscript.lua b/macros/luatex/generic/luaotfload/luaotfload-multiscript.lua index f7bb18c225..370d86d093 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-multiscript.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-multiscript.lua @@ -5,8 +5,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-multiscript", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / multiscript", license = "GPL v2.0", author = "Marcel Krüger" diff --git a/macros/luatex/generic/luaotfload/luaotfload-notdef.lua b/macros/luatex/generic/luaotfload/luaotfload-notdef.lua index 3923e8392c..b8c0c02346 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-notdef.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-notdef.lua @@ -5,8 +5,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-notdef", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / notdef", license = "GPL v2.0", author = "Marcel Krüger" @@ -88,6 +88,8 @@ local ignorable_codepoints do end end +ignorable_codepoints[0xAD] = nil + local function setnotdef(tfmdata, factor) local desc = tfmdata.shared.rawdata.descriptions -- So we have to find the .notdef glyph. We only know that it has GID diff --git a/macros/luatex/generic/luaotfload/luaotfload-parsers.lua b/macros/luatex/generic/luaotfload/luaotfload-parsers.lua index 0c91f4775c..00630a14a6 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-parsers.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-parsers.lua @@ -7,8 +7,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-parsers", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / parsers", license = "GPL v2.0" } diff --git a/macros/luatex/generic/luaotfload/luaotfload-resolvers.lua b/macros/luatex/generic/luaotfload/luaotfload-resolvers.lua index d215aad8be..7b2c7ac6aa 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-resolvers.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-resolvers.lua @@ -11,8 +11,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-resolvers", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / resolvers", license = "GPL v2.0" } diff --git a/macros/luatex/generic/luaotfload/luaotfload-scripts.lua b/macros/luatex/generic/luaotfload/luaotfload-scripts.lua index 222e893718..9430223332 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-scripts.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-scripts.lua @@ -5,8 +5,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-script", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / Script helpers", license = "CC0 1.0 Universal", author = "Marcel Krüger" diff --git a/macros/luatex/generic/luaotfload/luaotfload-status.lua b/macros/luatex/generic/luaotfload/luaotfload-status.lua index 12efcf4452..263982a2ca 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-status.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-status.lua @@ -1,15 +1,15 @@ return { ["hashes"]={ - { "fontloader-2022-10-03.lua", "f5384fb6e665b4c3af844e55c9890073" }, + { "fontloader-2023-08-19.lua", "5e8a5e13801cd8eff23f5e8dc4cbbc10" }, { "fontloader-util-fil.lua", "d0accf4180201efd567816a25ad5e037" }, - { "fontloader-util-str.lua", "f4a9dd15c3e40cd3915749ac13837c95" }, + { "fontloader-util-str.lua", "9a601a851ef3595cddc01b40dc79e1d6" }, { "fontloader-l-unicode.lua", "f368874f11f3c525de5864fd413e4b24" }, { "fontloader-l-math.lua", "e19c80b7e700a69df942d4df2e14aa28" }, { "fontloader-l-boolean.lua", "abe28515dd33e8f6c416c09bca351cf8" }, - { "fontloader-l-file.lua", "5839d88d4de96b9e9c7e7f8f8eb885b3" }, + { "fontloader-l-file.lua", "525b1c6af6f94d93ae929bfbe980d656" }, { "fontloader-l-io.lua", "3396a8644bae37e49b2cfc0c388c78f8" }, - { "fontloader-l-table.lua", "0330da8b3a08d39876def70df8d9c0e5" }, - { "fontloader-l-string.lua", "9457f2af85723e0e6c46d0b5122e9000" }, + { "fontloader-l-table.lua", "87aad875871bba16bbf7d4c3208b3637" }, + { "fontloader-l-string.lua", "3e97812b1d8eff26f19837ab00813e71" }, { "fontloader-l-function.lua", "a7e68a9703c35238729da41a474e951b" }, { "fontloader-l-lpeg.lua", "8315a56e6bc7b2ede3f70c49bf2b5af5" }, { "fontloader-l-lua.lua", "420bc442e6d81f4624728a6c56fcd175" }, @@ -23,77 +23,77 @@ return { { "fontloader-basics-chr.lua", "ce4afac7ba19471f3c8f90800839f315" }, { "fontloader-basics-nod.lua", "1750af43148def9e7a75c6900a96f9dc" }, { "fontloader-font-imp-effects.lua", "d05997c1826355548ec9aec1346f9f23" }, - { "fontloader-font-imp-italics.lua", "defcb415bc1e0a0999b27773902adc18" }, + { "fontloader-font-imp-italics.lua", "3cc555a1fe00dc45449f1e4a47a5c990" }, { "fontloader-font-imp-ligatures.lua", "250f6f4488ee770c23177afb2ff75676" }, - { "fontloader-font-imp-tex.lua", "ceb087ef6fa2f89aed7179f60ddf8f35" }, - { "fontloader-font-shp.lua", "a40862fe382d26c1f3753431254bcfdd" }, - { "fontloader-font-def.lua", "b9d908c2338b7dc443ce9d1e9fcb7139" }, + { "fontloader-font-imp-tex.lua", "9882d382700e714cace08b7f09820958" }, + { "fontloader-font-shp.lua", "a174ac26390bd0828805747500df0077" }, + { "fontloader-font-def.lua", "cec0e49aee881c4cbd36d541f0162c6f" }, { "fontloader-font-lua.lua", "1fbfdf7b689b2bdfd0e3bb9bf74ce136" }, - { "fontloader-font-afk.lua", "9da14e0fb22129c053acc599d1312544" }, - { "fontloader-font-one.lua", "bd39d42055a44ca2002f8ddbbbbf27c3" }, - { "fontloader-font-onr.lua", "6d161533f3437435e12a0ad64866df44" }, + { "fontloader-font-afk.lua", "b7bef80aa4c18357cbfa0ae4df4d4046" }, + { "fontloader-font-one.lua", "b7fb0389462a49bc1f41bebd2da85401" }, + { "fontloader-font-onr.lua", "a3f85c886cf22fb27760d98603d51ffd" }, { "fontloader-font-ocl.lua", "2a377351ae23c339764ec8ce2e8e9164" }, - { "fontloader-font-osd.lua", "1716513d8fe5f28e0e88daad2be0e05b" }, - { "fontloader-font-otc.lua", "57f5270b894e40efa93149c7d3fb0209" }, - { "fontloader-font-ots.lua", "55316a605d11a1d07d38795224c90a63" }, - { "fontloader-font-ota.lua", "2bb12d708e35bc05443eba791e2554e7" }, - { "fontloader-font-oup.lua", "76dc3379061e5650f772909966b5759e" }, + { "fontloader-font-osd.lua", "c38c14c118680202c6f4b09734542c49" }, + { "fontloader-font-otc.lua", "0ad931eec679ebeceed5d4f02f4ba31b" }, + { "fontloader-font-ots.lua", "c039b20490b526ec469e41a8584ebe6d" }, + { "fontloader-font-ota.lua", "7407b709ae7b2cdf36f68d5c98d51d12" }, + { "fontloader-font-oup.lua", "aaff9c28233bbea56e6d27ae50e04ff0" }, { "fontloader-font-otj.lua", "b2c165bd6771a57633f992d07384b739" }, - { "fontloader-font-oto.lua", "9febc4d75d17a543cd73fb17918f7307" }, - { "fontloader-font-otl.lua", "308b1aab04bc131da7eb8e8c3b0471d4" }, - { "fontloader-font-ott.lua", "3f67b1b1d40bbc222681d8db4aff0f42" }, + { "fontloader-font-oto.lua", "1cc20f34606fb55d4646a0dd323499ef" }, + { "fontloader-font-otl.lua", "21196d193ce16f3996c9aa75e81e440c" }, + { "fontloader-font-ott.lua", "427bdc77dd187158eafb79b7193400dc" }, { "fontloader-font-oti.lua", "309a75f9c14b77d87e94eba827dc4e71" }, - { "fontloader-font-dsp.lua", "23a82ec8fdb9f226427e78904402e48a" }, - { "fontloader-font-ttf.lua", "a3ff07150b3535fd32f68748d53fcd36" }, - { "fontloader-font-cff.lua", "651c74e4804fbb85d31267210298f466" }, - { "fontloader-font-otr.lua", "1896ac990a961f6d6fec551ca9b52a83" }, + { "fontloader-font-dsp.lua", "755beef1b31e9dfd050e9d221d4e9ae3" }, + { "fontloader-font-ttf.lua", "ff94e130d7c71edd899c4bae7745b7db" }, + { "fontloader-font-cff.lua", "999da544079698ce70178fd84bcdd67a" }, + { "fontloader-font-otr.lua", "2958a21bebcf0579f4e11f0646d1b402" }, { "fontloader-font-vfc.lua", "a81c29eda98cd62cbebdb6c93544b50d" }, { "fontloader-font-map.lua", "27ee748150e56f5f0e5f0fefc864f35e" }, { "fontloader-font-cid.lua", "22b0367742fb253deef84ef7ccf5e8de" }, - { "fontloader-font-con.lua", "724e5dd14aec2d4d189f8619898004cf" }, - { "fontloader-font-ini.lua", "5343de60613adb24cdd7a8d2ee1d153c" }, - { "fontloader-data-con.lua", "23a0f5386d46a1c157ae82a373e35fa0" }, - { "fontloader-reference.lua", "e4b70de7191ba92ba3b859427eeca91c" }, + { "fontloader-font-con.lua", "bdbaaa361308c9ccc0a7dac0bf6c17ec" }, + { "fontloader-font-ini.lua", "16b855c98602e4a3e9df39512916a427" }, + { "fontloader-data-con.lua", "b4ab51aaeab872d86d827f3e216bf05e" }, + { "fontloader-reference.lua", "50f2268d2d34d5f2ad630151fc1e5b8e" }, { "fontloader-basics-gen.lua", "4bc43036e9796fccb0b8869f4b05bf2e" }, { "mktests", "918cb50be9ee8bd645ac1a27dc501e8c" }, - { "mkstatus", "45611be8d0396d0e048e45fdb318fea0" }, + { "mkstatus", "0c93345ef76bb5458ea7b58144f8a716" }, { "mkcharacters", "bfca0e96e1e351afe7077502f9595af9" }, { "mkglyphlist", "7a8a8fdc0eac7fac2f13ec8f4e8e7aa9" }, { "mkimport", "7d62f1042e548f8b9368f26b9ba4be5c" }, - { "luaotfload-glyphlist.lua", "76f7660436e588112a74e2bbdd4a813c" }, + { "luaotfload-glyphlist.lua", "d07f2134f3e0f2339f278b8a168f85df" }, { "luaotfload-characters.lua", "76415ca3ede312cad6e09038323489ae" }, - { "luaotfload-dvi.lua", "34c763f62499f1bad2ae3883ef52e126" }, - { "luaotfload-tounicode.lua", "9bc62ed441ed23b5222925b019479f78" }, - { "luaotfload-unicode.lua", "30f5b1073daa0c6e85ca1db843fbd9cd" }, - { "luaotfload-resolvers.lua", "2b21b7b0f08aa03ca0d527331718dc13" }, - { "luaotfload-parsers.lua", "0dc623da7513746ee0e0d354505187b3" }, - { "luaotfload-fallback.lua", "34996c5eb80691e8e9969145a1c63fa8" }, - { "luaotfload-szss.lua", "87ac61c8fad7650fa6866518212f3a38" }, - { "luaotfload-scripts.lua", "857b55175273a8277bab059b1bbfa6a4" }, - { "luaotfload-multiscript.lua", "3436f18db0d08ee567e5051995a3165f" }, - { "luaotfload-loaders.lua", "7298c7dd711f8480f4bca2aef5df90af" }, - { "luaotfload-harf-plug.lua", "8b3b69f4c5e573212951c54336b6c75b" }, - { "luaotfload-harf-define.lua", "ed98bd38d43fbc67e6140c343475d8dd" }, - { "luaotfload-notdef.lua", "256afb391eb4010d3b69e5af1abebb7a" }, - { "luaotfload-embolden.lua", "2abe4a85a428d79cae1260908a492477" }, - { "luaotfload-letterspace.lua", "e950c4f3d6e466b7e59fd8d1d2598fa6" }, - { "luaotfload-features.lua", "edaf61a299497abb089f9f160acaf5ba" }, - { "luaotfload-database.lua", "6da3d95f9011b8320dab5c5a32a28978" }, - { "luaotfload-configuration.lua", "18bbb7350d32b6409b7c331542a886e6" }, - { "luaotfload-colors.lua", "4ad76dd049092806e62e93437674f003" }, - { "luaotfload-auxiliary.lua", "c869a8e7d2242a02b0e10928c0cdc59c" }, - { "luaotfload-filelist.lua", "105e78993704062bf12fd6773a3ed001" }, - { "luaotfload-tool.lua", "4ba963522c4182e127396e0daa1dd314" }, - { "luaotfload-diagnostics.lua", "fe454a8415defdce72fc7dbf8af92f39" }, - { "luaotfload-log.lua", "dee4da9bd54f1a5f7453826b8ecd70ea" }, - { "luaotfload-init.lua", "fdca1ee9ddbc4324dace4d89043ee1ff" }, + { "luaotfload-dvi.lua", "1f7115699a2b1e2b2dde2b2b06ecd6ea" }, + { "luaotfload-tounicode.lua", "57ebeb53c32ecf935c1f112e4d24e5a9" }, + { "luaotfload-unicode.lua", "6120395bbbd42023921c1e6eb5052fd8" }, + { "luaotfload-resolvers.lua", "84b3b14ab66c0c1b333cbd9f663908c9" }, + { "luaotfload-parsers.lua", "23650dae431d465b1f6599ffed4ee83f" }, + { "luaotfload-fallback.lua", "c5e14a494096dc9b1c20c04483f4fef3" }, + { "luaotfload-szss.lua", "3407719a32287f12a3f807f71ab5f24e" }, + { "luaotfload-scripts.lua", "01e3be892a2a4faa9d84d84ada15c367" }, + { "luaotfload-multiscript.lua", "5967d18a69e3b0dda2c5c1413e793984" }, + { "luaotfload-loaders.lua", "de540857896f6407e991dd00d8a9ccef" }, + { "luaotfload-harf-plug.lua", "7c8b3a70bc9e3989195ef8023620bb41" }, + { "luaotfload-harf-define.lua", "c39204ae392eebf0b121023a77b97e8e" }, + { "luaotfload-notdef.lua", "5dd6d665246f2af6225936cfde4a90c0" }, + { "luaotfload-embolden.lua", "7c1a7a88620b651b2564bfd6c2080e72" }, + { "luaotfload-letterspace.lua", "9907c492ff6c0c917578d1477ac3c16d" }, + { "luaotfload-features.lua", "902db5fc4316aa7c63c9f3e6565a2302" }, + { "luaotfload-database.lua", "99e8682432de72337f4f635c31b373c2" }, + { "luaotfload-configuration.lua", "261b1e6e7c1d79958008162bd376be52" }, + { "luaotfload-colors.lua", "238f8d1c9a0a296341ebc9b6522d668e" }, + { "luaotfload-auxiliary.lua", "a1a411bc17c7d147250ab04da62d205e" }, + { "luaotfload-filelist.lua", "c141386c0b9262d1e6e54228b35dac13" }, + { "luaotfload-tool.lua", "cea092171f0ca1ffc342aa66ad261d8f" }, + { "luaotfload-diagnostics.lua", "c54effd99e8412784d5c9876c6d298de" }, + { "luaotfload-log.lua", "01c847f9d12312f80971ae4eb04fa0ce" }, + { "luaotfload-init.lua", "aa5b3603a1b2696a27cd055e9174478a" }, { "luaotfload-main.lua", "b19c9cc34cf1d676c39f872cfb41aef6" }, }, ["notes"]={ ["committer"]="Marcel Fabian Krüger <tex@2krueger.de>", - ["description"]="v3.23/2022-10-03", - ["loader"]="fontloader-2022-10-03.lua", - ["revision"]="a36774ba186e3bacab9398e50d0069a0372d3c12", - ["timestamp"]="2022-10-03 20:33:45 +0200", + ["description"]="v3.24/2023-08-19", + ["loader"]="fontloader-2023-08-19.lua", + ["revision"]="fc1177f247ae78a916f4ef5387ec7e29b8cd8155", + ["timestamp"]="2023-08-19 23:56:21 +0200", }, }
\ No newline at end of file diff --git a/macros/luatex/generic/luaotfload/luaotfload-suppress.lua b/macros/luatex/generic/luaotfload/luaotfload-suppress.lua index 0e67e4eada..a8f283d972 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-suppress.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-suppress.lua @@ -5,8 +5,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-suppress", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / suppress", license = "GPL v2.0", author = "Marcel Krüger" diff --git a/macros/luatex/generic/luaotfload/luaotfload-szss.lua b/macros/luatex/generic/luaotfload/luaotfload-szss.lua index f8aca2bd64..30e9000064 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-szss.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-szss.lua @@ -5,8 +5,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-szss", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / Special feature handling", license = "GPL v2.0", author = "Marcel Krüger" diff --git a/macros/luatex/generic/luaotfload/luaotfload-tool.1 b/macros/luatex/generic/luaotfload/luaotfload-tool.1 index bd0617503a..58b9122109 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-tool.1 +++ b/macros/luatex/generic/luaotfload/luaotfload-tool.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH LUAOTFLOAD-TOOL 1 "2022-10-03" "3.23" "text processing" +.TH LUAOTFLOAD-TOOL 1 "2023-08-19" "3.24" "text processing" .SH NAME luaotfload-tool \- generate and query the Luaotfload font names database . diff --git a/macros/luatex/generic/luaotfload/luaotfload-tool.lua b/macros/luatex/generic/luaotfload/luaotfload-tool.lua index dc9dec543e..0883ee5ad2 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-tool.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-tool.lua @@ -9,8 +9,8 @@ local ProvidesLuaModule = { name = "luaotfload-tool", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload-tool / database functionality", license = "GPL v2.0" } diff --git a/macros/luatex/generic/luaotfload/luaotfload-tool.pdf b/macros/luatex/generic/luaotfload/luaotfload-tool.pdf Binary files differindex 640a657ea3..9f39d422c1 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-tool.pdf +++ b/macros/luatex/generic/luaotfload/luaotfload-tool.pdf diff --git a/macros/luatex/generic/luaotfload/luaotfload-tool.rst b/macros/luatex/generic/luaotfload/luaotfload-tool.rst index 68f761bdb0..92c7839ddf 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-tool.rst +++ b/macros/luatex/generic/luaotfload/luaotfload-tool.rst @@ -6,9 +6,9 @@ generate and query the Luaotfload font names database ----------------------------------------------------------------------- -:Date: 2022-10-03 +:Date: 2023-08-19 :Copyright: GPL v2.0 -:Version: 3.23 +:Version: 3.24 :Manual section: 1 :Manual group: text processing diff --git a/macros/luatex/generic/luaotfload/luaotfload-tounicode.lua b/macros/luatex/generic/luaotfload/luaotfload-tounicode.lua index cb34d12aeb..a78218f09b 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-tounicode.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-tounicode.lua @@ -5,8 +5,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-tounicode", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / tounicode", license = "GPL v2.0", author = "Hans Hagen, Khaled Hosny, Elie Roux, Philipp Gesang, Marcel Krüger", diff --git a/macros/luatex/generic/luaotfload/luaotfload-unicode.lua b/macros/luatex/generic/luaotfload/luaotfload-unicode.lua index 64a1eed448..cd67be7b75 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-unicode.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-unicode.lua @@ -5,8 +5,8 @@ assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-unicode", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "luaotfload submodule / Unicode helpers", license = "CC0 1.0 Universal", author = "Marcel Krüger" diff --git a/macros/luatex/generic/luaotfload/luaotfload.conf.5 b/macros/luatex/generic/luaotfload/luaotfload.conf.5 index 7617508bc3..56160f89fe 100644 --- a/macros/luatex/generic/luaotfload/luaotfload.conf.5 +++ b/macros/luatex/generic/luaotfload/luaotfload.conf.5 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH LUAOTFLOAD.CONF 5 "2022-10-03" "3.23" "text processing" +.TH LUAOTFLOAD.CONF 5 "2023-08-19" "3.24" "text processing" .SH NAME luaotfload.conf \- Luaotfload configuration file . @@ -216,6 +216,14 @@ T} T{ T} _ T{ +location\-precedence +T} T{ +s +T} T{ +\fB"system,texmf,local\fP +T} +_ +T{ max\-fonts T} T{ n @@ -287,6 +295,12 @@ It corresponds loosely to the \fB\-\-formats\fP option to list does not contain any useful identifiers, the default list \fB"otf,ttf,ttc"\fP will be used. .sp +The variable \fBlocation\-precedence\fP selects where and in which order +luaotfload searches for fonts. Fonts in earlier locations are preferred. +The three supported locations are \fBsystem\fP for system specific font +directories, \fBtexmf\fP for fonts which are part of the TeX{} distribution +and \fBlocal\fP for local fonts. +.sp The variable \fBmax\-fonts\fP determines after processing how many font files the font scanner will terminate the search. This is useful for debugging issues with the font index and has the same effect as the @@ -296,7 +310,8 @@ The \fBscan\-local\fP flag, if set, will incorporate the current working directory as a font search location. NB: This will potentially slow down document processing because a font index with local fonts will not be saved to disk, so these fonts will have to be re\-indexed whenever -the document is built. +the document is built. Setting \fBscan_local\fP to \fBfalse\fP is the same +as removing \fBlocal\fP from \fBlocation\-precedence\fP\&. .sp The \fBskip\-read\fP flag is only useful for debugging: It makes Luaotfload skip reading fonts. The font information for rebuilding the @@ -515,6 +530,14 @@ T} T{ \fB"default"\fP T} _ +T{ +default_dvi_driver +T} T{ +s +T} T{ +\fB"dvisvgm"\fP +T} +_ .TE .sp Unqualified font lookups are treated with the flexible “anonymous” @@ -588,6 +611,17 @@ subsequent lookups. The alternative, \fBnormal\fP circumvents the cache and resolves every request individually. (Since to the restructuring of the font name index in Luaotfload 2.4 the performance difference between the cached and uncached lookups should be marginal.) +.sp +When luaotfload is used in \fBDVI\fP mode, the \fBdefault_dvi_driver\fP option +determines how OpenType fonts are represented in the DVI output. In most +cases the default value \fBdvisvgm\fP should be set, it uses a format +supported by multiple backends including \fBdvipdfmx\fP and \fBdvisvgm\fP +which uses GIDs to identify characters. +Setting this to \fBxdvipsk\fP uses an unstable internal format instead +which will change depending on the luaotfload, engine, or font version. +No one should rely on the mapping between DVI character codes and font glyphs +in this mode unless they tightly control all involved versions and are deeply +familiar with the implementation. .SH FILES .sp Luaotfload only processes the first configuration file it encounters at diff --git a/macros/luatex/generic/luaotfload/luaotfload.conf.example b/macros/luatex/generic/luaotfload/luaotfload.conf.example index b0323afe51..c307f3611a 100644 --- a/macros/luatex/generic/luaotfload/luaotfload.conf.example +++ b/macros/luatex/generic/luaotfload/luaotfload.conf.example @@ -2,6 +2,7 @@ ;; defaults only, see luaotfload.conf(5) for more information. [db] + location-precedence = system, texmf, local compress = true formats = otf, ttf, ttc max-fonts = 2.2517998136852e15 @@ -25,6 +26,7 @@ definer = patch log-level = 0 resolver = cached + default-dvi-driver = dvisvgm ;; vim:ft=dosini:et:sw=4:ts=8 diff --git a/macros/luatex/generic/luaotfload/luaotfload.conf.rst b/macros/luatex/generic/luaotfload/luaotfload.conf.rst index 2f2bee0fa1..3604422099 100644 --- a/macros/luatex/generic/luaotfload/luaotfload.conf.rst +++ b/macros/luatex/generic/luaotfload/luaotfload.conf.rst @@ -6,9 +6,9 @@ Luaotfload configuration file ----------------------------------------------------------------------- -:Date: 2022-10-03 +:Date: 2023-08-19 :Copyright: GPL v2.0 -:Version: 3.23 +:Version: 3.24 :Manual section: 5 :Manual group: text processing @@ -125,25 +125,27 @@ the variable is unset. Section ``db`` ----------------------------------------------------------------------- -+--------------------+--------+---------------------------+ -| variable | type | default | -+--------------------+--------+---------------------------+ -| compress | b | ``true`` | -+--------------------+--------+---------------------------+ -| designsize-dimen | b | ``bp`` | -+--------------------+--------+---------------------------+ -| formats | s | ``"otf,ttf,ttc"`` | -+--------------------+--------+---------------------------+ -| max-fonts | n | ``2^51`` | -+--------------------+--------+---------------------------+ -| scan-local | b | ``false`` | -+--------------------+--------+---------------------------+ -| skip-read | b | ``false`` | -+--------------------+--------+---------------------------+ -| strip | b | ``true`` | -+--------------------+--------+---------------------------+ -| update-live | b | ``true`` | -+--------------------+--------+---------------------------+ ++----------------------+--------+---------------------------+ +| variable | type | default | ++----------------------+--------+---------------------------+ +| compress | b | ``true`` | ++----------------------+--------+---------------------------+ +| designsize-dimen | b | ``bp`` | ++----------------------+--------+---------------------------+ +| formats | s | ``"otf,ttf,ttc"`` | ++----------------------+--------+---------------------------+ +| location-precedence | s | ``"system,texmf,local`` | ++----------------------+--------+---------------------------+ +| max-fonts | n | ``2^51`` | ++----------------------+--------+---------------------------+ +| scan-local | b | ``false`` | ++----------------------+--------+---------------------------+ +| skip-read | b | ``false`` | ++----------------------+--------+---------------------------+ +| strip | b | ``true`` | ++----------------------+--------+---------------------------+ +| update-live | b | ``true`` | ++----------------------+--------+---------------------------+ The flag ``compress`` determines whether the font index (usually ``luaotfload-names.lua[.gz]`` will be stored in compressed forms. @@ -171,6 +173,12 @@ It corresponds loosely to the ``--formats`` option to list does not contain any useful identifiers, the default list ``"otf,ttf,ttc"`` will be used. +The variable ``location-precedence`` selects where and in which order +luaotfload searches for fonts. Fonts in earlier locations are preferred. +The three supported locations are ``system`` for system specific font +directories, ``texmf`` for fonts which are part of the \TeX{} distribution +and ``local`` for local fonts. + The variable ``max-fonts`` determines after processing how many font files the font scanner will terminate the search. This is useful for debugging issues with the font index and has the same effect as the @@ -180,7 +188,8 @@ The ``scan-local`` flag, if set, will incorporate the current working directory as a font search location. NB: This will potentially slow down document processing because a font index with local fonts will not be saved to disk, so these fonts will have to be re-indexed whenever -the document is built. +the document is built. Setting ``scan_local`` to ``false`` is the same +as removing ``local`` from ``location-precedence``. The ``skip-read`` flag is only useful for debugging: It makes Luaotfload skip reading fonts. The font information for rebuilding the @@ -277,21 +286,23 @@ version. Section ``run`` ----------------------------------------------------------------------- -+------------------+--------+------------------------------+ -| variable | type | default | -+------------------+--------+------------------------------+ -| anon-sequence | s | ``"tex,path,name"`` | -+------------------+--------+------------------------------+ -| color-callback | s | ``"post_linebreak_filter"`` | -+------------------+--------+------------------------------+ -| definer | s | ``"patch"`` | -+------------------+--------+------------------------------+ -| log-level | n | ``0`` | -+------------------+--------+------------------------------+ -| resolver | s | ``"cached"`` | -+------------------+--------+------------------------------+ -| fontloader | s | ``"default"`` | -+------------------+--------+------------------------------+ ++---------------------+--------+------------------------------+ +| variable | type | default | ++---------------------+--------+------------------------------+ +| anon-sequence | s | ``"tex,path,name"`` | ++---------------------+--------+------------------------------+ +| color-callback | s | ``"post_linebreak_filter"`` | ++---------------------+--------+------------------------------+ +| definer | s | ``"patch"`` | ++---------------------+--------+------------------------------+ +| log-level | n | ``0`` | ++---------------------+--------+------------------------------+ +| resolver | s | ``"cached"`` | ++---------------------+--------+------------------------------+ +| fontloader | s | ``"default"`` | ++---------------------+--------+------------------------------+ +| default_dvi_driver | s | ``"dvisvgm"`` | ++---------------------+--------+------------------------------+ Unqualified font lookups are treated with the flexible “anonymous” mechanism. This involves a chain of lookups applied successively until @@ -365,6 +376,16 @@ and resolves every request individually. (Since to the restructuring of the font name index in Luaotfload 2.4 the performance difference between the cached and uncached lookups should be marginal.) +When luaotfload is used in ``DVI`` mode, the ``default_dvi_driver`` option +determines how OpenType fonts are represented in the DVI output. In most +cases the default value ``dvisvgm`` should be set, it uses a format +supported by multiple backends including ``dvipdfmx`` and ``dvisvgm`` +which uses GIDs to identify characters. +Setting this to ``xdvipsk`` uses an unstable internal format instead +which will change depending on the luaotfload, engine, or font version. +No one should rely on the mapping between DVI character codes and font glyphs +in this mode unless they tightly control all involved versions and are deeply +familiar with the implementation. FILES ======================================================================= diff --git a/macros/luatex/generic/luaotfload/luaotfload.lua b/macros/luatex/generic/luaotfload/luaotfload.lua index a22880e736..2125387b90 100644 --- a/macros/luatex/generic/luaotfload/luaotfload.lua +++ b/macros/luatex/generic/luaotfload/luaotfload.lua @@ -20,8 +20,8 @@ local authors = "\z -- version number is used below! local ProvidesLuaModule = { name = "luaotfload", - version = "3.23", --TAGVERSION - date = "2022-10-03", --TAGDATE + version = "3.24", --TAGVERSION + date = "2023-08-19", --TAGDATE description = "Lua based OpenType font support", author = authors, copyright = authors, diff --git a/macros/luatex/generic/luaotfload/luaotfload.sty b/macros/luatex/generic/luaotfload/luaotfload.sty index aafcfb6930..44fce07432 100644 --- a/macros/luatex/generic/luaotfload/luaotfload.sty +++ b/macros/luatex/generic/luaotfload/luaotfload.sty @@ -39,7 +39,7 @@ \fi \ifdefined\ProvidesPackage \ProvidesPackage{luaotfload}% - [2022/10/03 v3.23 OpenType layout system] + [2023/08/19 v3.24 OpenType layout system] \fi \directlua{ if xpcall(function ()% diff --git a/macros/luatex/generic/luaotfload/scripts-demo.pdf b/macros/luatex/generic/luaotfload/scripts-demo.pdf Binary files differindex 4207a5fd7f..b6d0e7dd4c 100644 --- a/macros/luatex/generic/luaotfload/scripts-demo.pdf +++ b/macros/luatex/generic/luaotfload/scripts-demo.pdf diff --git a/macros/luatex/generic/luaotfload/shaper-demo-graphite.pdf b/macros/luatex/generic/luaotfload/shaper-demo-graphite.pdf Binary files differindex 1a8b1c182a..0c0ca16b3d 100644 --- a/macros/luatex/generic/luaotfload/shaper-demo-graphite.pdf +++ b/macros/luatex/generic/luaotfload/shaper-demo-graphite.pdf diff --git a/macros/luatex/generic/luaotfload/shaper-demo.pdf b/macros/luatex/generic/luaotfload/shaper-demo.pdf Binary files differindex f4fe93315d..a51bc51822 100644 --- a/macros/luatex/generic/luaotfload/shaper-demo.pdf +++ b/macros/luatex/generic/luaotfload/shaper-demo.pdf |