From 9f36b1ac422e48e70e11716f5550a833bc8be3f9 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 11 Apr 2016 21:33:01 +0200 Subject: [fontloader] sync with Context as of 2016-04-11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After some discussion, Hans came up with these extensions to the new reader. We get access to more items from the hideous “name” table. On the one hand, this means more brokenness to endure and a less sane matter to work with. But since our tracker was devoid of font-matching related bug reports for some time, it’s the right move nonetheless. In addition to the name table junk, the font loader now also includes the “version” field in the output of “getinfo()”. It’s meaningless per se, but it sure helps to distinguish historical bugs from the ones that matter. **UNTESTED** --- src/fontloader/misc/fontloader-font-gbn.lua | 5 +- src/fontloader/misc/fontloader-font-otr.lua | 220 ++++++++++++++++-------- src/fontloader/misc/fontloader-font-ots.lua | 46 +++-- src/fontloader/runtime/fontloader-reference.lua | 183 ++++++++++++++------ 4 files changed, 315 insertions(+), 139 deletions(-) diff --git a/src/fontloader/misc/fontloader-font-gbn.lua b/src/fontloader/misc/fontloader-font-gbn.lua index f81c877..a645a97 100644 --- a/src/fontloader/misc/fontloader-font-gbn.lua +++ b/src/fontloader/misc/fontloader-font-gbn.lua @@ -19,7 +19,6 @@ local nodes = nodes local nuts = nodes.nuts -- context abstraction of direct nodes local traverse_id = nuts.traverse_id -local free_node = nuts.free local remove_node = nuts.remove local glyph_code = nodes.nodecodes.glyph @@ -137,9 +136,7 @@ function nodes.handlers.nodepass(head) end if redundant then for i=1,#redundant do - local n = redundant[i] - remove_node(nuthead,n) - free_node(n) + remove_node(nuthead,redundant[i],true) end end for d in traverse_id(disc_code,nuthead) do diff --git a/src/fontloader/misc/fontloader-font-otr.lua b/src/fontloader/misc/fontloader-font-otr.lua index 1fc338b..0ad1e19 100644 --- a/src/fontloader/misc/fontloader-font-otr.lua +++ b/src/fontloader/misc/fontloader-font-otr.lua @@ -148,7 +148,7 @@ local function reportskippedtable(tag) end -- We have quite some data tables. We are somewhat ff compatible with names but as I used --- the information form the microsoft site there can be differences. Eventually I might end +-- the information from the microsoft site there can be differences. Eventually I might end -- up with a different ordering and naming. local reservednames = { [0] = @@ -163,14 +163,14 @@ local reservednames = { [0] = "manufacturer", "designer", "description", -- descriptor in ff - "venderurl", + "vendorurl", "designerurl", "license", "licenseurl", "reserved", "typographicfamily", -- preffamilyname "typographicsubfamily", -- prefmodifiers - "compatiblefullname", -- for mac + "compatiblefullname", -- for mac "sampletext", "cidfindfontname", "wwsfamily", @@ -244,7 +244,16 @@ local decoders = { macintosh = { }, iso = { }, windows = { - ["unicode bmp"] = utf16_to_utf8_be + -- maybe always utf16 + ["unicode semantics"] = utf16_to_utf8_be, + ["unicode bmp"] = utf16_to_utf8_be, + ["unicode full"] = utf16_to_utf8_be, + ["unicode 1.0 semantics"] = utf16_to_utf8_be, + ["unicode 1.1 semantics"] = utf16_to_utf8_be, + ["unicode 2.0 bmp"] = utf16_to_utf8_be, + ["unicode 2.0 full"] = utf16_to_utf8_be, + ["unicode variation sequences"] = utf16_to_utf8_be, + ["unicode full repertoire"] = utf16_to_utf8_be, }, custom = { }, } @@ -702,7 +711,17 @@ local panosewidths = { -- useful information about what we deal with. The complication is that we need -- to filter the best one available. -function readers.name(f,fontdata) +local platformnames = { + postscriptname = true, + fullname = true, + family = true, + subfamily = true, + typographicfamily = true, + typographicsubfamily = true, + compatiblefullname = true, +} + +function readers.name(f,fontdata,specification) local datatable = fontdata.tables.name if datatable then setposition(f,datatable.offset) @@ -710,6 +729,7 @@ function readers.name(f,fontdata) local nofnames = readushort(f) local offset = readushort(f) -- we can also provide a raw list as extra, todo as option + local start = datatable.offset + offset local namelists = { unicode = { }, windows = { }, @@ -738,7 +758,7 @@ function readers.name(f,fontdata) language = language, name = name, length = readushort(f), - offset = readushort(f), + offset = start + readushort(f), } else skipshort(f,2) @@ -766,7 +786,6 @@ function readers.name(f,fontdata) -- -- we need to choose one we like, for instance an unicode one -- - local start = datatable.offset + offset local names = { } local done = { } -- @@ -783,7 +802,7 @@ function readers.name(f,fontdata) local encoding = name.encoding local language = name.language if (not e or encoding == e) and (not l or language == l) then - setposition(f,start+name.offset) + setposition(f,name.offset) local content = readstring(f,name.length) local decoder = decoders[platform] if decoder then @@ -812,11 +831,57 @@ function readers.name(f,fontdata) filter("unicode") -- fontdata.names = names + -- + if specification.platformnames then + local collected = { } + for platform, namelist in next, namelists do + local filtered = false + for i=1,#namelist do + local entry = namelist[i] + local name = entry.name + if platformnames[name] then + setposition(f,entry.offset) + local content = readstring(f,entry.length) + local encoding = entry.encoding + local decoder = decoders[platform] + if decoder then + decoder = decoder[encoding] + end + if decoder then + content = decoder(content) + end + if filtered then + filtered[name] = content + else + filtered = { [name] = content } + end + end + end + if filtered then + collected[platform] = filtered + end + end + fontdata.platformnames = collected + end else fontdata.names = { } end end +----- validutf = lpeg.patterns.utf8character^0 * P(-1) +local validutf = lpeg.patterns.validutf8 + +local function getname(fontdata,key) + local names = fontdata.names + if names then + local value = names[key] + if value then + local content = value.content + return lpegmatch(validutf,content) and content or nil + end + end +end + -- This table is an original windows (with its precursor os/2) table. In ff this one is -- part of the pfminfo table but here we keep it separate (for now). We will create a -- properties table afterwards. @@ -1733,69 +1798,69 @@ otf.unpackoutlines = unpackoutlines -- some properties in order to read following tables. When details is true we also -- initialize the glyphs data. ------ validutf = lpeg.patterns.utf8character^0 * P(-1) -local validutf = lpeg.patterns.validutf8 - -local function getname(fontdata,key) - local names = fontdata.names - if names then - local value = names[key] - if value then - local content = value.content - return lpegmatch(validutf,content) and content or nil - end - end -end - -local function getinfo(maindata,sub) +local function getinfo(maindata,sub,platformnames) local fontdata = sub and maindata.subfonts and maindata.subfonts[sub] or maindata - local names = fontdata.names + local names = fontdata.names + local info = nil if names then - local metrics = fontdata.windowsmetrics or { } - local postscript = fontdata.postscript or { } - local fontheader = fontdata.fontheader or { } - local cffinfo = fontdata.cffinfo or { } - local filename = fontdata.filename - local weight = getname(fontdata,"weight") or cffinfo.weight or metrics.weight - local width = getname(fontdata,"width") or cffinfo.width or metrics.width - return { -- we inherit some inconsistencies/choices from ff - subfontindex = fontdata.subfontindex or sub or 0, - -- filename = filename, - -- version = name("version"), - -- format = fontdata.format, - fontname = getname(fontdata,"postscriptname"), - fullname = getname(fontdata,"fullname"), -- or file.nameonly(filename) - familyname = getname(fontdata,"typographicfamily") or getname(fontdata,"family"), - subfamily = getname(fontdata,"subfamily"), - modifiers = getname(fontdata,"typographicsubfamily"), - weight = weight and lower(weight), - width = width and lower(width), - pfmweight = metrics.weightclass or 400, -- will become weightclass - pfmwidth = metrics.widthclass or 5, -- will become widthclass - panosewidth = metrics.panosewidth, - panoseweight = metrics.panoseweight, - italicangle = postscript.italicangle or 0, - units = fontheader.units or 0, - designsize = fontdata.designsize, - minsize = fontdata.minsize, - maxsize = fontdata.maxsize, - monospaced = (tonumber(postscript.monospaced or 0) > 0) or metrics.panosewidth == "monospaced", - averagewidth = metrics.averagewidth, - xheight = metrics.xheight, - ascender = metrics.typoascender, - descender = metrics.typodescender, + local metrics = fontdata.windowsmetrics or { } + local postscript = fontdata.postscript or { } + local fontheader = fontdata.fontheader or { } + local cffinfo = fontdata.cffinfo or { } + local filename = fontdata.filename + local weight = getname(fontdata,"weight") or cffinfo.weight or metrics.weight + local width = getname(fontdata,"width") or cffinfo.width or metrics.width + local fontname = getname(fontdata,"postscriptname") + local fullname = getname(fontdata,"fullname") + local family = getname(fontdata,"family") + local subfamily = getname(fontdata,"subfamily") + local familyname = getname(fontdata,"typographicfamily") or family + local subfamilyname = getname(fontdata,"typographicsubfamily") or subfamily + local compatiblename = getname(fontdata,"compatiblefullname") + info = { -- we inherit some inconsistencies/choices from ff + subfontindex = fontdata.subfontindex or sub or 0, + -- filename = filename, + version = getname(fontdata,"version"), + -- format = fontdata.format, + fontname = fontname, + fullname = fullname, + family = family, + subfamily = subfamily, + familyname = familyname, + subfamilyname = subfamilyname, + compatiblename = compatiblename, + weight = weight and lower(weight), + width = width and lower(width), + pfmweight = metrics.weightclass or 400, -- will become weightclass + pfmwidth = metrics.widthclass or 5, -- will become widthclass + panosewidth = metrics.panosewidth, + panoseweight = metrics.panoseweight, + italicangle = postscript.italicangle or 0, + units = fontheader.units or 0, + designsize = fontdata.designsize, + minsize = fontdata.minsize, + maxsize = fontdata.maxsize, + monospaced = (tonumber(postscript.monospaced or 0) > 0) or metrics.panosewidth == "monospaced", + averagewidth = metrics.averagewidth, + xheight = metrics.xheight, + capheight = metrics.capheight, -- not always present and probably crap + ascender = metrics.typoascender, + descender = metrics.typodescender, + platformnames = platformnames and fontdata.platformnames or nil, } elseif n then - return { + info = { filename = fontdata.filename, comment = "there is no info for subfont " .. n, } else - return { + info = { filename = fontdata.filename, comment = "there is no info", } end + -- inspect(info) + return info end local function loadtables(f,specification,offset) @@ -1870,6 +1935,7 @@ local function readdata(f,offset,specification) end end -- + -- readers["os/2"](f,fontdata,specification) readers["head"](f,fontdata,specification) readers["maxp"](f,fontdata,specification) @@ -1989,7 +2055,10 @@ local function loadfont(specification,n) specification.details = true end if specification.details then - specification.info = true + specification.info = true -- not really used any more + end + if specification.platformnames then + specification.platformnames = true -- not really used any more end local function message(str) report("fatal error in file %a: %s\n%s",specification.filename,str,debug.traceback()) @@ -2043,7 +2112,7 @@ function readers.loadfont(filename,n) descriptions = fontdata.descriptions, format = fontdata.format, goodies = { }, - metadata = getinfo(fontdata,n), + metadata = getinfo(fontdata,n), -- no platformnames here ! properties = { hasitalics = fontdata.hasitalics or false, }, @@ -2067,27 +2136,38 @@ function readers.loadfont(filename,n) end end -function readers.getinfo(filename,n,details) +function readers.getinfo(filename,specification) -- string, nil|number|table + -- platformnames is optional and not used by context (a too unpredictable mess + -- that only add to the confusion) .. so it's only for checking things + local subfont = nil + local platformname = false + if type(specification) == "table" then + subfont = tonumber(specification.subfont) + platformnames = specification.platformnames + else + subfont = tonumber(specification) + end local fontdata = loadfont { - filename = filename, - details = true, + filename = filename, + details = true, + platformnames = platformnames, } if fontdata then local subfonts = fontdata.subfonts if not subfonts then - return getinfo(fontdata) - elseif type(n) ~= "number" then + return getinfo(fontdata,nil,platformnames) + elseif not subfont then local info = { } for i=1,#subfonts do - info[i] = getinfo(fontdata,i) + info[i] = getinfo(fontdata,i,platformnames) end return info - elseif n > 1 and n <= subfonts then - return getinfo(fontdata,n) + elseif subfont > 1 and subfont <= #subfonts then + return getinfo(fontdata,subfont,platformnames) else return { filename = filename, - comment = "there is no subfont " .. n .. " in this file" + comment = "there is no subfont " .. subfont .. " in this file" } end else diff --git a/src/fontloader/misc/fontloader-font-ots.lua b/src/fontloader/misc/fontloader-font-ots.lua index 4d5e8ec..d67db6d 100644 --- a/src/fontloader/misc/fontloader-font-ots.lua +++ b/src/fontloader/misc/fontloader-font-ots.lua @@ -2716,8 +2716,8 @@ function otf.dataset(tfmdata,font) -- generic variant, overloaded in context return rl end -local function report_disc(n) - report_run("kern: %s > %s",disc,languages.serializediscretionary(disc)) +local function report_disc(what,n) + report_run("%s: %s > %s",what,n,languages.serializediscretionary(n)) end local function kernrun(disc,k_run,font,attr,...) @@ -2725,7 +2725,7 @@ local function kernrun(disc,k_run,font,attr,...) -- we catch -- if trace_kernruns then - report_disc("kern") + report_disc("kern",disc) end -- local prev, next = getboth(disc) @@ -2819,7 +2819,7 @@ end local function comprun(disc,c_run,...) if trace_compruns then - report_disc("comp") + report_disc("comp",disc) end -- local pre, post, replace = getdisc(disc) @@ -2866,31 +2866,35 @@ end local function testrun(disc,t_run,c_run,...) if trace_testruns then - report_disc("test") + report_disc("test",disc) end local prev, next = getboth(disc) if not next then -- weird discretionary return end - local pre, post, replace, pretail, posttail, replacetail = getdisc(disc) + local pre, post, replace, pretail, posttail, replacetail = getdisc(disc,true) local done = false if replace and prev then - -- only look ahead - -- local nest = getprev(replace) + -- this is a bit strange as we only do replace here and not post + -- anyway, we only look ahead ... the idea is that we discard a + -- disc when there is a ligature crossing the replace boundary setlink(replacetail,next) - if t_run(replace,next,...) then - setfield(disc,"replace",nil) -- beware, side effects of nest so first + local ok, overflow = t_run(replace,next,...) + if ok and overflow then + -- so, we can have crossed the boundary + setfield(disc,"replace",nil) setlink(prev,replace) - setlink(replacetail,next) + -- setlink(replacetail,next) setboth(disc) flush_node_list(disc) return replace, true -- restart .. tricky ! else + -- we stay inside the disc setnext(replacetail) setprev(next,disc) end - -- pre, post, replace, pretail, posttail, replacetail = getdisc(disc) + -- pre, post, replace, pretail, posttail, replacetail = getdisc(disc,true) end -- -- like comprun @@ -2945,7 +2949,7 @@ end -- local function discrun(disc,drun,krun) -- local prev, next = getboth(disc) -- if trace_discruns then --- report_disc("disc") +-- report_disc("disc",disc) -- end -- if next and prev then -- setnext(prev,next) @@ -3043,7 +3047,13 @@ local function t_run_single(start,stop,font,attr,lookupcache) -- if we need more than ligatures we can outline the code and use functions local s = getnext(start) local l = nil + local d = 0 while s do + if s == stop then + d = 1 + elseif d > 0 then + d = d + 1 + end local lg = lookupmatch[getchar(s)] if lg then l = lg @@ -3053,7 +3063,7 @@ local function t_run_single(start,stop,font,attr,lookupcache) end end if l and l.ligature then - return true + return true, d > 1 end end end @@ -3168,7 +3178,13 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) -- if we need more than ligatures we can outline the code and use functions local s = getnext(start) local l = nil + local d = 0 while s do + if s == stop then + d = 1 + elseif d > 0 then + d = d + 1 + end local lg = lookupmatch[getchar(s)] if lg then l = lg @@ -3178,7 +3194,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) end end if l and l.ligature then - return true + return true, d > 1 end end else diff --git a/src/fontloader/runtime/fontloader-reference.lua b/src/fontloader/runtime/fontloader-reference.lua index e4ae182..a4677ef 100644 --- a/src/fontloader/runtime/fontloader-reference.lua +++ b/src/fontloader/runtime/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 : 04/04/16 13:06:24 +-- merge date : 04/11/16 19:04:35 do -- begin closure to overcome local limits and interference @@ -8184,7 +8184,7 @@ local reservednames={ [0]="copyright", "manufacturer", "designer", "description", - "venderurl", + "vendorurl", "designerurl", "license", "licenseurl", @@ -8244,7 +8244,15 @@ local decoders={ macintosh={}, iso={}, windows={ - ["unicode bmp"]=utf16_to_utf8_be + ["unicode semantics"]=utf16_to_utf8_be, + ["unicode bmp"]=utf16_to_utf8_be, + ["unicode full"]=utf16_to_utf8_be, + ["unicode 1.0 semantics"]=utf16_to_utf8_be, + ["unicode 1.1 semantics"]=utf16_to_utf8_be, + ["unicode 2.0 bmp"]=utf16_to_utf8_be, + ["unicode 2.0 full"]=utf16_to_utf8_be, + ["unicode variation sequences"]=utf16_to_utf8_be, + ["unicode full repertoire"]=utf16_to_utf8_be, }, custom={}, } @@ -8355,13 +8363,23 @@ local panosewidths={ [ 8]="verycondensed", [ 9]="monospaced", } -function readers.name(f,fontdata) +local platformnames={ + postscriptname=true, + fullname=true, + family=true, + subfamily=true, + typographicfamily=true, + typographicsubfamily=true, + compatiblefullname=true, +} +function readers.name(f,fontdata,specification) local datatable=fontdata.tables.name if datatable then setposition(f,datatable.offset) local format=readushort(f) local nofnames=readushort(f) local offset=readushort(f) + local start=datatable.offset+offset local namelists={ unicode={}, windows={}, @@ -8388,7 +8406,7 @@ function readers.name(f,fontdata) language=language, name=name, length=readushort(f), - offset=readushort(f), + offset=start+readushort(f), } else skipshort(f,2) @@ -8406,7 +8424,6 @@ function readers.name(f,fontdata) skipshort(f,5) end end - local start=datatable.offset+offset local names={} local done={} local function filter(platform,e,l) @@ -8418,7 +8435,7 @@ function readers.name(f,fontdata) local encoding=name.encoding local language=name.language if (not e or encoding==e) and (not l or language==l) then - setposition(f,start+name.offset) + setposition(f,name.offset) local content=readstring(f,name.length) local decoder=decoders[platform] if decoder then @@ -8444,10 +8461,52 @@ function readers.name(f,fontdata) filter("macintosh") filter("unicode") fontdata.names=names + if specification.platformnames then + local collected={} + for platform,namelist in next,namelists do + local filtered=false + for i=1,#namelist do + local entry=namelist[i] + local name=entry.name + if platformnames[name] then + setposition(f,entry.offset) + local content=readstring(f,entry.length) + local encoding=entry.encoding + local decoder=decoders[platform] + if decoder then + decoder=decoder[encoding] + end + if decoder then + content=decoder(content) + end + if filtered then + filtered[name]=content + else + filtered={ [name]=content } + end + end + end + if filtered then + collected[platform]=filtered + end + end + fontdata.platformnames=collected + end else fontdata.names={} end end +local validutf=lpeg.patterns.validutf8 +local function getname(fontdata,key) + local names=fontdata.names + if names then + local value=names[key] + if value then + local content=value.content + return lpegmatch(validutf,content) and content or nil + end + end +end readers["os/2"]=function(f,fontdata) local datatable=fontdata.tables["os/2"] if datatable then @@ -9233,20 +9292,10 @@ local function unpackoutlines(data) end otf.packoutlines=packoutlines otf.unpackoutlines=unpackoutlines -local validutf=lpeg.patterns.validutf8 -local function getname(fontdata,key) - local names=fontdata.names - if names then - local value=names[key] - if value then - local content=value.content - return lpegmatch(validutf,content) and content or nil - end - end -end -local function getinfo(maindata,sub) +local function getinfo(maindata,sub,platformnames) local fontdata=sub and maindata.subfonts and maindata.subfonts[sub] or maindata local names=fontdata.names + local info=nil if names then local metrics=fontdata.windowsmetrics or {} local postscript=fontdata.postscript or {} @@ -9255,13 +9304,23 @@ local function getinfo(maindata,sub) local filename=fontdata.filename local weight=getname(fontdata,"weight") or cffinfo.weight or metrics.weight local width=getname(fontdata,"width") or cffinfo.width or metrics.width - return { + local fontname=getname(fontdata,"postscriptname") + local fullname=getname(fontdata,"fullname") + local family=getname(fontdata,"family") + local subfamily=getname(fontdata,"subfamily") + local familyname=getname(fontdata,"typographicfamily") or family + local subfamilyname=getname(fontdata,"typographicsubfamily") or subfamily + local compatiblename=getname(fontdata,"compatiblefullname") + info={ subfontindex=fontdata.subfontindex or sub or 0, - fontname=getname(fontdata,"postscriptname"), - fullname=getname(fontdata,"fullname"), - familyname=getname(fontdata,"typographicfamily") or getname(fontdata,"family"), - subfamily=getname(fontdata,"subfamily"), - modifiers=getname(fontdata,"typographicsubfamily"), + version=getname(fontdata,"version"), + fontname=fontname, + fullname=fullname, + family=family, + subfamily=subfamily, + familyname=familyname, + subfamilyname=subfamilyname, + compatiblename=compatiblename, weight=weight and lower(weight), width=width and lower(width), pfmweight=metrics.weightclass or 400, @@ -9276,20 +9335,23 @@ local function getinfo(maindata,sub) monospaced=(tonumber(postscript.monospaced or 0)>0) or metrics.panosewidth=="monospaced", averagewidth=metrics.averagewidth, xheight=metrics.xheight, + capheight=metrics.capheight, ascender=metrics.typoascender, descender=metrics.typodescender, + platformnames=platformnames and fontdata.platformnames or nil, } elseif n then - return { + info={ filename=fontdata.filename, comment="there is no info for subfont "..n, } else - return { + info={ filename=fontdata.filename, comment="there is no info", } end + return info end local function loadtables(f,specification,offset) if offset then @@ -9470,7 +9532,10 @@ local function loadfont(specification,n) specification.details=true end if specification.details then - specification.info=true + specification.info=true + end + if specification.platformnames then + specification.platformnames=true end local function message(str) report("fatal error in file %a: %s\n%s",specification.filename,str,debug.traceback()) @@ -9538,27 +9603,36 @@ function readers.loadfont(filename,n) } end end -function readers.getinfo(filename,n,details) +function readers.getinfo(filename,specification) + local subfont=nil + local platformname=false + if type(specification)=="table" then + subfont=tonumber(specification.subfont) + platformnames=specification.platformnames + else + subfont=tonumber(specification) + end local fontdata=loadfont { filename=filename, details=true, + platformnames=platformnames, } if fontdata then local subfonts=fontdata.subfonts if not subfonts then - return getinfo(fontdata) - elseif type(n)~="number" then + return getinfo(fontdata,nil,platformnames) + elseif not subfont then local info={} for i=1,#subfonts do - info[i]=getinfo(fontdata,i) + info[i]=getinfo(fontdata,i,platformnames) end return info - elseif n>1 and n<=subfonts then - return getinfo(fontdata,n) + elseif subfont>1 and subfont<=#subfonts then + return getinfo(fontdata,subfont,platformnames) else return { filename=filename, - comment="there is no subfont "..n.." in this file" + comment="there is no subfont "..subfont.." in this file" } end else @@ -20229,12 +20303,12 @@ function otf.dataset(tfmdata,font) end return rl end -local function report_disc(n) - report_run("kern: %s > %s",disc,languages.serializediscretionary(disc)) +local function report_disc(what,n) + report_run("%s: %s > %s",what,n,languages.serializediscretionary(n)) end local function kernrun(disc,k_run,font,attr,...) if trace_kernruns then - report_disc("kern") + report_disc("kern",disc) end local prev,next=getboth(disc) local nextstart=next @@ -20315,7 +20389,7 @@ local function kernrun(disc,k_run,font,attr,...) end local function comprun(disc,c_run,...) if trace_compruns then - report_disc("comp") + report_disc("comp",disc) end local pre,post,replace=getdisc(disc) local renewed=false @@ -20355,20 +20429,20 @@ local function comprun(disc,c_run,...) end local function testrun(disc,t_run,c_run,...) if trace_testruns then - report_disc("test") + report_disc("test",disc) end local prev,next=getboth(disc) if not next then return end - local pre,post,replace,pretail,posttail,replacetail=getdisc(disc) + local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true) local done=false if replace and prev then setlink(replacetail,next) - if t_run(replace,next,...) then - setfield(disc,"replace",nil) + local ok,overflow=t_run(replace,next,...) + if ok and overflow then + setfield(disc,"replace",nil) setlink(prev,replace) - setlink(replacetail,next) setboth(disc) flush_node_list(disc) return replace,true @@ -20460,7 +20534,13 @@ local function t_run_single(start,stop,font,attr,lookupcache) if lookupmatch then local s=getnext(start) local l=nil + local d=0 while s do + if s==stop then + d=1 + elseif d>0 then + d=d+1 + end local lg=lookupmatch[getchar(s)] if lg then l=lg @@ -20470,7 +20550,7 @@ local function t_run_single(start,stop,font,attr,lookupcache) end end if l and l.ligature then - return true + return true,d>1 end end end @@ -20560,7 +20640,13 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) if lookupmatch then local s=getnext(start) local l=nil + local d=0 while s do + if s==stop then + d=1 + elseif d>0 then + d=d+1 + end local lg=lookupmatch[getchar(s)] if lg then l=lg @@ -20570,7 +20656,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) end end if l and l.ligature then - return true + return true,d>1 end end else @@ -23666,7 +23752,6 @@ local fonts=fonts local nodes=nodes local nuts=nodes.nuts local traverse_id=nuts.traverse_id -local free_node=nuts.free local remove_node=nuts.remove local glyph_code=nodes.nodecodes.glyph local disc_code=nodes.nodecodes.disc @@ -23769,9 +23854,7 @@ function nodes.handlers.nodepass(head) end if redundant then for i=1,#redundant do - local n=redundant[i] - remove_node(nuthead,n) - free_node(n) + remove_node(nuthead,redundant[i],true) end end for d in traverse_id(disc_code,nuthead) do -- cgit v1.2.3