From 44edf674bc30f87263c01103774d60400b8b3915 Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Sun, 26 Feb 2012 17:47:33 +0200 Subject: Sync with context beta 2012.02.21 14:02 --- otfl-font-con.lua | 18 ++++- otfl-font-def.lua | 11 --- otfl-font-otf.lua | 8 +-- otfl-font-otn.lua | 196 +++++++++++++++++++++++++++++------------------------- otfl-node-inj.lua | 89 ++++++++++++++++--------- 5 files changed, 182 insertions(+), 140 deletions(-) diff --git a/otfl-font-con.lua b/otfl-font-con.lua index 42ac8c2..9280996 100644 --- a/otfl-font-con.lua +++ b/otfl-font-con.lua @@ -44,7 +44,6 @@ local setmetatableindex = table.setmetatableindex -- will be directives constructors.dontembed = allocate() -constructors.mathactions = { } constructors.autocleanup = true constructors.namemode = "fullpath" -- will be a function @@ -89,7 +88,7 @@ constructors.keys = { finalized = "boolean", }, parameters = { - mathsize = "scaledpoints", + mathsize = "number", scriptpercentage = "float", scriptscriptpercentage = "float", units = "cardinal", @@ -278,6 +277,14 @@ function constructors.assignmathparameters(target,original) -- simple variant, n end end +function constructors.beforecopyingcharacters(target,original) + -- can be used for additional tweaking +end + +function constructors.aftercopyingcharacters(target,original) + -- can be used for additional tweaking +end + function constructors.enhanceparameters(parameters) local xheight = parameters.x_height local quad = parameters.quad @@ -527,7 +534,7 @@ function constructors.scale(tfmdata,specification) -- local italickey = "italic" -- - -- some context specific trickery (we might move this to a plug in into here + -- some context specific trickery (this will move to a plugin) -- if hasmath then if properties.mathitalics then @@ -553,6 +560,8 @@ function constructors.scale(tfmdata,specification) -- -- end of context specific trickery -- + constructors.beforecopyingcharacters(target,tfmdata) + -- local sharedkerns = { } -- -- we can have a dumb mode (basemode without math etc) that skips most @@ -795,6 +804,9 @@ function constructors.scale(tfmdata,specification) end targetcharacters[unicode] = chr end + -- + constructors.aftercopyingcharacters(target,tfmdata) + -- return target end diff --git a/otfl-font-def.lua b/otfl-font-def.lua index 5f79170..10958cf 100644 --- a/otfl-font-def.lua +++ b/otfl-font-def.lua @@ -214,17 +214,6 @@ function definers.resolve(specification) else specification.forced = specification.forced end - -- for the moment here (goodies set outside features) - local goodies = specification.goodies - if goodies and goodies ~= "" then - local normal = specification.features.normal - if not normal then - specification.features.normal = { goodies = goodies } - elseif not normal.goodies then - normal.goodies = goodies - end - end - -- specification.hash = lower(specification.name .. ' @ ' .. constructors.hashfeatures(specification)) if specification.sub and specification.sub ~= "" then specification.hash = specification.sub .. ' @ ' .. specification.hash diff --git a/otfl-font-otf.lua b/otfl-font-otf.lua index 03376f9..27a64e9 100644 --- a/otfl-font-otf.lua +++ b/otfl-font-otf.lua @@ -49,7 +49,7 @@ local otf = fonts.handlers.otf otf.glists = { "gsub", "gpos" } -otf.version = 2.735 -- beware: also sync font-mis.lua +otf.version = 2.736 -- beware: also sync font-mis.lua otf.cache = containers.define("fonts", "otf", otf.version, true) local fontdata = fonts.hashes.identifiers @@ -848,7 +848,7 @@ actions["analyze glyphs"] = function(data,filename,raw) -- maybe integrate this local properties = data.properties local hasitalics = false local widths = { } - local marks = { } + local marks = { } -- always present (saves checking) for unicode, description in next, descriptions do local glyph = description.glyph local italic = glyph.italic_correction @@ -1029,7 +1029,8 @@ actions["reorganize subtables"] = function(data,filename,raw) for k=1,#dw do local gk = dw[k] local features = gk.features - if features and supported(features) then +-- if features and supported(features) then + if not features or supported(features) then -- not always features ! local typ = gk.type local chain = g_directions[typ] or 0 local subtables = gk.subtables @@ -1057,7 +1058,6 @@ actions["reorganize subtables"] = function(data,filename,raw) -- local name = gk.name -- - local features = gk.features if features then -- scripts, tag, ismac local f = { } diff --git a/otfl-font-otn.lua b/otfl-font-otn.lua index 12ea975..2fd910e 100644 --- a/otfl-font-otn.lua +++ b/otfl-font-otn.lua @@ -27,6 +27,7 @@ if not modules then modules = { } end modules ['font-otn'] = { -- default features (per language, script) -- handle positions (we need example fonts) -- handle gpos_single (we might want an extra width field in glyph nodes because adding kerns might interfere) +-- mark (to mark) code is still not what it should be (too messy but we need some more extreem husayni tests) --[[ldx--

This module is a bit more split up that I'd like but since we also want to test @@ -192,14 +193,21 @@ local ligature_code = glyphcodes.ligature local privateattribute = attributes.private +-- Something is messed up: we have two mark / ligature indices, one at the injection +-- end and one here ... this is bases in KE's patches but there is something fishy +-- there as I'm pretty sure that for husayni we need some connection (as it's much +-- more complex than an average font) but I need proper examples of all cases, not +-- of only some. + local state = privateattribute('state') local markbase = privateattribute('markbase') local markmark = privateattribute('markmark') -local markdone = privateattribute('markdone') +local markdone = privateattribute('markdone') -- assigned at the injection end local cursbase = privateattribute('cursbase') local curscurs = privateattribute('curscurs') local cursdone = privateattribute('cursdone') local kernpair = privateattribute('kernpair') +local ligacomp = privateattribute('ligacomp') -- assigned here (ideally it should be combined) local injections = nodes.injections local setmark = injections.setmark @@ -367,47 +375,38 @@ local function toligature(kind,lookupname,start,stop,char,markflag,discfound) -- current.subtype = ligature_code current.components = start local head = current - if deletemarks then - if trace_marks then - while start do - if marks[start.char] then - logwarning("%s: remove mark %s",pref(kind,lookupname),gref(start.char)) - end - start = start.next + -- this is messy ... we should get rid of the components eventually + local i = 0 -- is index of base + while start do + if not marks[start.char] then + i = i + 1 + elseif not deletemarks then -- quite fishy + set_attribute(start,ligacomp,i) + if trace_marks then + logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i) end + head, current = insert_node_after(head,current,copy_node(start)) end - else - local i = 0 - while start do - if marks[start.char] then - set_attribute(start,markdone,i) - if trace_marks then - logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i) - end - head, current = insert_node_after(head,current,copy_node(start)) - else - i = i + 1 - end - start = start.next - end - start = current.next - while start and start.id == glyph_code do - if marks[start.char] then - set_attribute(start,markdone,i) - if trace_marks then - logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i) - end - else - break + start = start.next + end + start = current.next + while start and start.id == glyph_code do + if marks[start.char] then + set_attribute(start,ligacomp,i) + if trace_marks then + logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i) end - start = start.next + else + break end + start = start.next end - -- we do need components in funny kerning mode but maybe I can better reconstruct then - -- as we do have the font components info available; removing components makes the - -- previous code much simpler - -- - -- flush_node_list(head.components) + -- + -- we do need components in funny kerning mode but maybe I can better reconstruct then + -- as we do have the font components info available; removing components makes the + -- previous code much simpler + -- + -- flush_node_list(head.components) return head end end @@ -659,18 +658,14 @@ function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence) local markchar = start.char if marks[markchar] then local base = start.prev -- [glyph] [optional marks] [start=mark] - local index = 1 if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then local basechar = base.char if marks[basechar] then - index = index + 1 while true do base = base.prev if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then basechar = base.char - if marks[basechar] then - index = index + 1 - else + if not marks[basechar] then break end else @@ -681,8 +676,7 @@ function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence) end end end - local i = has_attribute(start,markdone) - if i then index = i end + local index = has_attribute(start,ligacomp) local baseanchors = descriptions[basechar] if baseanchors then baseanchors = baseanchors.anchors @@ -696,7 +690,7 @@ function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence) if ma then ba = ba[index] if ba then - local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,index) + local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma) -- index if trace_marks then logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%s,%s)", pref(kind,lookupname),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy) @@ -727,46 +721,55 @@ end function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence) local markchar = start.char if marks[markchar] then ---~ local alreadydone = markonce and has_attribute(start,markmark) ---~ if not alreadydone then - local base = start.prev -- [glyph] [basemark] [start=mark] - if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then -- subtype test can go - local basechar = base.char - local baseanchors = descriptions[basechar] + local base = start.prev -- [glyph] [basemark] [start=mark] + -- while base and has_attribute(base,ligacomp) and has_attribute(base,ligacomp) ~= has_attribute(start,ligacomp) do + -- base = base.prev -- KE: prevents mkmk for marks on different components of a ligature + -- end + local slc = has_attribute(start,ligacomp) + if slc then -- a rather messy loop ... needs checking with husayni + while base do + local blc = has_attribute(base,ligacomp) + if blc and blc ~= slc then + base = base.prev + else + break + end + end + end + if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then -- subtype test can go + local basechar = base.char + local baseanchors = descriptions[basechar] + if baseanchors then + baseanchors = baseanchors.anchors if baseanchors then - baseanchors = baseanchors.anchors + baseanchors = baseanchors['basemark'] if baseanchors then - baseanchors = baseanchors['basemark'] - if baseanchors then - local al = anchorlookups[lookupname] - for anchor,ba in next, baseanchors do - if al[anchor] then - local ma = markanchors[anchor] - if ma then - local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%s,%s)", - pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy) - end - return start,true + local al = anchorlookups[lookupname] + for anchor,ba in next, baseanchors do + if al[anchor] then + local ma = markanchors[anchor] + if ma then + local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma) + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%s,%s)", + pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy) end + return start,true end end - if trace_bugs then - logwarning("%s: no matching anchors for mark %s and basemark %s",pref(kind,lookupname),gref(markchar),gref(basechar)) - end + end + if trace_bugs then + logwarning("%s: no matching anchors for mark %s and basemark %s",pref(kind,lookupname),gref(markchar),gref(basechar)) end end - else -- if trace_bugs then - -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar)) - onetimemessage(currentfont,basechar,"no base anchors",report_fonts) end - elseif trace_bugs then - logwarning("%s: prev node is no mark",pref(kind,lookupname)) + else -- if trace_bugs then + -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar)) + onetimemessage(currentfont,basechar,"no base anchors",report_fonts) end ---~ elseif trace_marks and trace_details then ---~ logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone) ---~ end + elseif trace_bugs then + logwarning("%s: prev node is no mark",pref(kind,lookupname)) + end elseif trace_bugs then logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar)) end @@ -1292,18 +1295,14 @@ function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext, end if markanchors then local base = start.prev -- [glyph] [optional marks] [start=mark] - local index = 1 if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then local basechar = base.char if marks[basechar] then - index = index + 1 while true do base = base.prev if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then basechar = base.char - if marks[basechar] then - index = index + 1 - else + if not marks[basechar] then break end else @@ -1315,8 +1314,7 @@ function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext, end end -- todo: like marks a ligatures hash - local i = has_attribute(start,markdone) - if i then index = i end + local index = has_attribute(start,ligacomp) local baseanchors = descriptions[basechar].anchors if baseanchors then local baseanchors = baseanchors['baselig'] @@ -1328,7 +1326,7 @@ function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext, if ma then ba = ba[index] if ba then - local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,index) + local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma) -- index if trace_marks then logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%s,%s)", cref(kind,chainname,chainlookupname,lookupname),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy) @@ -1369,6 +1367,20 @@ function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,look end if markanchors then local base = start.prev -- [glyph] [basemark] [start=mark] + -- while (base and has_attribute(base,ligacomp) and has_attribute(base,ligacomp) ~= has_attribute(start,ligacomp)) do + -- base = base.prev -- KE: prevents mkmk for marks on different components of a ligature + -- end + local slc = has_attribute(start,ligacomp) + if slc then -- a rather messy loop ... needs checking with husayni + while base do + local blc = has_attribute(base,ligacomp) + if blc and blc ~= slc then + base = base.prev + else + break + end + end + end if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then -- subtype test can go local basechar = base.char local baseanchors = descriptions[basechar].anchors @@ -1584,7 +1596,7 @@ local function show_skip(kind,chainname,char,ck,class) end local function normal_handle_contextchain(start,kind,chainname,contexts,sequence,lookuphash) - -- local rule, lookuptype, sequence, f, l, lookups = ck[1], ck[2] ,ck[3], ck[4], ck[5], ck[6] + -- local rule, lookuptype, sequence, f, l, lookups = ck[1], ck[2] ,ck[3], ck[4], ck[5], ck[6] local flags = sequence.flags local done = false local skipmark = flags[1] @@ -1806,11 +1818,15 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence if nofchainlookups == 1 then local chainlookupname = chainlookups[1] local chainlookup = lookuptable[chainlookupname] - local cp = chainprocs[chainlookup.type] - if cp then - start, done = cp(start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) - else - logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type) + if chainlookup then + local cp = chainprocs[chainlookup.type] + if cp then + start, done = cp(start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) + else + logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type) + end + else -- shouldn't happen + logprocess("%s is not yet supported",cref(kind,chainname,chainlookupname)) end else local i = 1 diff --git a/otfl-node-inj.lua b/otfl-node-inj.lua index 7c91016..246aaad 100644 --- a/otfl-node-inj.lua +++ b/otfl-node-inj.lua @@ -45,6 +45,7 @@ local cursbase = attributes.private('cursbase') local curscurs = attributes.private('curscurs') local cursdone = attributes.private('cursdone') local kernpair = attributes.private('kernpair') +local ligacomp = attributes.private('ligacomp') local fontkern = attributes.private('fontkern') if context then @@ -61,16 +62,21 @@ if context then end +-- This injector has been tested by Idris Samawi Hamid (several arabic fonts as well as +-- the rather demanding Husayni font), Khaled Hosny (latin and arabic) and Kaj Eigner +-- (arabic, hebrew and thai) and myself (whatever font I come across). I'm pretty sure +-- that this code is not 100% okay but examples are needed to figure things out. + local cursives = { } local marks = { } local kerns = { } --- currently we do gpos/kern in a bit inofficial way but when we --- have the extra fields in glyphnodes to manipulate ht/dp/wd --- explicitly i will provide an alternative; also, we can share --- tables +-- Currently we do gpos/kern in a bit inofficial way but when we have the extra fields in +-- glyphnodes to manipulate ht/dp/wd explicitly I will provide an alternative; also, we +-- can share tables. --- for the moment we pass the r2l key ... volt/arabtype tests +-- For the moment we pass the r2l key ... volt/arabtype tests .. idris: this needs +-- checking with husayni (volt and fontforge). function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext) local dx, dy = factor*(exit[1]-entry[1]), factor*(exit[2]-entry[2]) @@ -113,14 +119,16 @@ function injections.setkern(current,factor,rlmode,x,tfmchr) end end -function injections.setmark(start,base,factor,rlmode,ba,ma,index) --ba=baseanchor, ma=markanchor - local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2]) - local bound = has_attribute(base,markbase) +function injections.setmark(start,base,factor,rlmode,ba,ma,index) -- ba=baseanchor, ma=markanchor + local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2]) -- the index argument is no longer used but when this + local bound = has_attribute(base,markbase) -- fails again we should pass it +local index = 1 if bound then local mb = marks[bound] if mb then - if not index then index = #mb + 1 end - mb[index] = { dx, dy } + -- if not index then index = #mb + 1 end +index = #mb + 1 + mb[index] = { dx, dy, rlmode } set_attribute(start,markmark,bound) set_attribute(start,markdone,index) return dx, dy, bound @@ -128,6 +136,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,index) --ba=baseancho report_injections("possible problem, U+%05X is base mark without data (id: %s)",base.char,bound) end end +-- index = index or 1 index = index or 1 bound = #marks + 1 set_attribute(base,markbase,bound) @@ -174,7 +183,7 @@ local function trace(head) end else m = m[1] - report_injections(" markmark: bound=%s, dx=%s, dy=%s",mm,m[1] or "?",m[2] or "?") + report_injections(" markmark: bound=%s, dx=%s, dy=%s",mm,m and m[1] or "?",m and m[2] or "?") end end if cb then @@ -192,7 +201,8 @@ end -- todo: reuse tables (i.e. no collection), but will be extra fields anyway -- todo: check for attribute --- we can have a fast test on a font being processed, so we can check faster for marks etc +-- We can have a fast test on a font being processed, so we can check faster for marks etc +-- but I'll make a context variant anyway. function injections.handler(head,where,keep) local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns) @@ -330,6 +340,7 @@ function injections.handler(head,where,keep) local p_markbase = has_attribute(p,markbase) if p_markbase then local mrks = marks[p_markbase] + local nofmarks = #mrks for n in traverse_id(glyph_code,p.next) do local n_markmark = has_attribute(n,markmark) if p_markbase == n_markmark then @@ -343,7 +354,7 @@ function injections.handler(head,where,keep) -- that makes sense but we no longer do that so as a -- consequence the sign of p.width was changed (we need -- to keep an eye on it as we don't have that many fonts - -- that enter this branch .. i'm still not sure if this + -- that enter this branch .. I'm still not sure if this -- one is right local k = wx[p] if k then @@ -366,9 +377,14 @@ function injections.handler(head,where,keep) else n.yoffset = n.yoffset + p.yoffset + d[2] end + if nofmarks == 1 then + break + else + nofmarks = nofmarks - 1 + end end else - break + -- KE: there can be sequences in ligatures end end end @@ -380,23 +396,32 @@ function injections.handler(head,where,keep) -- todo : combine if next(wx) then for n, k in next, wx do - -- only w can be nil, can be sped up when w == nil - local rl, x, w, r2l = k[1], k[2] or 0, k[4] or 0, k[6] - local wx = w - x - if r2l then - if wx ~= 0 then - insert_node_before(head,n,newkern(wx)) - end - if x ~= 0 then - insert_node_after (head,n,newkern(x)) - end - else - if x ~= 0 then - insert_node_before(head,n,newkern(x)) - end - if wx ~= 0 then - insert_node_after(head,n,newkern(wx)) + -- only w can be nil (kernclasses), can be sped up when w == nil + local x, w = k[2] or 0, k[4] + if w then + local rl = k[1] -- r2l = k[6] + local wx = w - x + if rl < 0 then -- KE: don't use r2l here + if wx ~= 0 then + insert_node_before(head,n,newkern(wx)) + end + if x ~= 0 then + insert_node_after (head,n,newkern(x)) + end + else + if x ~= 0 then + insert_node_before(head,n,newkern(x)) + end + if wx ~= 0 then + insert_node_after(head,n,newkern(wx)) + end end + elseif x ~= 0 then + -- 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) + insert_node_before(head,n,newkern(x)) end end end @@ -435,9 +460,9 @@ function injections.handler(head,where,keep) end if w then -- copied from above - local r2l = kk[6] + -- local r2l = kk[6] local wx = w - x - if r2l then + if rl < 0 then -- KE: don't use r2l here if wx ~= 0 then insert_node_before(head,n,newkern(wx)) end -- cgit v1.2.3