From 4f053696e1813fde4bd6cebbb77ff2a1e1f6800b Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 29 Oct 2015 07:14:40 +0100 Subject: [fontloader] sync with Context as of 2015-10-29 --- src/fontloader/misc/fontloader-fonts-inj.lua | 375 +++++++++++++++++---------- 1 file changed, 236 insertions(+), 139 deletions(-) (limited to 'src/fontloader/misc/fontloader-fonts-inj.lua') diff --git a/src/fontloader/misc/fontloader-fonts-inj.lua b/src/fontloader/misc/fontloader-fonts-inj.lua index 332e920..36781f7 100644 --- a/src/fontloader/misc/fontloader-fonts-inj.lua +++ b/src/fontloader/misc/fontloader-fonts-inj.lua @@ -8,7 +8,16 @@ if not modules then modules = { } end modules ['font-inj'] = { -- 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! +-- 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 @@ -80,8 +89,7 @@ function injections.resetcounts() keepregisteredcounts = false end --- We need to make sure that a possible metatable will not kick in --- unexpectedly. +-- We need to make sure that a possible metatable will not kick in unexpectedly. function injections.reset(n) local p = rawget(properties,n) @@ -146,7 +154,8 @@ 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, wn = tfmstart.width, tfmnext.width + local ws = tfmstart.width + local wn = tfmnext.width nofregisteredcursives = nofregisteredcursives + 1 if rlmode < 0 then dx = -(dx + wn) @@ -195,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 @@ -205,9 +217,12 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l 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,"injections") + local i = rawget(p,injection) if i then if leftkern ~= 0 then i.leftkern = (i.leftkern or 0) + leftkern @@ -219,19 +234,19 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l i.yoffset = (i.yoffset or 0) + yoffset end elseif leftkern ~= 0 or rightkern ~= 0 then - p.injections = { + p[injection] = { leftkern = leftkern, rightkern = rightkern, yoffset = yoffset, } else - p.injections = { + p[injection] = { yoffset = yoffset, } end elseif leftkern ~= 0 or rightkern ~= 0 then properties[current] = { - injections = { + [injection] = { leftkern = leftkern, rightkern = rightkern, yoffset = yoffset, @@ -239,7 +254,7 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l } else properties[current] = { - injections = { + [injection] = { yoffset = yoffset, }, } @@ -250,10 +265,9 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l 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) +-- 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 @@ -285,7 +299,7 @@ function injections.setkern(current,factor,rlmode,x,injection) end end -function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) -- ba=baseanchor, ma=markanchor +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 @@ -293,14 +307,20 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) -- ba=basean 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 - i.markx = dx - i.marky = dy - i.markdir = rlmode or 0 - i.markbase = nofregisteredmarks - i.markbasenode = base + 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, @@ -308,6 +328,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) -- ba=basean markdir = rlmode or 0, markbase = nofregisteredmarks, markbasenode = base, + markmark = mkmk, } end else @@ -318,6 +339,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) -- ba=basean markdir = rlmode or 0, markbase = nofregisteredmarks, markbasenode = base, + markmark = mkmk, }, } end @@ -430,30 +452,36 @@ local function show_result(head) end end --- we could also check for marks here but maybe not all are registered (needs checking) - -local function collect_glyphs_1(head) - local glyphs, nofglyphs = { }, 0 - local marks, nofmarks = { }, 0 +local function collect_glyphs(head,offsets) + local glyphs, glyphi, nofglyphs = { }, { }, 0 + local marks, marki, nofmarks = { }, { }, 0 local nf, tm = nil, nil - for n in traverse_id(glyph_code,head) do -- only needed for relevant fonts - if getsubtype(n) < 256 then - local f = getfont(n) - if f ~= nf then - nf = f - tm = fontdata[nf].resources.marks -- other hash in ctx - end - if tm and tm[getchar(n)] then - nofmarks = nofmarks + 1 - marks[nofmarks] = n - else - nofglyphs = nofglyphs + 1 - glyphs[nofglyphs] = n + local n = head + + local function identify(n,what) + local f = getfont(n) + if f ~= nf then + nf = f + -- other hash in ctx: + tm = fontdata[nf].resources + if tm then + tm = tm.marks end + end + if tm and tm[getchar(n)] then + nofmarks = nofmarks + 1 + marks[nofmarks] = n + marki[nofmarks] = "injections" + else + nofglyphs = nofglyphs + 1 + glyphs[nofglyphs] = n + glyphi[nofglyphs] = what + end + if offsets then -- yoffsets can influence curs steps local p = rawget(properties,n) if p then - local i = rawget(p,"injections") + local i = rawget(p,what) if i then local yoffset = i.yoffset if yoffset and yoffset ~= 0 then @@ -463,38 +491,50 @@ local function collect_glyphs_1(head) end end end - return glyphs, nofglyphs, marks, nofmarks -end -local function collect_glyphs_2(head) - local glyphs, nofglyphs = { }, 0 - local marks, nofmarks = { }, 0 - local nf, tm = nil, nil - for n in traverse_id(glyph_code,head) do - if getsubtype(n) < 256 then - local f = getfont(n) - if f ~= nf then - nf = f - tm = fontdata[nf].resources.marks -- other hash in ctx - end - if tm and tm[getchar(n)] then - nofmarks = nofmarks + 1 - marks[nofmarks] = n - else - nofglyphs = nofglyphs + 1 - glyphs[nofglyphs] = n - end + while n do -- only needed for relevant fonts + local id = getid(n) + if id == glyph_code then + identify(n,"injections") + elseif id == disc_code then + local d = getfield(n,"pre") + if d then + for n in traverse_id(glyph_code,d) do + if getsubtype(n) < 256 then + identify(n,"preinjections") + end + end + end + local d = getfield(n,"post") + if d then + for n in traverse_id(glyph_code,d) do + if getsubtype(n) < 256 then + identify(n,"postinjections") + end + end + end + local d = getfield(n,"replace") + if d then + for n in traverse_id(glyph_code,d) do + if getsubtype(n) < 256 then + identify(n,"replaceinjections") + end + end + end end + n = getnext(n) end - return glyphs, nofglyphs, marks, nofmarks + + return glyphs, glyphi, nofglyphs, marks, marki, nofmarks end -local function inject_marks(marks,nofmarks) +local function inject_marks(marks,marki,nofmarks) for i=1,nofmarks do - local n = marks[i] + local n = marks[i] local pn = rawget(properties,n) if pn then - pn = rawget(pn,"injections") + local ni = marki[i] + local pn = rawget(pn,ni) if pn then local p = pn.markbasenode if p then @@ -503,7 +543,7 @@ local function inject_marks(marks,nofmarks) local rightkern = nil local pp = rawget(properties,p) if pp then - pp = rawget(pp,"injections") + pp = rawget(pp,ni) if pp then rightkern = pp.rightkern end @@ -516,13 +556,22 @@ local function inject_marks(marks,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 + -- + -- 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 - leftkern + ox = px - pn.markx end --- report_injections("l2r case 1: %p",ox) end else -- we need to deal with fonts that have marks with width @@ -548,12 +597,13 @@ local function inject_marks(marks,nofmarks) 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 = 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) else -- normally this can't happen (only when in trace mode which is a special case anyway) @@ -564,14 +614,14 @@ local function inject_marks(marks,nofmarks) end end -local function inject_cursives(glyphs,nofglyphs) +local function inject_cursives(glyphs,glyphi,nofglyphs) local cursiveanchor, lastanchor = nil, nil local minc, maxc, last = 0, 0, nil for i=1,nofglyphs do - local n = glyphs[i] + local n = glyphs[i] local pn = rawget(properties,n) if pn then - pn = rawget(pn,"injections") + pn = rawget(pn,glyphi[i]) end if pn then local cursivex = pn.cursivex @@ -630,7 +680,7 @@ local function inject_cursives(glyphs,nofglyphs) -- if maxc > 0 and not cursiveanchor then -- local ny = getfield(n,"yoffset") -- for i=maxc,minc,-1 do - -- local ti = glyphs[i] + -- local ti = glyphs[i][1] -- ny = ny + properties[ti].cursivedy -- setfield(ti,"yoffset",ny) -- why not add ? -- end @@ -647,23 +697,67 @@ local function inject_cursives(glyphs,nofglyphs) end end -local function inject_kerns(head,list,length) - -- todo: pre/post/replace +-- 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(head,glist,ilist,length) -- not complete ! compare with inject_kerns_only (but unlikely disc here) for i=1,length do - local n = list[i] + local n = glist[i] local pn = rawget(properties,n) if pn then - local i = rawget(pn,"injections") - if i then - local leftkern = i.leftkern - if leftkern and leftkern ~= 0 then - insert_node_before(head,n,newkern(leftkern)) -- type 0/2 - end - local rightkern = i.rightkern - if rightkern and rightkern ~= 0 then - insert_node_after(head,n,newkern(rightkern)) -- type 0/2 - end - end + local dp = nil + local dr = nil + local ni = ilist[i] + local p = nil + if ni == "injections" then + p = getprev(n) + if p then + local id = getid(p) + if id == disc_code then + dp = getfield(p,"post") + dr = getfield(p,"replace") + end + end + end + if dp then + local i = rawget(pn,"postinjections") + if i then + local leftkern = i.leftkern + 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 + end + end + end + if dr then + local i = rawget(pn,"replaceinjections") + if i then + local leftkern = i.leftkern + 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 + end + end + else + local i = rawget(pn,ni) + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + insert_node_before(head,n,newkern(leftkern)) -- type 0/2 + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(head,n,newkern(rightkern)) -- type 0/2 + end + end + end end end end @@ -673,23 +767,18 @@ local function inject_everything(head,where) if trace_injections then trace(head,"everything") end - local glyphs, nofglyphs, marks, nofmarks - if nofregisteredpairs > 0 then - glyphs, nofglyphs, marks, nofmarks = collect_glyphs_1(head) - else - glyphs, nofglyphs, marks, nofmarks = collect_glyphs_2(head) - end + local glyphs, glyphi, nofglyphs, marks, marki, nofmarks = collect_glyphs(head,nofregisteredpairs > 0) if nofglyphs > 0 then if nofregisteredcursives > 0 then - inject_cursives(glyphs,nofglyphs) + inject_cursives(glyphs,glyphi,nofglyphs) end if nofregisteredmarks > 0 then -- and nofmarks > 0 - inject_marks(marks,nofmarks) + inject_marks(marks,marki,nofmarks) end - inject_kerns(head,glyphs,nofglyphs) + inject_kerns(head,glyphs,glyphi,nofglyphs) end if nofmarks > 0 then - inject_kerns(head,marks,nofmarks) + inject_kerns(head,marks,marki,nofmarks) end if keepregisteredcounts then keepregisteredcounts = false @@ -702,13 +791,21 @@ local function inject_everything(head,where) return tonode(head), true 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 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 @@ -724,6 +821,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 end end end @@ -735,6 +833,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,"replace",d) -- currently we need to force a tail refresh end end else @@ -747,6 +846,7 @@ local function inject_kerns_only(head,where) end end else + -- this is the most common case local i = rawget(pn,"injections") if i then local leftkern = i.leftkern @@ -756,8 +856,6 @@ local function inject_kerns_only(head,where) end end end - else - break end p = nil elseif id == disc_code then @@ -812,7 +910,7 @@ local function inject_kerns_only(head,where) 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 @@ -850,9 +948,8 @@ local function inject_pairs_only(head,where) if trace_injections then trace(head,"pairs") 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 @@ -868,6 +965,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 end -- local rightkern = i.rightkern -- if rightkern and rightkern ~= 0 then @@ -884,6 +982,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,"replace",d) -- currently we need to force a tail refresh end -- local rightkern = i.rightkern -- if rightkern and rightkern ~= 0 then @@ -909,24 +1008,22 @@ local function inject_pairs_only(head,where) -- 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 @@ -935,16 +1032,12 @@ local function inject_pairs_only(head,where) 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 @@ -952,6 +1045,10 @@ local function inject_pairs_only(head,where) 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 @@ -967,14 +1064,10 @@ local function inject_pairs_only(head,where) 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)) @@ -984,6 +1077,10 @@ local function inject_pairs_only(head,where) 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 @@ -999,14 +1096,10 @@ local function inject_pairs_only(head,where) 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)) @@ -1016,6 +1109,10 @@ local function inject_pairs_only(head,where) 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 @@ -1042,7 +1139,7 @@ local function inject_pairs_only(head,where) return tonode(head), true end -function injections.handler(head,where) -- optimize for n=1 ? +function injections.handler(head,where) if nofregisteredmarks > 0 or nofregisteredcursives > 0 then return inject_everything(head,where) elseif nofregisteredpairs > 0 then -- cgit v1.2.3