diff options
24 files changed, 2121 insertions, 535 deletions
diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv index fb713cf57..0d629b2fb 100644 --- a/tex/context/base/cont-new.mkiv +++ b/tex/context/base/cont-new.mkiv @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2015.09.01 11:10} +\newcontextversion{2015.09.04 11:00} %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/context-version.pdf b/tex/context/base/context-version.pdf Binary files differindex b2d52084f..5340fc16b 100644 --- a/tex/context/base/context-version.pdf +++ b/tex/context/base/context-version.pdf diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv index 31e02d6e5..4a84d5af8 100644 --- a/tex/context/base/context.mkiv +++ b/tex/context/base/context.mkiv @@ -39,7 +39,7 @@ %D up and the dependencies are more consistent. \edef\contextformat {\jobname} -\edef\contextversion{2015.09.01 11:10} +\edef\contextversion{2015.09.04 11:00} \edef\contextkind {beta} %D For those who want to use this: @@ -207,7 +207,7 @@ \loadmarkfile{hand-ini} \loadmarkfile{lang-ini} -\loadmarkfile{lang-hyp} +\loadmarkfile{lang-hyp} % also loads dis \loadmarkfile{lang-lab} \loadmarkfile{unic-ini} @@ -365,7 +365,7 @@ \loadmarkfile{char-enc} % will move up -\loadmkvifile{font-lib} % way too late +\loadmkvifile{font-lib} % way too late but after language \loadmkvifile{font-fil} \loadmkvifile{font-var} \loadmkvifile{font-fea} diff --git a/tex/context/base/font-aux.lua b/tex/context/base/font-aux.lua index 2a605d224..fc6c90bc1 100644 --- a/tex/context/base/font-aux.lua +++ b/tex/context/base/font-aux.lua @@ -11,6 +11,11 @@ local tonumber, type = tonumber, type local fonts, font = fonts, font +local fonts = fonts +local handlers = fonts.handlers +local otf = handlers.otf -- brrr +local afm = handlers.afm -- brrr + local iterators = { } fonts.iterators = iterators @@ -163,3 +168,74 @@ function iterators.glyphs(data) return dummy end end + +-- for the moment here, it might move to some other file later + +function afm.getkern(tfmdata,left,right) + local c = tfmdata.characters[left] + if c then + local kerns = c.kerns + if kerns then + return kerns[right] -- already scaled + end + end + return 0 +end + +local getters = { -- maybe better getters[format][...] + kern = { + ["type1"] = afm.getkern, + ["opentype"] = otf.getkern, + }, + substitution = { + ["opentype"] = otf.getsubstitution, + }, + alternate = { + ["opentype"] = otf.getalternate, + }, + multiple = { + ["opentype"] = otf.getmultiple, + } +} + +fonts.getters = getters + +function fonts.getkern(tfmdata,left,right) + local format = tfmdata.properties.format + local getter = getters.kern[format] + if getter then + return getter(tfmdata,left,right) + else + return 0 + end +end + +function fonts.getsubstitution(tfmdata,k,kind) + local format = tfmdata.properties.format + local getter = getters.substitution[format] + if getter then + return getter(tfmdata,k,kind,value) + else + return 0 + end +end + +function fonts.getalternate(tfmdata,k,kind,value) + local format = tfmdata.properties.format + local getter = getters.substitution[format] + if getter then + return getter(tfmdata,k,kind,value) + else + return 0 + end +end + +function fonts.getmultiple(tfmdata,k,kind) + local format = tfmdata.properties.format + local getter = getters.substitution[format] + if getter then + return getter(tfmdata,k,kind,value) + else + return 0 + end +end diff --git a/tex/context/base/font-ctx.lua b/tex/context/base/font-ctx.lua index ca9a83086..4dd75b480 100644 --- a/tex/context/base/font-ctx.lua +++ b/tex/context/base/font-ctx.lua @@ -50,6 +50,7 @@ local implement = interfaces.implement local fonts = fonts local handlers = fonts.handlers local otf = handlers.otf -- brrr +----- afm = handlers.afm -- brrr local names = fonts.names local definers = fonts.definers local specifiers = fonts.specifiers @@ -1366,14 +1367,14 @@ function constructors.calculatescale(tfmdata,scaledpoints,relativeid,specificati if special then -- we also have available specification.textsize local parameters = tfmdata.parameters - local designsize = parameters.designsize + -- local designsize = parameters.designsize if special == "ht" then --- inspect(parameters) - local height = parameters.ascender * designsize / parameters.units - scaledpoints = (scaledpoints/height) * designsize + local height = parameters.ascender / parameters.units + scaledpoints = scaledpoints / height elseif special == "cp" then - local height = (tfmdata.descriptions[utf.byte("X")].height or parameters.ascender) * designsize / parameters.units - scaledpoints = (scaledpoints/height) * designsize + local glyph = tfmdata.descriptions[utfbyte("X")] + local height = (glyph and glyph.height or parameters.ascender) / parameters.units + scaledpoints = scaledpoints / height end end end diff --git a/tex/context/base/font-dsp.lua b/tex/context/base/font-dsp.lua index 8cdd645c8..148889020 100644 --- a/tex/context/base/font-dsp.lua +++ b/tex/context/base/font-dsp.lua @@ -1745,6 +1745,7 @@ do }, nofsteps = 1, type = "gpos_pair", + -- type = "gpos_single", -- maybe better flags = { false, false, false, false }, order = { name }, features = { [name] = feature }, diff --git a/tex/context/base/font-inj.lua b/tex/context/base/font-inj.lua index cdf14b935..da1364d9d 100644 --- a/tex/context/base/font-inj.lua +++ b/tex/context/base/font-inj.lua @@ -204,7 +204,10 @@ function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmne end function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2lflag & tfmchr not used - local x, y, w, h = factor*spec[1], factor*spec[2], factor*spec[3], factor*spec[4] + local x = factor*spec[1] + local y = factor*spec[2] + local w = factor*spec[3] + local h = factor*spec[4] if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then -- okay? local yoffset = y - h local leftkern = x -- both kerns are set in a pair kern compared @@ -549,9 +552,19 @@ local function inject_marks(marks,marki,nofmarks) else -- kern(x) glyph(p) kern(w-x) mark(n) -- ox = px - getfield(p,"width") + pn.markx - pp.leftkern - local leftkern = pp.leftkern - if leftkern then - ox = px - pn.markx - leftkern + -- + -- According to Kai we don't need to handle leftkern here but I'm + -- pretty sure I've run into a case where it was needed so maybe + -- some day we need something more clever here. + -- + if false then + -- a mark with kerning + local leftkern = pp.leftkern + if leftkern then + ox = px - pn.markx - leftkern + else + ox = px - pn.markx + end else ox = px - pn.markx end @@ -714,7 +727,7 @@ local function inject_kerns(head,glist,ilist,length) -- not complete ! compare w if leftkern and leftkern ~= 0 then local t = find_tail(dp) insert_node_after(dp,t,newkern(leftkern)) -setfield(p,"post",dp) -- currently we need to force a tail refresh + setfield(p,"post",dp) -- currently we need to force a tail refresh end end end @@ -725,7 +738,7 @@ setfield(p,"post",dp) -- currently we need to force a tail refresh if leftkern and leftkern ~= 0 then local t = find_tail(dr) insert_node_after(dr,t,newkern(leftkern)) -setfield(p,"replace",dr) -- currently we need to force a tail refresh + setfield(p,"replace",dr) -- currently we need to force a tail refresh end end else @@ -788,7 +801,7 @@ local function inject_kerns_only(head,where) trace(head,"kerns") end local n = head - local p = nil + local p = nil -- disc node when non-nil while n do local id = getid(n) if id == glyph_code then @@ -804,7 +817,7 @@ local function inject_kerns_only(head,where) if leftkern and leftkern ~= 0 then local t = find_tail(d) insert_node_after(d,t,newkern(leftkern)) -setfield(p,"post",d) -- currently we need to force a tail refresh + setfield(p,"post",d) -- currently we need to force a tail refresh end end end @@ -816,7 +829,7 @@ setfield(p,"post",d) -- currently we need to force a tail refresh if leftkern and leftkern ~= 0 then local t = find_tail(d) insert_node_after(d,t,newkern(leftkern)) -setfield(p,"replace",d) -- currently we need to force a tail refresh + setfield(p,"replace",d) -- currently we need to force a tail refresh end end else @@ -829,6 +842,7 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh end end else + -- this is the most common case local i = rawget(pn,"injections") if i then local leftkern = i.leftkern @@ -838,8 +852,6 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh end end end - else - break end p = nil elseif id == disc_code then @@ -866,7 +878,6 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh setfield(n,"pre",h) end end - -- weird local d = getfield(n,"post") if d then local h = d @@ -895,7 +906,7 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh local h = d for n in traverse_id(glyph_code,d) do if getsubtype(n) < 256 then - local pn = rawget(properties,n) -- why can it be empty { } + local pn = rawget(properties,n) if pn then local i = rawget(pn,"replaceinjections") if i then @@ -933,7 +944,6 @@ local function inject_pairs_only(head,where) if trace_injections then trace(head,"pairs") end - -- local n = head local p = nil -- disc node when non-nil while n do @@ -951,7 +961,7 @@ local function inject_pairs_only(head,where) if leftkern and leftkern ~= 0 then local t = find_tail(d) insert_node_after(d,t,newkern(leftkern)) -setfield(p,"post",d) -- currently we need to force a tail refresh + setfield(p,"post",d) -- currently we need to force a tail refresh end -- local rightkern = i.rightkern -- if rightkern and rightkern ~= 0 then @@ -968,7 +978,7 @@ setfield(p,"post",d) -- currently we need to force a tail refresh if leftkern and leftkern ~= 0 then local t = find_tail(d) insert_node_after(d,t,newkern(leftkern)) -setfield(p,"replace",d) -- currently we need to force a tail refresh + setfield(p,"replace",d) -- currently we need to force a tail refresh end -- local rightkern = i.rightkern -- if rightkern and rightkern ~= 0 then @@ -994,24 +1004,22 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh -- this is the most common case local i = rawget(pn,"injections") if i then - local yoffset = i.yoffset - if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) - end local leftkern = i.leftkern if leftkern and leftkern ~= 0 then - insert_node_before(head,n,newkern(leftkern)) + head = insert_node_before(head,n,newkern(leftkern)) end local rightkern = i.rightkern if rightkern and rightkern ~= 0 then insert_node_after(head,n,newkern(rightkern)) n = getnext(n) -- to be checked end + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end end end end - else - break end p = nil elseif id == disc_code then @@ -1020,16 +1028,12 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh local h = d for n in traverse_id(glyph_code,d) do if getsubtype(n) < 256 then - local p = rawget(properties,n) - if p then - local i = rawget(p,"preinjections") + local pn = rawget(properties,n) + if pn then + local i = rawget(pn,"preinjections") if i then - local yoffset = i.yoffset - if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) - end local leftkern = i.leftkern - if leftkern ~= 0 then + if leftkern and leftkern ~= 0 then h = insert_node_before(h,n,newkern(leftkern)) end local rightkern = i.rightkern @@ -1037,6 +1041,10 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh insert_node_after(head,n,newkern(rightkern)) n = getnext(n) -- to be checked end + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end end end else @@ -1052,14 +1060,10 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh local h = d for n in traverse_id(glyph_code,d) do if getsubtype(n) < 256 then - local p = rawget(properties,n) - if p then - local i = rawget(p,"postinjections") + local pn = rawget(properties,n) + if pn then + local i = rawget(pn,"postinjections") if i then - local yoffset = i.yoffset - if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) - end local leftkern = i.leftkern if leftkern and leftkern ~= 0 then h = insert_node_before(h,n,newkern(leftkern)) @@ -1069,6 +1073,10 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh insert_node_after(head,n,newkern(rightkern)) n = getnext(n) -- to be checked end + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end end end else @@ -1084,14 +1092,10 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh local h = d for n in traverse_id(glyph_code,d) do if getsubtype(n) < 256 then - local p = rawget(properties,n) - if p then - local i = rawget(p,"replaceinjections") + local pn = rawget(properties,n) + if pn then + local i = rawget(pn,"replaceinjections") if i then - local yoffset = i.yoffset - if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) - end local leftkern = i.leftkern if leftkern and leftkern ~= 0 then h = insert_node_before(h,n,newkern(leftkern)) @@ -1101,6 +1105,10 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh insert_node_after(head,n,newkern(rightkern)) n = getnext(n) -- to be checked end + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end end end else diff --git a/tex/context/base/font-nod.lua b/tex/context/base/font-nod.lua index e2000be7e..8d199f868 100644 --- a/tex/context/base/font-nod.lua +++ b/tex/context/base/font-nod.lua @@ -184,6 +184,7 @@ function char_tracers.string(t) end local f_unicode = formatters["%U"] +local f_badcode = formatters["{%i}"] function char_tracers.unicodes(t,decimal) local tt = { } @@ -489,30 +490,35 @@ local function toutf(list,result,nofresult,stopcriterium) result, nofresult = toutf(components,result,nofresult) else local c = getchar(n) - local fc = fontcharacters[getfont(n)] - if fc then - local fcc = fc[c] - if fcc then - local u = fcc.unicode - if not u then - nofresult = nofresult + 1 - result[nofresult] = utfchar(c) - elseif type(u) == "table" then - for i=1,#u do + if c > 0 then + local fc = fontcharacters[getfont(n)] + if fc then + local fcc = fc[c] + if fcc then + local u = fcc.unicode + if not u then nofresult = nofresult + 1 - result[nofresult] = utfchar(u[i]) + result[nofresult] = utfchar(c) + elseif type(u) == "table" then + for i=1,#u do + nofresult = nofresult + 1 + result[nofresult] = utfchar(u[i]) + end + else + nofresult = nofresult + 1 + result[nofresult] = utfchar(u) end else nofresult = nofresult + 1 - result[nofresult] = utfchar(u) + result[nofresult] = utfchar(c) end else nofresult = nofresult + 1 - result[nofresult] = utfchar(c) + result[nofresult] = f_unicode(c) end else nofresult = nofresult + 1 - result[nofresult] = f_unicode(c) + result[nofresult] = f_badcode(c) end end elseif id == disc_code then diff --git a/tex/context/base/font-otf.lua b/tex/context/base/font-otf.lua index 79d3ac60d..851a25cca 100644 --- a/tex/context/base/font-otf.lua +++ b/tex/context/base/font-otf.lua @@ -2997,3 +2997,20 @@ function otf.getmultiple(tfmdata,k,kind) end return { k } end + +function otf.getkern(tfmdata,left,right,kind) + local kerns = getgsub(tfmdata,left,kind or "kern",true) -- for now we use getsub + if kerns then + local found = kerns[right] + local kind = type(found) + if kind == "table" then + found = found[1][3] -- can be more clever + elseif kind ~= "number" then + found = false + end + if found then + return found * tfmdata.parameters.factor + end + end + return 0 +end diff --git a/tex/context/base/font-otj.lua b/tex/context/base/font-otj.lua new file mode 100644 index 000000000..a8069b2dc --- /dev/null +++ b/tex/context/base/font-otj.lua @@ -0,0 +1,1286 @@ +if not modules then modules = { } end modules ['font-otj'] = { + version = 1.001, + comment = "companion to font-lib.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", +} + +-- This property based variant is not faster but looks nicer than the attribute one. We +-- need to use rawget (which is apbout 4 times slower than a direct access but we cannot +-- get/set that one for our purpose! This version does a bit more with discretionaries +-- (and Kai has tested it with his collection of weird fonts.) + +-- There is some duplicate code here (especially in the the pre/post/replace branches) but +-- we go for speed. We could store a list of glyph and mark nodes when registering but it's +-- cleaner to have an identification pass here. Also, I need to keep tracing in mind so +-- being too clever here is dangerous. + +-- The subtype test is not needed as there will be no (new) properties set, given that we +-- reset the properties. + +if not nodes.properties then return end + +local next, rawget = next, rawget +local utfchar = utf.char +local fastcopy = table.fastcopy + +local trace_injections = false trackers.register("fonts.injections", function(v) trace_injections = v end) + +local report_injections = logs.reporter("fonts","injections") + +local attributes, nodes, node = attributes, nodes, node + +fonts = fonts +local fontdata = fonts.hashes.identifiers + +nodes.injections = nodes.injections or { } +local injections = nodes.injections + +local nodecodes = nodes.nodecodes +local glyph_code = nodecodes.glyph +local disc_code = nodecodes.disc +local kern_code = nodecodes.kern + +local nuts = nodes.nuts +local nodepool = nuts.pool + +local newkern = nodepool.kern + +local tonode = nuts.tonode +local tonut = nuts.tonut + +local getfield = nuts.getfield +local setfield = nuts.setfield +local getnext = nuts.getnext +local getprev = nuts.getprev +local getid = nuts.getid +local getfont = nuts.getfont +local getsubtype = nuts.getsubtype +local getchar = nuts.getchar + +local traverse_id = nuts.traverse_id +local insert_node_before = nuts.insert_before +local insert_node_after = nuts.insert_after +local find_tail = nuts.tail + +local properties = nodes.properties.data + +function injections.installnewkern(nk) + newkern = nk or newkern +end + +local nofregisteredkerns = 0 +local nofregisteredpairs = 0 +local nofregisteredmarks = 0 +local nofregisteredcursives = 0 +local keepregisteredcounts = false + +function injections.keepcounts() + keepregisteredcounts = true +end + +function injections.resetcounts() + nofregisteredkerns = 0 + nofregisteredpairs = 0 + nofregisteredmarks = 0 + nofregisteredcursives = 0 + keepregisteredcounts = false +end + +-- We need to make sure that a possible metatable will not kick in unexpectedly. + +function injections.reset(n) + local p = rawget(properties,n) + if p and rawget(p,"injections") then + p.injections = nil + end +end + +function injections.copy(target,source) + local sp = rawget(properties,source) + if sp then + local tp = rawget(properties,target) + local si = rawget(sp,"injections") + if si then + si = fastcopy(si) + if tp then + tp.injections = si + else + propertydata[target] = { + injections = si, + } + end + else + if tp then + tp.injections = nil + end + end + end +end + +function injections.setligaindex(n,index) + local p = rawget(properties,n) + if p then + local i = rawget(p,"injections") + if i then + i.ligaindex = index + else + p.injections = { + ligaindex = index + } + end + else + properties[n] = { + injections = { + ligaindex = index + } + } + end +end + +function injections.getligaindex(n,default) + local p = rawget(properties,n) + if p then + local i = rawget(p,"injections") + if i then + return i.ligaindex or default + end + end + return default +end + +function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext) -- hm: nuts or nodes + local dx = factor*(exit[1]-entry[1]) + local dy = -factor*(exit[2]-entry[2]) + local ws = tfmstart.width + local wn = tfmnext.width + nofregisteredcursives = nofregisteredcursives + 1 + if rlmode < 0 then + dx = -(dx + wn) + else + dx = dx - ws + end + -- + local p = rawget(properties,start) + if p then + local i = rawget(p,"injections") + if i then + i.cursiveanchor = true + else + p.injections = { + cursiveanchor = true, + } + end + else + properties[start] = { + injections = { + cursiveanchor = true, + }, + } + end + local p = rawget(properties,nxt) + if p then + local i = rawget(p,"injections") + if i then + i.cursivex = dx + i.cursivey = dy + else + p.injections = { + cursivex = dx, + cursivey = dy, + } + end + else + properties[nxt] = { + injections = { + cursivex = dx, + cursivey = dy, + }, + } + end + return dx, dy, nofregisteredcursives +end + +function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2lflag & tfmchr not used + local x = factor*spec[1] + local y = factor*spec[2] + local w = factor*spec[3] + local h = factor*spec[4] + if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then -- okay? + local yoffset = y - h + local leftkern = x -- both kerns are set in a pair kern compared + local rightkern = w - x -- to normal kerns where we set only leftkern + if leftkern ~= 0 or rightkern ~= 0 or yoffset ~= 0 then + nofregisteredpairs = nofregisteredpairs + 1 + if rlmode and rlmode < 0 then + leftkern, rightkern = rightkern, leftkern + end + if not injection then + injection = "injections" + end + local p = rawget(properties,current) + if p then + local i = rawget(p,injection) + if i then + if leftkern ~= 0 then + i.leftkern = (i.leftkern or 0) + leftkern + end + if rightkern ~= 0 then + i.rightkern = (i.rightkern or 0) + rightkern + end + if yoffset ~= 0 then + i.yoffset = (i.yoffset or 0) + yoffset + end + elseif leftkern ~= 0 or rightkern ~= 0 then + p[injection] = { + leftkern = leftkern, + rightkern = rightkern, + yoffset = yoffset, + } + else + p[injection] = { + yoffset = yoffset, + } + end + elseif leftkern ~= 0 or rightkern ~= 0 then + properties[current] = { + [injection] = { + leftkern = leftkern, + rightkern = rightkern, + yoffset = yoffset, + }, + } + else + properties[current] = { + [injection] = { + yoffset = yoffset, + }, + } + end + return x, y, w, h, nofregisteredpairs + end + end + return x, y, w, h -- no bound +end + +-- This needs checking for rl < 0 but it is unlikely that a r2l script uses kernclasses between +-- glyphs so we're probably safe (KE has a problematic font where marks interfere with rl < 0 in +-- the previous case) + +function injections.setkern(current,factor,rlmode,x,injection) + local dx = factor * x + if dx ~= 0 then + nofregisteredkerns = nofregisteredkerns + 1 + local p = rawget(properties,current) + if not injection then + injection = "injections" + end + if p then + local i = rawget(p,injection) + if i then + i.leftkern = dx + (i.leftkern or 0) + else + p[injection] = { + leftkern = dx, + } + end + else + properties[current] = { + [injection] = { + leftkern = dx, + }, + } + end + return dx, nofregisteredkerns + else + return 0, 0 + end +end + +function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk) -- ba=baseanchor, ma=markanchor + local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2]) + nofregisteredmarks = nofregisteredmarks + 1 + -- markanchors[nofregisteredmarks] = base + if rlmode >= 0 then + dx = tfmbase.width - dx -- see later commented ox + end + local p = rawget(properties,start) + -- hm, dejavu serif does a sloppy mark2mark before mark2base + if p then + local i = rawget(p,"injections") + if i then + if i.markmark then + -- out of order mkmk: yes or no or option + else + i.markx = dx + i.marky = dy + i.markdir = rlmode or 0 + i.markbase = nofregisteredmarks + i.markbasenode = base + i.markmark = mkmk + end + else + p.injections = { + markx = dx, + marky = dy, + markdir = rlmode or 0, + markbase = nofregisteredmarks, + markbasenode = base, + markmark = mkmk, + } + end + else + properties[start] = { + injections = { + markx = dx, + marky = dy, + markdir = rlmode or 0, + markbase = nofregisteredmarks, + markbasenode = base, + markmark = mkmk, + }, + } + end + return dx, dy, nofregisteredmarks +end + +local function dir(n) + return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or "unset" +end + +local function showchar(n,nested) + local char = getchar(n) + report_injections("%wfont %s, char %U, glyph %c",nested and 2 or 0,getfont(n),char,char) +end + +local function show(n,what,nested,symbol) + if n then + local p = rawget(properties,n) + if p then + local i = rawget(p,what) + if i then + local leftkern = i.leftkern or 0 + local rightkern = i.rightkern or 0 + local yoffset = i.yoffset or 0 + local markx = i.markx or 0 + local marky = i.marky or 0 + local markdir = i.markdir or 0 + local markbase = i.markbase or 0 -- will be markbasenode + local cursivex = i.cursivex or 0 + local cursivey = i.cursivey or 0 + local ligaindex = i.ligaindex or 0 + local margin = nested and 4 or 2 + -- + if rightkern ~= 0 or yoffset ~= 0 then + report_injections("%w%s pair: lx %p, rx %p, dy %p",margin,symbol,leftkern,rightkern,yoffset) + elseif leftkern ~= 0 then + report_injections("%w%s kern: dx %p",margin,symbol,leftkern) + end + if markx ~= 0 or marky ~= 0 or markbase ~= 0 then + report_injections("%w%s mark: dx %p, dy %p, dir %s, base %s",margin,symbol,markx,marky,markdir,markbase ~= 0 and "yes" or "no") + end + if cursivex ~= 0 or cursivey ~= 0 then + report_injections("%w%s curs: dx %p, dy %p",margin,symbol,cursivex,cursivey) + end + if ligaindex ~= 0 then + report_injections("%w%s liga: index %i",margin,symbol,ligaindex) + end + end + end + end +end + +local function showsub(n,what,where) + report_injections("begin subrun: %s",where) + for n in traverse_id(glyph_code,n) do + showchar(n,where) + show(n,what,where," ") + end + report_injections("end subrun") +end + +local function trace(head,where) + report_injections("begin run %s: %s kerns, %s pairs, %s marks and %s cursives registered", + where or "",nofregisteredkerns,nofregisteredpairs,nofregisteredmarks,nofregisteredcursives) + local n = head + while n do + local id = getid(n) + if id == glyph_code then + showchar(n) + show(n,"injections",false," ") + show(n,"preinjections",false,"<") + show(n,"postinjections",false,">") + show(n,"replaceinjections",false,"=") + show(n,"emptyinjections",false,"*") + elseif id == disc_code then + local pre = getfield(n,"pre") + local post = getfield(n,"post") + local replace = getfield(n,"replace") + if pre then + showsub(pre,"preinjections","pre") + end + if post then + showsub(post,"postinjections","post") + end + if replace then + showsub(replace,"replaceinjections","replace") + end + show(n,"emptyinjections",false,"*") + end + n = getnext(n) + end + report_injections("end run") +end + +local function show_result(head) + local current = head + local skipping = false + while current do + local id = getid(current) + if id == glyph_code then + report_injections("char: %C, width %p, xoffset %p, yoffset %p", + getchar(current),getfield(current,"width"),getfield(current,"xoffset"),getfield(current,"yoffset")) + skipping = false + elseif id == kern_code then + report_injections("kern: %p",getfield(current,"kern")) + skipping = false + elseif not skipping then + report_injections() + skipping = true + end + current = getnext(current) + end +end + +-- G +D-pre G +-- D-post+ +-- +D-replace+ +-- +-- G +D-pre +D-pre +-- D-post +D-post +-- +D-replace +D-replace + +local function inject_kerns_only(head,where) + head = tonut(head) + if trace_injections then + trace(head,"kerns") + end + local current = head + local prev = nil + local next = nil + local prevdisc = nil + local prevglyph = nil + local pre = nil -- saves a lookup + local post = nil -- saves a lookup + local replace = nil -- saves a lookup + while current do + local id = getid(current) + local next = getnext(current) + if id == glyph_code then + if getsubtype(current) < 256 then + local p = rawget(properties,current) + if p then + local i = rawget(p,"injections") + if i then + -- left|glyph|right + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + insert_node_before(head,current,newkern(leftkern)) + end + end + if prevdisc then + local postdone = false + local replacedone = false + if post then + local i = rawget(p,"postinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + local posttail = find_tail(post) + insert_node_after(post,posttail,newkern(leftkern)) + postdone = true + end + end + end + if replace then + local i = rawget(p,"replaceinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + local replacetail = find_tail(replace) + insert_node_after(replace,replacetail,newkern(leftkern)) + replacedone = true + end + end + else +-- local i = rawget(p,"emptyinjections") +-- if i then +-- inspect(i) +-- local leftkern = i.leftkern +-- if leftkern and leftkern ~= 0 then +-- replace = newkern(leftkern) +-- done = true +-- end +-- end + end + if postdone then + setfield(prevdisc,"post",post) + end + if replacedone then + setfield(prevdisc,"replace",replace) + end + end + end + end + prevdisc = nil + prevglyph = current + elseif id == disc_code then + pre = getfield(current,"pre") + post = getfield(current,"post") + replace = getfield(current,"replace") + local predone = false + local postdone = false + local replacedone = false + if pre then + -- left|pre glyphs|right + for n in traverse_id(glyph_code,pre) do + if getsubtype(n) < 256 then + local p = rawget(properties,n) + if p then + local i = rawget(p,"injections") or rawget(p,"preinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + pre = insert_node_before(pre,n,newkern(leftkern)) + predone = true + end + end + end + end + end + end + if post then + -- left|post glyphs|right + for n in traverse_id(glyph_code,post) do + if getsubtype(n) < 256 then + local p = rawget(properties,n) + if p then + local i = rawget(p,"injections") or rawget(p,"postinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + post = insert_node_before(post,n,newkern(leftkern)) + postdone = true + end + end + end + end + end + end + if replace then + -- left|replace glyphs|right + for n in traverse_id(glyph_code,replace) do + if getsubtype(n) < 256 then + local p = rawget(properties,n) + if p then + local i = rawget(p,"injections") or rawget(p,"replaceinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + replace = insert_node_before(replace,n,newkern(leftkern)) + replacedone = true + end + end + end + end + end + end + if predone then + setfield(current,"pre",pre) + end + if postdone then + setfield(current,"post",post) + end + if replacedone then + setfield(current,"replace",replace) + end + prevglyph = nil + prevdisc = current + else + prevglyph = nil + prevdisc = nil + end + prev = current + current = next + end + -- + if keepregisteredcounts then + keepregisteredcounts = false + else + nofregisteredkerns = 0 + end + return tonode(head), true +end + +local function inject_pairs_only(head,where) + head = tonut(head) + if trace_injections then + trace(head,"pairs") + end + local current = head + local prev = nil + local next = nil + local prevdisc = nil + local prevglyph = nil + local pre = nil -- saves a lookup + local post = nil -- saves a lookup + local replace = nil -- saves a lookup + while current do + local id = getid(current) + local next = getnext(current) + if id == glyph_code then + if getsubtype(current) < 256 then + local p = rawget(properties,current) + if p then + local i = rawget(p,"injections") + if i then + -- left|glyph|right + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(current,"yoffset",yoffset) + end + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + insert_node_before(head,current,newkern(leftkern)) + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(head,current,newkern(rightkern)) + end + else + local i = rawget(p,"replaceinjections") + if i then + -- glyph|disc|glyph (special case) + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + if next and getid(next) == disc_code then + local replace = getfield(pr,"replace") + if replace then + -- error, we expect an empty one + else + setfield(next,"replace",newkern(rightkern)) -- maybe also leftkern + end + end + end + end + end + if prevdisc and p then + local postdone = false + local replacedone = false + if post then + local i = rawget(p,"postinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + local posttail = find_tail(post) + insert_node_after(post,posttail,newkern(leftkern)) + postdone = true + end + end + end + if replace then + local i = rawget(p,"replaceinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + local replacetail = find_tail(replace) + insert_node_after(replace,replacetail,newkern(leftkern)) + replacedone = true + end + end + end + if postdone then + setfield(prevdisc,"post",post) + end + if replacedone then + setfield(prevdisc,"replace",replace) + end + end + end + end + prevdisc = nil + prevglyph = current + elseif id == disc_code then + pre = getfield(current,"pre") + post = getfield(current,"post") + replace = getfield(current,"replace") + local predone = false + local postdone = false + local replacedone = false + if pre then + -- left|pre glyphs|right + for n in traverse_id(glyph_code,pre) do + if getsubtype(n) < 256 then + local p = rawget(properties,n) + if p then + local i = rawget(p,"injections") or rawget(p,"preinjections") + if i then + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + pre = insert_node_before(pre,n,newkern(leftkern)) + predone = true + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(pre,n,newkern(rightkern)) + predone = true + end + end + end + end + end + end + if post then + -- left|post glyphs|right + for n in traverse_id(glyph_code,post) do + if getsubtype(n) < 256 then + local p = rawget(properties,n) + if p then + local i = rawget(p,"injections") or rawget(p,"postinjections") + if i then + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + post = insert_node_before(post,n,newkern(leftkern)) + postdone = true + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(post,n,newkern(rightkern)) + postdone = true + end + end + end + end + end + end + if replace then + -- left|replace glyphs|right + for n in traverse_id(glyph_code,replace) do + if getsubtype(n) < 256 then + local p = rawget(properties,n) + if p then + local i = rawget(p,"injections") or rawget(p,"replaceinjections") + if i then + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + replace = insert_node_before(replace,n,newkern(leftkern)) + replacedone = true + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(replace,n,newkern(rightkern)) + replacedone = true + end + end + end + end + end + end + if prevglyph then + if pre then + local p = rawget(properties,prevglyph) + if p then + local i = rawget(p,"preinjections") + if i then + -- glyph|pre glyphs + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + pre = insert_node_before(pre,pre,newkern(rightkern)) + predone = true + end + end + end + end + if replace then + local p = rawget(properties,prevglyph) + if p then + local i = rawget(p,"replaceinjections") + if i then + -- glyph|replace glyphs + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + replace = insert_node_before(replace,replace,newkern(rightkern)) + replacedone = true + end + end + end + end + end + if predone then + setfield(current,"pre",pre) + end + if postdone then + setfield(current,"post",post) + end + if replacedone then + setfield(current,"replace",replace) + end + prevglyph = nil + prevdisc = current + else + prevglyph = nil + prevdisc = nil + end + prev = current + current = next + end + -- + if keepregisteredcounts then + keepregisteredcounts = false + else + nofregisteredkerns = 0 + end + return tonode(head), true +end + +local function inject_everything(head,where) + head = tonut(head) + if trace_injections then + trace(head,"everything") + end + local hascursives = nofregisteredcursives > 0 + local hasmarks = nofregisteredmarks > 0 + -- + local current = head + local prev = nil + local next = nil + local prevdisc = nil + local prevglyph = nil + local pre = nil -- saves a lookup + local post = nil -- saves a lookup + local replace = nil -- saves a lookup + -- + local cursiveanchor = nil + local lastanchor = nil + local minc = 0 + local maxc = 0 + local last = 0 + local glyphs = { } + -- + local function processmark(p,n,pn) -- p = basenode + local px = getfield(p,"xoffset") + local ox = 0 + local rightkern = nil + local pp = rawget(properties,p) + if pp then + pp = rawget(pp,"injections") + if pp then + rightkern = pp.rightkern + end + end + if rightkern then -- x and w ~= 0 + if pn.markdir < 0 then + -- kern(w-x) glyph(p) kern(x) mark(n) + ox = px - pn.markx - rightkern + -- report_injections("r2l case 1: %p",ox) + else + -- kern(x) glyph(p) kern(w-x) mark(n) + -- ox = px - getfield(p,"width") + pn.markx - pp.leftkern + -- + -- According to Kai we don't need to handle leftkern here but I'm + -- pretty sure I've run into a case where it was needed so maybe + -- some day we need something more clever here. + -- + if false then + -- a mark with kerning + local leftkern = pp.leftkern + if leftkern then + ox = px - pn.markx - leftkern + else + ox = px - pn.markx + end + else + ox = px - pn.markx + end + end + else + -- we need to deal with fonts that have marks with width + -- if pn.markdir < 0 then + -- ox = px - pn.markx + -- -- report_injections("r2l case 3: %p",ox) + -- else + -- -- ox = px - getfield(p,"width") + pn.markx + ox = px - pn.markx + -- report_injections("l2r case 3: %p",ox) + -- end + local wn = getfield(n,"width") -- in arial marks have widths + if wn ~= 0 then + -- bad: we should center + -- insert_node_before(head,n,newkern(-wn/2)) + -- insert_node_after(head,n,newkern(-wn/2)) + pn.leftkern = -wn/2 + pn.rightkern = -wn/2 + -- wx[n] = { 0, -wn/2, 0, -wn } + end + -- so far + end + setfield(n,"xoffset",ox) + -- + local py = getfield(p,"yoffset") + -- local oy = 0 + -- if marks[p] then + -- oy = py + pn.marky + -- else + -- oy = getfield(n,"yoffset") + py + pn.marky + -- end + local oy = getfield(n,"yoffset") + py + pn.marky + setfield(n,"yoffset",oy) + end + -- + while current do + local id = getid(current) + local next = getnext(current) + if id == glyph_code then + if getsubtype(current) < 256 then + local p = rawget(properties,current) + if p then + local i = rawget(p,"injections") + if i then + -- cursives + if hascursives then + local cursivex = p.cursivex + if cursivex then + if cursiveanchor then + if cursivex ~= 0 then + p.leftkern = (p.leftkern or 0) + cursivex + end + if lastanchor then + if maxc == 0 then + minc = 1 + maxc = 1 + glyphs[1] = lastanchor + else + maxc = maxc + 1 + glyphs[maxc] = lastanchor + end + properties[cursiveanchor].cursivedy = p.cursivey + end + last = n + else + maxc = 0 + end + elseif maxc > 0 then + local ny = getfield(n,"yoffset") + for i=maxc,minc,-1 do + local ti = glyphs[i] + ny = ny + properties[ti].cursivedy + setfield(ti,"yoffset",ny) -- why not add ? + end + maxc = 0 + end + if p.cursiveanchor then + cursiveanchor = current -- no need for both now + lastanchor = current + else + cursiveanchor = nil + lastanchor = nil + if maxc > 0 then + local ny = getfield(n,"yoffset") + for i=maxc,minc,-1 do + local ti = glyphs[i] + ny = ny + properties[ti].cursivedy + setfield(ti,"yoffset",ny) -- why not add ? + end + maxc = 0 + end + end + end + -- marks + if hasmarks then + local pm = i.markbasenode + if pm then + processmark(pm,current,i) + end + end + -- left|glyph|right + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(current,"yoffset",yoffset) + end + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + insert_node_before(head,current,newkern(leftkern)) + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(head,current,newkern(rightkern)) + end + else + local i = rawget(p,"replaceinjections") + if i then + -- glyph|disc|glyph (special case) + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + if next and getid(next) == disc_code then + local replace = getfield(pr,"replace") + if replace then + -- error, we expect an empty one + else + setfield(next,"replace",newkern(rightkern)) -- maybe also leftkern + end + end + end + end + end + if prevdisc then + if p then + local postdone = false + local replacedone = false + if post then + local i = rawget(p,"postinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + local posttail = find_tail(post) + insert_node_after(post,posttail,newkern(leftkern)) + postdone = true + end + end + end + if replace then + local i = rawget(p,"replaceinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + local replacetail = find_tail(replace) + insert_node_after(replace,replacetail,newkern(leftkern)) + replacedone = true + end + end + end + if postdone then + setfield(prevdisc,"post",post) + end + if replacedone then + setfield(prevdisc,"replace",replace) + end + end + end + else + -- cursive + if hascursives and maxc > 0 then + local ny = getfield(current,"yoffset") + for i=maxc,minc,-1 do + local ti = glyphs[i] + ny = ny + properties[ti].cursivedy + setfield(ti,"yoffset",getfield(ti,"yoffset") + ny) -- ? + end + maxc = 0 + cursiveanchor = nil + lastanchor = nil + end + end + end + prevdisc = nil + prevglyph = current + elseif id == disc_code then + pre = getfield(current,"pre") + post = getfield(current,"post") + replace = getfield(current,"replace") + local predone = false + local postdone = false + local replacedone = false + if pre then + -- left|pre glyphs|right + for n in traverse_id(glyph_code,pre) do + if getsubtype(n) < 256 then + local p = rawget(properties,n) + if p then + local i = rawget(p,"injections") or rawget(p,"preinjections") + if i then + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + pre = insert_node_before(pre,n,newkern(leftkern)) + predone = true + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(pre,n,newkern(rightkern)) + predone = true + end + end + if hasmarks then + local pm = i.markbasenode + if pm then + processmark(pm,current,i) + end + end + end + end + end + end + if post then + -- left|post glyphs|right + for n in traverse_id(glyph_code,post) do + if getsubtype(n) < 256 then + local p = rawget(properties,n) + if p then + local i = rawget(p,"injections") or rawget(p,"postinjections") + if i then + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + post = insert_node_before(post,n,newkern(leftkern)) + postdone = true + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(post,n,newkern(rightkern)) + postdone = true + end + end + if hasmarks then + local pm = i.markbasenode + if pm then + processmark(pm,current,i) + end + end + end + end + end + end + if replace then + -- left|replace glyphs|right + for n in traverse_id(glyph_code,replace) do + if getsubtype(n) < 256 then + local p = rawget(properties,n) + if p then + local i = rawget(p,"injections") or rawget(p,"replaceinjections") + if i then + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + insert_node_before(replace,n,newkern(leftkern)) + replacedone = true + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(replace,n,newkern(rightkern)) + replacedone = true + end + end + if hasmarks then + local pm = i.markbasenode + if pm then + processmark(pm,current,i) + end + end + end + end + end + end + if prevglyph then + if pre then + local p = rawget(properties,prevglyph) + if p then + local i = rawget(p,"preinjections") + if i then + -- glyph|pre glyphs + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + pre = insert_node_before(pre,pre,newkern(rightkern)) + predone = true + end + end + end + end + if replace then + local p = rawget(properties,prevglyph) + if p then + local i = rawget(p,"replaceinjections") + if i then + -- glyph|replace glyphs + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + replace = insert_node_before(replace,replace,newkern(rightkern)) + replacedone = true + end + end + end + end + end + if predone then + setfield(current,"pre",pre) + end + if postdone then + setfield(current,"post",post) + end + if replacedone then + setfield(current,"replace",replace) + end + prevglyph = nil + prevdisc = current + else + prevglyph = nil + prevdisc = nil + end + prev = current + current = next + end + -- cursive + if hascursives then + if last and maxc > 0 then + local ny = getfield(last,"yoffset") + for i=maxc,minc,-1 do + local ti = glyphs[i] + ny = ny + properties[ti].cursivedy + setfield(ti,"yoffset",ny) -- why not add ? + end + end + end + -- + if keepregisteredcounts then + keepregisteredcounts = false + else + nofregisteredkerns = 0 + nofregisteredpairs = 0 + nofregisteredmarks = 0 + nofregisteredcursives = 0 + end + return tonode(head), true +end + +function injections.handler(head,where) + if nofregisteredmarks > 0 or nofregisteredcursives > 0 then + return inject_everything(head,where) + elseif nofregisteredpairs > 0 then + return inject_pairs_only(head,where) + elseif nofregisteredkerns > 0 then + return inject_kerns_only(head,where) + else + return head, false + end +end diff --git a/tex/context/base/font-otl.lua b/tex/context/base/font-otl.lua index 96775d0f0..5a4831835 100644 --- a/tex/context/base/font-otl.lua +++ b/tex/context/base/font-otl.lua @@ -679,7 +679,7 @@ function otf.collectlookups(rawdata,kind,script,language) return unpack(languagelookup) end --- moved from font-oth.lua +-- moved from font-oth.lua, todo: also afm local function getgsub(tfmdata,k,kind,value) local shared = tfmdata.shared @@ -735,6 +735,23 @@ function otf.getmultiple(tfmdata,k,kind) return { k } end +function otf.getkern(tfmdata,left,right,kind) + local kerns = getgsub(tfmdata,left,kind or "kern",true) -- for now we use getsub + if kerns then + local found = kerns[right] + local kind = type(found) + if kind == "table" then + found = found[1][3] -- can be more clever + elseif kind ~= "number" then + found = false + end + if found then + return found * tfmdata.parameters.factor + end + end + return 0 +end + local function check_otf(forced,specification,suffix) local name = specification.name if forced then diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua index 9a85dcf96..9c09185a3 100644 --- a/tex/context/base/font-otn.lua +++ b/tex/context/base/font-otn.lua @@ -255,11 +255,7 @@ local math_code = nodecodes.math local dir_code = whatcodes.dir local localpar_code = whatcodes.localpar - local discretionary_code = disccodes.discretionary -local regular_code = disccodes.regular ------ automatic_code = disccodes.automatic - local ligature_code = glyphcodes.ligature local privateattribute = attributes.private @@ -508,8 +504,8 @@ end -- iteration this becomes a KAF-LAM-ALEF with a SHADDA on the second and a FATHA on the -- third component. -local function getcomponentindex(start) - if getid(start) ~= glyph_code then +local function getcomponentindex(start) -- we could store this offset in the glyph (nofcomponents) + if getid(start) ~= glyph_code then -- and then get rid of all components return 0 elseif getsubtype(start) == ligature_code then local i = 0 @@ -526,69 +522,7 @@ local function getcomponentindex(start) end end -local a_noligature = attributes.private("noligature") -local prehyphenchar = languages and languages.prehyphenchar -local posthyphenchar = languages and languages.posthyphenchar ------ preexhyphenchar = languages and languages.preexhyphenchar ------ postexhyphenchar = languages and languages.postexhyphenchar - -if prehyphenchar then - - -- okay - -elseif context then - - report_warning("no language support") os.exit() - -else - - local newlang = lang.new - local getpre = lang.prehyphenchar - local getpost = lang.posthyphenchar - -- local getpreex = lang.preexhyphenchar - -- local getpostex = lang.postexhyphenchar - - prehyphenchar = function(l) local l = newlang(l) return l and getpre (l) or -1 end - posthyphenchar = function(l) local l = newlang(l) return l and getpost (l) or -1 end - -- preexhyphenchar = function(l) local l = newlang(l) return l and getpreex (l) or -1 end - -- postexhyphenchar = function(l) local l = newlang(l) return l and getpostex(l) or -1 end - -end - -local function addhyphens(template,pre,post) - -- inserted by hyphenation algorithm - local l = getfield(template,"lang") - local p = prehyphenchar(l) - if p and p > 0 then - local c = copy_node(template) - setfield(c,"char",p) - if pre then - local t = find_node_tail(pre) - setfield(t,"next",c) - setfield(c,"prev",t) - else - pre = c - end - end - local p = posthyphenchar(l) - if p and p > 0 then - local c = copy_node(template) - setfield(c,"char",p) - if post then - -- post has a prev nesting node .. alternatively we could - local prev = getprev(post) - setfield(c,"next",post) - setfield(post,"prev",c) - if prev then - setfield(prev,"next",c) - setfield(c,"prev",prev) - end - else - post = c - end - end - return pre, post -end +local a_noligature = attributes.private("noligature") local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) -- brr head if getattr(start,a_noligature) == 1 then @@ -603,8 +537,8 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun -- needs testing (side effects): local components = getfield(start,"components") if components then --- we get a double free .. needs checking --- flush_node_list(components) + -- we get a double free .. needs checking + -- flush_node_list(components) end -- local prev = getprev(start) @@ -626,8 +560,8 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun if next then setfield(next,"prev",base) end - setfield(base,"next",next) setfield(base,"prev",prev) + setfield(base,"next",next) if not discfound then local deletemarks = markflag ~= "mark" local components = start @@ -674,53 +608,34 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun local discprev = getfield(discfound,"prev") local discnext = getfield(discfound,"next") if discprev and discnext then - local subtype = getsubtype(discfound) - if subtype == discretionary_code then - local pre = getfield(discfound,"pre") - local post = getfield(discfound,"post") - local replace = getfield(discfound,"replace") - if not replace then -- todo: signal simple hyphen - local prev = getfield(base,"prev") - local copied = copy_node_list(comp) - setfield(discnext,"prev",nil) -- also blocks funny assignments - setfield(discprev,"next",nil) -- also blocks funny assignments - if pre then - setfield(discprev,"next",pre) - setfield(pre,"prev",discprev) - end - pre = comp - if post then - local tail = find_node_tail(post) - setfield(tail,"next",discnext) - setfield(discnext,"prev",tail) - setfield(post,"prev",nil) - else - post = discnext - end - setfield(prev,"next",discfound) - setfield(next,"prev",discfound) - setfield(discfound,"next",next) - setfield(discfound,"prev",prev) - setfield(base,"next",nil) - setfield(base,"prev",nil) - setfield(base,"components",copied) - setfield(discfound,"pre",pre) - setfield(discfound,"post",post) - setfield(discfound,"replace",base) - setfield(discfound,"subtype",discretionary_code) - base = prev -- restart - end - elseif subtype == regular_code then - -- local prev = getfield(base,"prev") - -- local next = getfield(base,"next") + -- we assume normalization in context, and don't care about generic ... especially + -- \- can give problems as there we can have a negative char but that won't match + -- anyway + local pre = getfield(discfound,"pre") + local post = getfield(discfound,"post") + local replace = getfield(discfound,"replace") + if not replace then -- todo: signal simple hyphen + local prev = getfield(base,"prev") local copied = copy_node_list(comp) setfield(discnext,"prev",nil) -- also blocks funny assignments setfield(discprev,"next",nil) -- also blocks funny assignments - local pre, post = addhyphens(comp,comp,discnext,subtype) -- takes from components + if pre then + setfield(discprev,"next",pre) + setfield(pre,"prev",discprev) + end + pre = comp + if post then + local tail = find_node_tail(post) + setfield(tail,"next",discnext) + setfield(discnext,"prev",tail) + setfield(post,"prev",nil) + else + post = discnext + end setfield(prev,"next",discfound) - setfield(next,"prev",discfound) - setfield(discfound,"next",next) setfield(discfound,"prev",prev) + setfield(discfound,"next",next) + setfield(next,"prev",discfound) setfield(base,"next",nil) setfield(base,"prev",nil) setfield(base,"components",copied) @@ -728,9 +643,7 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun setfield(discfound,"post",post) setfield(discfound,"replace",base) setfield(discfound,"subtype",discretionary_code) - base = next -- or restart - else - -- forget about it in generic usage + base = prev -- restart end end end @@ -753,8 +666,8 @@ local function multiple_glyphs(head,start,multiple,ignoremarks) local n = copy_node(start) -- ignore components resetinjection(n) setfield(n,"char",multiple[k]) - setfield(n,"next",sn) setfield(n,"prev",start) + setfield(n,"next",sn) if sn then setfield(sn,"prev",n) end @@ -949,7 +862,8 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence,lookuphash if not snext then return head, start, false else - local prev, done = start, false + local prev = start + local done = false local factor = tfmdata.parameters.factor local lookuptype = lookuptypes[lookupname] while snext and getid(snext) == glyph_code and getfont(snext) == currentfont and getsubtype(snext)<256 do @@ -1518,11 +1432,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, else local schar = getchar(s) if skipmark and marks[schar] then -- marks --- if s == stop then -- maybe add this --- break --- else s = getnext(s) --- end else local lg = ligatures[schar] if lg then @@ -1955,7 +1865,7 @@ end local function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,chainindex,sequence,chainproc) if not start then - return -- safeguard + return head, start, false end local startishead = start == head @@ -2165,7 +2075,7 @@ local function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlooku setfield(tail,"next",replace) setfield(replace,"prev",tail) end - setfield(lookaheaddisc,"pre",cf) -- also updates tail + setfield(lookaheaddisc,"pre",cf) -- also updates tail setfield(lookaheaddisc,"replace",new) -- also updates tail start = getprev(lookaheaddisc) @@ -2248,6 +2158,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq local skipbase = flags[3] local markclass = sequence.markclass local skipped = false + for k=1,#contexts do -- i've only seen ccmp having > 1 (e.g. dejavu) local match = true local current = start @@ -2316,7 +2227,8 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq notmatchpre[last] = nil notmatchpost[last] = true notmatchreplace[last] = nil - local pre = getfield(last,"pre") + local pre = getfield(last,"pre") + local replace = getfield(last,"replace") if pre then local n = n while pre do @@ -2336,7 +2248,6 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq else notmatchpre[last] = true end - local replace = getfield(last,"replace") if replace then -- so far we never entered this branch while replace do @@ -2361,10 +2272,12 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq break end else - last = getnext(last) -- no skipping here + notmatchreplace[last] = true end + last = getnext(last) else - last = getnext(last) -- no skipping here + match = false + break end else match = false @@ -2726,7 +2639,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end end end - if diskchain then -- maybe move up so that we can turn checking on/off + if diskseen then -- maybe move up so that we can turn checking on/off notmatchpre = { } notmatchpost = { } notmatchreplace = { } @@ -2815,7 +2728,7 @@ local function initialize(sequence,script,language,enabled) local order = sequence.order if order then for i=1,#order do -- - local kind = order[i] -- + local kind = order[i] -- local valid = enabled[kind] if valid then local scripts = features[kind] -- @@ -2869,7 +2782,7 @@ end -- -- * languages that use complex disc nodes -local function kernrun(disc,run) -- we can assume that prev and next are glyphs +local function kernrun(disc,run) -- -- we catch <font 1><disc font 2> -- @@ -2886,22 +2799,18 @@ local function kernrun(disc,run) -- we can assume that prev and next are glyphs -- local prevmarks = prev -- - -- can be optional: + -- can be optional, because why on earth do we get a disc after a mark (okay, maybe when a ccmp + -- has happened but then it should be in the disc so basically this test indicates an error) -- - -- while prevmarks and getid(prevmarks) == glyph_code and getfont(prevmarks) == currentfont and marks[getchar(prevmarks)] and getsubtype(prevmarks) < 256 do while prevmarks and getid(prevmarks) == glyph_code and marks[getchar(prevmarks)] and getfont(prevmarks) == currentfont and getsubtype(prevmarks) < 256 do prevmarks = getprev(prevmarks) end -- - if prev and (pre or replace) then - if not (getid(prev) == glyph_code and getfont(prev) == currentfont and getsubtype(prev)<256) then - prev = false - end + if prev and (pre or replace) and not (getid(prev) == glyph_code and getfont(prev) == currentfont and getsubtype(prev)<256) then + prev = false end - if next and (post or replace) then - if not (getid(next) == glyph_code and getfont(next) == currentfont and getsubtype(next)<256) then - next = false - end + if next and (post or replace) and not (getid(next) == glyph_code and getfont(next) == currentfont and getsubtype(next)<256) then + next = false end -- if not pre then @@ -3123,8 +3032,6 @@ local function featuresprocessor(head,font,attr) -- Keeping track of the headnode is needed for devanagari (I generalized it a bit -- so that multiple cases are also covered.) - -- todo: retain prev - -- We don't goto the next node of a disc node is created so that we can then treat -- the pre, post and replace. It's abit of a hack but works out ok for most cases. @@ -3144,7 +3051,6 @@ local function featuresprocessor(head,font,attr) local gpossing = typ == "gpos_single" or typ == "gpos_pair" -- maybe all of them local subtables = sequence.subtables local handler = handlers[typ] - if typ == "gsub_reversecontextchain" then -- chain < 0 -- this is a limited case, no special treatments like 'init' etc -- we need to get rid of this slide! probably no longer needed in latest luatex @@ -3165,8 +3071,7 @@ local function featuresprocessor(head,font,attr) local lookupname = subtables[i] local lookupcache = lookuphash[lookupname] if lookupcache then - -- local lookupmatch = lookupcache[getchar(start)] - local lookupmatch = lookupcache[start] + local lookupmatch = lookupcache[char] if lookupmatch then -- todo: disc? head, start, success = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i) @@ -3194,7 +3099,7 @@ local function featuresprocessor(head,font,attr) local start = head -- local ? rlmode = 0 -- to be checked ? if ns == 1 then -- happens often - local lookupname = subtables[1] + local lookupname = subtables[1] local lookupcache = lookuphash[lookupname] if not lookupcache then -- also check for empty cache report_missing_cache(typ,lookupname) @@ -3294,7 +3199,7 @@ local function featuresprocessor(head,font,attr) -- sequence kan weg local h, d, ok = handler(head,prev,kind,lookupname,lookupmatch,sequence,lookuphash,1) if ok then - done = true + done = true success = true end end @@ -3320,7 +3225,7 @@ local function featuresprocessor(head,font,attr) if lookupmatch then local h, d, ok = handler(sub,n,kind,lookupname,lookupmatch,sequence,lookuphash,1,injection) if ok then - done = true + done = true success = true end end @@ -3364,24 +3269,15 @@ local function featuresprocessor(head,font,attr) start = getnext(start) end elseif id == disc_code then - local discretionary = getsubtype(start) == discretionary_code - if gpossing then - if discretionary then - kernrun(start,k_run) - else - discrun(start,d_run,k_run) - end - start = getnext(start) - elseif discretionary then - if typ == "gsub_ligature" then - start = testrun(start,t_run,c_run) - else - comprun(start,c_run) - start = getnext(start) - end - else + if gpossing then + kernrun(start,k_run) + start = getnext(start) + elseif typ == "gsub_ligature" then + start = testrun(start,t_run,c_run) + else + comprun(start,c_run) start = getnext(start) - end + end elseif id == whatsit_code then -- will be function local subtype = getsubtype(start) if subtype == dir_code then @@ -3497,7 +3393,7 @@ local function featuresprocessor(head,font,attr) -- brr prev can be disc local char = getchar(prev) for i=1,ns do - local lookupname = subtables[i] + local lookupname = subtables[i] local lookupcache = lookuphash[lookupname] if lookupcache then local lookupmatch = lookupcache[char] @@ -3532,7 +3428,7 @@ local function featuresprocessor(head,font,attr) if id == glyph_code then local char = getchar(n) for i=1,ns do - local lookupname = subtables[i] + local lookupname = subtables[i] local lookupcache = lookuphash[lookupname] if lookupcache then local lookupmatch = lookupcache[char] @@ -3567,7 +3463,7 @@ local function featuresprocessor(head,font,attr) if a then local char = getchar(start) for i=1,ns do - local lookupname = subtables[i] + local lookupname = subtables[i] local lookupcache = lookuphash[lookupname] if lookupcache then local lookupmatch = lookupcache[char] @@ -3612,7 +3508,7 @@ local function featuresprocessor(head,font,attr) end if a then for i=1,ns do - local lookupname = subtables[i] + local lookupname = subtables[i] local lookupcache = lookuphash[lookupname] if lookupcache then local char = getchar(start) @@ -3645,27 +3541,19 @@ local function featuresprocessor(head,font,attr) start = getnext(start) end elseif id == disc_code then - local discretionary = getsubtype(start) == discretionary_code if gpossing then - if discretionary then - kernrun(start,k_run) - else - discrun(start,d_run,k_run) - end + kernrun(start,k_run) start = getnext(start) - elseif discretionary then - if typ == "gsub_ligature" then - start = testrun(start,t_run,c_run) - else - comprun(start,c_run) - start = getnext(start) - end + elseif typ == "gsub_ligature" then + start = testrun(start,t_run,c_run) else + comprun(start,c_run) start = getnext(start) end elseif id == whatsit_code then local subtype = getsubtype(start) if subtype == dir_code then + local dir = getfield(start,"dir") if dir == "+TLT" then topstack = topstack + 1 dirstack[topstack] = dir diff --git a/tex/context/base/font-ots.lua b/tex/context/base/font-ots.lua index 27e0f161e..2204d1496 100644 --- a/tex/context/base/font-ots.lua +++ b/tex/context/base/font-ots.lua @@ -126,6 +126,7 @@ local trace_compruns = false registertracker("otf.compruns", function(v local quit_on_no_replacement = true -- maybe per font local zwnjruns = true +local optimizekerns = true registerdirective("otf.zwnjruns", function(v) zwnjruns = v end) registerdirective("otf.chain.quitonnoreplacement",function(value) quit_on_no_replacement = value end) @@ -196,11 +197,7 @@ local math_code = nodecodes.math local dir_code = whatcodes.dir local localpar_code = whatcodes.localpar - local discretionary_code = disccodes.discretionary -local regular_code = disccodes.regular ------ automatic_code = disccodes.automatic - local ligature_code = glyphcodes.ligature local privateattribute = attributes.private @@ -563,69 +560,7 @@ local function getcomponentindex(start) -- we could store this offset in the gly end end -local a_noligature = attributes.private("noligature") -local prehyphenchar = languages and languages.prehyphenchar -local posthyphenchar = languages and languages.posthyphenchar ------ preexhyphenchar = languages and languages.preexhyphenchar ------ postexhyphenchar = languages and languages.postexhyphenchar - -if prehyphenchar then - - -- okay - -elseif context then - - report_warning("no language support") os.exit() - -else - - local newlang = lang.new - local getpre = lang.prehyphenchar - local getpost = lang.posthyphenchar - -- local getpreex = lang.preexhyphenchar - -- local getpostex = lang.postexhyphenchar - - prehyphenchar = function(l) local l = newlang(l) return l and getpre (l) or -1 end - posthyphenchar = function(l) local l = newlang(l) return l and getpost (l) or -1 end - -- preexhyphenchar = function(l) local l = newlang(l) return l and getpreex (l) or -1 end - -- postexhyphenchar = function(l) local l = newlang(l) return l and getpostex(l) or -1 end - -end - -local function addhyphens(template,pre,post) - -- inserted by hyphenation algorithm - local l = getfield(template,"lang") - local p = prehyphenchar(l) - if p and p > 0 then - local c = copy_node(template) - setfield(c,"char",p) - if pre then - local t = find_node_tail(pre) - setfield(t,"next",c) - setfield(c,"prev",t) - else - pre = c - end - end - local p = posthyphenchar(l) - if p and p > 0 then - local c = copy_node(template) - setfield(c,"char",p) - if post then - -- post has a prev nesting node .. alternatively we could - local prev = getprev(post) - setfield(c,"next",post) - setfield(post,"prev",c) - if prev then - setfield(prev,"next",c) - setfield(c,"prev",prev) - end - else - post = c - end - end - return pre, post -end +local a_noligature = attributes.private("noligature") local function toligature(head,start,stop,char,dataset,sequence,markflag,discfound) -- brr head if getattr(start,a_noligature) == 1 then @@ -640,8 +575,8 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou -- needs testing (side effects): local components = getfield(start,"components") if components then --- we get a double free .. needs checking --- flush_node_list(components) + -- we get a double free .. needs checking + -- flush_node_list(components) end -- local prev = getprev(start) @@ -663,8 +598,8 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou if next then setfield(next,"prev",base) end - setfield(base,"next",next) setfield(base,"prev",prev) + setfield(base,"next",next) if not discfound then local deletemarks = markflag ~= "mark" local components = start @@ -711,53 +646,34 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou local discprev = getfield(discfound,"prev") local discnext = getfield(discfound,"next") if discprev and discnext then - local subtype = getsubtype(discfound) - if subtype == discretionary_code then - local pre = getfield(discfound,"pre") - local post = getfield(discfound,"post") - local replace = getfield(discfound,"replace") - if not replace then -- todo: signal simple hyphen - local prev = getfield(base,"prev") - local copied = copy_node_list(comp) - setfield(discnext,"prev",nil) -- also blocks funny assignments - setfield(discprev,"next",nil) -- also blocks funny assignments - if pre then - setfield(discprev,"next",pre) - setfield(pre,"prev",discprev) - end - pre = comp - if post then - local tail = find_node_tail(post) - setfield(tail,"next",discnext) - setfield(discnext,"prev",tail) - setfield(post,"prev",nil) - else - post = discnext - end - setfield(prev,"next",discfound) - setfield(next,"prev",discfound) - setfield(discfound,"next",next) - setfield(discfound,"prev",prev) - setfield(base,"next",nil) - setfield(base,"prev",nil) - setfield(base,"components",copied) - setfield(discfound,"pre",pre) - setfield(discfound,"post",post) - setfield(discfound,"replace",base) - setfield(discfound,"subtype",discretionary_code) - base = prev -- restart - end - elseif subtype == regular_code then - -- local prev = getfield(base,"prev") - -- local next = getfield(base,"next") + -- we assume normalization in context, and don't care about generic ... especially + -- \- can give problems as there we can have a negative char but that won't match + -- anyway + local pre = getfield(discfound,"pre") + local post = getfield(discfound,"post") + local replace = getfield(discfound,"replace") + if not replace then -- todo: signal simple hyphen + local prev = getfield(base,"prev") local copied = copy_node_list(comp) setfield(discnext,"prev",nil) -- also blocks funny assignments setfield(discprev,"next",nil) -- also blocks funny assignments - local pre, post = addhyphens(comp,comp,discnext,subtype) -- takes from components + if pre then + setfield(discprev,"next",pre) + setfield(pre,"prev",discprev) + end + pre = comp + if post then + local tail = find_node_tail(post) + setfield(tail,"next",discnext) + setfield(discnext,"prev",tail) + setfield(post,"prev",nil) + else + post = discnext + end setfield(prev,"next",discfound) - setfield(next,"prev",discfound) - setfield(discfound,"next",next) setfield(discfound,"prev",prev) + setfield(discfound,"next",next) + setfield(next,"prev",discfound) setfield(base,"next",nil) setfield(base,"prev",nil) setfield(base,"components",copied) @@ -765,9 +681,7 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou setfield(discfound,"post",post) setfield(discfound,"replace",base) setfield(discfound,"subtype",discretionary_code) - base = next -- or restart - else - -- forget about it in generic usage + base = prev -- restart end end end @@ -790,8 +704,8 @@ local function multiple_glyphs(head,start,multiple,ignoremarks) local n = copy_node(start) -- ignore components resetinjection(n) setfield(n,"char",multiple[k]) - setfield(n,"next",sn) setfield(n,"prev",start) + setfield(n,"next",sn) if sn then setfield(sn,"prev",n) end @@ -980,13 +894,13 @@ function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,step,i,in if step.format == "pair" then local dx, dy, w, h = setpair(start,factor,rlmode,sequence.flags[4],kerns,injection) if trace_kerns then - logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(dataset,sequence),gref(startchar),dx,dy,w,h) + logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),dx,dy,w,h,injection or "injections") 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",pref(dataset,sequence),gref(startchar),k) + logprocess("%s: shifting single %s by %p as %s",pref(dataset,sequence),gref(startchar),k,injection or "injections") end end return head, start, false @@ -1009,18 +923,30 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje 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],injection) + if trace_kerns then + logprocess("%s: shifting single %s by %p",pref(dataset,sequence),gref(nextchar),k) + end + done = true + break + end + end if a and #a > 0 then - local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,injection) -- characters[startchar]) + local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,injection) if trace_kerns then local startchar = getchar(start) - logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") end end if b and #b > 0 then - local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,injection) -- characters[nextchar]) + local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,injection) if trace_kerns then local startchar = getchar(snext) - logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") end end done = true @@ -1028,7 +954,7 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje elseif krn ~= 0 then local k = setkern(snext,factor,rlmode,krn,injection) if trace_kerns then - logprocess("%s: inserting kern %p between %s and %s",pref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar)) + logprocess("%s: inserting kern %p between %s and %s as %s",pref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar),injection or "injections") end done = true break @@ -1566,16 +1492,28 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm 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 + done = true + break + 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) -- currentlookups flags? + 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) 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) + 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 @@ -1848,7 +1786,7 @@ end local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,ck,chainproc) if not start then - return -- safeguard + return head, start, false end local startishead = start == head @@ -2058,8 +1996,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c setfield(tail,"next",replace) setfield(replace,"prev",tail) end - setfield(lookaheaddisc,"pre",cf) -- also updates pre-tail - setfield(lookaheaddisc,"replace",new) -- also updates replace-tail + setfield(lookaheaddisc,"pre",cf) -- also updates tail + setfield(lookaheaddisc,"replace",new) -- also updates tail start = getprev(lookaheaddisc) sweephead[cf] = getnext(clast) @@ -2114,8 +2052,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c else replace = new end - setfield(backtrackdisc,"post",post) -- also updates post-tail - setfield(backtrackdisc,"replace",replace) -- also updates replace-tail + setfield(backtrackdisc,"post",post) -- also updates tail + setfield(backtrackdisc,"replace",replace) -- also updates tail start = getprev(backtrackdisc) sweephead[post] = getnext(clast) sweephead[replace] = getnext(last) @@ -2270,7 +2208,8 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) notmatchpre[last] = nil notmatchpost[last] = true notmatchreplace[last] = nil - local pre = getfield(last,"pre") + local pre = getfield(last,"pre") + local replace = getfield(last,"replace") if pre then local n = n while pre do @@ -2290,7 +2229,6 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else notmatchpre[last] = true end - local replace = getfield(last,"replace") if replace then -- so far we never entered this branch while replace do @@ -2315,10 +2253,12 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) break end else - last = getnext(last) -- no skipping here + notmatchreplace[last] = true end + last = getnext(last) else - last = getnext(last) -- no skipping here + match = false + break end else match = false @@ -2808,78 +2748,61 @@ local function kernrun(disc,run) prevmarks = getprev(prevmarks) end -- - if prev and (pre or replace) then - if not (getid(prev) == glyph_code and getfont(prev) == currentfont and getsubtype(prev)<256) then - prev = false - end + if prev and (pre or replace) and not (getid(prev) == glyph_code and getfont(prev) == currentfont and getsubtype(prev)<256) then + prev = false end - if next and (post or replace) then - if not (getid(next) == glyph_code and getfont(next) == currentfont and getsubtype(next)<256) then - next = false - end + if next and (post or replace) and not (getid(next) == glyph_code and getfont(next) == currentfont and getsubtype(next)<256) then + next = false end -- - if not pre then - -- go on - elseif prev then - local nest = getprev(pre) - setfield(pre,"prev",prev) - setfield(prev,"next",pre) - run(prevmarks,"preinjections") - setfield(pre,"prev",nest) - setfield(prev,"next",disc) - else - run(pre,"preinjections") + if pre then + run(pre,"injections") + if prev then + local nest = getprev(pre) + setfield(pre,"prev",prev) + setfield(prev,"next",pre) + run(prevmarks,"preinjections",getnext(pre)) + setfield(pre,"prev",nest) + setfield(prev,"next",disc) + end end -- - if not post then - -- go on - elseif next then - local tail = find_node_tail(post) - setfield(tail,"next",next) - setfield(next,"prev",tail) - run(post,"postinjections",next) - setfield(tail,"next",nil) - setfield(next,"prev",disc) - else - run(post,"postinjections") + if post then + run(post,"injections") + if next then + local tail = find_node_tail(post) + setfield(tail,"next",next) + setfield(next,"prev",tail) + run(tail,"postinjections",next) + setfield(tail,"next",nil) + setfield(next,"prev",disc) + end end -- - if not replace and prev and next then - -- this should be already done by discfound + if replace then + run(replace,"injections") + if prev then + local nest = getprev(replace) + setfield(replace,"prev",prev) + setfield(prev,"next",replace) + run(prevmarks,"replaceinjections",getnext(replace)) + setfield(replace,"prev",nest) + setfield(prev,"next",disc) + end + if next then + local tail = find_node_tail(replace) + setfield(tail,"next",next) + setfield(next,"prev",tail) + run(tail,"replaceinjections",next) + setfield(tail,"next",nil) + setfield(next,"prev",disc) + end + elseif prev and next then setfield(prev,"next",next) setfield(next,"prev",prev) - run(prevmarks,"injections",next) - setfield(prev,"next",disc) - setfield(next,"prev",disc) - elseif prev and next then - local tail = find_node_tail(replace) - local nest = getprev(replace) - setfield(replace,"prev",prev) - setfield(prev,"next",replace) - setfield(tail,"next",next) - setfield(next,"prev",tail) - run(prevmarks,"replaceinjections",next) - setfield(replace,"prev",nest) - setfield(prev,"next",disc) - setfield(tail,"next",nil) - setfield(next,"prev",disc) - elseif prev then - local nest = getprev(replace) - setfield(replace,"prev",prev) - setfield(prev,"next",replace) - run(prevmarks,"replaceinjections") - setfield(replace,"prev",nest) + run(prevmarks,"emptyinjections",next) setfield(prev,"next",disc) - elseif next then - local tail = find_node_tail(replace) - setfield(tail,"next",next) - setfield(next,"prev",tail) - run(replace,"replaceinjections",next) - setfield(tail,"next",nil) setfield(next,"prev",disc) - else - run(replace,"replaceinjections") end end @@ -2903,7 +2826,7 @@ local function comprun(disc,run) local pre = getfield(disc,"pre") if pre then sweepnode = disc - sweeptype = "pre" -- in alternative code preinjections is used (also used then for proeprties, saves a variable) + sweeptype = "pre" local new, done = run(pre) if done then setfield(disc,"pre",new) @@ -3144,7 +3067,7 @@ local function featuresprocessor(head,font,attr) local start = head -- local ? rlmode = 0 -- to be checked ? if nofsteps == 1 then -- happens often - local step = steps[1] + local step = steps[1] local lookupcache = step.coverage if not lookupcache then -- also check for empty cache report_missing_cache(dataset,sequence) @@ -3247,14 +3170,14 @@ if not a or (a == attr) then -- sequence kan weg local h, d, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1) if ok then - done = true + done = true success = true end end end end - local function k_run(sub,injection,last) + local function k_run(sub,injection,last,bound) local a = getattr(sub,0) -- if a then -- a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute) @@ -3272,9 +3195,9 @@ if not a or (a == attr) then if id == glyph_code then local lookupmatch = lookupcache[getchar(n)] if lookupmatch then - local h, d, ok = handler(sub,n,dataset,sequence,lookupmatch,rlmode,step,1,injection) + local h, d, ok = handler(sub,n,dataset,sequence,lookupmatch,rlmode,step,1,injection,bound) if ok then - done = true + done = true success = true end end @@ -3318,24 +3241,15 @@ if not a or (a == attr) then start = getnext(start) end elseif id == disc_code then - local discretionary = getsubtype(start) == discretionary_code - if gpossing then - if discretionary then - kernrun(start,k_run) - else - discrun(start,d_run,k_run) - end - start = getnext(start) - elseif discretionary then - if typ == "gsub_ligature" then - start = testrun(start,t_run,c_run) - else - comprun(start,c_run) - start = getnext(start) - end - else + if gpossing then + kernrun(start,k_run) + start = getnext(start) + elseif typ == "gsub_ligature" then + start = testrun(start,t_run,c_run) + else + comprun(start,c_run) start = getnext(start) - end + end elseif id == whatsit_code then -- will be function local subtype = getsubtype(start) if subtype == dir_code then @@ -3472,7 +3386,7 @@ if not a or (a == attr) then end end - local function k_run(sub,injection,last) + local function k_run(sub,injection,last,bound) local a = getattr(sub,0) -- if a then -- a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute) @@ -3494,7 +3408,7 @@ if not a or (a == attr) then if lookupcache then local lookupmatch = lookupcache[char] if lookupmatch then - local h, d, ok = handler(head,n,dataset,sequence,lookupmatch,step,rlmode,i,injection) + local h, d, ok = handler(head,n,dataset,sequence,lookupmatch,step,rlmode,i,injection,bound) if ok then done = true break @@ -3525,7 +3439,7 @@ if not a or (a == attr) then if not a or (a == attr) then local char = getchar(start) for i=1,nofsteps do - local step = steps[i] + local step = steps[i] local lookupcache = step.coverage if lookupcache then local lookupmatch = lookupcache[char] @@ -3603,27 +3517,19 @@ if not a or (a == attr) then start = getnext(start) end elseif id == disc_code then - local discretionary = getsubtype(start) == discretionary_code if gpossing then - if discretionary then - kernrun(start,k_run) - else - discrun(start,d_run,k_run) - end + kernrun(start,k_run) start = getnext(start) - elseif discretionary then - if typ == "gsub_ligature" then - start = testrun(start,t_run,c_run) - else - comprun(start,c_run) - start = getnext(start) - end + elseif typ == "gsub_ligature" then + start = testrun(start,t_run,c_run) else + comprun(start,c_run) start = getnext(start) end elseif id == whatsit_code then local subtype = getsubtype(start) if subtype == dir_code then + local dir = getfield(start,"dir") if dir == "+TLT" then topstack = topstack + 1 dirstack[topstack] = dir diff --git a/tex/context/base/lang-dis.lua b/tex/context/base/lang-dis.lua index 91b0e9460..d503cdffd 100644 --- a/tex/context/base/lang-dis.lua +++ b/tex/context/base/lang-dis.lua @@ -47,6 +47,8 @@ local setattribute = tex.setattribute local getlanguagedata = languages.getdata +local check_regular = true + -- local expanders = { -- [disccodes.discretionary] = function(d,template) -- -- \discretionary @@ -207,41 +209,47 @@ local expanders = { return template end, [disccodes.regular] = function(d,template) - -- simple - if not template then - -- can there be font kerns already? - template = getprev(d) - if template and getid(template) ~= glyph_code then - template = getnext(d) + if check_regular then + -- simple + if not template then + -- can there be font kerns already? + template = getprev(d) if template and getid(template) ~= glyph_code then - template = nil + template = getnext(d) + if template and getid(template) ~= glyph_code then + template = nil + end end end - end - if template then - local language = template and getfield(template,"lang") - local data = getlanguagedata(language) - local prechar = data.prehyphenchar - local postchar = data.posthyphenchar - local pre, post, replace = getdisc(d) -- pre can be set - local done = false - if prechar and prechar > 0 then - done = true - pre = copy_node(template) - setfield(pre,"char",prechar) - end - if postchar and postchar > 0 then - done = true - post = copy_node(template) - setfield(post,"char",postchar) - end - if done then - setdisc(d,pre,post,replace,discretionary_code) + if template then + local language = template and getfield(template,"lang") + local data = getlanguagedata(language) + local prechar = data.prehyphenchar + local postchar = data.posthyphenchar + local pre, post, replace = getdisc(d) -- pre can be set + local done = false + if prechar and prechar > 0 then + done = true + pre = copy_node(template) + -- setfield(pre,"char",prechar) + setchar(pre,prechar) + end + if postchar and postchar > 0 then + done = true + post = copy_node(template) + -- setfield(post,"char",postchar) + setchar(post,postchar) + end + if done then + setdisc(d,pre,post,replace,discretionary_code) + end + else + -- print("lone regular discretionary ignored") end + return template else - -- print("lone regular discretionary ignored") + setfield(d,"subtype",discretionary_code) end - return template end, [disccodes.first] = function() -- forget about them diff --git a/tex/context/base/lpdf-epa.lua b/tex/context/base/lpdf-epa.lua index dd5ecc609..59f62a310 100644 --- a/tex/context/base/lpdf-epa.lua +++ b/tex/context/base/lpdf-epa.lua @@ -12,6 +12,7 @@ if not modules then modules = { } end modules ['lpdf-epa'] = { local type, tonumber = type, tonumber local format, gsub, lower = string.format, string.gsub, string.lower local formatters = string.formatters +local abs = math.abs ----- lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns @@ -38,6 +39,8 @@ local escapetex = characters.filters.utf.private.escape local bookmarks = structures.bookmarks +local maxdimen = 2^30-1 + local layerspec = { -- predefining saves time "epdflinks" } @@ -178,7 +181,11 @@ function codeinjections.mergereferences(specification) local h = yscale * (a_ury - a_lly) if subtype == "Link" then local a = annotation.A - if a then + if not a then + report_link("missing link annotation") + elseif w > width or h > height or w < 0 or h < 0 or abs(x) > (maxdimen/2) or abs(y) > (maxdimen/2) then + report_link("broken link rectangle [%f %f %f %f] (max: %f)",a_llx,a_lly,a_urx,a_ury,maxdimen/2) + else local linktype = a.S if linktype == "GoTo" then link_goto(x,y,w,h,document,annotation,pagedata,namespace) @@ -189,8 +196,6 @@ function codeinjections.mergereferences(specification) elseif trace_links then report_link("unsupported link annotation %a",linktype) end - else - report_link("missing link annotation") end elseif trace_links then report_link("unsupported annotation %a",subtype) diff --git a/tex/context/base/m-morse.mkvi b/tex/context/base/m-morse.mkvi new file mode 100644 index 000000000..a2c20dff7 --- /dev/null +++ b/tex/context/base/m-morse.mkvi @@ -0,0 +1,273 @@ +%D \module +%D [ file=m-morse, +%D version=2010.12.10, +%D title=\CONTEXT\ Extra Modules, +%D subtitle=Morse, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +% todo: act upon the node list +% make it a buffer operation +% nice in cld manual + +\startluacode + +moduledata.morse = moduledata.morse or { } +local morse = moduledata.morse + +local utfcharacters, gsub = string.utfcharacters, string.gsub +local ucchars, shchars = characters.ucchars, characters.shchars + +local codes = { + + ["A"] = "·—", + ["B"] = "—···", + ["C"] = "—·—·", + ["D"] = "—··", + ["E"] = "·", + ["F"] = "··—·", + ["G"] = "——·", + ["H"] = "····", + ["I"] = "··", + ["J"] = "·———", + ["K"] = "—·—", + ["L"] = "·—··", + ["M"] = "——", + ["N"] = "—·", + ["O"] = "———", + ["P"] = "·——·", + ["Q"] = "——·—", + ["R"] = "·—·", + ["S"] = "···", + ["T"] = "—", + ["U"] = "··—", + ["V"] = "···—", + ["W"] = "·——", + ["X"] = "—··—", + ["Y"] = "—·——", + ["Z"] = "——··", + + ["0"] = "—————", + ["1"] = "·————", + ["2"] = "··———", + ["3"] = "···——", + ["4"] = "····—", + ["5"] = "·····", + ["6"] = "—····", + ["7"] = "——···", + ["8"] = "———··", + ["9"] = "————·", + + ["."] = "·—·—·—", + [","] = "——··——", + [":"] = "———···", + [";"] = "—·—·—", + + ["?"] = "··——··", + ["!"] = "—·—·——", + + ["-"] = "—····—", + ["/"] = "—··—· ", + + ["("] = "—·——·", + [")"] = "—·——·—", + + ["="] = "—···—", + ["@"] = "·——·—·", + + ["'"] = "·————·", + ['"'] = "·—··—·", + + ["À"] = "·——·—", + ["Å"] = "·——·—", + ["Ä"] = "·—·—", + ["Æ"] = "·—·—", + ["Ç"] = "—·—··", + ["É"] = "··—··", + ["È"] = "·—··—", + ["Ñ"] = "——·——", + ["Ö"] = "———·", + ["Ø"] = "———·", + ["Ü"] = "··——", + ["ß"] = "··· ···", + +} + +morse.codes = codes + +local fallbackself = false + +local function codefallback(t,k) + if k then + local u = ucchars[k] + local v = rawget(t,u) or rawget(t,shchars[u]) or false + t[k] = v + return v + elseif fallbackself then + return k + else + return false + end +end + +table.setmetatableindex(codes,codefallback) + +local MorseBetweenWords = context.MorseBetweenWords +local MorseBetweenCharacters = context.MorseBetweenCharacters +local MorseLong = context.MorseLong +local MorseShort = context.MorseShort +local MorseSpace = context.MorseSpace +local MorseUnknown = context.MorseUnknown + +local function toverbose(str) + str = gsub(str,"%s*+%s*","+") + str = gsub(str,"%s+"," ") + local done = false + for m in utfcharacters(str) do + if done then + MorseBetweenCharacters() + end + if m == "·" or m == "." then + MorseShort() + done = true + elseif m == "—" or m == "-" then + MorseLong() + done = true + elseif m == " " then + if done then + MorseBetweenCharacters() + end + done = false + elseif m == "+" then + MorseBetweenWords() + done = false + else + MorseUnknown(m) + end + end +end + +local function toregular(str) + local inmorse = false + for s in utfcharacters(str) do + local m = codes[s] + if m then + if inmorse then + MorseBetweenWords() + else + inmorse = true + end + local done = false + for m in utfcharacters(m) do + if done then + MorseBetweenCharacters() + else + done = true + end + if m == "·" then + MorseShort() + elseif m == "—" then + MorseLong() + elseif m == " " then + MorseBetweenCharacters() + end + end + inmorse = true + elseif s == "\n" or s == " " then + MorseSpace() + inmorse = false + else + if inmorse then + MorseBetweenWords() + else + inmorse = true + end + MorseUnknown(s) + end + end +end + +local function tomorse(str,verbose) + if verbose then + toverbose(str) + else + toregular(str) + end +end + +morse.tomorse = tomorse + +function morse.filetomorse(name,verbose) + tomorse(resolvers.loadtexfile(name),verbose) +end + +function morse.showtable() + context.starttabulate { "|l|l|" } -- { "|l|l|l|" } + for k, v in table.sortedpairs(codes) do + context.NC() context(k) + -- context.NC() context(v) + context.NC() tomorse(v,true) + context.NC() context.NR() + end + context.stoptabulate() +end + +\stopluacode + +\unprotect + +% todo: \setupmorse, but probably it's not worth the trouble. + +\def\MorseWidth {0.4em} +\def\MorseHeight {0.2em} +%def\MorseShort {\dontleavehmode\blackrule[\c!height=\MorseHeight,\c!width=\dimexpr\MorseWidth]} +%def\MorseLong {\dontleavehmode\blackrule[\c!height=\MorseHeight,\c!width=3\dimexpr\MorseWidth]} +\def\MorseShort {\dontleavehmode\vrule\!!width \dimexpr\MorseWidth\!!height\MorseHeight\!!depth\zeropoint\relax} +\def\MorseLong {\dontleavehmode\vrule\!!width3\dimexpr\MorseWidth\!!height\MorseHeight\!!depth\zeropoint\relax} +\def\MorseBetweenCharacters {\kern\MorseWidth} +\def\MorseBetweenWords {\hskip3\dimexpr\MorseWidth\relax} +\def\MorseSpace {\hskip7\dimexpr\MorseWidth\relax} +\def\MorseUnknown #text{[\detokenize{#text}]} + +\unexpanded\def\MorseCode #text{\ctxlua{moduledata.morse.tomorse(\!!bs#text\!!es,true)}} +\unexpanded\def\MorseString #text{\ctxlua{moduledata.morse.tomorse(\!!bs#text\!!es)}} +\unexpanded\def\MorseFile #text{\ctxlua{moduledata.morse.filetomorse("#text")}} +\unexpanded\def\MorseTable {\ctxlua{moduledata.morse.showtable()}} + +\let\Morse \MorseString + +%def\MorseShort {·} +%def\MorseLong {—} + +\protect + +\continueifinputfile{m-morse.mkvi} + +\starttext + +\MorseTable + +\startlines +\MorseCode{—·—· ——— —· — · —··— —+—— —·— ·· ···—} +\MorseCode{—·—· ——— —· — · —··— — + —— —·— ·· ···—} +\Morse{ÀÁÂÃÄÅàáâãäå} +\Morse{ÆÇæç} +\Morse{ÈÉÊËèéêë} +\Morse{ÌÍÎÏìíîï} +\Morse{Ññ} +\Morse{ÒÓÔÕÖòóôõö} +\Morse{Øø} +\Morse{ÙÚÛÜùúû} +\Morse{Ýýÿ} +\Morse{ß} +\Morse{Ţţ} +\stoplines + +\Morse{A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} + +\stoptext diff --git a/tex/context/base/m-newotf.mkiv b/tex/context/base/m-newotf.mkiv index df91cbe02..8668eb827 100644 --- a/tex/context/base/m-newotf.mkiv +++ b/tex/context/base/m-newotf.mkiv @@ -11,6 +11,8 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. +% \endinput + %D This module will go away as soon as we use the new loader code by default. %D That will happen after extensive testing. Generic support will happen after %D that. @@ -19,6 +21,8 @@ \startluacode local files = { + "font-otj", +"font-otj-new", "font-otr", "font-cff", "font-ttf", @@ -67,6 +71,17 @@ directives.register("nodes.injections.fontkern", function(v) setfield(kern,"subtype",v and 0 or 1) end) + local fonts = fonts + local handlers = fonts.handlers + local otf = handlers.otf -- brrr + local afm = handlers.afm -- brrr + local getters = fonts.getters + + getters.kern .opentype = otf.getkern + getters.substitution.opentype = otf.getsubstitution + getters.alternate .opentype = otf.getalternate + getters.multiple .opentype = otf.getmultiple + \stopluacode \protect \endinput diff --git a/tex/context/base/node-fnt.lua b/tex/context/base/node-fnt.lua index 9cb9b487d..4272f304b 100644 --- a/tex/context/base/node-fnt.lua +++ b/tex/context/base/node-fnt.lua @@ -138,6 +138,8 @@ function fonts.setdiscexpansion(v) end end +fonts.setdiscexpansion(true) + function handlers.characters(head) -- either next or not, but definitely no already processed list starttiming(nodes) diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf Binary files differindex 7ccbf6cdc..b1f0fb99b 100644 --- a/tex/context/base/status-files.pdf +++ b/tex/context/base/status-files.pdf diff --git a/tex/context/base/status-lua.pdf b/tex/context/base/status-lua.pdf Binary files differindex c8718cfe4..0d09a329b 100644 --- a/tex/context/base/status-lua.pdf +++ b/tex/context/base/status-lua.pdf diff --git a/tex/context/base/typo-cap.lua b/tex/context/base/typo-cap.lua index eaf14bd63..7f0656130 100644 --- a/tex/context/base/typo-cap.lua +++ b/tex/context/base/typo-cap.lua @@ -11,6 +11,7 @@ local format, insert = string.format, table.insert local div, randomnumber = math.div, math.random local trace_casing = false trackers.register("typesetters.casing", function(v) trace_casing = v end) +local check_kerns = false directives.register("typesetters.casing.checkkerns", function(v) check_kerns = v end) local report_casing = logs.reporter("typesetting","casing") @@ -51,6 +52,8 @@ local userskip_code = skipcodes.userskip local tasks = nodes.tasks +local newkern = nuts.pool.kern + local fonthashes = fonts.hashes local fontdata = fonthashes.identifiers local fontchar = fonthashes.characters @@ -199,25 +202,67 @@ local function camel(start,attr,lastfont,n,count,where,first) return start, done_1 or done_2, true end +-- local function mixed(start,attr,lastfont,n,count,where,first) +-- if where == "post" then +-- return +-- end +-- local used = first or start +-- local char = getchar(first) +-- local dc = uccodes[char] +-- if not dc then +-- return start, false, true +-- elseif dc == char then +-- local lfa = lastfont[n] +-- if lfa then +-- setfield(first,"font",lfa) +-- return start, true, true +-- else +-- return start, false, true +-- end +-- else +-- replacer(first or start,uccodes) +-- return start, true, true +-- end +-- end + local function mixed(start,attr,lastfont,n,count,where,first) if where == "post" then return end local used = first or start - local char = getchar(first) + local char = getchar(used) local dc = uccodes[char] if not dc then return start, false, true elseif dc == char then local lfa = lastfont[n] if lfa then - setfield(first,"font",lfa) + setfield(used,"font",lfa) return start, true, true else return start, false, true end else - replacer(first or start,uccodes) + if check_kerns then + local p = getprev(used) + if p and getid(p) == glyph_code then + local c = lccodes[char] + local c = type(c) == "table" and c[1] or c + replacer(used,uccodes) + local fp = getfont(p) + local fc = getfont(used) + if fp ~= fc then + local k = fonts.getkern(fontdata[fp],getchar(p),c) + if k ~= 0 then + insert_after(p,p,newkern(k)) + end + end + else + replacer(used,uccodes) + end + else + replacer(used,uccodes) + end return start, true, true end end diff --git a/tex/context/base/typo-cap.mkiv b/tex/context/base/typo-cap.mkiv index 2859ba104..114532e4e 100644 --- a/tex/context/base/typo-cap.mkiv +++ b/tex/context/base/typo-cap.mkiv @@ -266,14 +266,14 @@ % [MixedCaps] % [MixedCaps*default cp \the\exheight] -\definefontfeature - [mixeddefault] - [default] - [extend=1.2] +% \definefontfeature +% [mixeddefault] +% [default] +% [extend=1.2] \definefont [MixedCaps] - [CurrentFont*default,mixeddefault cp \the\exheight] + [CurrentFont*default cp 1.2\exheight] \setupcapitals [\v!mixed] diff --git a/tex/generic/context/luatex/luatex-fonts-inj.lua b/tex/generic/context/luatex/luatex-fonts-inj.lua index cdf14b935..10108a271 100644 --- a/tex/generic/context/luatex/luatex-fonts-inj.lua +++ b/tex/generic/context/luatex/luatex-fonts-inj.lua @@ -549,9 +549,19 @@ local function inject_marks(marks,marki,nofmarks) else -- kern(x) glyph(p) kern(w-x) mark(n) -- ox = px - getfield(p,"width") + pn.markx - pp.leftkern - local leftkern = pp.leftkern - if leftkern then - ox = px - pn.markx - leftkern + -- + -- According to Kai we don't need to handle leftkern here but I'm + -- pretty sure I've run into a case where it was needed so maybe + -- some day we need something more clever here. + -- + if false then + -- a mark with kerning + local leftkern = pp.leftkern + if leftkern then + ox = px - pn.markx - leftkern + else + ox = px - pn.markx + end else ox = px - pn.markx end diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index da21fa6d8..7d3e981fe 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 : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 09/01/15 11:10:11 +-- merge date : 09/04/15 11:00:13 do -- begin closure to overcome local limits and interference @@ -9496,6 +9496,22 @@ function otf.getmultiple(tfmdata,k,kind) end return { k } end +function otf.getkern(tfmdata,left,right,kind) + local kerns=getgsub(tfmdata,left,kind or "kern",true) + if kerns then + local found=kerns[right] + local kind=type(found) + if kind=="table" then + found=found[1][3] + elseif kind~="number" then + found=false + end + if found then + return found*tfmdata.parameters.factor + end + end + return 0 +end end -- closure @@ -10572,9 +10588,15 @@ local function inject_marks(marks,marki,nofmarks) if pn.markdir<0 then ox=px-pn.markx-rightkern else - local leftkern=pp.leftkern - if leftkern then - ox=px-pn.markx-leftkern + + + if false then + local leftkern=pp.leftkern + if leftkern then + ox=px-pn.markx-leftkern + else + ox=px-pn.markx + end else ox=px-pn.markx end |