summaryrefslogtreecommitdiff
path: root/tex/context/base/font-otn.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/font-otn.lua')
-rw-r--r--tex/context/base/font-otn.lua338
1 files changed, 91 insertions, 247 deletions
diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua
index 2c670825a..d97ef7363 100644
--- a/tex/context/base/font-otn.lua
+++ b/tex/context/base/font-otn.lua
@@ -116,8 +116,6 @@ 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 type, next, tonumber, tostring = type, next, tonumber, tostring
@@ -153,7 +151,6 @@ 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)
@@ -313,229 +310,105 @@ local function pref(kind,lookupname)
return format("feature %s, lookup %s",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.
-
--- 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)
+-- 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
end
+ start.prev, stop.next = nil, nil
+ current.char, current.subtype, current.components = char, ligature_code, start
+ return keep
end
--- start is a mark and we need to keep that one
-
--- local function markstoligature(kind,lookupname,start,stop,char)
--- -- [start]..[stop]
--- local keep = start
--- local prev = start.prev
--- local next = stop.next
--- local base = copy_glyph(start)
--- local current, start = insert_node_after(start,start,base)
--- -- [current][start]..[stop]
--- current.next = next
--- if next then
--- next.prev = current
--- end
--- start.prev = nil
--- stop.next = nil
--- current.char = char
--- current.subtype = ligature_code
--- current.components = start
--- return keep
--- end
-
-local function markstoligature(kind,lookupname,start,stop,char)
- if start == stop and start.char == char then
+local function toligature(kind,lookupname,start,stop,char,markflag,discfound) -- brr head
+ if start == stop then
+ start.char = char
return start
- else
- local prev = start.prev
+ 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.prev = nil
+ local prev = start.prev
stop.next = nil
- local base = copy_glyph(start)
- base.char = char
- base.subtype = ligature_code
- base.components = start
- if prev then
- prev.next = base
- end
+ start.prev = nil
+ lignode.components = start
+ -- print("lignode",nodes.tosequence(lignode))
+ -- print("components",nodes.tosequence(lignode.components))
+ prev.next = lignode
if next then
- next.prev = base
+ next.prev = lignode
end
- base.next = next
- base.prev = prev
- return 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
+ lignode.next = next
+ lignode.prev = prev
+ -- print("start->end",nodes.tosequence(start))
+ return lignode
else
- return 0
- end
-end
-
--- local function toligature(kind,lookupname,start,stop,char,markflag,discfound) -- brr head
--- if start == stop and start.char == char then
--- start.char = char
--- return start
--- elseif discfound then
--- local prev = start.prev
--- local next = stop.next
--- start.prev = nil
--- stop.next = nil
--- local base = copy_glyph(start)
--- 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
--- return base
--- else
--- -- start is the ligature
--- local deletemarks = markflag ~= "mark"
--- local prev = start.prev
--- local next = stop.next
--- local base = copy_glyph(start)
--- local current, start = insert_node_after(start,start,base)
--- -- [start->current][copyofstart->start]...[stop]
--- current.next = next
--- if next then
--- next.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 baseindex = 0
--- local componentindex = 0
--- while start do
--- 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,baseindex + (has_attribute(start,ligacomp) or componentindex))
--- if trace_marks then
--- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),has_attribute(start,ligacomp))
--- end
--- head, current = insert_node_after(head,current,copy_glyph(start)) -- unlikely that mark has components
--- end
--- start = start.next
--- end
--- start = current.next
--- while start and start.id == glyph_code do -- hm, is id test needed ?
--- local char = start.char
--- if marks[char] then
--- set_attribute(start,ligacomp,baseindex + (has_attribute(start,ligacomp) or componentindex))
--- if trace_marks then
--- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),has_attribute(start,ligacomp))
--- end
--- else
--- break
--- end
--- start = start.next
--- end
--- return head
--- end
--- end
-
-local function toligature(kind,lookupname,start,stop,char,markflag,discfound) -- brr head
- if start == stop and start.char == char then
- start.char = char
- return start
- end
- local prev = start.prev
- local next = stop.next
- start.prev = nil
- stop.next = nil
- local base = copy_glyph(start)
- 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
+ -- start is the ligature
local deletemarks = markflag ~= "mark"
- local components = start
- local baseindex = 0
- local componentindex = 0
- local head = base
- local current = base
+ 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
while start do
- local char = start.char
- if not marks[char] then
- baseindex = baseindex + componentindex
- componentindex = getcomponentindex(start)
+ if not marks[start.char] then
+ i = i + 1
elseif not deletemarks then -- quite fishy
- set_attribute(start,ligacomp,baseindex + (has_attribute(start,ligacomp) or componentindex))
+ set_attribute(start,ligacomp,i)
if trace_marks then
- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),has_attribute(start,ligacomp))
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
end
- head, current = insert_node_after(head,current,copy_node(start)) -- unlikely that mark has components
+ head, current = insert_node_after(head,current,copy_node(start))
end
start = start.next
end
- local start = components
- while start and start.id == glyph_code do -- hm, is id test needed ?
- local char = start.char
- if marks[char] then
- set_attribute(start,ligacomp,baseindex + (has_attribute(start,ligacomp) or componentindex))
+ start = current.next
+ while start and start.id == glyph_code do
+ if marks[start.char] then
+ set_attribute(start,ligacomp,i)
if trace_marks then
- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),has_attribute(start,ligacomp))
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
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 base
end
function handlers.gsub_single(start,kind,lookupname,replacement)
@@ -590,7 +463,7 @@ local function multiple_glyphs(start,multiple) -- marks ?
if nofmultiples > 1 then
local sn = start.next
for k=2,nofmultiples do -- todo: use insert_node
- local n = copy_node(start) -- ignore components
+ local n = copy_node(start)
n.char = multiple[k]
n.next = sn
n.prev = start
@@ -615,12 +488,12 @@ function handlers.gsub_alternate(start,kind,lookupname,alternative,sequence)
local choice = get_alternative_glyph(start,alternative,value)
if choice then
if trace_alternatives then
- logprocess("%s: replacing %s by alternative %s (%s)",pref(kind,lookupname),gref(start.char),gref(choice),choice)
+ logprocess("%s: replacing %s by alternative %s (%s)",pref(kind,lookupname),gref(char),gref(choice),choice)
end
start.char = choice
else
if trace_alternatives then
- logwarning("%s: no variant %s for %s",pref(kind,lookupname),tostring(value),gref(start.char))
+ logwarning("%s: no variant %s for %s",pref(kind,lookupname),tostring(value),gref(char))
end
end
return start, true
@@ -1114,10 +987,6 @@ 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
@@ -1125,10 +994,6 @@ end
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
@@ -1857,7 +1722,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
break
end
prev = prev.prev
- elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces
+ elseif seq[n][32] then -- somehat special, as zapfino can have many preceding spaces
n = n -1
else
match = false
@@ -2097,7 +1962,12 @@ end)
-- fonts.hashes.lookups = lookuphashes
-local constants = fonts.analyzers.constants
+local special_attributes = {
+ init = 1,
+ medi = 2,
+ fina = 3,
+ isol = 4
+}
local function initialize(sequence,script,language,enabled)
local features = sequence.features
@@ -2107,7 +1977,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, constants[kind] or false, sequence.chain or 0, kind, sequence }
+ return { valid, special_attributes[kind] or false, sequence.chain or 0, kind, sequence }
end
end
end
@@ -2115,7 +1985,7 @@ local function initialize(sequence,script,language,enabled)
return false
end
-function otf.dataset(tfmdata,font) -- generic variant, overloaded in context
+function otf.dataset(tfmdata,sequences,font) -- generic variant, overloaded in context
local shared = tfmdata.shared
local properties = tfmdata.properties
local language = properties.language or "dflt"
@@ -2133,17 +2003,12 @@ function otf.dataset(tfmdata,font) -- generic variant, overloaded in context
end
local rl = rs[language]
if not rl then
- rl = {
- -- indexed but we can also add specific data by key
- }
+ rl = { }
rs[language] = rl
- 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
+ local v = enabled and initialize(sequences[k],script,language,enabled)
+ t[k] = v
+ return v
end)
end
return rl
@@ -2165,8 +2030,6 @@ 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
@@ -2194,7 +2057,7 @@ local function featuresprocessor(head,font,attr)
local sequences = resources.sequences
local done = false
- local datasets = otf.dataset(tfmdata,font,attr)
+ local datasets = otf.dataset(tfmdata,sequences,font,attr)
local dirstack = { } -- could move outside function
@@ -2203,9 +2066,6 @@ 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.
- -- 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
@@ -2241,12 +2101,8 @@ local function featuresprocessor(head,font,attr)
if lookupcache then
local lookupmatch = lookupcache[start.char]
if lookupmatch then
- local headnode = start == head
start, success = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
if success then
- if headnode then
- head = start
- end
break
end
end
@@ -2290,14 +2146,10 @@ local function featuresprocessor(head,font,attr)
local lookupmatch = lookupcache[start.char]
if lookupmatch then
-- sequence kan weg
- local headnode = start == head
local ok
start, ok = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
if ok then
success = true
- if headnode then
- head = start
- end
end
end
if start then start = start.next end
@@ -2367,14 +2219,10 @@ local function featuresprocessor(head,font,attr)
local lookupmatch = lookupcache[start.char]
if lookupmatch then
-- we could move all code inline but that makes things even more unreadable
- local headnode = start == head
local ok
start, ok = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
if ok then
success = true
- if headnode then
- head = start
- end
break
end
end
@@ -2700,7 +2548,3 @@ registerotffeature {
node = featuresprocessor,
}
}
-
--- this will change but is needed for an experiment:
-
-otf.handlers = handlers