From 1987348696a38821137cc579a986d37086b87404 Mon Sep 17 00:00:00 2001 From: Hans Hagen Date: Wed, 22 Mar 2017 12:26:18 +0100 Subject: 2017-03-22 12:03:00 --- tex/context/base/mkii/cont-new.mkii | 2 +- tex/context/base/mkii/context.mkii | 2 +- tex/context/base/mkiv/cont-new.mkiv | 2 +- tex/context/base/mkiv/context.mkiv | 2 +- tex/context/base/mkiv/font-fea.mkvi | 18 + tex/context/base/mkiv/font-otc.lua | 133 +++- tex/context/base/mkiv/font-ots.lua | 704 ++++++++++--------- tex/context/base/mkiv/status-files.pdf | Bin 25644 -> 25656 bytes tex/context/base/mkiv/status-lua.pdf | Bin 422422 -> 422634 bytes tex/context/base/mkiv/tabl-ntb.mkiv | 3 +- tex/context/interface/mkiv/i-context.pdf | Bin 804059 -> 804232 bytes tex/context/interface/mkiv/i-fonts.xml | 6 + tex/context/interface/mkiv/i-readme.pdf | Bin 60772 -> 60773 bytes tex/context/modules/mkiv/s-fonts-variable.lua | 6 +- tex/generic/context/luatex/luatex-fonts-merged.lua | 768 ++++++++++++--------- 15 files changed, 985 insertions(+), 661 deletions(-) (limited to 'tex') diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii index e2bd35d0e..f480ab318 100644 --- a/tex/context/base/mkii/cont-new.mkii +++ b/tex/context/base/mkii/cont-new.mkii @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2017.03.21 14:21} +\newcontextversion{2017.03.22 11:57} %D This file is loaded at runtime, thereby providing an %D excellent place for hacks, patches, extensions and new diff --git a/tex/context/base/mkii/context.mkii b/tex/context/base/mkii/context.mkii index b6b570e81..d29fb8fd4 100644 --- a/tex/context/base/mkii/context.mkii +++ b/tex/context/base/mkii/context.mkii @@ -20,7 +20,7 @@ %D your styles an modules. \edef\contextformat {\jobname} -\edef\contextversion{2017.03.21 14:21} +\edef\contextversion{2017.03.22 11:57} %D For those who want to use this: diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index 2b9f458b6..86d4d8ca4 100644 --- a/tex/context/base/mkiv/cont-new.mkiv +++ b/tex/context/base/mkiv/cont-new.mkiv @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2017.03.21 14:21} +\newcontextversion{2017.03.22 11:57} %D This file is loaded at runtime, thereby providing an excellent place for %D hacks, patches, extensions and new features. diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index 9bd5b1aba..51f13612a 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -39,7 +39,7 @@ %D up and the dependencies are more consistent. \edef\contextformat {\jobname} -\edef\contextversion{2017.03.21 14:21} +\edef\contextversion{2017.03.22 11:57} \edef\contextkind {beta} %D For those who want to use this: diff --git a/tex/context/base/mkiv/font-fea.mkvi b/tex/context/base/mkiv/font-fea.mkvi index 354fc6310..840b64e9c 100644 --- a/tex/context/base/mkiv/font-fea.mkvi +++ b/tex/context/base/mkiv/font-fea.mkvi @@ -391,4 +391,22 @@ 0% \endgroup} +% not nice but maybe handy + +% \starttyping +% \blockligatures[fi,ff] \blockligatures[fl] +% +% \definefontfeature[default:b][default][blockligatures=yes] +% +% \setupbodyfont[pagella] \showfontkerns +% +% \definedfont[Serif*default:b] +% +% \startTEXpage[offset=1em] +% fi ff fl +% \stopTEXpage +% \stoptyping + +\unexpanded\def\blockligatures[#1]{\clf_blockligatures{#1}} + \protect \endinput diff --git a/tex/context/base/mkiv/font-otc.lua b/tex/context/base/mkiv/font-otc.lua index dc855a74d..bed2adf85 100644 --- a/tex/context/base/mkiv/font-otc.lua +++ b/tex/context/base/mkiv/font-otc.lua @@ -9,7 +9,8 @@ if not modules then modules = { } end modules ['font-otc'] = { local format, insert, sortedkeys, tohash = string.format, table.insert, table.sortedkeys, table.tohash local type, next = type, next local lpegmatch = lpeg.match -local utfbyte, utflen = utf.byte, utf.len +local utfbyte, utflen, utfsplit = utf.byte, utf.len, utf.split +local settings_to_array = utilities.parsers.settings_to_array -- we assume that the other otf stuff is loaded already @@ -231,7 +232,7 @@ local function addfeature(data,feature,specifications) local r = { } for i=1,#replacement do local u = tounicode(replacement[i]) - r[i] = descriptions[u] and u or unicode + r[i] = (nocheck or descriptions[u]) and u or unicode end cover(coverage,unicode,r) done = done + 1 @@ -260,7 +261,7 @@ local function addfeature(data,feature,specifications) local r, n = { }, 0 for i=1,#replacement do local u = tounicode(replacement[i]) - if descriptions[u] then + if nocheck or descriptions[u] then n = n + 1 r[n] = u end @@ -300,7 +301,7 @@ local function addfeature(data,feature,specifications) for i=1,#ligature do local l = ligature[i] local u = tounicode(l) - if descriptions[u] then + if nocheck or descriptions[u] then ligature[i] = u else present = false @@ -443,14 +444,21 @@ local function addfeature(data,feature,specifications) local subtype = nil if lookups and sublookups then for k, v in next, lookups do - local lookup = sublookups[v] - if lookup then - lookups[k] = lookup - if not subtype then - subtype = lookup.type + local t = type(v) + if t == "table" then + -- already ok + elseif t == "number" then + local lookup = sublookups[v] + if lookup then + lookups[k] = lookup + if not subtype then + subtype = lookup.type + end + else + lookups[k] = false -- new end else - -- already expanded + lookups[k] = false -- new end end end @@ -531,7 +539,7 @@ local function addfeature(data,feature,specifications) if f then for k in next, f do if k == position then - index = i + index = i break end end @@ -580,6 +588,7 @@ local function addfeature(data,feature,specifications) local featuretype = normalized[specification.type or "substitution"] or "substitution" local featureflags = specification.flags or noflags local nocheck = specification.nocheck + local futuresteps = specification.futuresteps local featureorder = specification.order or { feature } local featurechain = (featuretype == "chainsubstitution" or featuretype == "chainposition") and 1 or 0 local nofsteps = 0 @@ -622,6 +631,7 @@ local function addfeature(data,feature,specifications) s[i] = { [stepkey] = steps, nofsteps = nofsteps, + flags = featureflags, type = types[featuretype], } end @@ -736,11 +746,16 @@ function otf.addfeature(name,specification) specification, name = validspecification(specification,name) if name and specification then local slot = knownfeatures[name] - if slot then - -- we overload one .. should be option - else + if not slot then + -- we have a new one + slot = #extrafeatures + 1 + knownfeatures[name] = slot + elseif specification.overload == false then + -- we add an extre one slot = #extrafeatures + 1 knownfeatures[name] = slot + else + -- we overload a previous one end specification.name = name -- to be sure extrafeatures[slot] = specification @@ -978,3 +993,93 @@ registerotffeature { -- a = { b = -500 }, -- } -- } + +-- This is a quick and dirty hack. + +local lookups = { } +local protect = { } +local revert = { } +local zwj = { 0x200C } + +otf.addfeature { + name = "blockligatures", + type = "chainsubstitution", + nocheck = true, -- because there is no 0x200C in the font + prepend = true, -- make sure we do it early + future = true, -- avoid nilling due to no steps yet + lookups = { + { + type = "multiple", + data = lookups, + }, + }, + data = { + rules = protect, + } +} + +otf.addfeature { + name = "blockligatures", + type = "chainsubstitution", + nocheck = true, -- because there is no 0x200C in the font + append = true, -- this is done late + overload = false, -- we don't want to overload the previous definition + lookups = { + { + type = "ligature", + data = lookups, + }, + }, + data = { + rules = revert, + } +} + +registerotffeature { + name = 'blockligatures', + description = 'block certain ligatures', +} + +local function blockligatures(str) + + local t = settings_to_array(str) + + for i=1,#t do + local ti = utfsplit(t[i]) + if #ti > 1 then + local one = ti[1] + local two = ti[2] + lookups[one] = { one, 0x200C } + local one = { one } + local two = { two } + local new = #protect + 1 + protect[new] = { + current = { one, two }, + lookups = { 1 }, -- not shared ! + } + revert[new] = { + current = { one, zwj }, + after = { two }, + lookups = { 1 }, -- not shared ! + } + end + end + +end + +-- blockligatures("\0\0") + +otf.helpers.blockligatures = blockligatures + +-- blockligatures("fi,ff") +-- blockligatures("fl") + +if context then + + interfaces.implement { + name = "blockligatures", + arguments = "string", + actions = blockligatures, + } + +end diff --git a/tex/context/base/mkiv/font-ots.lua b/tex/context/base/mkiv/font-ots.lua index 7ef395330..c86a0ccda 100644 --- a/tex/context/base/mkiv/font-ots.lua +++ b/tex/context/base/mkiv/font-ots.lua @@ -227,10 +227,8 @@ local localpar_code = nodecodes.localpar local discretionary_code = disccodes.discretionary local ligature_code = glyphcodes.ligature -local privateattribute = attributes.private - -local a_state = privateattribute('state') -local a_noligature = privateattribute("noligature") +local a_state = attributes.private('state') +local a_noligature = attributes.private("noligature") local injections = nodes.injections local setmark = injections.setmark @@ -1278,41 +1276,53 @@ as less as needed but that would also make the code even more messy.

-- this is messy: do we need this disc checking also in alternaties? +local function reportzerosteps(dataset,sequence) + logwarning("%s: no steps",cref(dataset,sequence)) +end + local function reportmoresteps(dataset,sequence) logwarning("%s: more than 1 step",cref(dataset,sequence)) end +-- local function reportbadsteps(dataset,sequence) +-- logwarning("%s: bad step, no proper return values",cref(dataset,sequence)) +-- end + function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,chainindex) local steps = currentlookup.steps local nofsteps = currentlookup.nofsteps if nofsteps > 1 then reportmoresteps(dataset,sequence) end - local current = start - local mapping = steps[1].coverage - while current do - local currentchar = ischar(current) - if currentchar then - local replacement = mapping[currentchar] - if not replacement or replacement == "" then - if trace_bugs then - logwarning("%s: no single for %s",cref(dataset,sequence,chainindex),gref(currentchar)) + if nofsteps == 0 then + reportzerosteps(dataset,sequence) + else + local current = start + local mapping = steps[1].coverage + while current do + local currentchar = ischar(current) + if currentchar then + local replacement = mapping[currentchar] + if not replacement or replacement == "" then + if trace_bugs then + logwarning("%s: no single for %s",cref(dataset,sequence,chainindex),gref(currentchar)) + end + else + if trace_singles then + logprocess("%s: replacing single %s by %s",cref(dataset,sequence,chainindex),gref(currentchar),gref(replacement)) + end + resetinjection(current) + setchar(current,replacement) end + return head, start, true + elseif currentchar == false then + -- can't happen + break + elseif current == stop then + break else - if trace_singles then - logprocess("%s: replacing single %s by %s",cref(dataset,sequence,chainindex),gref(currentchar),gref(replacement)) - end - resetinjection(current) - setchar(current,replacement) + current = getnext(current) end - return head, start, true - elseif currentchar == false then - -- can't happen - break - elseif current == stop then - break - else - current = getnext(current) end end return head, start, false @@ -1328,17 +1338,21 @@ function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup if nofsteps > 1 then reportmoresteps(dataset,sequence) end - local startchar = getchar(start) - local replacement = steps[1].coverage[startchar] - if not replacement or replacement == "" then - if trace_bugs then - logwarning("%s: no multiple for %s",cref(dataset,sequence),gref(startchar)) - end + if nofsteps == 0 then + reportzerosteps(dataset,sequence) else - if trace_multiples then - logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement)) + local startchar = getchar(start) + local replacement = steps[1].coverage[startchar] + if not replacement or replacement == "" then + if trace_bugs then + logwarning("%s: no multiple for %s",cref(dataset,sequence),gref(startchar)) + end + else + if trace_multiples then + logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement)) + end + return multiple_glyphs(head,start,replacement,sequence.flags[1],dataset[1]) end - return multiple_glyphs(head,start,replacement,sequence.flags[1],dataset[1]) end return head, start, false end @@ -1361,37 +1375,41 @@ function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlooku if nofsteps > 1 then reportmoresteps(dataset,sequence) end - local kind = dataset[4] - local what = dataset[1] - local value = what == true and tfmdata.shared.features[kind] or what -- todo: optimize in ctx - local current = start - local mapping = steps[1].coverage - while current do - local currentchar = ischar(current) - if currentchar then - local alternatives = mapping[currentchar] - if alternatives then - local choice, comment = get_alternative_glyph(current,alternatives,value) - if choice then - if trace_alternatives then - logprocess("%s: replacing %s by alternative %a to %s, %s",cref(dataset,sequence),gref(char),choice,gref(choice),comment) - end - resetinjection(start) - setchar(start,choice) - else - if trace_alternatives then - logwarning("%s: no variant %a for %s, %s",cref(dataset,sequence),value,gref(char),comment) + if nofsteps == 0 then + reportzerosteps(dataset,sequence) + else + local kind = dataset[4] + local what = dataset[1] + local value = what == true and tfmdata.shared.features[kind] or what -- todo: optimize in ctx + local current = start + local mapping = steps[1].coverage + while current do + local currentchar = ischar(current) + if currentchar then + local alternatives = mapping[currentchar] + if alternatives then + local choice, comment = get_alternative_glyph(current,alternatives,value) + if choice then + if trace_alternatives then + logprocess("%s: replacing %s by alternative %a to %s, %s",cref(dataset,sequence),gref(char),choice,gref(choice),comment) + end + resetinjection(start) + setchar(start,choice) + else + if trace_alternatives then + logwarning("%s: no variant %a for %s, %s",cref(dataset,sequence),value,gref(char),comment) + end end end + return head, start, true + elseif currentchar == false then + -- can't happen + break + elseif current == stop then + break + else + current = getnext(current) end - return head, start, true - elseif currentchar == false then - -- can't happen - break - elseif current == stop then - break - else - current = getnext(current) end end return head, start, false @@ -1409,75 +1427,79 @@ function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup if nofsteps > 1 then reportmoresteps(dataset,sequence) end - local startchar = getchar(start) - local ligatures = steps[1].coverage[startchar] - if not ligatures then - if trace_bugs then - logwarning("%s: no ligatures starting with %s",cref(dataset,sequence,chainindex),gref(startchar)) - end + if nofsteps == 0 then + reportzerosteps(dataset,sequence) else - local current = getnext(start) - local discfound = false - local last = stop - local nofreplacements = 1 - local skipmark = currentlookup.flags[1] -- sequence.flags? - while current do - -- todo: ischar ... can there really be disc nodes here? - local id = getid(current) - if id == disc_code then - if not discfound then - discfound = current - end - if current == stop then - break -- okay? or before the disc - else - current = getnext(current) - end - else - local schar = getchar(current) - if skipmark and marks[schar] then -- marks - -- if current == stop then -- maybe add this - -- break - -- else + local startchar = getchar(start) + local ligatures = steps[1].coverage[startchar] + if not ligatures then + if trace_bugs then + logwarning("%s: no ligatures starting with %s",cref(dataset,sequence,chainindex),gref(startchar)) + end + else + local current = getnext(start) + local discfound = false + local last = stop + local nofreplacements = 1 + local skipmark = currentlookup.flags[1] -- sequence.flags? + while current do + -- todo: ischar ... can there really be disc nodes here? + local id = getid(current) + if id == disc_code then + if not discfound then + discfound = current + end + if current == stop then + break -- okay? or before the disc + else current = getnext(current) - -- end + end else - local lg = ligatures[schar] - if lg then - ligatures = lg - last = current - nofreplacements = nofreplacements + 1 - if current == stop then - break - else + local schar = getchar(current) + if skipmark and marks[schar] then -- marks + -- if current == stop then -- maybe add this + -- break + -- else current = getnext(current) - end + -- end else - break + local lg = ligatures[schar] + if lg then + ligatures = lg + last = current + nofreplacements = nofreplacements + 1 + if current == stop then + break + else + current = getnext(current) + end + else + break + end end end end - end - local ligature = ligatures.ligature - if ligature then - if chainindex then - stop = last - end - if trace_ligatures then + local ligature = ligatures.ligature + if ligature then + if chainindex then + stop = last + end + if trace_ligatures then + if start == stop then + logprocess("%s: replacing character %s by ligature %s case 3",cref(dataset,sequence,chainindex),gref(startchar),gref(ligature)) + else + logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)),gref(ligature)) + end + end + head, start = toligature(head,start,stop,ligature,dataset,sequence,skipmark,discfound) + return head, start, true, nofreplacements, discfound + elseif trace_bugs then if start == stop then - logprocess("%s: replacing character %s by ligature %s case 3",cref(dataset,sequence,chainindex),gref(startchar),gref(ligature)) + logwarning("%s: replacing character %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar)) else - logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)),gref(ligature)) + logwarning("%s: replacing character %s upto %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop))) end end - head, start = toligature(head,start,stop,ligature,dataset,sequence,skipmark,discfound) - return head, start, true, nofreplacements, discfound - elseif trace_bugs then - if start == stop then - logwarning("%s: replacing character %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar)) - else - logwarning("%s: replacing character %s upto %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop))) - end end end return head, start, false, 0, false @@ -1489,20 +1511,24 @@ function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,r if nofsteps > 1 then reportmoresteps(dataset,sequence) end - local startchar = getchar(start) - local step = steps[1] - local kerns = step.coverage[startchar] - if not kerns then - -- skip - elseif step.format == "pair" then - local dx, dy, w, h = setpair(start,factor,rlmode,sequence.flags[4],kerns) -- currentlookup.flags ? - if trace_kerns then - logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),dx,dy,w,h) - end - else -- needs checking .. maybe no kerns format for single - local k = setkern(start,factor,rlmode,kerns,injection) - if trace_kerns then - logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k) + if nofsteps == 0 then + reportzerosteps(dataset,sequence) + else + local startchar = getchar(start) + local step = steps[1] + local kerns = step.coverage[startchar] + if not kerns then + -- skip + elseif step.format == "pair" then + local dx, dy, w, h = setpair(start,factor,rlmode,sequence.flags[4],kerns) -- currentlookup.flags ? + if trace_kerns then + logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),dx,dy,w,h) + end + else -- needs checking .. maybe no kerns format for single + local k = setkern(start,factor,rlmode,kerns,injection) + if trace_kerns then + logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k) + end end end return head, start, false @@ -1514,60 +1540,64 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm if nofsteps > 1 then reportmoresteps(dataset,sequence) end - local snext = getnext(start) - if snext then - local startchar = getchar(start) - local step = steps[1] - local kerns = step.coverage[startchar] -- always 1 step - if kerns then - local prev = start - while snext do - local nextchar = ischar(snext,currentfont) - if not nextchar then - break - end - local krn = kerns[nextchar] - if not krn and marks[nextchar] then - prev = snext - snext = getnext(snext) - elseif not krn then - break - elseif step.format == "pair" then - local a, b = krn[1], krn[2] - if optimizekerns then - -- this permits a mixed table, but we could also decide to optimize this - -- in the loader and use format 'kern' - if not b and a[1] == 0 and a[2] == 0 and a[4] == 0 then - local k = setkern(snext,factor,rlmode,a[3],"injections") + if nofsteps == 0 then + reportzerosteps(dataset,sequence) + else + local snext = getnext(start) + if snext then + local startchar = getchar(start) + local step = steps[1] + local kerns = step.coverage[startchar] -- always 1 step + if kerns then + local prev = start + while snext do + local nextchar = ischar(snext,currentfont) + if not nextchar then + break + end + local krn = kerns[nextchar] + if not krn and marks[nextchar] then + prev = snext + snext = getnext(snext) + elseif not krn then + break + elseif step.format == "pair" then + local a, b = krn[1], krn[2] + if optimizekerns then + -- this permits a mixed table, but we could also decide to optimize this + -- in the loader and use format 'kern' + if not b and a[1] == 0 and a[2] == 0 and a[4] == 0 then + local k = setkern(snext,factor,rlmode,a[3],"injections") + if trace_kerns then + logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k) + end + return head, start, true + end + end + if a and #a > 0 then + local startchar = getchar(start) + local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,"injections") -- currentlookups flags? if trace_kerns then - logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k) + logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) end - return head, start, true end - end - if a and #a > 0 then - local startchar = getchar(start) - local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,"injections") -- currentlookups flags? - if trace_kerns then - logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + if b and #b > 0 then + local startchar = getchar(start) + local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,"injections") + if trace_kerns then + logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + end end - end - if b and #b > 0 then - local startchar = getchar(start) - local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,"injections") + return head, start, true + elseif krn ~= 0 then + local k = setkern(snext,factor,rlmode,krn) if trace_kerns then - logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + logprocess("%s: inserting kern %s between %s and %s",cref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar)) end + return head, start, true + else + break end - return head, start, true - elseif krn ~= 0 then - local k = setkern(snext,factor,rlmode,krn) - if trace_kerns then - logprocess("%s: inserting kern %s between %s and %s",cref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar)) - end - return head, start, true - else - break end end end @@ -1581,60 +1611,64 @@ function chainprocs.gpos_mark2base(head,start,stop,dataset,sequence,currentlooku if nofsteps > 1 then reportmoresteps(dataset,sequence) end - local markchar = getchar(start) - if marks[markchar] then - local markanchors = steps[1].coverage[markchar] -- always 1 step - if markanchors then - local base = getprev(start) -- [glyph] [start=mark] - if base then - local basechar = ischar(base,currentfont) - if basechar then - if marks[basechar] then - while base do - base = getprev(base) - if base then - local basechar = ischar(base,currentfont) - if basechar then - if not marks[basechar] then - break + if nofsteps == 0 then + reportzerosteps(dataset,sequence) + else + local markchar = getchar(start) + if marks[markchar] then + local markanchors = steps[1].coverage[markchar] -- always 1 step + if markanchors then + local base = getprev(start) -- [glyph] [start=mark] + if base then + local basechar = ischar(base,currentfont) + if basechar then + if marks[basechar] then + while base do + base = getprev(base) + if base then + local basechar = ischar(base,currentfont) + if basechar then + if not marks[basechar] then + break + end + else + if trace_bugs then + logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1) + end + return head, start, false end else if trace_bugs then - logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1) + logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2) end return head, start, false end - else - if trace_bugs then - logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2) - end - return head, start, false end end - end - local ba = markanchors[1][basechar] - if ba then - local ma = markanchors[2] - if ma then - local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)", - cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy) + local ba = markanchors[1][basechar] + if ba then + local ma = markanchors[2] + if ma then + local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks) + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)", + cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy) + end + return head, start, true end - return head, start, true end + elseif trace_bugs then + logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),1) end elseif trace_bugs then - logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),1) + logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),2) end elseif trace_bugs then - logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),2) + logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar)) end elseif trace_bugs then - logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar)) + logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar)) end - elseif trace_bugs then - logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar)) end return head, start, false end @@ -1645,64 +1679,68 @@ function chainprocs.gpos_mark2ligature(head,start,stop,dataset,sequence,currentl if nofsteps > 1 then reportmoresteps(dataset,sequence) end - local markchar = getchar(start) - if marks[markchar] then - local markanchors = steps[1].coverage[markchar] -- always 1 step - if markanchors then - local base = getprev(start) -- [glyph] [optional marks] [start=mark] - if base then - local basechar = ischar(base,currentfont) - if basechar then - if marks[basechar] then - while base do - base = getprev(base) - if base then - local basechar = ischar(base,currentfont) - if basechar then - if not marks[basechar] then - break + if nofsteps == 0 then + reportzerosteps(dataset,sequence) + else + local markchar = getchar(start) + if marks[markchar] then + local markanchors = steps[1].coverage[markchar] -- always 1 step + if markanchors then + local base = getprev(start) -- [glyph] [optional marks] [start=mark] + if base then + local basechar = ischar(base,currentfont) + if basechar then + if marks[basechar] then + while base do + base = getprev(base) + if base then + local basechar = ischar(base,currentfont) + if basechar then + if not marks[basechar] then + break + end + else + if trace_bugs then + logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,1) + end + return head, start, false end else if trace_bugs then - logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,1) + logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,2) end return head, start, false end - else - if trace_bugs then - logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,2) - end - return head, start, false end end - end - local ba = markanchors[1][basechar] - if ba then - local ma = markanchors[2] - if ma then - local index = getligaindex(start) - ba = ba[index] - if ba then - local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)", - cref(dataset,sequence),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy) + local ba = markanchors[1][basechar] + if ba then + local ma = markanchors[2] + if ma then + local index = getligaindex(start) + ba = ba[index] + if ba then + local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks) + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)", + cref(dataset,sequence),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy) + end + return head, start, true end - return head, start, true end end + elseif trace_bugs then + logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),1) end elseif trace_bugs then - logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),1) + logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),2) end elseif trace_bugs then - logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),2) + logwarning("%s, mark %s has no anchors",cref(dataset,sequence),gref(markchar)) end elseif trace_bugs then - logwarning("%s, mark %s has no anchors",cref(dataset,sequence),gref(markchar)) + logwarning("%s, mark %s is no mark",cref(dataset,sequence),gref(markchar)) end - elseif trace_bugs then - logwarning("%s, mark %s is no mark",cref(dataset,sequence),gref(markchar)) end return head, start, false end @@ -1713,48 +1751,52 @@ function chainprocs.gpos_mark2mark(head,start,stop,dataset,sequence,currentlooku if nofsteps > 1 then reportmoresteps(dataset,sequence) end - local markchar = getchar(start) - if marks[markchar] then - local markanchors = steps[1].coverage[markchar] -- always 1 step - if markanchors then - local base = getprev(start) -- [glyph] [basemark] [start=mark] - local slc = getligaindex(start) - if slc then -- a rather messy loop ... needs checking with husayni - while base do - local blc = getligaindex(base) - if blc and blc ~= slc then - base = getprev(base) - else - break + if nofsteps == 0 then + reportzerosteps(dataset,sequence) + else + local markchar = getchar(start) + if marks[markchar] then + local markanchors = steps[1].coverage[markchar] -- always 1 step + if markanchors then + local base = getprev(start) -- [glyph] [basemark] [start=mark] + local slc = getligaindex(start) + if slc then -- a rather messy loop ... needs checking with husayni + while base do + local blc = getligaindex(base) + if blc and blc ~= slc then + base = getprev(base) + else + break + end end end - end - if base then -- subtype test can go - local basechar = ischar(base,currentfont) - if basechar then - local ba = markanchors[1][basechar] - if ba then - local ma = markanchors[2] - if ma then - local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)", - cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy) + if base then -- subtype test can go + local basechar = ischar(base,currentfont) + if basechar then + local ba = markanchors[1][basechar] + if ba then + local ma = markanchors[2] + if ma then + local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks) + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)", + cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy) + end + return head, start, true end - return head, start, true end + elseif trace_bugs then + logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),1) end elseif trace_bugs then - logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),1) + logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),2) end elseif trace_bugs then - logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),2) + logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar)) end elseif trace_bugs then - logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar)) + logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar)) end - elseif trace_bugs then - logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar)) end return head, start, false end @@ -1765,45 +1807,49 @@ function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup, if nofsteps > 1 then reportmoresteps(dataset,sequence) end - local startchar = getchar(start) - local exitanchors = steps[1].coverage[startchar] -- always 1 step - if exitanchors then - if marks[startchar] then - if trace_cursive then - logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar)) - end - else - local nxt = getnext(start) - while nxt do - local nextchar = ischar(nxt,currentfont) - if not nextchar then - break - elseif marks[nextchar] then - -- should not happen (maybe warning) - nxt = getnext(nxt) - else - local exit = exitanchors[3] - if exit then - local entry = exitanchors[1][nextchar] - if entry then - entry = entry[2] + if nofsteps == 0 then + reportzerosteps(dataset,sequence) + else + local startchar = getchar(start) + local exitanchors = steps[1].coverage[startchar] -- always 1 step + if exitanchors then + if marks[startchar] then + if trace_cursive then + logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar)) + end + else + local nxt = getnext(start) + while nxt do + local nextchar = ischar(nxt,currentfont) + if not nextchar then + break + elseif marks[nextchar] then + -- should not happen (maybe warning) + nxt = getnext(nxt) + else + local exit = exitanchors[3] + if exit then + local entry = exitanchors[1][nextchar] if entry then - local dx, dy, bound = setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar]) - if trace_cursive then - logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode)) + entry = entry[2] + if entry then + local dx, dy, bound = setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar]) + if trace_cursive then + logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode)) + end + return head, start, true end - return head, start, true end + elseif trace_bugs then + onetimemessage(currentfont,startchar,"no entry anchors",report_fonts) end - elseif trace_bugs then - onetimemessage(currentfont,startchar,"no entry anchors",report_fonts) + break end - break end end + elseif trace_cursive and trace_details then + logprocess("%s, cursive %s is already done",pref(dataset,sequence),gref(getchar(start)),alreadydone) end - elseif trace_cursive and trace_details then - logprocess("%s, cursive %s is already done",pref(dataset,sequence),gref(getchar(start)),alreadydone) end return head, start, false end @@ -2794,6 +2840,24 @@ chainprocs.gsub_reversecontextchain = chained_contextchain chainprocs.gpos_contextchain = chained_contextchain chainprocs.gpos_context = chained_contextchain +-- experiment (needs no handler in font-otc so not now): +-- +-- function otf.registerchainproc(name,f) +-- -- chainprocs[name] = f +-- chainprocs[name] = function(head,start,stop,dataset,sequence,currentlookup,rlmode) +-- local done = currentlookup.nofsteps > 0 +-- if not done then +-- reportzerosteps(dataset,sequence) +-- else +-- head, start, done = f(head,start,stop,dataset,sequence,currentlookup,rlmode) +-- if not head or not start then +-- reportbadsteps(dataset,sequence) +-- end +-- end +-- return head, start, done +-- end +-- end + local missing = setmetatableindex("table") local function logprocess(...) diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf index 3327fca5f..f8d27c500 100644 Binary files a/tex/context/base/mkiv/status-files.pdf and b/tex/context/base/mkiv/status-files.pdf differ diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf index 4710e5c0d..a4f723e61 100644 Binary files a/tex/context/base/mkiv/status-lua.pdf and b/tex/context/base/mkiv/status-lua.pdf differ diff --git a/tex/context/base/mkiv/tabl-ntb.mkiv b/tex/context/base/mkiv/tabl-ntb.mkiv index c1805ada9..276f85d31 100644 --- a/tex/context/base/mkiv/tabl-ntb.mkiv +++ b/tex/context/base/mkiv/tabl-ntb.mkiv @@ -1313,7 +1313,8 @@ \dostoptagged} \unexpanded\def\tabl_ntb_span#1% - {\dorecurse{#1} + {\hskip\tabl_ntb_get_dis\c_tabl_ntb_col + \dorecurse{#1} {\hskip\tabl_ntb_get_wid\c_tabl_ntb_col\relax \global\advance\c_tabl_ntb_col\plusone}} diff --git a/tex/context/interface/mkiv/i-context.pdf b/tex/context/interface/mkiv/i-context.pdf index e24960fd7..53fbd8f72 100644 Binary files a/tex/context/interface/mkiv/i-context.pdf and b/tex/context/interface/mkiv/i-context.pdf differ diff --git a/tex/context/interface/mkiv/i-fonts.xml b/tex/context/interface/mkiv/i-fonts.xml index 46e8a0930..434d1f694 100644 --- a/tex/context/interface/mkiv/i-fonts.xml +++ b/tex/context/interface/mkiv/i-fonts.xml @@ -1665,4 +1665,10 @@ + + + + + + diff --git a/tex/context/interface/mkiv/i-readme.pdf b/tex/context/interface/mkiv/i-readme.pdf index a003f6f03..05309faec 100644 Binary files a/tex/context/interface/mkiv/i-readme.pdf and b/tex/context/interface/mkiv/i-readme.pdf differ diff --git a/tex/context/modules/mkiv/s-fonts-variable.lua b/tex/context/modules/mkiv/s-fonts-variable.lua index d507141e2..d50df0121 100644 --- a/tex/context/modules/mkiv/s-fonts-variable.lua +++ b/tex/context/modules/mkiv/s-fonts-variable.lua @@ -31,10 +31,14 @@ function moduledata.fonts.variable.showvariations(specification) local id, fontdata = fonts.definers.define { name = fontfile, - size = fontsize, + -- size = fontsize, cs = fontname, } + if not fontdata then + context("no font with name %a found",fontname) + end + local resources = fontdata.resources if not resources then diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index d5ea30f8b..93167c68b 100644 --- a/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,6 +1,6 @@ -- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua -- parent file : c:/data/develop/context/sources/luatex-fonts.lua --- merge date : 03/21/17 14:21:12 +-- merge date : 03/22/17 11:57:55 do -- begin closure to overcome local limits and interference @@ -20554,9 +20554,8 @@ local dir_code=nodecodes.dir local localpar_code=nodecodes.localpar local discretionary_code=disccodes.discretionary local ligature_code=glyphcodes.ligature -local privateattribute=attributes.private -local a_state=privateattribute('state') -local a_noligature=privateattribute("noligature") +local a_state=attributes.private('state') +local a_noligature=attributes.private("noligature") local injections=nodes.injections local setmark=injections.setmark local setcursive=injections.setcursive @@ -21341,6 +21340,9 @@ local function reversesub(head,start,stop,dataset,sequence,replacements,rlmode) end end chainprocs.reversesub=reversesub +local function reportzerosteps(dataset,sequence) + logwarning("%s: no steps",cref(dataset,sequence)) +end local function reportmoresteps(dataset,sequence) logwarning("%s: more than 1 step",cref(dataset,sequence)) end @@ -21350,30 +21352,34 @@ function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,c if nofsteps>1 then reportmoresteps(dataset,sequence) end - local current=start - local mapping=steps[1].coverage - while current do - local currentchar=ischar(current) - if currentchar then - local replacement=mapping[currentchar] - if not replacement or replacement=="" then - if trace_bugs then - logwarning("%s: no single for %s",cref(dataset,sequence,chainindex),gref(currentchar)) + if nofsteps==0 then + reportzerosteps(dataset,sequence) + else + local current=start + local mapping=steps[1].coverage + while current do + local currentchar=ischar(current) + if currentchar then + local replacement=mapping[currentchar] + if not replacement or replacement=="" then + if trace_bugs then + logwarning("%s: no single for %s",cref(dataset,sequence,chainindex),gref(currentchar)) + end + else + if trace_singles then + logprocess("%s: replacing single %s by %s",cref(dataset,sequence,chainindex),gref(currentchar),gref(replacement)) + end + resetinjection(current) + setchar(current,replacement) end + return head,start,true + elseif currentchar==false then + break + elseif current==stop then + break else - if trace_singles then - logprocess("%s: replacing single %s by %s",cref(dataset,sequence,chainindex),gref(currentchar),gref(replacement)) - end - resetinjection(current) - setchar(current,replacement) + current=getnext(current) end - return head,start,true - elseif currentchar==false then - break - elseif current==stop then - break - else - current=getnext(current) end end return head,start,false @@ -21384,17 +21390,21 @@ function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup if nofsteps>1 then reportmoresteps(dataset,sequence) end - local startchar=getchar(start) - local replacement=steps[1].coverage[startchar] - if not replacement or replacement=="" then - if trace_bugs then - logwarning("%s: no multiple for %s",cref(dataset,sequence),gref(startchar)) - end + if nofsteps==0 then + reportzerosteps(dataset,sequence) else - if trace_multiples then - logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement)) + local startchar=getchar(start) + local replacement=steps[1].coverage[startchar] + if not replacement or replacement=="" then + if trace_bugs then + logwarning("%s: no multiple for %s",cref(dataset,sequence),gref(startchar)) + end + else + if trace_multiples then + logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement)) + end + return multiple_glyphs(head,start,replacement,sequence.flags[1],dataset[1]) end - return multiple_glyphs(head,start,replacement,sequence.flags[1],dataset[1]) end return head,start,false end @@ -21404,36 +21414,40 @@ function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlooku if nofsteps>1 then reportmoresteps(dataset,sequence) end - local kind=dataset[4] - local what=dataset[1] - local value=what==true and tfmdata.shared.features[kind] or what - local current=start - local mapping=steps[1].coverage - while current do - local currentchar=ischar(current) - if currentchar then - local alternatives=mapping[currentchar] - if alternatives then - local choice,comment=get_alternative_glyph(current,alternatives,value) - if choice then - if trace_alternatives then - logprocess("%s: replacing %s by alternative %a to %s, %s",cref(dataset,sequence),gref(char),choice,gref(choice),comment) - end - resetinjection(start) - setchar(start,choice) - else - if trace_alternatives then - logwarning("%s: no variant %a for %s, %s",cref(dataset,sequence),value,gref(char),comment) + if nofsteps==0 then + reportzerosteps(dataset,sequence) + else + local kind=dataset[4] + local what=dataset[1] + local value=what==true and tfmdata.shared.features[kind] or what + local current=start + local mapping=steps[1].coverage + while current do + local currentchar=ischar(current) + if currentchar then + local alternatives=mapping[currentchar] + if alternatives then + local choice,comment=get_alternative_glyph(current,alternatives,value) + if choice then + if trace_alternatives then + logprocess("%s: replacing %s by alternative %a to %s, %s",cref(dataset,sequence),gref(char),choice,gref(choice),comment) + end + resetinjection(start) + setchar(start,choice) + else + if trace_alternatives then + logwarning("%s: no variant %a for %s, %s",cref(dataset,sequence),value,gref(char),comment) + end end end + return head,start,true + elseif currentchar==false then + break + elseif current==stop then + break + else + current=getnext(current) end - return head,start,true - elseif currentchar==false then - break - elseif current==stop then - break - else - current=getnext(current) end end return head,start,false @@ -21444,70 +21458,74 @@ function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup if nofsteps>1 then reportmoresteps(dataset,sequence) end - local startchar=getchar(start) - local ligatures=steps[1].coverage[startchar] - if not ligatures then - if trace_bugs then - logwarning("%s: no ligatures starting with %s",cref(dataset,sequence,chainindex),gref(startchar)) - end + if nofsteps==0 then + reportzerosteps(dataset,sequence) else - local current=getnext(start) - local discfound=false - local last=stop - local nofreplacements=1 - local skipmark=currentlookup.flags[1] - while current do - local id=getid(current) - if id==disc_code then - if not discfound then - discfound=current - end - if current==stop then - break - else - current=getnext(current) - end - else - local schar=getchar(current) - if skipmark and marks[schar] then + local startchar=getchar(start) + local ligatures=steps[1].coverage[startchar] + if not ligatures then + if trace_bugs then + logwarning("%s: no ligatures starting with %s",cref(dataset,sequence,chainindex),gref(startchar)) + end + else + local current=getnext(start) + local discfound=false + local last=stop + local nofreplacements=1 + local skipmark=currentlookup.flags[1] + while current do + local id=getid(current) + if id==disc_code then + if not discfound then + discfound=current + end + if current==stop then + break + else current=getnext(current) + end else - local lg=ligatures[schar] - if lg then - ligatures=lg - last=current - nofreplacements=nofreplacements+1 - if current==stop then - break - else + local schar=getchar(current) + if skipmark and marks[schar] then current=getnext(current) - end else - break + local lg=ligatures[schar] + if lg then + ligatures=lg + last=current + nofreplacements=nofreplacements+1 + if current==stop then + break + else + current=getnext(current) + end + else + break + end end end end - end - local ligature=ligatures.ligature - if ligature then - if chainindex then - stop=last - end - if trace_ligatures then + local ligature=ligatures.ligature + if ligature then + if chainindex then + stop=last + end + if trace_ligatures then + if start==stop then + logprocess("%s: replacing character %s by ligature %s case 3",cref(dataset,sequence,chainindex),gref(startchar),gref(ligature)) + else + logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)),gref(ligature)) + end + end + head,start=toligature(head,start,stop,ligature,dataset,sequence,skipmark,discfound) + return head,start,true,nofreplacements,discfound + elseif trace_bugs then if start==stop then - logprocess("%s: replacing character %s by ligature %s case 3",cref(dataset,sequence,chainindex),gref(startchar),gref(ligature)) + logwarning("%s: replacing character %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar)) else - logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)),gref(ligature)) + logwarning("%s: replacing character %s upto %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop))) end end - head,start=toligature(head,start,stop,ligature,dataset,sequence,skipmark,discfound) - return head,start,true,nofreplacements,discfound - elseif trace_bugs then - if start==stop then - logwarning("%s: replacing character %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar)) - else - logwarning("%s: replacing character %s upto %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop))) - end end end return head,start,false,0,false @@ -21518,19 +21536,23 @@ function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,r if nofsteps>1 then reportmoresteps(dataset,sequence) end - local startchar=getchar(start) - local step=steps[1] - local kerns=step.coverage[startchar] - if not kerns then - elseif step.format=="pair" then - local dx,dy,w,h=setpair(start,factor,rlmode,sequence.flags[4],kerns) - if trace_kerns then - logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),dx,dy,w,h) - end - else - local k=setkern(start,factor,rlmode,kerns,injection) - if trace_kerns then - logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k) + if nofsteps==0 then + reportzerosteps(dataset,sequence) + else + local startchar=getchar(start) + local step=steps[1] + local kerns=step.coverage[startchar] + if not kerns then + elseif step.format=="pair" then + local dx,dy,w,h=setpair(start,factor,rlmode,sequence.flags[4],kerns) + if trace_kerns then + logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),dx,dy,w,h) + end + else + local k=setkern(start,factor,rlmode,kerns,injection) + if trace_kerns then + logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k) + end end end return head,start,false @@ -21541,58 +21563,62 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm if nofsteps>1 then reportmoresteps(dataset,sequence) end - local snext=getnext(start) - if snext then - local startchar=getchar(start) - local step=steps[1] - local kerns=step.coverage[startchar] - if kerns then - local prev=start - while snext do - local nextchar=ischar(snext,currentfont) - if not nextchar then - break - end - local krn=kerns[nextchar] - if not krn and marks[nextchar] then - prev=snext - snext=getnext(snext) - elseif not krn then - break - elseif step.format=="pair" then - local a,b=krn[1],krn[2] - if optimizekerns then - if not b and a[1]==0 and a[2]==0 and a[4]==0 then - local k=setkern(snext,factor,rlmode,a[3],"injections") + if nofsteps==0 then + reportzerosteps(dataset,sequence) + else + local snext=getnext(start) + if snext then + local startchar=getchar(start) + local step=steps[1] + local kerns=step.coverage[startchar] + if kerns then + local prev=start + while snext do + local nextchar=ischar(snext,currentfont) + if not nextchar then + break + end + local krn=kerns[nextchar] + if not krn and marks[nextchar] then + prev=snext + snext=getnext(snext) + elseif not krn then + break + elseif step.format=="pair" then + local a,b=krn[1],krn[2] + if optimizekerns then + if not b and a[1]==0 and a[2]==0 and a[4]==0 then + local k=setkern(snext,factor,rlmode,a[3],"injections") + if trace_kerns then + logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k) + end + return head,start,true + end + end + if a and #a>0 then + local startchar=getchar(start) + local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,"injections") if trace_kerns then - logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k) + logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) end - return head,start,true end - end - if a and #a>0 then - local startchar=getchar(start) - local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,"injections") - if trace_kerns then - logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + if b and #b>0 then + local startchar=getchar(start) + local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,"injections") + if trace_kerns then + logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + end end - end - if b and #b>0 then - local startchar=getchar(start) - local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,"injections") + return head,start,true + elseif krn~=0 then + local k=setkern(snext,factor,rlmode,krn) if trace_kerns then - logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + logprocess("%s: inserting kern %s between %s and %s",cref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar)) end + return head,start,true + else + break end - return head,start,true - elseif krn~=0 then - local k=setkern(snext,factor,rlmode,krn) - if trace_kerns then - logprocess("%s: inserting kern %s between %s and %s",cref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar)) - end - return head,start,true - else - break end end end @@ -21605,60 +21631,64 @@ function chainprocs.gpos_mark2base(head,start,stop,dataset,sequence,currentlooku if nofsteps>1 then reportmoresteps(dataset,sequence) end - local markchar=getchar(start) - if marks[markchar] then - local markanchors=steps[1].coverage[markchar] - if markanchors then - local base=getprev(start) - if base then - local basechar=ischar(base,currentfont) - if basechar then - if marks[basechar] then - while base do - base=getprev(base) - if base then - local basechar=ischar(base,currentfont) - if basechar then - if not marks[basechar] then - break + if nofsteps==0 then + reportzerosteps(dataset,sequence) + else + local markchar=getchar(start) + if marks[markchar] then + local markanchors=steps[1].coverage[markchar] + if markanchors then + local base=getprev(start) + if base then + local basechar=ischar(base,currentfont) + if basechar then + if marks[basechar] then + while base do + base=getprev(base) + if base then + local basechar=ischar(base,currentfont) + if basechar then + if not marks[basechar] then + break + end + else + if trace_bugs then + logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1) + end + return head,start,false end else if trace_bugs then - logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1) + logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2) end return head,start,false end - else - if trace_bugs then - logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2) - end - return head,start,false end end - end - local ba=markanchors[1][basechar] - if ba then - local ma=markanchors[2] - if ma then - local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)", - cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy) + local ba=markanchors[1][basechar] + if ba then + local ma=markanchors[2] + if ma then + local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks) + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)", + cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy) + end + return head,start,true end - return head,start,true end + elseif trace_bugs then + logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),1) end elseif trace_bugs then - logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),1) + logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),2) end elseif trace_bugs then - logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),2) + logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar)) end elseif trace_bugs then - logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar)) + logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar)) end - elseif trace_bugs then - logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar)) end return head,start,false end @@ -21668,64 +21698,68 @@ function chainprocs.gpos_mark2ligature(head,start,stop,dataset,sequence,currentl if nofsteps>1 then reportmoresteps(dataset,sequence) end - local markchar=getchar(start) - if marks[markchar] then - local markanchors=steps[1].coverage[markchar] - if markanchors then - local base=getprev(start) - if base then - local basechar=ischar(base,currentfont) - if basechar then - if marks[basechar] then - while base do - base=getprev(base) - if base then - local basechar=ischar(base,currentfont) - if basechar then - if not marks[basechar] then - break + if nofsteps==0 then + reportzerosteps(dataset,sequence) + else + local markchar=getchar(start) + if marks[markchar] then + local markanchors=steps[1].coverage[markchar] + if markanchors then + local base=getprev(start) + if base then + local basechar=ischar(base,currentfont) + if basechar then + if marks[basechar] then + while base do + base=getprev(base) + if base then + local basechar=ischar(base,currentfont) + if basechar then + if not marks[basechar] then + break + end + else + if trace_bugs then + logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,1) + end + return head,start,false end else if trace_bugs then - logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,1) + logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,2) end return head,start,false end - else - if trace_bugs then - logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,2) - end - return head,start,false end end - end - local ba=markanchors[1][basechar] - if ba then - local ma=markanchors[2] - if ma then - local index=getligaindex(start) - ba=ba[index] - if ba then - local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)", - cref(dataset,sequence),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy) + local ba=markanchors[1][basechar] + if ba then + local ma=markanchors[2] + if ma then + local index=getligaindex(start) + ba=ba[index] + if ba then + local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks) + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)", + cref(dataset,sequence),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy) + end + return head,start,true end - return head,start,true end end + elseif trace_bugs then + logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),1) end elseif trace_bugs then - logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),1) + logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),2) end elseif trace_bugs then - logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),2) + logwarning("%s, mark %s has no anchors",cref(dataset,sequence),gref(markchar)) end elseif trace_bugs then - logwarning("%s, mark %s has no anchors",cref(dataset,sequence),gref(markchar)) + logwarning("%s, mark %s is no mark",cref(dataset,sequence),gref(markchar)) end - elseif trace_bugs then - logwarning("%s, mark %s is no mark",cref(dataset,sequence),gref(markchar)) end return head,start,false end @@ -21735,48 +21769,52 @@ function chainprocs.gpos_mark2mark(head,start,stop,dataset,sequence,currentlooku if nofsteps>1 then reportmoresteps(dataset,sequence) end - local markchar=getchar(start) - if marks[markchar] then - local markanchors=steps[1].coverage[markchar] - if markanchors then - local base=getprev(start) - local slc=getligaindex(start) - if slc then - while base do - local blc=getligaindex(base) - if blc and blc~=slc then - base=getprev(base) - else - break + if nofsteps==0 then + reportzerosteps(dataset,sequence) + else + local markchar=getchar(start) + if marks[markchar] then + local markanchors=steps[1].coverage[markchar] + if markanchors then + local base=getprev(start) + local slc=getligaindex(start) + if slc then + while base do + local blc=getligaindex(base) + if blc and blc~=slc then + base=getprev(base) + else + break + end end end - end - if base then - local basechar=ischar(base,currentfont) - if basechar then - local ba=markanchors[1][basechar] - if ba then - local ma=markanchors[2] - if ma then - local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)", - cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy) + if base then + local basechar=ischar(base,currentfont) + if basechar then + local ba=markanchors[1][basechar] + if ba then + local ma=markanchors[2] + if ma then + local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks) + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)", + cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy) + end + return head,start,true end - return head,start,true end + elseif trace_bugs then + logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),1) end elseif trace_bugs then - logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),1) + logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),2) end elseif trace_bugs then - logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),2) + logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar)) end elseif trace_bugs then - logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar)) + logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar)) end - elseif trace_bugs then - logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar)) end return head,start,false end @@ -21786,44 +21824,48 @@ function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup, if nofsteps>1 then reportmoresteps(dataset,sequence) end - local startchar=getchar(start) - local exitanchors=steps[1].coverage[startchar] - if exitanchors then - if marks[startchar] then - if trace_cursive then - logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar)) - end - else - local nxt=getnext(start) - while nxt do - local nextchar=ischar(nxt,currentfont) - if not nextchar then - break - elseif marks[nextchar] then - nxt=getnext(nxt) - else - local exit=exitanchors[3] - if exit then - local entry=exitanchors[1][nextchar] - if entry then - entry=entry[2] + if nofsteps==0 then + reportzerosteps(dataset,sequence) + else + local startchar=getchar(start) + local exitanchors=steps[1].coverage[startchar] + if exitanchors then + if marks[startchar] then + if trace_cursive then + logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar)) + end + else + local nxt=getnext(start) + while nxt do + local nextchar=ischar(nxt,currentfont) + if not nextchar then + break + elseif marks[nextchar] then + nxt=getnext(nxt) + else + local exit=exitanchors[3] + if exit then + local entry=exitanchors[1][nextchar] if entry then - local dx,dy,bound=setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar]) - if trace_cursive then - logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode)) + entry=entry[2] + if entry then + local dx,dy,bound=setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar]) + if trace_cursive then + logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode)) + end + return head,start,true end - return head,start,true end + elseif trace_bugs then + onetimemessage(currentfont,startchar,"no entry anchors",report_fonts) end - elseif trace_bugs then - onetimemessage(currentfont,startchar,"no entry anchors",report_fonts) + break end - break end end + elseif trace_cursive and trace_details then + logprocess("%s, cursive %s is already done",pref(dataset,sequence),gref(getchar(start)),alreadydone) end - elseif trace_cursive and trace_details then - logprocess("%s, cursive %s is already done",pref(dataset,sequence),gref(getchar(start)),alreadydone) end return head,start,false end @@ -26104,7 +26146,8 @@ if not modules then modules={} end modules ['font-otc']={ local format,insert,sortedkeys,tohash=string.format,table.insert,table.sortedkeys,table.tohash local type,next=type,next local lpegmatch=lpeg.match -local utfbyte,utflen=utf.byte,utf.len +local utfbyte,utflen,utfsplit=utf.byte,utf.len,utf.split +local settings_to_array=utilities.parsers.settings_to_array local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end) local report_otf=logs.reporter("fonts","otf loading") local fonts=fonts @@ -26295,7 +26338,7 @@ local function addfeature(data,feature,specifications) local r={} for i=1,#replacement do local u=tounicode(replacement[i]) - r[i]=descriptions[u] and u or unicode + r[i]=(nocheck or descriptions[u]) and u or unicode end cover(coverage,unicode,r) done=done+1 @@ -26323,7 +26366,7 @@ local function addfeature(data,feature,specifications) local r,n={},0 for i=1,#replacement do local u=tounicode(replacement[i]) - if descriptions[u] then + if nocheck or descriptions[u] then n=n+1 r[n]=u end @@ -26362,7 +26405,7 @@ local function addfeature(data,feature,specifications) for i=1,#ligature do local l=ligature[i] local u=tounicode(l) - if descriptions[u] then + if nocheck or descriptions[u] then ligature[i]=u else present=false @@ -26497,13 +26540,20 @@ local function addfeature(data,feature,specifications) local subtype=nil if lookups and sublookups then for k,v in next,lookups do - local lookup=sublookups[v] - if lookup then - lookups[k]=lookup - if not subtype then - subtype=lookup.type + local t=type(v) + if t=="table" then + elseif t=="number" then + local lookup=sublookups[v] + if lookup then + lookups[k]=lookup + if not subtype then + subtype=lookup.type + end + else + lookups[k]=false end else + lookups[k]=false end end end @@ -26579,7 +26629,7 @@ local function addfeature(data,feature,specifications) if f then for k in next,f do if k==position then - index=i + index=i break end end @@ -26626,6 +26676,7 @@ local function addfeature(data,feature,specifications) local featuretype=normalized[specification.type or "substitution"] or "substitution" local featureflags=specification.flags or noflags local nocheck=specification.nocheck + local futuresteps=specification.futuresteps local featureorder=specification.order or { feature } local featurechain=(featuretype=="chainsubstitution" or featuretype=="chainposition") and 1 or 0 local nofsteps=0 @@ -26668,6 +26719,7 @@ local function addfeature(data,feature,specifications) s[i]={ [stepkey]=steps, nofsteps=nofsteps, + flags=featureflags, type=types[featuretype], } end @@ -26775,10 +26827,13 @@ function otf.addfeature(name,specification) specification,name=validspecification(specification,name) if name and specification then local slot=knownfeatures[name] - if slot then - else + if not slot then + slot=#extrafeatures+1 + knownfeatures[name]=slot + elseif specification.overload==false then slot=#extrafeatures+1 knownfeatures[name]=slot + else end specification.name=name extrafeatures[slot]=specification @@ -26884,6 +26939,77 @@ registerotffeature { name='anum', description='arabic digits', } +local lookups={} +local protect={} +local revert={} +local zwj={ 0x200C } +otf.addfeature { + name="blockligatures", + type="chainsubstitution", + nocheck=true, + prepend=true, + future=true, + lookups={ + { + type="multiple", + data=lookups, + }, + }, + data={ + rules=protect, + } +} +otf.addfeature { + name="blockligatures", + type="chainsubstitution", + nocheck=true, + append=true, + overload=false, + lookups={ + { + type="ligature", + data=lookups, + }, + }, + data={ + rules=revert, + } +} +registerotffeature { + name='blockligatures', + description='block certain ligatures', +} +local function blockligatures(str) + local t=settings_to_array(str) + for i=1,#t do + local ti=utfsplit(t[i]) + if #ti>1 then + local one=ti[1] + local two=ti[2] + lookups[one]={ one,0x200C } + local one={ one } + local two={ two } + local new=#protect+1 + protect[new]={ + current={ one,two }, + lookups={ 1 }, + } + revert[new]={ + current={ one,zwj }, + after={ two }, + lookups={ 1 }, + } + end + end +end +otf.helpers.blockligatures=blockligatures +if context then + interfaces.implement { + name="blockligatures", + arguments="string", + actions=blockligatures, + } +end end -- closure -- cgit v1.2.3