summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/font-otn.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-otn.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/font-otn.lua733
1 files changed, 398 insertions, 335 deletions
diff --git a/Master/texmf-dist/tex/context/base/font-otn.lua b/Master/texmf-dist/tex/context/base/font-otn.lua
index d97ef7363b7..39a3f77dda0 100644
--- a/Master/texmf-dist/tex/context/base/font-otn.lua
+++ b/Master/texmf-dist/tex/context/base/font-otn.lua
@@ -3,9 +3,11 @@ if not modules then modules = { } end modules ['font-otn'] = {
comment = "companion to font-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
+ license = "see context related readme files",
}
+-- preprocessors = { "nodes" }
+
-- this is still somewhat preliminary and it will get better in due time;
-- much functionality could only be implemented thanks to the husayni font
-- of Idris Samawi Hamid to who we dedicate this module.
@@ -28,6 +30,8 @@ if not modules then modules = { } end modules ['font-otn'] = {
-- 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)
+-- remove some optimizations (when I have a faster machine)
+
--[[ldx--
<p>This module is a bit more split up that I'd like but since we also want to test
@@ -116,11 +120,14 @@ results in different tables.</p>
-- we now use only one hash. If needed we can have multiple again but in that
-- case I will probably prefix (i.e. rename) the lookups in the cached font file.
+-- Todo: make plugin feature that operates on char/glyphnode arrays
+
local concat, insert, remove = table.concat, table.insert, table.remove
-local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
+local gmatch, gsub, find, match, lower, strip = string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
local type, next, tonumber, tostring = type, next, tonumber, tostring
local lpegmatch = lpeg.match
local random = math.random
+local formatters = string.formatters
local logs, trackers, nodes, attributes = logs, trackers, nodes, attributes
@@ -151,6 +158,7 @@ local report_subchain = logs.reporter("fonts","otf subchain")
local report_chain = logs.reporter("fonts","otf chain")
local report_process = logs.reporter("fonts","otf process")
local report_prepare = logs.reporter("fonts","otf prepare")
+local report_warning = logs.reporter("fonts","otf warning")
registertracker("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end)
registertracker("otf.normal_chain", function(v) otf.setcontextchain(v and "normal") end)
@@ -166,9 +174,8 @@ local insert_node_after = node.insert_after
local delete_node = nodes.delete
local copy_node = node.copy
local find_node_tail = node.tail or node.slide
-local set_attribute = node.set_attribute
-local has_attribute = node.has_attribute
local flush_node_list = node.flush_list
+local end_of_math = node.end_of_math
local setmetatableindex = table.setmetatableindex
@@ -185,6 +192,7 @@ local glyph_code = nodecodes.glyph
local glue_code = nodecodes.glue
local disc_code = nodecodes.disc
local whatsit_code = nodecodes.whatsit
+local math_code = nodecodes.math
local dir_code = whatcodes.dir
local localpar_code = whatcodes.localpar
@@ -199,15 +207,15 @@ local privateattribute = attributes.private
-- 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') -- 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 a_state = privateattribute('state')
+local a_markbase = privateattribute('markbase')
+local a_markmark = privateattribute('markmark')
+local a_markdone = privateattribute('markdone') -- assigned at the injection end
+local a_cursbase = privateattribute('cursbase')
+local a_curscurs = privateattribute('curscurs')
+local a_cursdone = privateattribute('cursdone')
+local a_kernpair = privateattribute('kernpair')
+local a_ligacomp = privateattribute('ligacomp') -- assigned here (ideally it should be combined)
local injections = nodes.injections
local setmark = injections.setmark
@@ -229,8 +237,7 @@ local onetimemessage = fonts.loggers.onetimemessage
otf.defaultnodealternate = "none" -- first last
--- we share some vars here, after all, we have no nested lookups and
--- less code
+-- we share some vars here, after all, we have no nested lookups and less code
local tfmdata = false
local characters = false
@@ -245,9 +252,6 @@ local handlers = { }
local rlmode = 0
local featurevalue = false
--- we cannot optimize with "start = first_glyph(head)" because then we don't
--- know which rlmode we're in which messes up cursive handling later on
---
-- head is always a whatsit so we can safely assume that head is not changed
-- we use this for special testing and documentation
@@ -267,203 +271,238 @@ local function logwarning(...)
report_direct(...)
end
-local function gref(n)
+local f_unicode = formatters["%U"]
+local f_uniname = formatters["%U (%s)"]
+local f_unilist = formatters["% t (% t)"]
+
+local function gref(n) -- currently the same as in font-otb
if type(n) == "number" then
local description = descriptions[n]
local name = description and description.name
if name then
- return format("U+%05X (%s)",n,name)
+ return f_uniname(n,name)
else
- return format("U+%05X",n)
+ return f_unicode(n)
end
- elseif not n then
- return "<error in tracing>"
- else
+ elseif n then
local num, nam = { }, { }
for i=1,#n do
local ni = n[i]
if tonumber(ni) then -- later we will start at 2
local di = descriptions[ni]
- num[i] = format("U+%05X",ni)
- nam[i] = di and di.name or "?"
+ num[i] = f_unicode(ni)
+ nam[i] = di and di.name or "-"
end
end
- return format("%s (%s)",concat(num," "), concat(nam," "))
+ return f_unilist(num,nam)
+ else
+ return "<error in node mode tracing>"
end
end
-local function cref(kind,chainname,chainlookupname,lookupname,index)
+local function cref(kind,chainname,chainlookupname,lookupname,index) -- not in the mood to alias f_
if index then
- return format("feature %s, chain %s, sub %s, lookup %s, index %s",kind,chainname,chainlookupname,lookupname,index)
+ return formatters["feature %a, chain %a, sub %a, lookup %a, index %a"](kind,chainname,chainlookupname,lookupname,index)
elseif lookupname then
- return format("feature %s, chain %s, sub %s, lookup %s",kind,chainname or "?",chainlookupname or "?",lookupname)
+ return formatters["feature %a, chain %a, sub %a, lookup %a"](kind,chainname,chainlookupname,lookupname)
elseif chainlookupname then
- return format("feature %s, chain %s, sub %s",kind,chainname or "?",chainlookupname)
+ return formatters["feature %a, chain %a, sub %a"](kind,chainname,chainlookupname)
elseif chainname then
- return format("feature %s, chain %s",kind,chainname)
+ return formatters["feature %a, chain %a"](kind,chainname)
else
- return format("feature %s",kind)
+ return formatters["feature %a"](kind)
end
end
local function pref(kind,lookupname)
- return format("feature %s, lookup %s",kind,lookupname)
+ return formatters["feature %a, lookup %a"](kind,lookupname)
end
--- we can assume that languages that use marks are not hyphenated
--- we can also assume that at most one discretionary is present
-
-local function markstoligature(kind,lookupname,start,stop,char)
- local n = copy_node(start)
- local keep = start
- local current
- current, start = insert_node_after(start,start,n)
- local snext = stop.next
- current.next = snext
- if snext then
- snext.prev = current
+-- We can assume that languages that use marks are not hyphenated. We can also assume
+-- that at most one discretionary is present.
+
+-- 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. Also, later on copying and freeing becomes easier.
+-- However, for arabic we need to keep them around for the sake of mark placement
+-- and indices.
+
+local function copy_glyph(g) -- next and prev are untouched !
+ local components = g.components
+ if components then
+ g.components = nil
+ local n = copy_node(g)
+ g.components = components
+ return n
+ else
+ return copy_node(g)
end
- start.prev, stop.next = nil, nil
- current.char, current.subtype, current.components = char, ligature_code, start
- return keep
end
-local function toligature(kind,lookupname,start,stop,char,markflag,discfound) -- brr head
- if start == stop then
- start.char = char
- return start
- elseif discfound then
- -- print("start->stop",nodes.tosequence(start,stop))
- local components = start.components
- if components then
- flush_node_list(components)
- start.components = nil
- end
- local lignode = copy_node(start)
- lignode.font = start.font
- lignode.char = char
- lignode.subtype = ligature_code
- local next = stop.next
+-- start is a mark and we need to keep that one
+
+local function markstoligature(kind,lookupname,head,start,stop,char)
+ if start == stop and start.char == char then
+ return head, start
+ else
local prev = start.prev
- stop.next = nil
+ local next = stop.next
start.prev = nil
- lignode.components = start
- -- print("lignode",nodes.tosequence(lignode))
- -- print("components",nodes.tosequence(lignode.components))
- prev.next = lignode
+ stop.next = nil
+ local base = copy_glyph(start)
+ if head == start then
+ head = base
+ end
+ base.char = char
+ base.subtype = ligature_code
+ base.components = start
+ if prev then
+ prev.next = base
+ end
if next then
- next.prev = lignode
+ next.prev = base
end
- lignode.next = next
- lignode.prev = prev
- -- print("start->end",nodes.tosequence(start))
- return lignode
+ base.next = next
+ base.prev = prev
+ return head, base
+ end
+end
+
+-- The next code is somewhat complicated by the fact that some fonts can have ligatures made
+-- from ligatures that themselves have marks. This was identified by Kai in for instance
+-- arabtype: KAF LAM SHADDA ALEF FATHA (0x0643 0x0644 0x0651 0x0627 0x064E). This becomes
+-- KAF LAM-ALEF with a SHADDA on the first and a FATHA op de second component. In a next
+-- 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 start.id ~= glyph_code then
+ return 0
+ elseif start.subtype == ligature_code then
+ local i = 0
+ local components = start.components
+ while components do
+ i = i + getcomponentindex(components)
+ components = components.next
+ end
+ return i
+ elseif not marks[start.char] then
+ return 1
else
- -- start is the ligature
+ return 0
+ end
+end
+
+local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) -- brr head
+ if start == stop and start.char == char then
+ start.char = char
+ return head, start
+ end
+ local prev = start.prev
+ local next = stop.next
+ start.prev = nil
+ stop.next = nil
+ local base = copy_glyph(start)
+ if start == head then
+ head = base
+ end
+ base.char = char
+ base.subtype = ligature_code
+ base.components = start -- start can have components
+ if prev then
+ prev.next = base
+ end
+ if next then
+ next.prev = base
+ end
+ base.next = next
+ base.prev = prev
+ if not discfound then
local deletemarks = markflag ~= "mark"
- local n = copy_node(start)
- local current
- current, start = insert_node_after(start,start,n)
- local snext = stop.next
- current.next = snext
- if snext then
- snext.prev = current
- end
- start.prev = nil
- stop.next = nil
- current.char = char
- current.subtype = ligature_code
- current.components = start
- local head = current
- -- this is messy ... we should get rid of the components eventually
- local i = 0 -- is index of base
+ local components = start
+ local baseindex = 0
+ local componentindex = 0
+ local head = base
+ local current = base
while start do
- if not marks[start.char] then
- i = i + 1
+ local char = start.char
+ if not marks[char] then
+ baseindex = baseindex + componentindex
+ componentindex = getcomponentindex(start)
elseif not deletemarks then -- quite fishy
- set_attribute(start,ligacomp,i)
+ start[a_ligacomp] = baseindex + (start[a_ligacomp] or componentindex)
if trace_marks then
- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),start[a_ligacomp])
end
- head, current = insert_node_after(head,current,copy_node(start))
+ head, current = insert_node_after(head,current,copy_node(start)) -- unlikely that mark has components
end
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)
+ local start = components
+ while start and start.id == glyph_code do -- hm, is id test needed ?
+ local char = start.char
+ if marks[char] then
+ start[a_ligacomp] = baseindex + (start[a_ligacomp] or componentindex)
if trace_marks then
- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),start[a_ligacomp])
end
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)
- return head
end
+ return head, base
end
-function handlers.gsub_single(start,kind,lookupname,replacement)
+function handlers.gsub_single(head,start,kind,lookupname,replacement)
if trace_singles then
logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(start.char),gref(replacement))
end
start.char = replacement
- return start, true
+ return head, start, true
end
-local function get_alternative_glyph(start,alternatives,value)
- -- needs checking: (global value, brrr)
- local choice = nil
- local n = #alternatives
- local char = start.char
- --
+local function get_alternative_glyph(start,alternatives,value,trace_alternatives)
+ local n = #alternatives
if value == "random" then
local r = random(1,n)
- value, choice = format("random, choice %s",r), alternatives[r]
+ return alternatives[r], trace_alternatives and formatters["value %a, taking %a"](value,r)
elseif value == "first" then
- value, choice = format("first, choice %s",1), alternatives[1]
+ return alternatives[1], trace_alternatives and formatters["value %a, taking %a"](value,1)
elseif value == "last" then
- value, choice = format("last, choice %s",n), alternatives[n]
+ return alternatives[n], trace_alternatives and formatters["value %a, taking %a"](value,n)
else
value = tonumber(value)
if type(value) ~= "number" then
- value, choice = "default, choice 1", alternatives[1]
+ return alternatives[1], trace_alternatives and formatters["invalid value %s, taking %a"](value,1)
elseif value > n then
local defaultalt = otf.defaultnodealternate
if defaultalt == "first" then
- value, choice = format("no %s variants, taking %s",value,n), alternatives[n]
+ return alternatives[n], trace_alternatives and formatters["invalid value %s, taking %a"](value,1)
elseif defaultalt == "last" then
- value, choice = format("no %s variants, taking %s",value,1), alternatives[1]
+ return alternatives[1], trace_alternatives and formatters["invalid value %s, taking %a"](value,n)
else
- value, choice = format("no %s variants, ignoring",value), false
+ return false, trace_alternatives and formatters["invalid value %a, %s"](value,"out of range")
end
elseif value == 0 then
- value, choice = format("choice %s (no change)",value), char
+ return start.char, trace_alternatives and formatters["invalid value %a, %s"](value,"no change")
elseif value < 1 then
- value, choice = format("no %s variants, taking %s",value,1), alternatives[1]
+ return alternatives[1], trace_alternatives and formatters["invalid value %a, taking %a"](value,1)
else
- value, choice = format("choice %s",value), alternatives[value]
+ return alternatives[value], trace_alternatives and formatters["value %a, taking %a"](value,value)
end
end
- return choice
end
-local function multiple_glyphs(start,multiple) -- marks ?
+local function multiple_glyphs(head,start,multiple) -- marks ?
local nofmultiples = #multiple
if nofmultiples > 0 then
start.char = multiple[1]
if nofmultiples > 1 then
local sn = start.next
for k=2,nofmultiples do -- todo: use insert_node
- local n = copy_node(start)
+ local n = copy_node(start) -- ignore components
n.char = multiple[k]
n.next = sn
n.prev = start
@@ -474,45 +513,45 @@ local function multiple_glyphs(start,multiple) -- marks ?
start = n
end
end
- return start, true
+ return head, start, true
else
if trace_multiples then
logprocess("no multiple for %s",gref(start.char))
end
- return start, false
+ return head, start, false
end
end
-function handlers.gsub_alternate(start,kind,lookupname,alternative,sequence)
+function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence)
local value = featurevalue == true and tfmdata.shared.features[kind] or featurevalue
- local choice = get_alternative_glyph(start,alternative,value)
+ local choice, comment = get_alternative_glyph(start,alternative,value,trace_alternatives)
if choice then
if trace_alternatives then
- logprocess("%s: replacing %s by alternative %s (%s)",pref(kind,lookupname),gref(char),gref(choice),choice)
+ logprocess("%s: replacing %s by alternative %a to %s, %s",pref(kind,lookupname),gref(start.char),choice,gref(choice),comment)
end
start.char = choice
else
if trace_alternatives then
- logwarning("%s: no variant %s for %s",pref(kind,lookupname),tostring(value),gref(char))
+ logwarning("%s: no variant %a for %s, %s",pref(kind,lookupname),value,gref(start.char),comment)
end
end
- return start, true
+ return head, start, true
end
-function handlers.gsub_multiple(start,kind,lookupname,multiple)
+function handlers.gsub_multiple(head,start,kind,lookupname,multiple)
if trace_multiples then
logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(start.char),gref(multiple))
end
- return multiple_glyphs(start,multiple)
+ return multiple_glyphs(head,start,multiple)
end
-function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence)
+function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
local s, stop, discfound = start.next, nil, false
local startchar = start.char
if marks[startchar] then
while s do
local id = s.id
- if id == glyph_code and s.subtype<256 and s.font == currentfont then
+ if id == glyph_code and s.font == currentfont and s.subtype<256 then
local lg = ligature[s.char]
if lg then
stop = s
@@ -530,12 +569,12 @@ function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence)
if lig then
if trace_ligatures then
local stopchar = stop.char
- start = markstoligature(kind,lookupname,start,stop,lig)
- logprocess("%s: replacing %s upto %s by ligature %s",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
+ head, start = markstoligature(kind,lookupname,head,start,stop,lig)
+ logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
else
- start = markstoligature(kind,lookupname,start,stop,lig)
+ head, start = markstoligature(kind,lookupname,head,start,stop,lig)
end
- return start, true
+ return head, start, true
else
-- ok, goto next lookup
end
@@ -574,18 +613,18 @@ function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence)
if lig then
if trace_ligatures then
local stopchar = stop.char
- start = toligature(kind,lookupname,start,stop,lig,skipmark,discfound)
- logprocess("%s: replacing %s upto %s by ligature %s",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
+ head, start = toligature(kind,lookupname,head, start,stop,lig,skipmark,discfound)
+ logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
else
- start = toligature(kind,lookupname,start,stop,lig,skipmark,discfound)
+ head, start = toligature(kind,lookupname,head, start,stop,lig,skipmark,discfound)
end
- return start, true
+ return head, start, true
else
-- ok, goto next lookup
end
end
end
- return start, false
+ return head, start, false
end
--[[ldx--
@@ -593,16 +632,16 @@ end
we need to explicitly test for basechar, baselig and basemark entries.</p>
--ldx]]--
-function handlers.gpos_mark2base(start,kind,lookupname,markanchors,sequence)
+function handlers.gpos_mark2base(head,start,kind,lookupname,markanchors,sequence)
local markchar = start.char
if marks[markchar] then
local base = start.prev -- [glyph] [start=mark]
- if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
local basechar = base.char
if marks[basechar] then
while true do
base = base.prev
- if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
basechar = base.char
if not marks[basechar] then
break
@@ -611,7 +650,7 @@ function handlers.gpos_mark2base(start,kind,lookupname,markanchors,sequence)
if trace_bugs then
logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
end
- return start, false
+ return head, start, false
end
end
end
@@ -629,10 +668,10 @@ function handlers.gpos_mark2base(start,kind,lookupname,markanchors,sequence)
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 basechar %s => (%s,%s)",
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
end
- return start, true
+ return head, start, true
end
end
end
@@ -650,20 +689,20 @@ function handlers.gpos_mark2base(start,kind,lookupname,markanchors,sequence)
elseif trace_bugs then
logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
end
- return start, false
+ return head, start, false
end
-function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence)
+function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequence)
-- check chainpos variant
local markchar = start.char
if marks[markchar] then
local base = start.prev -- [glyph] [optional marks] [start=mark]
- if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
local basechar = base.char
if marks[basechar] then
while true do
base = base.prev
- if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
basechar = base.char
if not marks[basechar] then
break
@@ -672,11 +711,11 @@ function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence)
if trace_bugs then
logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
end
- return start, false
+ return head, start, false
end
end
end
- local index = has_attribute(start,ligacomp)
+ local index = start[a_ligacomp]
local baseanchors = descriptions[basechar]
if baseanchors then
baseanchors = baseanchors.anchors
@@ -692,10 +731,10 @@ function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence)
if ba then
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)",
+ logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
pref(kind,lookupname),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy)
end
- return start, true
+ return head, start, true
end
end
end
@@ -715,20 +754,17 @@ function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence)
elseif trace_bugs then
logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
end
- return start, false
+ return head, start, false
end
-function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence)
+function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence)
local markchar = start.char
if marks[markchar] 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)
+ local slc = start[a_ligacomp]
if slc then -- a rather messy loop ... needs checking with husayni
while base do
- local blc = has_attribute(base,ligacomp)
+ local blc = base[a_ligacomp]
if blc and blc ~= slc then
base = base.prev
else
@@ -736,7 +772,7 @@ function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence)
end
end
end
- if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then -- subtype test can go
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then -- subtype test can go
local basechar = base.char
local baseanchors = descriptions[basechar]
if baseanchors then
@@ -751,10 +787,10 @@ function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence)
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)",
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
end
- return start,true
+ return head, start, true
end
end
end
@@ -773,11 +809,11 @@ function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence)
elseif trace_bugs then
logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
end
- return start,false
+ return head, start, false
end
-function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to be checked
- local alreadydone = cursonce and has_attribute(start,cursbase)
+function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence) -- to be checked
+ local alreadydone = cursonce and start[a_cursbase]
if not alreadydone then
local done = false
local startchar = start.char
@@ -787,7 +823,7 @@ function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to
end
else
local nxt = start.next
- while not done and nxt and nxt.id == glyph_code and nxt.subtype<256 and nxt.font == currentfont do
+ while not done and nxt and nxt.id == glyph_code and nxt.font == currentfont and nxt.subtype<256 do
local nextchar = nxt.char
if marks[nextchar] then
-- should not happen (maybe warning)
@@ -806,7 +842,7 @@ function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to
if exit then
local dx, dy, bound = setcursive(start,nxt,tfmdata.parameters.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
if trace_cursive then
- logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)
+ logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)
end
done = true
break
@@ -823,35 +859,35 @@ function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to
end
end
end
- return start, done
+ return head, start, done
else
if trace_cursive and trace_details then
logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
end
- return start, false
+ return head, start, false
end
end
-function handlers.gpos_single(start,kind,lookupname,kerns,sequence)
+function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence)
local startchar = start.char
local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
if trace_kerns then
- logprocess("%s: shifting single %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),dx,dy,w,h)
+ logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h)
end
- return start, false
+ return head, start, false
end
-function handlers.gpos_pair(start,kind,lookupname,kerns,sequence)
+function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
-- todo: kerns in disc nodes: pre, post, replace -> loop over disc too
-- todo: kerns in components of ligatures
local snext = start.next
if not snext then
- return start, false
+ return head, start, false
else
local prev, done = start, false
local factor = tfmdata.parameters.factor
local lookuptype = lookuptypes[lookupname]
- while snext and snext.id == glyph_code and snext.subtype<256 and snext.font == currentfont do
+ while snext and snext.id == glyph_code and snext.font == currentfont and snext.subtype<256 do
local nextchar = snext.char
local krn = kerns[nextchar]
if not krn and marks[nextchar] then
@@ -868,14 +904,14 @@ function handlers.gpos_pair(start,kind,lookupname,kerns,sequence)
local startchar = start.char
local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
if trace_kerns then
- logprocess("%s: shifting first of pair %s and %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
end
if b and #b > 0 then
local startchar = start.char
local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
if trace_kerns then
- logprocess("%s: shifting second of pair %s and %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
end
else -- wrong ... position has different entries
@@ -902,7 +938,7 @@ function handlers.gpos_pair(start,kind,lookupname,kerns,sequence)
break
end
end
- return start, done
+ return head, start, done
end
end
@@ -935,21 +971,21 @@ local logwarning = report_chain
-- We could share functions but that would lead to extra function calls with many
-- arguments, redundant tests and confusing messages.
-function chainprocs.chainsub(start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname)
+function chainprocs.chainsub(head,start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname)
logwarning("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
- return start, false
+ return head, start, false
end
-function chainmores.chainsub(start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname,n)
+function chainmores.chainsub(head,start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname,n)
logprocess("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
- return start, false
+ return head, start, false
end
-- The reversesub is a special case, which is why we need to store the replacements
-- 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(start,stop,kind,chainname,currentcontext,lookuphash,replacements)
+function chainprocs.reversesub(head,start,stop,kind,chainname,currentcontext,lookuphash,replacements)
local char = start.char
local replacement = replacements[char]
if replacement then
@@ -957,9 +993,9 @@ function chainprocs.reversesub(start,stop,kind,chainname,currentcontext,lookupha
logprocess("%s: single reverse replacement of %s by %s",cref(kind,chainname),gref(char),gref(replacement))
end
start.char = replacement
- return start, true
+ return head, start, true
else
- return start, false
+ return head, start, false
end
end
@@ -987,6 +1023,10 @@ local function delete_till_stop(start,stop,ignoremarks) -- keeps start
repeat -- start x x m x x stop => start m
local next = start.next
if not marks[next.char] then
+ local components = next.components
+ if components then -- probably not needed
+ flush_node_list(components)
+ end
delete_node(start,next)
end
n = n + 1
@@ -994,6 +1034,10 @@ local function delete_till_stop(start,stop,ignoremarks) -- keeps start
else -- start x x x stop => start
repeat
local next = start.next
+ local components = next.components
+ if components then -- probably not needed
+ flush_node_list(components)
+ end
delete_node(start,next)
n = n + 1
until next == stop
@@ -1006,7 +1050,7 @@ end
match.</p>
--ldx]]--
-function chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
+function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
-- todo: marks ?
local current = start
local subtables = currentlookup.subtables
@@ -1024,7 +1068,7 @@ function chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,lookuph
end
else
replacement = replacement[currentchar]
- if not replacement then
+ if not replacement or replacement == "" then
if trace_bugs then
logwarning("%s: no single for %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar))
end
@@ -1035,14 +1079,14 @@ function chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,lookuph
current.char = replacement
end
end
- return start, true
+ return head, start, true
elseif current == stop then
break
else
current = current.next
end
end
- return start, false
+ return head, start, false
end
chainmores.gsub_single = chainprocs.gsub_single
@@ -1052,7 +1096,7 @@ chainmores.gsub_single = chainprocs.gsub_single
the match.</p>
--ldx]]--
-function chainprocs.gsub_multiple(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
+function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
delete_till_stop(start,stop) -- we could pass ignoremarks as #3 ..
local startchar = start.char
local subtables = currentlookup.subtables
@@ -1064,7 +1108,7 @@ function chainprocs.gsub_multiple(start,stop,kind,chainname,currentcontext,looku
end
else
replacements = replacements[startchar]
- if not replacements then
+ if not replacements or replacement == "" then
if trace_bugs then
logwarning("%s: no multiple for %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar))
end
@@ -1072,17 +1116,12 @@ function chainprocs.gsub_multiple(start,stop,kind,chainname,currentcontext,looku
if trace_multiples then
logprocess("%s: replacing %s by multiple characters %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar),gref(replacements))
end
- return multiple_glyphs(start,replacements)
+ return multiple_glyphs(head,start,replacements)
end
end
- return start, false
+ return head, start, false
end
--- function chainmores.gsub_multiple(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
--- logprocess("%s: gsub_multiple not yet supported",cref(kind,chainname,chainlookupname))
--- return start, false
--- end
-
chainmores.gsub_multiple = chainprocs.gsub_multiple
--[[ldx--
@@ -1097,7 +1136,7 @@ chainmores.gsub_multiple = chainprocs.gsub_multiple
-- marks come last anyway
-- are there cases where we need to delete the mark
-function chainprocs.gsub_alternate(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
+function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
local current = start
local subtables = currentlookup.subtables
local value = featurevalue == true and tfmdata.shared.features[kind] or featurevalue
@@ -1113,36 +1152,31 @@ function chainprocs.gsub_alternate(start,stop,kind,chainname,currentcontext,look
else
alternatives = alternatives[currentchar]
if alternatives then
- local choice = get_alternative_glyph(current,alternatives,value)
+ local choice, comment = get_alternative_glyph(current,alternatives,value,trace_alternatives)
if choice then
if trace_alternatives then
- logprocess("%s: replacing %s by alternative %s (%s)",cref(kind,chainname,chainlookupname,lookupname),gref(char),gref(choice),choice)
+ logprocess("%s: replacing %s by alternative %a to %s, %s",cref(kind,chainname,chainlookupname,lookupname),gref(char),choice,gref(choice),comment)
end
start.char = choice
else
if trace_alternatives then
- logwarning("%s: no variant %s for %s",cref(kind,chainname,chainlookupname,lookupname),tostring(value),gref(char))
+ logwarning("%s: no variant %a for %s, %s",cref(kind,chainname,chainlookupname,lookupname),value,gref(char),comment)
end
end
elseif trace_bugs then
- logwarning("%s: no alternative for %s",cref(kind,chainname,chainlookupname,lookupname),gref(currentchar))
+ logwarning("%s: no alternative for %s, %s",cref(kind,chainname,chainlookupname,lookupname),gref(currentchar),comment)
end
end
- return start, true
+ return head, start, true
elseif current == stop then
break
else
current = current.next
end
end
- return start, false
+ return head, start, false
end
--- function chainmores.gsub_alternate(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
--- logprocess("%s: gsub_alternate not yet supported",cref(kind,chainname,chainlookupname))
--- return start, false
--- end
-
chainmores.gsub_alternate = chainprocs.gsub_alternate
--[[ldx--
@@ -1151,7 +1185,7 @@ this function (move code inline and handle the marks by a separate function). We
assume rather stupid ligatures (no complex disc nodes).</p>
--ldx]]--
-function chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
+function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
local startchar = start.char
local subtables = currentlookup.subtables
local lookupname = subtables[1]
@@ -1203,13 +1237,13 @@ function chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,looku
end
if trace_ligatures then
if start == stop then
- logprocess("%s: replacing character %s by ligature %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(l2))
+ logprocess("%s: replacing character %s by ligature %s case 3",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(l2))
else
- logprocess("%s: replacing character %s upto %s by ligature %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char),gref(l2))
+ logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char),gref(l2))
end
end
- start = toligature(kind,lookupname,start,stop,l2,currentlookup.flags[1],discfound)
- return start, true, nofreplacements
+ head, start = toligature(kind,lookupname,head,start,stop,l2,currentlookup.flags[1],discfound)
+ return head, start, true, nofreplacements
elseif trace_bugs then
if start == stop then
logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
@@ -1219,12 +1253,12 @@ function chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,looku
end
end
end
- return start, false, 0
+ return head, start, false, 0
end
chainmores.gsub_ligature = chainprocs.gsub_ligature
-function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
+function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
local markchar = start.char
if marks[markchar] then
local subtables = currentlookup.subtables
@@ -1235,12 +1269,12 @@ function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,look
end
if markanchors then
local base = start.prev -- [glyph] [start=mark]
- if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
local basechar = base.char
if marks[basechar] then
while true do
base = base.prev
- if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
basechar = base.char
if not marks[basechar] then
break
@@ -1249,7 +1283,7 @@ function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,look
if trace_bugs then
logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
end
- return start, false
+ return head, start, false
end
end
end
@@ -1264,10 +1298,10 @@ function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,look
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 basechar %s => (%s,%s)",
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
end
- return start, true
+ return head, start, true
end
end
end
@@ -1285,10 +1319,10 @@ function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,look
elseif trace_bugs then
logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
end
- return start, false
+ return head, start, false
end
-function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
+function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
local markchar = start.char
if marks[markchar] then
local subtables = currentlookup.subtables
@@ -1299,12 +1333,12 @@ function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,
end
if markanchors then
local base = start.prev -- [glyph] [optional marks] [start=mark]
- if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
local basechar = base.char
if marks[basechar] then
while true do
base = base.prev
- if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
basechar = base.char
if not marks[basechar] then
break
@@ -1313,12 +1347,12 @@ function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,
if trace_bugs then
logwarning("%s: no base for mark %s",cref(kind,chainname,chainlookupname,lookupname),markchar)
end
- return start, false
+ return head, start, false
end
end
end
-- todo: like marks a ligatures hash
- local index = has_attribute(start,ligacomp)
+ local index = start[a_ligacomp]
local baseanchors = descriptions[basechar].anchors
if baseanchors then
local baseanchors = baseanchors['baselig']
@@ -1332,10 +1366,10 @@ function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,
if ba then
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)",
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
cref(kind,chainname,chainlookupname,lookupname),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy)
end
- return start, true
+ return head, start, true
end
end
end
@@ -1354,13 +1388,13 @@ function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,
elseif trace_bugs then
logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
end
- return start, false
+ return head, start, false
end
-function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
+function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
local markchar = start.char
if marks[markchar] then
---~ local alreadydone = markonce and has_attribute(start,markmark)
+--~ local alreadydone = markonce and start[a_markmark]
--~ if not alreadydone then
-- local markanchors = descriptions[markchar].anchors markanchors = markanchors and markanchors.mark
local subtables = currentlookup.subtables
@@ -1371,13 +1405,10 @@ 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)
+ local slc = start[a_ligacomp]
if slc then -- a rather messy loop ... needs checking with husayni
while base do
- local blc = has_attribute(base,ligacomp)
+ local blc = base[a_ligacomp]
if blc and blc ~= slc then
base = base.prev
else
@@ -1385,7 +1416,7 @@ function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,look
end
end
end
- if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then -- subtype test can go
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then -- subtype test can go
local basechar = base.char
local baseanchors = descriptions[basechar].anchors
if baseanchors then
@@ -1398,10 +1429,10 @@ function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,look
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)",
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
end
- return start, true
+ return head, start, true
end
end
end
@@ -1422,13 +1453,11 @@ function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,look
elseif trace_bugs then
logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
end
- return start, false
+ return head, start, false
end
--- ! ! ! untested ! ! !
-
-function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
- local alreadydone = cursonce and has_attribute(start,cursbase)
+function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
+ local alreadydone = cursonce and start[a_cursbase]
if not alreadydone then
local startchar = start.char
local subtables = currentlookup.subtables
@@ -1445,7 +1474,7 @@ function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,lookup
end
else
local nxt = start.next
- while not done and nxt and nxt.id == glyph_code and nxt.subtype<256 and nxt.font == currentfont do
+ while not done and nxt and nxt.id == glyph_code and nxt.font == currentfont and nxt.subtype<256 do
local nextchar = nxt.char
if marks[nextchar] then
-- should not happen (maybe warning)
@@ -1464,7 +1493,7 @@ function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,lookup
if exit then
local dx, dy, bound = setcursive(start,nxt,tfmdata.parameters.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
if trace_cursive then
- logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)
+ logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)
end
done = true
break
@@ -1481,18 +1510,18 @@ function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,lookup
end
end
end
- return start, done
+ return head, start, done
else
if trace_cursive and trace_details then
logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
end
- return start, false
+ return head, start, false
end
end
- return start, false
+ return head, start, false
end
-function chainprocs.gpos_single(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
+function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
-- untested .. needs checking for the new model
local startchar = start.char
local subtables = currentlookup.subtables
@@ -1503,16 +1532,16 @@ function chainprocs.gpos_single(start,stop,kind,chainname,currentcontext,lookuph
if kerns then
local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
if trace_kerns then
- logprocess("%s: shifting single %s by (%s,%s) and correction (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h)
+ logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h)
end
end
end
- return start, false
+ return head, start, false
end
-- when machines become faster i will make a shared function
-function chainprocs.gpos_pair(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
+function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
-- logwarning("%s: gpos_pair not yet supported",cref(kind,chainname,chainlookupname))
local snext = start.next
if snext then
@@ -1526,7 +1555,7 @@ function chainprocs.gpos_pair(start,stop,kind,chainname,currentcontext,lookuphas
local lookuptype = lookuptypes[lookupname]
local prev, done = start, false
local factor = tfmdata.parameters.factor
- while snext and snext.id == glyph_code and snext.subtype<256 and snext.font == currentfont do
+ while snext and snext.id == glyph_code and snext.font == currentfont and snext.subtype<256 do
local nextchar = snext.char
local krn = kerns[nextchar]
if not krn and marks[nextchar] then
@@ -1542,14 +1571,14 @@ function chainprocs.gpos_pair(start,stop,kind,chainname,currentcontext,lookuphas
local startchar = start.char
local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
if trace_kerns then
- logprocess("%s: shifting first of pair %s and %s by (%s,%s) and correction (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
end
if b and #b > 0 then
local startchar = start.char
local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
if trace_kerns then
- logprocess("%s: shifting second of pair %s and %s by (%s,%s) and correction (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
end
else
@@ -1576,11 +1605,11 @@ function chainprocs.gpos_pair(start,stop,kind,chainname,currentcontext,lookuphas
break
end
end
- return start, done
+ return head, start, done
end
end
end
- return start, false
+ return head, start, false
end
-- what pointer to return, spec says stop
@@ -1593,13 +1622,13 @@ end
local function show_skip(kind,chainname,char,ck,class)
if ck[9] then
- logwarning("%s: skipping char %s (%s) in rule %s, lookuptype %s (%s=>%s)",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10])
+ logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a, %a => %a",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10])
else
- logwarning("%s: skipping char %s (%s) in rule %s, lookuptype %s",cref(kind,chainname),gref(char),class,ck[1],ck[2])
+ logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(kind,chainname),gref(char),class,ck[1],ck[2])
end
end
-local function normal_handle_contextchain(start,kind,chainname,contexts,sequence,lookuphash)
+local function normal_handle_contextchain(head,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 flags = sequence.flags
local done = false
@@ -1619,7 +1648,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
-- f..l = mid string
if s == 1 then
-- never happens
- match = current.id == glyph_code and current.subtype<256 and current.font == currentfont and seq[1][current.char]
+ match = current.id == glyph_code and current.font == currentfont and current.subtype<256 and seq[1][current.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
@@ -1639,7 +1668,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
if last then
local id = last.id
if id == glyph_code then
- if last.subtype<256 and last.font == currentfont then
+ if last.font == currentfont and last.subtype<256 then
local char = last.char
local ccd = descriptions[char]
if ccd then
@@ -1689,7 +1718,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
if prev then
local id = prev.id
if id == glyph_code then
- if prev.subtype<256 and prev.font == currentfont then -- normal char
+ if prev.font == currentfont and prev.subtype<256 then -- normal char
local char = prev.char
local ccd = descriptions[char]
if ccd then
@@ -1722,7 +1751,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
break
end
prev = prev.prev
- elseif seq[n][32] then -- somehat special, as zapfino can have many preceding spaces
+ elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces
n = n -1
else
match = false
@@ -1750,7 +1779,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
if current then
local id = current.id
if id == glyph_code then
- if current.subtype<256 and current.font == currentfont then -- normal char
+ if current.font == currentfont and current.subtype<256 then -- normal char
local char = current.char
local ccd = descriptions[char]
if ccd then
@@ -1808,10 +1837,10 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
local rule, lookuptype, f, l = ck[1], ck[2], ck[4], ck[5]
local char = start.char
if ck[9] then
- logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %s (%s=>%s)",
+ logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a, %a => %a",
cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype,ck[9],ck[10])
else
- logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %s",
+ logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a",
cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype)
end
end
@@ -1825,7 +1854,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
if chainlookup then
local cp = chainprocs[chainlookup.type]
if cp then
- start, done = cp(start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence)
+ head, start, done = cp(head,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
@@ -1856,7 +1885,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
local cp = chainlookup and chainmores[chainlookup.type]
if cp then
local ok, n
- start, ok, n = cp(start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence)
+ head, start, ok, n = cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence)
-- messy since last can be changed !
if ok then
done = true
@@ -1870,13 +1899,17 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
-- logprocess("%s: multiple subchains for %s are not yet supported",cref(kind,chainname,chainlookupname),chainlookup and chainlookup.type or "?")
i = i + 1
end
- start = start.next
+ if start then
+ start = start.next
+ else
+ -- weird
+ end
until i > nofchainlookups
end
else
local replacements = ck[7]
if replacements then
- start, done = chainprocs.reversesub(start,last,kind,chainname,ck,lookuphash,replacements) -- sequence
+ head, start, done = chainprocs.reversesub(head,start,last,kind,chainname,ck,lookuphash,replacements) -- sequence
else
done = true -- can be meant to be skipped
if trace_contexts then
@@ -1886,7 +1919,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
end
end
end
- return start, done
+ return head, start, done
end
-- Because we want to keep this elsewhere (an because speed is less an issue) we
@@ -1899,7 +1932,7 @@ local verbose_handle_contextchain = function(font,...)
end
otf.chainhandlers = {
- normal = normal_handle_contextchain,
+ normal = normal_handle_contextchain,
verbose = verbose_handle_contextchain,
}
@@ -1910,7 +1943,7 @@ function otf.setcontextchain(method)
end
handlers.contextchain = normal_handle_contextchain
else
- logwarning("installing contextchain handler '%s'",method)
+ logwarning("installing contextchain handler %a",method)
local handler = otf.chainhandlers[method]
handlers.contextchain = function(...)
return handler(currentfont,...) -- hm, get rid of ...
@@ -1941,7 +1974,7 @@ local function report_missing_cache(typ,lookup)
local t = f[typ] if not t then t = { } f[typ] = t end
if not t[lookup] then
t[lookup] = true
- logwarning("missing cache for lookup %s of type %s in font %s (%s)",lookup,typ,currentfont,tfmdata.properties.fullname)
+ logwarning("missing cache for lookup %a, type %a, font %a, name %a",lookup,typ,currentfont,tfmdata.properties.fullname)
end
end
@@ -1962,12 +1995,7 @@ end)
-- fonts.hashes.lookups = lookuphashes
-local special_attributes = {
- init = 1,
- medi = 2,
- fina = 3,
- isol = 4
-}
+local autofeatures = fonts.analyzers.features -- was: constants
local function initialize(sequence,script,language,enabled)
local features = sequence.features
@@ -1977,7 +2005,7 @@ local function initialize(sequence,script,language,enabled)
if valid then
local languages = scripts[script] or scripts[wildcard]
if languages and (languages[language] or languages[wildcard]) then
- return { valid, special_attributes[kind] or false, sequence.chain or 0, kind, sequence }
+ return { valid, autofeatures[kind] or false, sequence.chain or 0, kind, sequence }
end
end
end
@@ -1985,7 +2013,7 @@ local function initialize(sequence,script,language,enabled)
return false
end
-function otf.dataset(tfmdata,sequences,font) -- generic variant, overloaded in context
+function otf.dataset(tfmdata,font) -- generic variant, overloaded in context
local shared = tfmdata.shared
local properties = tfmdata.properties
local language = properties.language or "dflt"
@@ -2003,13 +2031,24 @@ function otf.dataset(tfmdata,sequences,font) -- generic variant, overloaded in c
end
local rl = rs[language]
if not rl then
- rl = { }
+ rl = {
+ -- indexed but we can also add specific data by key
+ }
rs[language] = rl
- setmetatableindex(rl, function(t,k)
- local v = enabled and initialize(sequences[k],script,language,enabled)
- t[k] = v
- return v
- end)
+ local sequences = tfmdata.resources.sequences
+-- setmetatableindex(rl, function(t,k)
+-- if type(k) == "number" then
+-- local v = enabled and initialize(sequences[k],script,language,enabled)
+-- t[k] = v
+-- return v
+-- end
+-- end)
+for s=1,#sequences do
+ local v = enabled and initialize(sequences[s],script,language,enabled)
+ if v then
+ rl[#rl+1] = v
+ end
+end
end
return rl
end
@@ -2030,6 +2069,8 @@ end
-- start = start.next
-- end
+-- there will be a new direction parser (pre-parsed etc)
+
local function featuresprocessor(head,font,attr)
local lookuphash = lookuphashes[font] -- we can also check sequences here
@@ -2057,7 +2098,7 @@ local function featuresprocessor(head,font,attr)
local sequences = resources.sequences
local done = false
- local datasets = otf.dataset(tfmdata,sequences,font,attr)
+ local datasets = otf.dataset(tfmdata,font,attr)
local dirstack = { } -- could move outside function
@@ -2066,12 +2107,20 @@ local function featuresprocessor(head,font,attr)
-- to keep track of directions anyway. Also at some point I want to play with
-- font interactions and then we do need the full sweeps.
- for s=1,#sequences do
- local dataset = datasets[s]
- if dataset then
- featurevalue = dataset[1] -- todo: pass to function instead of using a global
- if featurevalue then
- local sequence = sequences[s] -- also dataset[5]
+ -- Keeping track of the headnode is needed for devanagari (I generalized it a bit
+ -- so that multiple cases are also covered.)
+
+-- for s=1,#sequences do
+-- local dataset = datasets[s]
+-- if dataset then
+-- featurevalue = dataset[1] -- todo: pass to function instead of using a global
+-- if featurevalue then -- never false
+
+for s=1,#datasets do
+ local dataset = datasets[s]
+ featurevalue = dataset[1] -- todo: pass to function instead of using a global
+
+ local sequence = dataset[5] -- sequences[s] -- also dataset[5]
local rlparmode = 0
local topstack = 0
local success = false
@@ -2087,8 +2136,8 @@ local function featuresprocessor(head,font,attr)
while start do
local id = start.id
if id == glyph_code then
- if start.subtype<256 and start.font == font then
- local a = has_attribute(start,0)
+ if start.font == font and start.subtype<256 then
+ local a = start[0]
if a then
a = a == attr
else
@@ -2101,7 +2150,7 @@ local function featuresprocessor(head,font,attr)
if lookupcache then
local lookupmatch = lookupcache[start.char]
if lookupmatch then
- start, success = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
+ head, start, success = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
if success then
break
end
@@ -2135,19 +2184,19 @@ local function featuresprocessor(head,font,attr)
while start do
local id = start.id
if id == glyph_code then
- if start.subtype<256 and start.font == font then
- local a = has_attribute(start,0)
+ if start.font == font and start.subtype<256 then
+ local a = start[0]
if a then
- a = (a == attr) and (not attribute or has_attribute(start,state,attribute))
+ a = (a == attr) and (not attribute or start[a_state] == attribute)
else
- a = not attribute or has_attribute(start,state,attribute)
+ a = not attribute or start[a_state] == attribute
end
if a then
local lookupmatch = lookupcache[start.char]
if lookupmatch then
-- sequence kan weg
local ok
- start, ok = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
+ head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
if ok then
success = true
end
@@ -2156,6 +2205,8 @@ local function featuresprocessor(head,font,attr)
else
start = start.next
end
+ elseif id == math_code then
+ start = end_of_math(start).next
else
start = start.next
end
@@ -2178,7 +2229,7 @@ local function featuresprocessor(head,font,attr)
rlmode = rlparmode
end
if trace_directions then
- report_process("directions after txtdir %s: txtdir=%s:%s, parmode=%s, txtmode=%s",dir,topstack,newdir or "unset",rlparmode,rlmode)
+ report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir)
end
elseif subtype == localpar_code then
local dir = start.dir
@@ -2191,10 +2242,12 @@ local function featuresprocessor(head,font,attr)
end
rlmode = rlparmode
if trace_directions then
- report_process("directions after pardir %s: parmode=%s, txtmode=%s",dir,rlparmode,rlmode)
+ report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode)
end
end
start = start.next
+ elseif id == math_code then
+ start = end_of_math(start).next
else
start = start.next
end
@@ -2204,12 +2257,12 @@ local function featuresprocessor(head,font,attr)
while start do
local id = start.id
if id == glyph_code then
- if start.subtype<256 and start.font == font then
- local a = has_attribute(start,0)
+ if start.font == font and start.subtype<256 then
+ local a = start[0]
if a then
- a = (a == attr) and (not attribute or has_attribute(start,state,attribute))
+ a = (a == attr) and (not attribute or start[a_state] == attribute)
else
- a = not attribute or has_attribute(start,state,attribute)
+ a = not attribute or start[a_state] == attribute
end
if a then
for i=1,ns do
@@ -2220,7 +2273,7 @@ local function featuresprocessor(head,font,attr)
if lookupmatch then
-- we could move all code inline but that makes things even more unreadable
local ok
- start, ok = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
+ head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
if ok then
success = true
break
@@ -2256,7 +2309,7 @@ local function featuresprocessor(head,font,attr)
rlmode = rlparmode
end
if trace_directions then
- report_process("directions after txtdir %s: txtdir=%s:%s, parmode=%s, txtmode=%s",dir,topstack,newdir or "unset",rlparmode,rlmode)
+ report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir)
end
elseif subtype == localpar_code then
local dir = start.dir
@@ -2269,10 +2322,12 @@ local function featuresprocessor(head,font,attr)
end
rlmode = rlparmode
if trace_directions then
- report_process("directions after pardir %s: parmode=%s, txtmode=%s",dir,rlparmode,rlmode)
+ report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode)
end
end
start = start.next
+ elseif id == math_code then
+ start = end_of_math(start).next
else
start = start.next
end
@@ -2285,8 +2340,12 @@ local function featuresprocessor(head,font,attr)
if trace_steps then -- ?
registerstep(head)
end
- end
- end
+
+-- end
+-- else
+-- -- report_process("warning, no dataset %a",s)
+-- end
+
end
return head, done
end
@@ -2450,10 +2509,10 @@ local function prepare_contextchains(tfmdata)
local format = lookupdata.format
local validformat = valid[format]
if not validformat then
- report_prepare("unsupported format %s",format)
+ report_prepare("unsupported format %a",format)
elseif not validformat[lookuptype] then
-- todo: dejavu-serif has one (but i need to see what use it has)
- report_prepare("unsupported %s %s for %s",format,lookuptype,lookupname)
+ report_prepare("unsupported format %a, lookuptype %a, lookupname %a",format,lookuptype,lookupname)
else
local contexts = lookuphash[lookupname]
if not contexts then
@@ -2469,7 +2528,7 @@ local function prepare_contextchains(tfmdata)
local replacements = rule.replacements
local sequence = { }
local nofsequences = 0
- -- Wventually we can store start, stop and sequence in the cached file
+ -- Eventually we can store start, stop and sequence in the cached file
-- but then less sharing takes place so best not do that without a lot
-- of profiling so let's forget about it.
if before then
@@ -2509,7 +2568,7 @@ local function prepare_contextchains(tfmdata)
-- no rules
end
else
- report_prepare("missing lookuptype for %s",lookupname)
+ report_prepare("missing lookuptype for lookupname %a",lookupname)
end
end
end
@@ -2530,7 +2589,7 @@ local function featuresinitializer(tfmdata,value)
prepare_lookups(tfmdata)
properties.initialized = true
if trace_preparing then
- report_prepare("preparation time is %0.3f seconds for %s",os.clock()-starttime,tfmdata.properties.fullname or "?")
+ report_prepare("preparation time is %0.3f seconds for %a",os.clock()-starttime,tfmdata.properties.fullname)
end
end
end
@@ -2548,3 +2607,7 @@ registerotffeature {
node = featuresprocessor,
}
}
+
+-- This can be used for extra handlers, but should be used with care!
+
+otf.handlers = handlers