diff options
Diffstat (limited to 'tex/context/base/font-ots.lua')
-rw-r--r-- | tex/context/base/font-ots.lua | 790 |
1 files changed, 453 insertions, 337 deletions
diff --git a/tex/context/base/font-ots.lua b/tex/context/base/font-ots.lua index 3bb2d326a..dd50a2e62 100644 --- a/tex/context/base/font-ots.lua +++ b/tex/context/base/font-ots.lua @@ -196,7 +196,6 @@ local wildcard = "*" local default = "dflt" local nodecodes = nodes.nodecodes -local whatcodes = nodes.whatcodes local glyphcodes = nodes.glyphcodes local disccodes = nodes.disccodes @@ -204,8 +203,8 @@ local glyph_code = nodecodes.glyph local glue_code = nodecodes.glue local disc_code = nodecodes.disc local math_code = nodecodes.math -local dir_code = nodecodes.dir or whatcodes.dir -local localpar_code = nodecodes.localpar or whatcodes.localpar +local dir_code = nodecodes.dir +local localpar_code = nodecodes.localpar local discretionary_code = disccodes.discretionary local ligature_code = glyphcodes.ligature @@ -314,7 +313,9 @@ local function gref(n) -- currently the same as in font-otb end local function cref(dataset,sequence,index) - if index then + if not dataset then + return "no valid dataset" + elseif index then return formatters["feature %a, type %a, chain lookup %a, index %a"](dataset[4],sequence.type,sequence.name,index) else return formatters["feature %a, type %a, chain lookup %a"](dataset[4],sequence.type,sequence.name) @@ -671,7 +672,7 @@ local function multiple_glyphs(head,start,multiple,ignoremarks) setchar(start,multiple[1]) if nofmultiples > 1 then local sn = getnext(start) - for k=2,nofmultiples do -- todo: use insert_node + for k=2,nofmultiples do -- untested: -- -- while ignoremarks and marks[getchar(sn)] then @@ -680,11 +681,7 @@ local function multiple_glyphs(head,start,multiple,ignoremarks) local n = copy_node(start) -- ignore components resetinjection(n) setchar(n,multiple[k]) - setboth(n,start,sn) - if sn then - setprev(sn,n) - end - setnext(start,n) + insert_node_after(head,start,n) start = n end end @@ -777,9 +774,9 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature) local startchar = getchar(start) if marks[startchar] then while current do - local id = getid(current) - if ischar(current,currentfont) then - local lg = ligature[getchar(current)] + local ch = ischar(current,currentfont) + if ch then + local lg = ligature[ch] if lg then stop = current ligature = lg @@ -814,8 +811,8 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature) local id = getid(current) -- weird test here if id == glyph_code then -- not needed - if ischar(current,currentfont) then - local char = getchar(current) + local char = ischar(current,currentfont) + if char then if skipmark and marks[char] then current = getnext(current) else -- ligature is a tree @@ -894,50 +891,54 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje else local prev = start local done = false - while snext and ischar(snext,currentfont) do - local nextchar = getchar(snext) - local krn = kerns[nextchar] - if not krn and marks[nextchar] then - prev = snext - snext = getnext(snext) - elseif not krn then - break - elseif step.format == "pair" then - local a, b = krn[1], krn[2] - if optimizekerns then - -- this permits a mixed table, but we could also decide to optimize this - -- in the loader and use format 'kern' - if not b and a[1] == 0 and a[2] == 0 and a[4] == 0 then - local k = setkern(snext,factor,rlmode,a[3],injection) + while snext do + local nextchar = ischar(snext,currentfont) + if nextchar then + local krn = kerns[nextchar] + if not krn and marks[nextchar] then + prev = snext + snext = getnext(snext) + elseif not krn then + break + elseif step.format == "pair" then + local a, b = krn[1], krn[2] + if optimizekerns then + -- this permits a mixed table, but we could also decide to optimize this + -- in the loader and use format 'kern' + if not b and a[1] == 0 and a[2] == 0 and a[4] == 0 then + local k = setkern(snext,factor,rlmode,a[3],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) if trace_kerns then - logprocess("%s: shifting single %s by %p",pref(dataset,sequence),gref(nextchar),k) + local startchar = getchar(start) + 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 - 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) - if trace_kerns then - local startchar = getchar(start) - 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") + if b and #b > 0 then + 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) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") + end end - end - if b and #b > 0 then - local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,injection) + done = true + break + elseif krn ~= 0 then + local k = setkern(snext,factor,rlmode,krn,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) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") + 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 end - done = true - break - 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 as %s",pref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar),injection or "injections") - end - done = true + else break end end @@ -956,36 +957,47 @@ function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode) local markchar = getchar(start) if marks[markchar] then local base = getprev(start) -- [glyph] [start=mark] - if base and ischar(base,currentfont) then - local basechar = getchar(base) - if marks[basechar] then - while true do - base = getprev(base) - if base and ischar(base,currentfont) then - basechar = getchar(base) - if not marks[basechar] then - break - end - else - if trace_bugs then - logwarning("%s: no base for mark %s",pref(dataset,sequence),gref(markchar)) + if base then + local basechar = ischar(base,currentfont) + if basechar then + if marks[basechar] then + while true do + base = getprev(base) + if base then + basechar = ischar(base,currentfont) + if basechar then + if not marks[basechar] then + break + end + else + if trace_bugs then + logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1) + end + return head, start, false + end + else + if trace_bugs then + logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2) + end + return head, start, false end - return head, start, false end end - end - local ba = markanchors[1][basechar] - if ba then - local ma = markanchors[2] - local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar]) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)", - pref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy) + local ba = markanchors[1][basechar] + if ba then + local ma = markanchors[2] + local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar]) + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)", + pref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy) + end + return head, start, true end - return head, start, true + elseif trace_bugs then + logwarning("%s: nothing preceding, case %i",pref(dataset,sequence),1) end elseif trace_bugs then - logwarning("%s: prev node is no char",pref(dataset,sequence)) + logwarning("%s: nothing preceding, case %i",pref(dataset,sequence),2) end elseif trace_bugs then logwarning("%s: mark %s is no mark",pref(dataset,sequence),gref(markchar)) @@ -999,49 +1011,60 @@ function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlm local markchar = getchar(start) if marks[markchar] then local base = getprev(start) -- [glyph] [optional marks] [start=mark] - if base and ischar(base,currentfont) then - local basechar = getchar(base) - if marks[basechar] then - while true do - base = getprev(base) - if base and ischar(base,currentfont) then - basechar = getchar(base) - if not marks[basechar] then - break - end - else - if trace_bugs then - logwarning("%s: no base for mark %s",pref(dataset,sequence),gref(markchar)) + if base then + local basechar = ischar(base,currentfont) + if basechar then + if marks[basechar] then + while true do + base = getprev(base) + if base then + basechar = ischar(base,currentfont) + if basechar then + if not marks[basechar] then + break + end + else + if trace_bugs then + logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1) + end + return head, start, false + end + else + if trace_bugs then + logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2) + end + return head, start, false end - return head, start, false end end - end - local ba = markanchors[1][basechar] - if ba then - local ma = markanchors[2] - if ma then - local index = getligaindex(start) - ba = ba[index] - if ba then - local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar]) -- index - if trace_marks then - logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)", - pref(dataset,sequence),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy) - end - return head, start, true - else - if trace_bugs then - logwarning("%s: no matching anchors for mark %s and baselig %s with index %a",pref(dataset,sequence),gref(markchar),gref(basechar),index) + local ba = markanchors[1][basechar] + if ba then + local ma = markanchors[2] + if ma then + local index = getligaindex(start) + ba = ba[index] + if ba then + local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar]) -- index + if trace_marks then + logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)", + pref(dataset,sequence),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy) + end + return head, start, true + else + if trace_bugs then + logwarning("%s: no matching anchors for mark %s and baselig %s with index %a",pref(dataset,sequence),gref(markchar),gref(basechar),index) + end end end + elseif trace_bugs then + -- logwarning("%s: char %s is missing in font",pref(dataset,sequence),gref(basechar)) + onetimemessage(currentfont,basechar,"no base anchors",report_fonts) end elseif trace_bugs then - -- logwarning("%s: char %s is missing in font",pref(dataset,sequence),gref(basechar)) - onetimemessage(currentfont,basechar,"no base anchors",report_fonts) + logwarning("%s: prev node is no char, case %i",pref(dataset,sequence),1) end elseif trace_bugs then - logwarning("%s: prev node is no char",pref(dataset,sequence)) + logwarning("%s: prev node is no char, case %i",pref(dataset,sequence),2) end elseif trace_bugs then logwarning("%s: mark %s is no mark",pref(dataset,sequence),gref(markchar)) @@ -1064,17 +1087,19 @@ function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode) end end end - if base and ischar(base,currentfont) then -- subtype test can go - local basechar = getchar(base) - local ba = markanchors[1][basechar] -- slot 1 has been made copy of the class hash - if ba then - local ma = markanchors[2] - local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)", - pref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy) + if base then + local basechar = ischar(base,currentfont) + if basechar then -- subtype test can go + local ba = markanchors[1][basechar] -- slot 1 has been made copy of the class hash + if ba then + local ma = markanchors[2] + local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true) + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)", + pref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy) + end + return head, start, true end - return head, start, true end end elseif trace_bugs then @@ -1094,9 +1119,11 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st end else local nxt = getnext(start) - while not done and nxt and ischar(nxt,currentfont) do - local nextchar = getchar(nxt) - if marks[nextchar] then + while not done and nxt do + local nextchar = ischar(nxt,currentfont) + if not nextchar then + break + elseif marks[nextchar] then -- should not happen (maybe warning) nxt = getnext(nxt) else @@ -1159,7 +1186,7 @@ local logwarning = report_chain -- in a bit weird way. There is no lookup and the replacement comes from the lookup -- itself. It is meant mostly for dealing with Urdu. -function chainprocs.reversesub(head,start,stop,dataset,sequence,replacements,rlmode) +local function reversesub(head,start,stop,dataset,sequence,replacements,rlmode) local char = getchar(start) local replacement = replacements[char] if replacement then @@ -1174,6 +1201,9 @@ function chainprocs.reversesub(head,start,stop,dataset,sequence,replacements,rlm end end + +chainprocs.reversesub = reversesub + --[[ldx-- <p>This chain stuff is somewhat tricky since we can have a sequence of actions to be applied: single, alternate, multiple or ligature where ligature can be an invalid @@ -1282,7 +1312,7 @@ function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup end else if trace_multiples then - logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacements)) + logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement)) end return multiple_glyphs(head,start,replacement,currentlookup.flags[1]) -- not sequence.flags? end @@ -1463,8 +1493,11 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm if kerns then local prev = start local done = false - while snext and ischar(snext,currentfont) do - local nextchar = getchar(snext) + while snext do + local nextchar = ischar(snext,currentfont) + if not nextchar then + break + end local krn = kerns[nextchar] if not krn and marks[nextchar] then prev = snext @@ -1527,38 +1560,49 @@ function chainprocs.gpos_mark2base(head,start,stop,dataset,sequence,currentlooku local markanchors = steps[1].coverage[markchar] -- always 1 step if markanchors then local base = getprev(start) -- [glyph] [start=mark] - if base and ischar(base,currentfont) then - local basechar = getchar(base) - if marks[basechar] then - while true do - base = getprev(base) - if base and ischar(base,currentfont) then - basechar = getchar(base) - if not marks[basechar] then - break - end - else - if trace_bugs then - logwarning("%s: no base for mark %s",pref(dataset,sequence),gref(markchar)) + if base then + local basechar = ischar(base,currentfont) + if basechar then + if marks[basechar] then + while true do + base = getprev(base) + if base then + local basechar = ischar(base,currentfont) + if basechar then + if not marks[basechar] then + break + end + else + if trace_bugs then + logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1) + end + return head, start, false + end + else + if trace_bugs then + logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2) + end + return head, start, false end - return head, start, false end end - end - local ba = markanchors[1][basechar] - if ba then - local ma = markanchors[2] - if ma then - local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar]) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)", - cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy) + local ba = markanchors[1][basechar] + if ba then + local ma = markanchors[2] + if ma then + local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar]) + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)", + cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy) + end + return head, start, true end - return head, start, true end + elseif trace_bugs then + logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),1) end elseif trace_bugs then - logwarning("%s: prev node is no char",cref(dataset,sequence)) + logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),2) end elseif trace_bugs then logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar)) @@ -1580,42 +1624,53 @@ function chainprocs.gpos_mark2ligature(head,start,stop,dataset,sequence,currentl local markanchors = steps[1].coverage[markchar] -- always 1 step if markanchors then local base = getprev(start) -- [glyph] [optional marks] [start=mark] - if base and ischar(base,currentfont) then - local basechar = getchar(base) - if marks[basechar] then - while true do - base = getprev(base) - if base and ischar(base,currentfont) then - basechar = getchar(base) - if not marks[basechar] then - break - end - else - if trace_bugs then - logwarning("%s: no base for mark %s",cref(dataset,sequence),markchar) + if base then + local basechar = ischar(base,currentfont) + if basechar then + if marks[basechar] then + while true do + base = getprev(base) + if base then + local basechar = ischar(base,currentfont) + if basechar then + if not marks[basechar] then + break + end + else + if trace_bugs then + logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,1) + end + return head, start, false + end + else + if trace_bugs then + logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,2) + end + return head, start, false end - return head, start, false end end - end - local ba = markanchors[1][basechar] - if ba then - local ma = markanchors[2] - if ma then - local index = getligaindex(start) - ba = ba[index] - if ba then - local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar]) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)", - cref(dataset,sequence),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy) + local ba = markanchors[1][basechar] + if ba then + local ma = markanchors[2] + if ma then + local index = getligaindex(start) + ba = ba[index] + if ba then + local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar]) + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)", + cref(dataset,sequence),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy) + end + return head, start, true end - return head, start, true end end + elseif trace_bugs then + logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),1) end elseif trace_bugs then - logwarning("%s, prev node is no char",cref(dataset,sequence)) + logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),2) end elseif trace_bugs then logwarning("%s, mark %s has no anchors",cref(dataset,sequence),gref(markchar)) @@ -1648,22 +1703,26 @@ function chainprocs.gpos_mark2mark(head,start,stop,dataset,sequence,currentlooku end end end - if base and ischar(base,currentfont) then -- subtype test can go - local basechar = getchar(base) - local ba = markanchors[1][basechar] - if ba then - local ma = markanchors[2] - if ma then - local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)", - cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy) + if base then -- subtype test can go + local basechar = ischar(base,currentfont) + if basechar then + local ba = markanchors[1][basechar] + if ba then + local ma = markanchors[2] + if ma then + local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true) + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)", + cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy) + end + return head, start, true end - return head, start, true end + elseif trace_bugs then + logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),1) end elseif trace_bugs then - logwarning("%s: prev node is no mark",cref(dataset,sequence)) + logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),2) end elseif trace_bugs then logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar)) @@ -1692,9 +1751,11 @@ function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup, end else local nxt = getnext(start) - while not done and nxt and ischar(nxt,currentfont) do - local nextchar = getchar(nxt) - if marks[nextchar] then + while not done and nxt do + local nextchar = ischar(nxt,currentfont) + if not nextchar then + break + elseif marks[nextchar] then -- should not happen (maybe warning) nxt = getnext(nxt) else @@ -1934,11 +1995,16 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c local cprev = getprev(start) local insertedmarks = 0 - while cprev and ischar(cf,currentfont) and marks[getchar(cf)] do - insertedmarks = insertedmarks + 1 - cf = cprev - startishead = cf == head - cprev = getprev(cprev) + while cprev do + local char = ischar(cf,currentfont) + if char and marks[char] then + insertedmarks = insertedmarks + 1 + cf = cprev + startishead = cf == head + cprev = getprev(cprev) + else + break + end end setprev(lookaheaddisc,cprev) @@ -1985,10 +2051,15 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c local cnext = getnext(start) local insertedmarks = 0 - while cnext and ischar(cnext,currentfont) and marks[getchar(cnext)] do - insertedmarks = insertedmarks + 1 - cl = cnext - cnext = getnext(cnext) + while cnext do + local char = ischar(cnext,currentfont) + if char and marks[char] then + insertedmarks = insertedmarks + 1 + cl = cnext + cnext = getnext(cnext) + else + break + end end if cnext then setprev(cnext,backtrackdisc) @@ -2119,7 +2190,8 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) -- f..l = mid string if s == 1 then -- never happens - match = ischar(current,currentfont) and seq[1][getchar(current)] + local char = ischar(current,currentfont) + match = char and seq[1][char] else -- maybe we need a better space check (maybe check for glue or category or combination) -- we cannot optimize for n=2 because there can be disc nodes @@ -2145,8 +2217,8 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) if last then local id = getid(last) if id == glyph_code then - if ischar(last,currentfont) then - local char = getchar(last) + local char = ischar(last,currentfont) + if char then local ccd = descriptions[char] if ccd then local class = ccd.class or "base" @@ -2259,15 +2331,15 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) if prev then local id = getid(prev) if id == glyph_code then - if ischar(prev,currentfont) then - local char = getchar(prev) + local char = ischar(prev,currentfont) + if char then local ccd = descriptions[char] if ccd then local class = ccd.class if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then skipped = true if trace_skips then - show_skip(kind,chainname,char,ck,class) + show_skip(dataset,sequence,char,ck,class) end elseif seq[n][char] then n = n -1 @@ -2397,15 +2469,15 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) if current then local id = getid(current) if id == glyph_code then - if ischar(current,currentfont) then - local char = getchar(current) + local char = ischar(current,currentfont) + if char then local ccd = descriptions[char] if ccd then local class = ccd.class if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then skipped = true if trace_skips then - show_skip(kind,chainname,char,ck,class) + show_skip(dataset,sequence,char,ck,class) end elseif seq[n][char] then n = n + 1 @@ -2534,7 +2606,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) done = true end else - logprocess("%s: %s is not yet supported",cref(dataset,sequence),chainkind) + logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind) end else local i = 1 @@ -2591,7 +2663,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end else -- actually an error - logprocess("%s: %s is not yet supported",cref(dataset,sequence),chainkind) + logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind) end i = i + 1 end @@ -2605,7 +2677,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else local replacements = ck[7] if replacements then - head, start, done = chainprocs.reversesub(head,start,last,dataset,sequence,replacements,rlmode) + head, start, done = reversesub(head,start,last,dataset,sequence,replacements,rlmode) else done = quit_on_no_replacement -- can be meant to be skipped / quite inconsistent in fonts if trace_contexts then @@ -2632,6 +2704,23 @@ handlers.gsub_reversecontextchain = handle_contextchain handlers.gpos_contextchain = handle_contextchain handlers.gpos_context = handle_contextchain +-- this needs testing + +function chained_contextchain(head,start,stop,dataset,sequence,currentlookup,rlmode) + local steps = currentlookup.steps + local nofsteps = currentlookup.nofsteps + if nofsteps > 1 then + reportmoresteps(dataset,sequence) + end + return handle_contextchain(head,start,dataset,sequence,currentlookup,rlmode) +end + +chainprocs.gsub_context = chained_contextchain +chainprocs.gsub_contextchain = chained_contextchain +chainprocs.gsub_reversecontextchain = chained_contextchain +chainprocs.gpos_contextchain = chained_contextchain +chainprocs.gpos_context = chained_contextchain + local missing = setmetatableindex("table") local function logprocess(...) @@ -2667,20 +2756,33 @@ end) -- fonts.hashes.sequences = sequencelists -local autofeatures = fonts.analyzers.features -- was: constants +local autofeatures = fonts.analyzers.features +local featuretypes = otf.tables.featuretypes +local defaultscript = otf.features.checkeddefaultscript +local defaultlanguage = otf.features.checkeddefaultlanguage -local function initialize(sequence,script,language,enabled) +local function initialize(sequence,script,language,enabled,autoscript,autolanguage) local features = sequence.features if features then local order = sequence.order if order then - for i=1,#order do -- - local kind = order[i] -- + local featuretype = featuretypes[sequence.type or "unknown"] + for i=1,#order do + local kind = order[i] local valid = enabled[kind] if valid then - local scripts = features[kind] -- - local languages = scripts[script] or scripts[wildcard] - if languages and (languages[language] or languages[wildcard]) then + local scripts = features[kind] + local languages = scripts and ( + scripts[script] or + scripts[wildcard] or + (autoscript and defaultscript(featuretype,autoscript,scripts)) + ) + local enabled = languages and ( + languages[language] or + languages[wildcard] or + (autolanguage and defaultlanguage(featuretype,autolanguage,languages)) + ) + if enabled then return { valid, autofeatures[kind] or false, sequence, kind } end end @@ -2693,11 +2795,13 @@ local function initialize(sequence,script,language,enabled) end function otf.dataset(tfmdata,font) -- generic variant, overloaded in context - local shared = tfmdata.shared - local properties = tfmdata.properties - local language = properties.language or "dflt" - local script = properties.script or "dflt" - local enabled = shared.features + local shared = tfmdata.shared + local properties = tfmdata.properties + local language = properties.language or "dflt" + local script = properties.script or "dflt" + local enabled = shared.features + local autoscript = enabled and enabled.autoscript + local autolanguage = enabled and enabled.autolanguage local res = resolved[font] if not res then res = { } @@ -2716,7 +2820,7 @@ function otf.dataset(tfmdata,font) -- generic variant, overloaded in context rs[language] = rl local sequences = tfmdata.resources.sequences for s=1,#sequences do - local v = enabled and initialize(sequences[s],script,language,enabled) + local v = enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage) if v then rl[#rl+1] = v end @@ -2746,8 +2850,13 @@ local function kernrun(disc,run) -- 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 ischar(prevmarks,currentfont) and marks[getchar(prevmarks)] do - prevmarks = getprev(prevmarks) + while prevmarks do + local char = ischar(prevmarks,currentfont) + if char and marks[char] then + prevmarks = getprev(prevmarks) + else + break + end end -- if prev and (pre or replace) and not ischar(prev,currentfont) then @@ -3014,8 +3123,9 @@ local function featuresprocessor(head,font,attr) -- we need to get rid of this slide! probably no longer needed in latest luatex local start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo while start do - local id = getid(start) - if ischar(start,font) then + local id = getid(start) + local char = ischar(start,font) + if char then local a = getattr(start,0) if a then a = a == attr @@ -3023,7 +3133,6 @@ local function featuresprocessor(head,font,attr) a = true end if a then - local char = getchar(start) for i=1,nofsteps do local step = steps[i] local lookupcache = step.coverage @@ -3069,32 +3178,35 @@ local function featuresprocessor(head,font,attr) while start do local id = getid(start) if id ~= glyph_code then - -- very unlikely + -- very unlikely (if so we could use ischar) start = getnext(start) - elseif ischar(start,font) then - local a = getattr(start,0) --- if a then --- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) --- else --- a = not attribute or getprop(start,a_state) == attribute --- end --- if a then -if not a or (a == attr) then - local lookupmatch = lookupcache[getchar(start)] - if lookupmatch then - -- sequence kan weg - local ok - head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1) - if ok then - done = true + else + local char = ischar(start,font) + if char then + local a = getattr(start,0) + -- if a then + -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) + -- else + -- a = not attribute or getprop(start,a_state) == attribute + -- end + -- if a then + if not a or (a == attr) then + local lookupmatch = lookupcache[char] + if lookupmatch then + -- sequence kan weg + local ok + head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1) + if ok then + done = true + end end + if start then start = getnext(start) end + else + start = getnext(start) end - if start then start = getnext(start) end else - start = getnext(start) + return head, false end - else - return head, false end end if done then @@ -3106,16 +3218,17 @@ if not a or (a == attr) then local function t_run(start,stop) while start ~= stop do local id = getid(start) - if ischar(start,font) then + local char = ischar(start,font) + if char then local a = getattr(start,0) --- if a then --- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) --- else --- a = not attribute or getprop(start,a_state) == attribute --- end --- if a then -if not a or (a == attr) then - local lookupmatch = lookupcache[getchar(start)] + -- if a then + -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) + -- else + -- a = not attribute or getprop(start,a_state) == attribute + -- end + -- if a then + if not a or (a == attr) then + local lookupmatch = lookupcache[char] if lookupmatch then -- hm, hyphens can match (tlig) so we need to really check -- if we need more than ligatures we can outline the code and use functions local s = getnext(start) @@ -3143,13 +3256,13 @@ if not a or (a == attr) then local function d_run(prev) -- we can assume that prev and next are glyphs local a = getattr(prev,0) --- if a then --- a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute) --- else --- a = not attribute or getprop(prev,a_state) == attribute --- end --- if a then -if not a or (a == attr) then + -- if a then + -- a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute) + -- else + -- a = not attribute or getprop(prev,a_state) == attribute + -- end + -- if a then + if not a or (a == attr) then local lookupmatch = lookupcache[getchar(prev)] if lookupmatch then -- sequence kan weg @@ -3164,13 +3277,13 @@ if not a or (a == attr) then local function k_run(sub,injection,last) local a = getattr(sub,0) --- if a then --- a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute) --- else --- a = not attribute or getprop(sub,a_state) == attribute --- end --- if a then -if not a or (a == attr) then + -- if a then + -- a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute) + -- else + -- a = not attribute or getprop(sub,a_state) == attribute + -- end + -- if a then + if not a or (a == attr) then -- sequence kan weg for n in traverse_nodes(sub) do -- only gpos if n == last then @@ -3196,7 +3309,8 @@ if not a or (a == attr) then while start do local id = getid(start) if id == glyph_code then - if ischar(start,font) then + local char = ischar(start,font) + if char then local a = getattr(start,0) if a then a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) @@ -3204,7 +3318,6 @@ if not a or (a == attr) then a = not attribute or getprop(start,a_state) == attribute end if a then - local char = getchar(start) local lookupmatch = lookupcache[char] if lookupmatch then -- sequence kan weg @@ -3293,43 +3406,45 @@ if not a or (a == attr) then if id ~= glyph_code then -- very unlikely start = getnext(start) - elseif ischar(start,font) then - local a = getattr(start,0) --- if a then --- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) --- else --- a = not attribute or getprop(start,a_state) == attribute --- end --- if a then -if not a or (a == attr) then - local char = getchar(start) - for i=1,nofsteps do - local step = steps[i] - local lookupcache = step.coverage - if lookupcache then - local lookupmatch = lookupcache[char] - if lookupmatch then - -- we could move all code inline but that makes things even more unreadable - local ok - head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i) - if ok then - done = true - break - elseif not start then - -- don't ask why ... shouldn't happen - break + else + local char = ischar(start,font) + if char then + local a = getattr(start,0) + -- if a then + -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) + -- else + -- a = not attribute or getprop(start,a_state) == attribute + -- end + -- if a then + if not a or (a == attr) then + for i=1,nofsteps do + local step = steps[i] + local lookupcache = step.coverage + if lookupcache then + local lookupmatch = lookupcache[char] + if lookupmatch then + -- we could move all code inline but that makes things even more unreadable + local ok + head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i) + if ok then + done = true + break + elseif not start then + -- don't ask why ... shouldn't happen + break + end end + else + report_missing_cache(dataset,sequence) end - else - report_missing_cache(dataset,sequence) end + if start then start = getnext(start) end + else + start = getnext(start) end - if start then start = getnext(start) end else - start = getnext(start) + return head, false end - else - return head, false end end if done then @@ -3340,13 +3455,13 @@ if not a or (a == attr) then local function d_run(prev) local a = getattr(prev,0) --- if a then --- a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute) --- else --- a = not attribute or getprop(prev,a_state) == attribute --- end --- if a then -if not a or (a == attr) then + -- if a then + -- a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute) + -- else + -- a = not attribute or getprop(prev,a_state) == attribute + -- end + -- if a then + if not a or (a == attr) then -- brr prev can be disc local char = getchar(prev) for i=1,nofsteps do @@ -3371,13 +3486,13 @@ if not a or (a == attr) then local function k_run(sub,injection,last) local a = getattr(sub,0) --- if a then --- a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute) --- else --- a = not attribute or getprop(sub,a_state) == attribute --- end --- if a then -if not a or (a == attr) then + -- if a then + -- a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute) + -- else + -- a = not attribute or getprop(sub,a_state) == attribute + -- end + -- if a then + if not a or (a == attr) then for n in traverse_nodes(sub) do -- only gpos if n == last then break @@ -3410,17 +3525,17 @@ if not a or (a == attr) then local function t_run(start,stop) while start ~= stop do - local id = getid(start) - if ischar(start,font) then + local id = getid(start) + local char = ischar(start,font) + if char then local a = getattr(start,0) --- if a then --- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) --- else --- a = not attribute or getprop(start,a_state) == attribute --- end --- if a then -if not a or (a == attr) then - local char = getchar(start) + -- if a then + -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) + -- else + -- a = not attribute or getprop(start,a_state) == attribute + -- end + -- if a then + if not a or (a == attr) then for i=1,nofsteps do local step = steps[i] local lookupcache = step.coverage @@ -3458,7 +3573,8 @@ if not a or (a == attr) then while start do local id = getid(start) if id == glyph_code then - if ischar(start,font) then + local char = ischar(start,font) + if char then local a = getattr(start,0) if a then a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) @@ -3470,7 +3586,7 @@ if not a or (a == attr) then local step = steps[i] local lookupcache = step.coverage if lookupcache then - local char = getchar(start) + -- local char = getchar(start) local lookupmatch = lookupcache[char] if lookupmatch then -- we could move all code inline but that makes things even more unreadable |