summaryrefslogtreecommitdiff
path: root/tex/context/base/font-otn.lua
diff options
context:
space:
mode:
authorHans Hagen <pragma@wxs.nl>2012-10-05 19:52:00 +0200
committerHans Hagen <pragma@wxs.nl>2012-10-05 19:52:00 +0200
commitc9b5e0c8f0273527f74ff7b032e7e2482166574e (patch)
treebf16769ccbb14d5b4419feafffce16c392ffa16d /tex/context/base/font-otn.lua
parent08f8bbb60ad11fe3fe1b5632b2eca97422c5bf8c (diff)
downloadcontext-c9b5e0c8f0273527f74ff7b032e7e2482166574e.tar.gz
beta 2012.10.05 19:52
Diffstat (limited to 'tex/context/base/font-otn.lua')
-rw-r--r--tex/context/base/font-otn.lua206
1 files changed, 160 insertions, 46 deletions
diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua
index ef842b099..ba9b0ed94 100644
--- a/tex/context/base/font-otn.lua
+++ b/tex/context/base/font-otn.lua
@@ -116,6 +116,8 @@ 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
@@ -151,6 +153,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)
@@ -185,7 +188,6 @@ local glyph_code = nodecodes.glyph
local glue_code = nodecodes.glue
local disc_code = nodecodes.disc
local whatsit_code = nodecodes.whatsit
-local user_code = nodecodes.user
local dir_code = whatcodes.dir
local localpar_code = whatcodes.localpar
@@ -311,35 +313,110 @@ 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 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 collapsecomponents(start)
+-- local c = start
+-- while c do
+-- local cp = c.components
+-- if cp then
+-- flush_node_list(cp)
+-- c.components = nil
+-- end
+-- c = c.next
+-- end
+-- return start
+-- end
-local function markstoligature(kind,lookupname,start,stop,char)
- local n = copy_node(start)
+local function collapsecomponents(start)
+ if not start.next then
+ report_warning("suspicious ligature components")
+ -- actually an error
+ return components
+ else
+ local head = nil
+ local tail = nil
+ while start do
+ local components = start.components
+ if components then
+ if head then
+ tail.next = components
+ components.prev = tail
+ else
+ head = components
+ end
+ tail = find_node_tail(components)
+ start.components = nil
+ else
+ if head then
+ tail.next = start
+ start.prev = tail
+ tail = start
+ else
+ head = start
+ tail = start
+ end
+ end
+ start = start.next
+ end
+ return head
+ end
+end
+
+local function markstoligature(kind,lookupname,start,stop,char) -- some trickery to keep head as is
+ -- [start]..[stop]
local keep = start
- local current
- current, start = insert_node_after(start,start,n)
+ local current, start = insert_node_after(start,start,copy_node(start))
+ -- [current][start]..[stop]
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
+ start.prev = nil
+ stop.next = nil
+ current.char = char
+ current.subtype = ligature_code
+ current.components = collapsecomponents(start)
return keep
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) -- so we cannot remove components !
+ local i = 0
+ if start.subtype == ligature_code then
+ local comp = start.components
+ while comp do
+ i = i + getcomponentindex(comp)
+ comp = comp.next
+ end
+ return i
+ elseif not marks[start.char] then
+ return 1
+ else
+ return 0
+ end
+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
@@ -348,7 +425,7 @@ local function toligature(kind,lookupname,start,stop,char,markflag,discfound) --
local prev = start.prev
stop.next = nil
start.prev = nil
- lignode.components = start
+ lignode.components = collapsecomponents(start)
-- print("lignode",nodes.tosequence(lignode))
-- print("components",nodes.tosequence(lignode.components))
prev.next = lignode
@@ -362,29 +439,32 @@ local function toligature(kind,lookupname,start,stop,char,markflag,discfound) --
else
-- start is the ligature
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
+ local prev = start.prev
+ local next = stop.next
+ local current, start = insert_node_after(start,start,copy_node(start))
+ -- [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
+ current.components = collapsecomponents(start)
local head = current
-- this is messy ... we should get rid of the components eventually
- local i = 0 -- is index of base
+ local baseindex = 0
+ local componentindex = 0
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)
+ 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(start.char),i)
+ 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_node(start))
end
@@ -392,22 +472,17 @@ local function toligature(kind,lookupname,start,stop,char,markflag,discfound) --
end
start = current.next
while start and start.id == glyph_code do
- if marks[start.char] then
- set_attribute(start,ligacomp,i)
+ 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(start.char),i)
+ 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
- --
- -- we do need components in funny kerning mode but maybe I can better reconstruct then
- -- as we do have the font components info available; removing components makes the
- -- previous code much simpler
- --
- -- flush_node_list(head.components)
return head
end
end
@@ -489,12 +564,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
@@ -577,6 +652,7 @@ function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence)
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))
+-- print("start",nodes.listtoutf(start.components))
else
start = toligature(kind,lookupname,start,stop,lig,skipmark,discfound)
end
@@ -988,6 +1064,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
+ node.flush_list(components)
+end
delete_node(start,next)
end
n = n + 1
@@ -995,6 +1075,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
+ node.flush_list(components)
+end
delete_node(start,next)
n = n + 1
until next == stop
@@ -1967,7 +2051,13 @@ local special_attributes = {
init = 1,
medi = 2,
fina = 3,
- isol = 4
+ isol = 4,
+ -- devanagari
+ rphf = 5,
+ half = 6,
+ pref = 7,
+ blwf = 8,
+ pstf = 9,
}
local function initialize(sequence,script,language,enabled)
@@ -1986,7 +2076,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"
@@ -2004,12 +2094,17 @@ 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
+ local sequences = tfmdata.resources.sequences
setmetatableindex(rl, function(t,k)
- local v = enabled and initialize(sequences[k],script,language,enabled)
- t[k] = v
- return v
+ if type(k) == "number" then
+ local v = enabled and initialize(sequences[k],script,language,enabled)
+ t[k] = v
+ return v
+ end
end)
end
return rl
@@ -2060,7 +2155,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
@@ -2069,6 +2164,9 @@ 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
@@ -2104,8 +2202,12 @@ 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
@@ -2149,10 +2251,14 @@ 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
@@ -2222,10 +2328,14 @@ 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
@@ -2551,3 +2661,7 @@ registerotffeature {
node = featuresprocessor,
}
}
+
+-- this will change but is needed for an experiment:
+
+otf.handlers = handlers