summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/font-odk.lua
diff options
context:
space:
mode:
authorContext Git Mirror Bot <phg42.2a@gmail.com>2016-01-12 17:15:07 +0100
committerContext Git Mirror Bot <phg42.2a@gmail.com>2016-01-12 17:15:07 +0100
commit8d8d528d2ad52599f11250cfc567fea4f37f2a8b (patch)
tree94286bc131ef7d994f9432febaf03fe23d10eef8 /tex/context/base/mkiv/font-odk.lua
parentf5aed2e51223c36c84c5f25a6cad238b2af59087 (diff)
downloadcontext-8d8d528d2ad52599f11250cfc567fea4f37f2a8b.tar.gz
2016-01-12 16:26:00
Diffstat (limited to 'tex/context/base/mkiv/font-odk.lua')
-rw-r--r--tex/context/base/mkiv/font-odk.lua904
1 files changed, 904 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/font-odk.lua b/tex/context/base/mkiv/font-odk.lua
new file mode 100644
index 000000000..c34efc120
--- /dev/null
+++ b/tex/context/base/mkiv/font-odk.lua
@@ -0,0 +1,904 @@
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+-- We keep the original around for a while so that we can check it --
+-- when the above code does it wrong (data tables are not included). --
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+
+-- author : Kai Eigner, TAT Zetwerk
+-- copyright : TAT Zetwerk
+-- comment : see font-odv.lua for current implementation
+
+-- local state = attributes.private('state')
+-- local sylnr = attributes.private('syllabe')
+--
+-- local function install_dev(tfmdata)
+-- local features = tfmdata.resources.features
+-- local sequences = tfmdata.resources.sequences
+--
+-- local insertpos = 1
+-- for s=1,#sequences do -- classify chars
+-- for k in pairs(basic_shaping_forms) do
+-- if sequences[s].features and ( sequences[s].features[k] or sequences[s].features.locl ) then insertpos = s + 1 end
+-- end
+-- end
+--
+-- features.gsub["dev2_reorder_matras"] = { ["dev2"] = { ["dflt"] = true } }
+-- features.gsub["dev2_reorder_reph"] = { ["dev2"] = { ["dflt"] = true } }
+-- features.gsub["dev2_reorder_pre_base_reordering_consonants"] = { ["dev2"] = { ["dflt"] = true } }
+-- features.gsub["remove_joiners"] = { ["deva"] = { ["dflt"] = true }, ["dev2"] = { ["dflt"] = true } }
+--
+-- local sequence_dev2_reorder_matras = {
+-- chain = 0,
+-- features = { dev2_reorder_matras = { dev2 = { dflt = true } } },
+-- flags = { false, false, false, false },
+-- name = "dev2_reorder_matras",
+-- subtables = { "dev2_reorder_matras" },
+-- type = "dev2_reorder_matras",
+-- }
+-- local sequence_dev2_reorder_reph = {
+-- chain = 0,
+-- features = { dev2_reorder_reph = { dev2 = { dflt = true } } },
+-- flags = { false, false, false, false },
+-- name = "dev2_reorder_reph",
+-- subtables = { "dev2_reorder_reph" },
+-- type = "dev2_reorder_reph",
+-- }
+-- local sequence_dev2_reorder_pre_base_reordering_consonants = {
+-- chain = 0,
+-- features = { dev2_reorder_pre_base_reordering_consonants = { dev2 = { dflt = true } } },
+-- flags = { false, false, false, false },
+-- name = "dev2_reorder_pre_base_reordering_consonants",
+-- subtables = { "dev2_reorder_pre_base_reordering_consonants" },
+-- type = "dev2_reorder_pre_base_reordering_consonants",
+-- }
+-- local sequence_remove_joiners = {
+-- chain = 0,
+-- features = { remove_joiners = { deva = { dflt = true }, dev2 = { dflt = true } } },
+-- flags = { false, false, false, false },
+-- name = "remove_joiners",
+-- subtables = { "remove_joiners" },
+-- type = "remove_joiners",
+-- }
+-- table.insert(sequences, insertpos, sequence_dev2_reorder_pre_base_reordering_consonants)
+-- table.insert(sequences, insertpos, sequence_dev2_reorder_reph)
+-- table.insert(sequences, insertpos, sequence_dev2_reorder_matras)
+-- table.insert(sequences, insertpos, sequence_remove_joiners)
+-- end
+--
+-- local function deva_reorder(head,start,stop,font,attr)
+-- local tfmdata = fontdata[font]
+-- local lookuphash = tfmdata.resources.lookuphash
+-- local sequences = tfmdata.resources.sequences
+--
+-- if not lookuphash["remove_joiners"] then install_dev(tfmdata) end --install Devanagari-features
+--
+-- local sharedfeatures = tfmdata.shared.features
+-- sharedfeatures["remove_joiners"] = true
+-- local datasets = otf.dataset(tfmdata,font,attr)
+--
+-- lookuphash["remove_joiners"] = { [0x200C] = true, [0x200D] = true }
+--
+-- local current, n, base, firstcons, lastcons, basefound = start, start.next, nil, nil, nil, false
+-- local reph, vattu = false, false
+-- for s=1,#sequences do
+-- local dataset = datasets[s]
+-- featurevalue = dataset and dataset[1]
+-- if featurevalue and dataset[4] == "rphf" then reph = true end
+-- if featurevalue and dataset[4] == "blwf" then vattu = true end
+-- end
+-- if ra[start.char] and halant[n.char] and reph then -- if syllable starts with Ra + H and script has 'Reph' then exclude Reph from candidates for base consonants
+-- if n == stop then return head, stop end
+-- if zwj[n.next.char] then
+-- current = start
+-- else
+-- current = n.next
+-- set_attribute(start,state,5) -- rphf
+-- end
+-- end
+--
+-- if nbsp[current.char] then --Stand Alone cluster
+-- if current == stop then
+-- stop = stop.prev
+-- head = node.remove(head, current)
+-- node.free(current)
+-- return head, stop
+-- else
+-- base, firstcons, lastcons = current, current, current
+-- current = current.next
+-- if current ~= stop then
+-- if nukta[current.char] then current = current.next end
+-- if zwj[current.char] then
+-- if current ~= stop and current.next ~= stop and halant[current.next.char] then
+-- current = current.next
+-- local tmp = current.next.next
+-- local changestop = current.next == stop
+-- local tempcurrent = node.copy(current.next)
+-- tempcurrent.next = node.copy(current)
+-- tempcurrent.next.prev = tempcurrent
+-- set_attribute(tempcurrent,state,8) --blwf
+-- tempcurrent = nodes.handlers.characters(tempcurrent)
+-- unset_attribute(tempcurrent,state)
+-- if current.next.char == tempcurrent.char then
+-- node.flush_list(tempcurrent)
+-- local n = node.copy(current)
+-- current.char = dotted_circle
+-- head = node.insert_after(head, current, n)
+-- else
+-- current.char = tempcurrent.char -- (assumes that result of blwf consists of one node)
+-- local freenode = current.next
+-- current.next = tmp
+-- tmp.prev = current
+-- node.free(freenode)
+-- node.flush_list(tempcurrent)
+-- if changestop then stop = current end
+-- end
+-- end
+-- end
+-- end
+-- end
+-- end
+--
+-- while not basefound do -- find base consonant
+-- if consonant[current.char] then
+-- set_attribute(current, state, 6) -- half
+-- if not firstcons then firstcons = current end
+-- lastcons = current
+-- if not base then
+-- base = current
+-- else --check whether consonant has below-base (or post-base) form
+-- local baseform = true
+-- for s=1,#sequences do
+-- local sequence = sequences[s]
+-- local dataset = datasets[s]
+-- featurevalue = dataset and dataset[1]
+-- if featurevalue and dataset[4] == "blwf" then
+-- local subtables = sequence.subtables
+-- for i=1,#subtables do
+-- local lookupname = subtables[i]
+-- local lookupcache = lookuphash[lookupname]
+-- if lookupcache then
+-- local lookupmatch = lookupcache[current.char]
+-- if lookupmatch then
+-- set_attribute(current, state, 8) -- blwf
+-- baseform = false
+-- end
+-- end
+-- end
+-- end
+-- end
+-- if baseform then base = current end
+-- end
+-- end
+-- basefound = current == stop
+-- current = current.next
+-- end
+-- if base ~= lastcons then -- if base consonant is not last one then move halant from base consonant to last one
+-- n = base.next
+-- if nukta[n.char] then n = n.next end
+-- if halant[n.char] then
+-- if lastcons ~= stop then
+-- local ln = lastcons.next
+-- if nukta[ln.char] then lastcons = ln end
+-- end
+-- local np, nn, ln = n.prev, n.next, lastcons.next
+-- np.next = n.next
+-- nn.prev = n.prev
+-- lastcons.next = n
+-- if ln then ln.prev = n end
+-- n.next = ln
+-- n.prev = lastcons
+-- if lastcons == stop then stop = n end
+-- end
+-- end
+--
+-- n = start.next
+-- if ra[start.char] and halant[n.char] and not ( n ~= stop and ( zwj[n.next.char] or zwnj[n.next.char] ) ) then -- if syllable starts with Ra + H then move this combination so that it follows either: the post-base 'matra' (if any) or the base consonant
+-- local matra = base
+-- if base ~= stop and dependent_vowel[base.next.char] then matra = base.next end
+-- local sp, nn, mn = start.prev, n.next, matra.next
+-- if sp then sp.next = nn end
+-- nn.prev = sp
+-- matra.next = start
+-- start.prev = matra
+-- n.next = mn
+-- if mn then mn.prev = n end
+-- if head == start then head = nn end
+-- start = nn
+-- if matra == stop then stop = n end
+-- end
+--
+-- local current = start
+-- while current ~= stop do
+-- if halant[current.next.char] and current.next ~= stop and zwnj[current.next.next.char] then unset_attribute(current, state) end
+-- current = current.next
+-- end
+--
+-- if has_attribute(base, state) and base ~= stop and halant[base.next.char] and not ( base.next ~= stop and zwj[base.next.next.char] ) then unset_attribute(base, state) end
+--
+-- local current, allreordered, moved = start, false, { [base] = true }
+-- local a, b, p, bn = base, base, base, base.next
+-- if base ~= stop and nukta[bn.char] then a, b, p = bn, bn, bn end
+-- while not allreordered do
+-- local c, n, l = current, current.next, nil --current is always consonant
+-- if c ~= stop and nukta[n.char] then c = n n = n.next end
+-- if c ~= stop and halant[n.char] then c = n n = n.next end
+-- while c ~= stop and dependent_vowel[n.char] do c = n n = n.next end
+-- if c ~= stop and vowel_modifier[n.char] then c = n n = n.next end
+-- if c ~= stop and stress_tone_mark[n.char] then c = n n = n.next end
+-- local bp, cn = firstcons.prev, current.next
+-- while cn ~= c.next do -- move pre-base matras...
+-- if pre_mark[cn.char] then
+-- if bp then bp.next = cn end
+-- cn.prev.next = cn.next
+-- if cn.next then cn.next.prev = cn.prev end
+-- if cn == stop then stop = cn.prev end
+-- cn.prev = bp
+-- cn.next = firstcons
+-- firstcons.prev = cn
+-- if firstcons == start then
+-- if head == start then head = cn end
+-- start = cn
+-- end
+-- break
+-- end
+-- cn = cn.next
+-- end
+-- allreordered = c == stop
+-- current = c.next
+-- end
+--
+-- if reph or vattu then
+-- local current, cns = start, nil
+-- while current ~= stop do
+-- local c, n = current, current.next
+-- if ra[current.char] and halant[n.char] then
+-- c, n = n, n.next
+-- local b, bn = base, base
+-- while bn ~= stop do
+-- if dependent_vowel[bn.next.char] then b = bn.next end
+-- bn = bn.next
+-- end
+-- if has_attribute(current,state,attribute) == 5 then -- position Reph (Ra + H) after post-base 'matra' (if any) since these become marks on the 'matra', not on the base glyph
+-- if b ~= current then
+-- if current == start then
+-- if head == start then head = n end
+-- start = n
+-- end
+-- if b == stop then stop = c end
+-- if current.prev then current.prev.next = n end
+-- if n then n.prev = current.prev end
+-- c.next = b.next
+-- if b.next then b.next.prev = c end
+-- b.next = current
+-- current.prev = b
+-- end
+-- elseif cns and cns.next ~= current then -- position below-base Ra (vattu) following the consonants on which it is placed (either the base consonant or one of the pre-base consonants)
+-- local cp, cnsn = current.prev, cns.next
+-- if cp then cp.next = n end
+-- if n then n.prev = cp end
+-- cns.next = current
+-- current.prev = cns
+-- c.next = cnsn
+-- if cnsn then cnsn.prev = c end
+-- if c == stop then stop = cp break end
+-- current = n.prev
+-- end
+-- elseif consonant[current.char] or nbsp[current.char] then
+-- cns = current
+-- if halant[cns.next.char] then cns = cns.next end
+-- end
+-- current = current.next
+-- end
+-- end
+--
+-- if nbsp[base.char] then
+-- head = node.remove(head, base)
+-- node.free(base)
+-- end
+--
+-- return head, stop
+-- end
+--
+-- function dev2_reorder_matras(start,kind,lookupname,replacement)
+-- local current = start
+-- while current and current.id == glyph and current.subtype<256 and current.font == start.font and has_attribute(current, sylnr) == has_attribute(start, sylnr) do
+-- if halant[current.char] and not has_attribute(current, state) then
+-- if current.next and current.next.id == glyph and current.next.subtype<256 and current.next.font == start.font and has_attribute(current.next, sylnr) == has_attribute(start, sylnr) and ( zwj[current.next.char] or zwnj[current.next.char] ) then current = current.next end
+-- local sn = start.next
+-- start.next.prev = start.prev
+-- if start.prev then start.prev.next = start.next end
+-- if current.next then current.next.prev = start end
+-- start.next = current.next
+-- current.next = start
+-- start.prev = current
+-- start = sn
+-- break
+-- end
+-- current = current.next
+-- end
+-- return start, true
+-- end
+--
+-- function dev2_reorder_reph(start,kind,lookupname,replacement)
+-- local current, sn = start.next, nil
+-- while current and current.id == glyph and current.subtype<256 and current.font == start.font and has_attribute(current, sylnr) == has_attribute(start, sylnr) do --step 2
+-- if halant[current.char] and not has_attribute(current, state) then
+-- if current.next and current.next.id == glyph and current.next.subtype<256 and current.next.font == start.font and has_attribute(current.next, sylnr) == has_attribute(start, sylnr) and ( zwj[current.next.char] or zwnj[current.next.char] ) then current = current.next end
+-- sn = start.next
+-- start.next.prev = start.prev
+-- if start.prev then start.prev.next = start.next end
+-- if current.next then current.next.prev = start end
+-- start.next = current.next
+-- current.next = start
+-- start.prev = current
+-- start = sn
+-- break
+-- end
+-- current = current.next
+-- end
+-- if not sn then
+-- current = start.next
+-- while current and current.id == glyph and current.subtype<256 and current.font == start.font and has_attribute(current, sylnr) == has_attribute(start, sylnr) do --step 4
+-- if has_attribute(current, state) == 9 then --post-base
+-- sn = start.next
+-- start.next.prev = start.prev
+-- if start.prev then start.prev.next = start.next end
+-- start.prev = current.prev
+-- current.prev.next = start
+-- start.next = current
+-- current.prev = start
+-- start = sn
+-- break
+-- end
+-- current = current.next
+-- end
+-- end
+-- if not sn then
+-- current = start.next
+-- local c = nil
+-- while current and current.id == glyph and current.subtype<256 and current.font == start.font and has_attribute(current, sylnr) == has_attribute(start, sylnr) do --step 5
+-- if not c and ( above_mark[current.char] or below_mark[current.char] or post_mark[current.char] ) and ReorderClass[current.char] ~= "after subscript" then c = current end
+-- current = current.next
+-- end
+-- if c then
+-- sn = start.next
+-- start.next.prev = start.prev
+-- if start.prev then start.prev.next = start.next end
+-- start.prev = c.prev
+-- c.prev.next = start
+-- start.next = c
+-- c.prev = start
+-- start = sn
+-- end
+-- end
+-- if not sn then
+-- current = start
+-- while current.next and current.next.id == glyph and current.next.subtype<256 and current.next.font == start.font and has_attribute(current.next, sylnr) == has_attribute(start, sylnr) do --step 6
+-- current = current.next
+-- end
+-- if start ~= current then
+-- sn = start.next
+-- start.next.prev = start.prev
+-- if start.prev then start.prev.next = start.next end
+-- if current.next then current.next.prev = start end
+-- start.next = current.next
+-- current.next = start
+-- start.prev = current
+-- start = sn
+-- end
+-- end
+-- return start, true
+-- end
+--
+-- function dev2_reorder_pre_base_reordering_consonants(start,kind,lookupname,replacement)
+-- local current, sn = start, nil
+-- while current and current.id == glyph and current.subtype<256 and current.font == start.font and has_attribute(current, sylnr) == has_attribute(start, sylnr) do
+-- if halant[current.char] and not has_attribute(current, state) then
+-- if current.next and current.next.id == glyph and current.next.subtype<256 and current.next.font == start.font and has_attribute(current.next, sylnr) == has_attribute(start, sylnr) and ( zwj[current.next.char] or zwnj[current.next.char] ) then current = current.next end
+-- sn = start.next
+-- start.next.prev = start.prev
+-- if start.prev then start.prev.next = start.next end
+-- if current.next then current.next.prev = start end
+-- start.next = current.next
+-- current.next = start
+-- start.prev = current
+-- start = sn
+-- break
+-- end
+-- current = current.next
+-- end
+-- if not sn then
+-- current = start.next
+-- while current and current.id == glyph and current.subtype<256 and current.font == start.font and has_attribute(current, sylnr) == has_attribute(start, sylnr) do
+-- if not consonant[current.char] and has_attribute(current, state) then --main
+-- sn = start.next
+-- start.next.prev = start.prev
+-- if start.prev then start.prev.next = start.next end
+-- start.prev = current.prev
+-- current.prev.next = start
+-- start.next = current
+-- current.prev = start
+-- start = sn
+-- break
+-- end
+-- current = current.next
+-- end
+-- end
+-- return start, true
+-- end
+--
+-- function remove_joiners(start,kind,lookupname,replacement)
+-- local stop = start.next
+-- while stop and stop.id == glyph and stop.subtype<256 and stop.font == start.font and (zwj[stop.char] or zwnj[stop.char]) do stop = stop.next end
+-- if stop then stop.prev.next = nil stop.prev = start.prev end
+-- if start.prev then start.prev.next = stop end
+-- node.flush_list(start)
+-- return stop, true
+-- end
+--
+-- local function dev2_reorder(head,start,stop,font,attr)
+-- local tfmdata = fontdata[font]
+-- local lookuphash = tfmdata.resources.lookuphash
+-- local sequences = tfmdata.resources.sequences
+--
+-- if not lookuphash["remove_joiners"] then install_dev(tfmdata) end --install Devanagari-features
+--
+-- local sharedfeatures = tfmdata.shared.features
+-- sharedfeatures["dev2_reorder_matras"] = true
+-- sharedfeatures["dev2_reorder_reph"] = true
+-- sharedfeatures["dev2_reorder_pre_base_reordering_consonants"] = true
+-- sharedfeatures["remove_joiners"] = true
+-- local datasets = otf.dataset(tfmdata,font,attr)
+--
+-- local reph, pre_base_reordering_consonants = false, nil
+-- local halfpos, basepos, subpos, postpos = nil, nil, nil, nil
+-- local locl = { }
+--
+-- for s=1,#sequences do -- classify chars
+-- local sequence = sequences[s]
+-- local dataset = datasets[s]
+-- featurevalue = dataset and dataset[1]
+-- if featurevalue and dataset[4] then
+-- local subtables = sequence.subtables
+-- for i=1,#subtables do
+-- local lookupname = subtables[i]
+-- local lookupcache = lookuphash[lookupname]
+-- if lookupcache then
+-- if dataset[4] == "rphf" then
+-- if dataset[3] ~= 0 then --rphf is result of of chain
+-- else
+-- reph = lookupcache[0x0930] and lookupcache[0x0930][0x094D] and lookupcache[0x0930][0x094D]["ligature"]
+-- end
+-- end
+-- if dataset[4] == "pref" and not pre_base_reordering_consonants then
+-- for k, v in pairs(lookupcache[0x094D]) do
+-- pre_base_reordering_consonants[k] = v and v["ligature"] --ToDo: reph might also be result of chain
+-- end
+-- end
+-- local current = start
+-- while current ~= stop.next do
+-- if dataset[4] == "locl" then locl[current] = lookupcache[current.char] end --ToDo: locl might also be result of chain
+-- if current ~= stop then
+-- local c, n = locl[current] or current.char, locl[current.next] or current.next.char
+-- if dataset[4] == "rphf" and lookupcache[c] and lookupcache[c][n] then --above-base: rphf Consonant + Halant
+-- if current.next ~= stop and ( zwj[current.next.next.char] or zwnj[current.next.next.char] ) then --ZWJ and ZWNJ prevent creation of reph
+-- current = current.next
+-- elseif current == start then
+-- set_attribute(current,state,5)
+-- end
+-- current = current.next
+-- end
+-- if dataset[4] == "half" and lookupcache[c] and lookupcache[c][n] then --half forms: half Consonant + Halant
+-- if current.next ~= stop and zwnj[current.next.next.char] then --ZWNJ prevent creation of half
+-- current = current.next
+-- else
+-- set_attribute(current,state,6)
+-- if not halfpos then halfpos = current end
+-- end
+-- current = current.next
+-- end
+-- if dataset[4] == "pref" and lookupcache[c] and lookupcache[c][n] then --pre-base: pref Halant + Consonant
+-- set_attribute(current,state,7)
+-- set_attribute(current.next,state,7)
+-- current = current.next
+-- end
+-- if dataset[4] == "blwf" and lookupcache[c] and lookupcache[c][n] then --below-base: blwf Halant + Consonant
+-- set_attribute(current,state,8)
+-- set_attribute(current.next,state,8)
+-- current = current.next
+-- subpos = current
+-- end
+-- if dataset[4] == "pstf" and lookupcache[c] and lookupcache[c][n] then --post-base: pstf Halant + Consonant
+-- set_attribute(current,state,9)
+-- set_attribute(current.next,state,9)
+-- current = current.next
+-- postpos = current
+-- end
+-- end
+-- current = current.next
+-- end
+-- end
+-- end
+-- end
+-- end
+--
+-- lookuphash["dev2_reorder_matras"] = pre_mark
+-- lookuphash["dev2_reorder_reph"] = { [reph] = true }
+-- lookuphash["dev2_reorder_pre_base_reordering_consonants"] = pre_base_reordering_consonants or { }
+-- lookuphash["remove_joiners"] = { [0x200C] = true, [0x200D] = true }
+--
+-- local current, base, firstcons = start, nil, nil
+-- if has_attribute(start,state) == 5 then current = start.next.next end -- if syllable starts with Ra + H and script has 'Reph' then exclude Reph from candidates for base consonants
+--
+-- if current ~= stop.next and nbsp[current.char] then --Stand Alone cluster
+-- if current == stop then
+-- stop = stop.prev
+-- head = node.remove(head, current)
+-- node.free(current)
+-- return head, stop
+-- else
+-- base = current
+-- current = current.next
+-- if current ~= stop then
+-- if nukta[current.char] then current = current.next end
+-- if zwj[current.char] then
+-- if current ~= stop and current.next ~= stop and halant[current.next.char] then
+-- current = current.next
+-- local tmp = current.next.next
+-- local changestop = current.next == stop
+-- current.next.next = nil
+-- set_attribute(current,state,7) --pref
+-- current = nodes.handlers.characters(current)
+-- set_attribute(current,state,8) --blwf
+-- current = nodes.handlers.characters(current)
+-- set_attribute(current,state,9) --pstf
+-- current = nodes.handlers.characters(current)
+-- unset_attribute(current,state)
+-- if halant[current.char] then
+-- current.next.next = tmp
+-- local nc = node.copy(current)
+-- current.char = dotted_circle
+-- head = node.insert_after(head, current, nc)
+-- else
+-- current.next = tmp -- (assumes that result of pref, blwf, or pstf consists of one node)
+-- if changestop then stop = current end
+-- end
+-- end
+-- end
+-- end
+-- end
+-- else --not Stand Alone cluster
+-- while current ~= stop.next do -- find base consonant
+-- if consonant[current.char] and not ( current ~= stop and halant[current.next.char] and current.next ~= stop and zwj[current.next.next.char] ) then
+-- if not firstcons then firstcons = current end
+-- if not ( has_attribute(current, state) == 7 or has_attribute(current, state) == 8 or has_attribute(current, state) == 9 ) then base = current end --check whether consonant has below-base or post-base form or is pre-base reordering Ra
+-- end
+-- current = current.next
+-- end
+-- if not base then
+-- base = firstcons
+-- end
+-- end
+--
+-- if not base then
+-- if has_attribute(start, state) == 5 then unset_attribute(start, state) end
+-- return head, stop
+-- else
+-- if has_attribute(base, state) then unset_attribute(base, state) end
+-- basepos = base
+-- end
+-- if not halfpos then halfpos = base end
+-- if not subpos then subpos = base end
+-- if not postpos then postpos = subpos or base end
+--
+-- --Matra characters are classified and reordered by which consonant in a conjunct they have affinity for
+-- local moved = { }
+-- current = start
+-- while current ~= stop.next do
+-- local char, target, cn = locl[current] or current.char, nil, current.next
+-- if not moved[current] and dependent_vowel[char] then
+-- if pre_mark[char] then -- Before first half form in the syllable
+-- moved[current] = true
+-- if current.prev then current.prev.next = current.next end
+-- if current.next then current.next.prev = current.prev end
+-- if current == stop then stop = current.prev end
+-- if halfpos == start then
+-- if head == start then head = current end
+-- start = current
+-- end
+-- if halfpos.prev then halfpos.prev.next = current end
+-- current.prev = halfpos.prev
+-- halfpos.prev = current
+-- current.next = halfpos
+-- halfpos = current
+-- elseif above_mark[char] then -- After main consonant
+-- target = basepos
+-- if subpos == basepos then subpos = current end
+-- if postpos == basepos then postpos = current end
+-- basepos = current
+-- elseif below_mark[char] then -- After subjoined consonants
+-- target = subpos
+-- if postpos == subpos then postpos = current end
+-- subpos = current
+-- elseif post_mark[char] then -- After post-form consonant
+-- target = postpos
+-- postpos = current
+-- end
+-- if ( above_mark[char] or below_mark[char] or post_mark[char] ) and current.prev ~= target then
+-- if current.prev then current.prev.next = current.next end
+-- if current.next then current.next.prev = current.prev end
+-- if current == stop then stop = current.prev end
+-- if target.next then target.next.prev = current end
+-- current.next = target.next
+-- target.next = current
+-- current.prev = target
+-- end
+-- end
+-- current = cn
+-- end
+--
+-- --Reorder marks to canonical order: Adjacent nukta and halant or nukta and vedic sign are always repositioned if necessary, so that the nukta is first.
+-- local current, c = start, nil
+-- while current ~= stop do
+-- if halant[current.char] or stress_tone_mark[current.char] then
+-- if not c then c = current end
+-- else
+-- c = nil
+-- end
+-- if c and nukta[current.next.char] then
+-- if head == c then head = current.next end
+-- if stop == current.next then stop = current end
+-- if c.prev then c.prev.next = current.next end
+-- current.next.prev = c.prev
+-- current.next = current.next.next
+-- if current.next.next then current.next.next.prev = current end
+-- c.prev = current.next
+-- current.next.next = c
+-- end
+-- if stop == current then break end
+-- current = current.next
+-- end
+--
+-- if nbsp[base.char] then
+-- head = node.remove(head, base)
+-- node.free(base)
+-- end
+--
+-- return head, stop
+-- end
+--
+-- function fonts.analyzers.methods.deva(head,font,attr)
+-- local orighead = head
+-- local current, start, done = head, true, false
+-- while current do
+-- if current.id == glyph and current.subtype<256 and current.font == font then
+-- done = true
+-- local syllablestart, syllableend = current, nil
+--
+-- local c = current --Checking Stand Alone cluster (this behavior is copied from dev2)
+-- if ra[c.char] and c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and halant[c.next.char] and c.next.next and c.next.next.id == glyph and c.next.next.subtype<256 and c.next.next.font == font then c = c.next.next end
+-- if nbsp[c.char] and ( not current.prev or current.prev.id ~= glyph or current.prev.subtype>=256 or current.prev.font ~= font or
+-- ( not consonant[current.prev.char] and not independent_vowel[current.prev.char] and not dependent_vowel[current.prev.char] and
+-- not vowel_modifier[current.prev.char] and not stress_tone_mark[current.prev.char] and not nukta[current.prev.char] and not halant[current.prev.char] )
+-- ) then --Stand Alone cluster (at the start of the word only): #[Ra+H]+NBSP+[N]+[<[<ZWJ|ZWNJ>]+H+C>]+[{M}+[N]+[H]]+[SM]+[(VD)]
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and nukta[c.next.char] then c = c.next end
+-- local n = c.next
+-- if n and n.id == glyph and n.subtype<256 and n.font == font then
+-- local ni = n.next
+-- if ( zwj[n.char] or zwnj[n.char] ) and ni and ni.id == glyph and ni.subtype<256 and ni.font == font then n = ni ni = ni.next end
+-- if halant[n.char] and ni and ni.id == glyph and ni.subtype<256 and ni.font == font and consonant[ni.char] then c = ni end
+-- end
+-- while c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and dependent_vowel[c.next.char] do c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and nukta[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and halant[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and vowel_modifier[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and stress_tone_mark[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and stress_tone_mark[c.next.char] then c = c.next end
+-- current = c.next
+-- syllableend = c
+-- if syllablestart ~= syllableend then
+-- head, current = deva_reorder(head, syllablestart,syllableend,font,attr)
+-- current = current.next
+-- end
+-- elseif consonant[current.char] then -- syllable containing consonant
+-- prevc = true
+-- while prevc do
+-- prevc = false
+-- local n = current.next
+-- if n and n.id == glyph and n.subtype<256 and n.font == font and nukta[n.char] then n = n.next end
+-- if n and n.id == glyph and n.subtype<256 and n.font == font and halant[n.char] then
+-- local n = n.next
+-- if n and n.id == glyph and n.subtype<256 and n.font == font and ( zwj[n.char] or zwnj[n.char] ) then n = n.next end
+-- if n and n.id == glyph and n.subtype<256 and n.font == font and consonant[n.char] then
+-- prevc = true
+-- current = n
+-- end
+-- end
+-- end
+-- if current.next and current.next.id == glyph and current.next.subtype<256 and current.next.font == font and nukta[current.next.char] then current = current.next end -- nukta (not specified in Microsft Devanagari OpenType specification)
+-- syllableend = current
+-- current = current.next
+-- if current and current.id == glyph and current.subtype<256 and current.font == font and halant[current.char] then -- syllable containing consonant without vowels: {C + [Nukta] + H} + C + H
+-- if current.next and current.next.id == glyph and current.next.subtype<256 and current.next.font == font and ( zwj[current.next.char] or zwnj[current.next.char] ) then current = current.next end
+-- syllableend = current
+-- current = current.next
+-- else -- syllable containing consonant with vowels: {C + [Nukta] + H} + C + [M] + [VM] + [SM]
+-- if current and current.id == glyph and current.subtype<256 and current.font == font and dependent_vowel[current.char] then
+-- syllableend = current
+-- current = current.next
+-- end
+-- if current and current.id == glyph and current.subtype<256 and current.font == font and vowel_modifier[current.char] then
+-- syllableend = current
+-- current = current.next
+-- end
+-- if current and current.id == glyph and current.subtype<256 and current.font == font and stress_tone_mark[current.char] then
+-- syllableend = current
+-- current = current.next
+-- end
+-- end
+-- if syllablestart ~= syllableend then
+-- head, current = deva_reorder(head,syllablestart,syllableend,font,attr)
+-- current = current.next
+-- end
+-- elseif current.id == glyph and current.subtype<256 and current.font == font and independent_vowel[current.char] then -- syllable without consonants: VO + [VM] + [SM]
+-- syllableend = current
+-- current = current.next
+-- if current and current.id == glyph and current.subtype<256 and current.font == font and vowel_modifier[current.char] then
+-- syllableend = current
+-- current = current.next
+-- end
+-- if current and current.id == glyph and current.subtype<256 and current.font == font and stress_tone_mark[current.char] then
+-- syllableend = current
+-- current = current.next
+-- end
+-- else -- Syntax error
+-- if pre_mark[current.char] or above_mark[current.char] or below_mark[current.char] or post_mark[current.char] then
+-- local n = node.copy(current)
+-- if pre_mark[current.char] then
+-- n.char = dotted_circle
+-- else
+-- current.char = dotted_circle
+-- end
+-- head, current = node.insert_after(head, current, n)
+-- end
+-- current = current.next
+-- end
+-- else
+-- current = current.next
+-- end
+-- start = false
+-- end
+--
+-- return head, done
+-- end
+--
+-- function fonts.analyzers.methods.dev2(head,font,attr)
+-- local current, start, done, syl_nr = head, true, false, 0
+-- while current do
+-- local syllablestart, syllableend = nil, nil
+-- if current.id == glyph and current.subtype<256 and current.font == font then
+-- syllablestart = current
+-- done = true
+-- local c, n = current, current.next
+-- if ra[current.char] and n and n.id == glyph and n.subtype<256 and n.font == font and halant[n.char] and n.next and n.next.id == glyph and n.next.subtype<256 and n.next.font == font then c = n.next end
+-- if independent_vowel[c.char] then --Vowel-based syllable: [Ra+H]+V+[N]+[<[<ZWJ|ZWNJ>]+H+C|ZWJ+C>]+[{M}+[N]+[H]]+[SM]+[(VD)]
+-- n = c.next
+-- local ni, nii = nil, nil
+-- if n and n.id == glyph and n.subtype<256 and n.font == font and nukta[n.char] then n = n.next end
+-- if n and n.id == glyph and n.subtype<256 and n.font == font then local ni = n.next end
+-- if ni and ni.id == glyph and ni.subtype<256 and ni.font == font and ni.next and ni.next.id == glyph and ni.next.subtype<256 and ni.next.font == font then
+-- nii = ni.next
+-- if zwj[ni.char] and consonant[nii.char] then
+-- c = nii
+-- elseif (zwj[ni.char] or zwnj[ni.char]) and halant[nii.char] and nii.next and nii.next.id == glyph and nii.next.subtype<256 and nii.next.font == font and consonant[nii.next.char] then
+-- c = nii.next
+-- end
+-- end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and dependent_vowel[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and nukta[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and halant[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and vowel_modifier[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and stress_tone_mark[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and stress_tone_mark[c.next.char] then c = c.next end
+-- current = c
+-- syllableend = c
+-- elseif nbsp[c.char] and ( not current.prev or current.prev.id ~= glyph or current.prev.subtype>=256 or current.prev.font ~= font or
+-- ( not consonant[current.prev.char] and not independent_vowel[current.prev.char] and not dependent_vowel[current.prev.char] and
+-- not vowel_modifier[current.prev.char] and not stress_tone_mark[current.prev.char] and not nukta[current.prev.char] and not halant[current.prev.char] )
+-- ) then --Stand Alone cluster (at the start of the word only): #[Ra+H]+NBSP+[N]+[<[<ZWJ|ZWNJ>]+H+C>]+[{M}+[N]+[H]]+[SM]+[(VD)]
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and nukta[c.next.char] then c = c.next end
+-- n = c.next
+-- if n and n.id == glyph and n.subtype<256 and n.font == font then
+-- local ni = n.next
+-- if ( zwj[n.char] or zwnj[n.char] ) and ni and ni.id == glyph and ni.subtype<256 and ni.font == font then n = ni ni = ni.next end
+-- if halant[n.char] and ni and ni.id == glyph and ni.subtype<256 and ni.font == font and consonant[ni.char] then c = ni end
+-- end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and dependent_vowel[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and nukta[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and halant[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and vowel_modifier[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and stress_tone_mark[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and stress_tone_mark[c.next.char] then c = c.next end
+-- current = c
+-- syllableend = c
+-- elseif consonant[current.char] then --Consonant syllable: {C+[N]+<H+[<ZWNJ|ZWJ>]|<ZWNJ|ZWJ>+H>} + C+[N]+[A] + [< H+[<ZWNJ|ZWJ>] | {M}+[N]+[H]>]+[SM]+[(VD)]
+-- c = current
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and nukta[c.next.char] then c = c.next end
+-- n = c
+-- while n.next and n.next.id == glyph and n.next.subtype<256 and n.next.font == font and ( halant[n.next.char] or zwnj[n.next.char] or zwj[n.next.char] ) do
+-- if halant[n.next.char] then
+-- n = n.next
+-- if n.next and n.next.id == glyph and n.next.subtype<256 and n.next.font == font and ( zwnj[n.next.char] or zwj[n.next.char] ) then n = n.next end
+-- else
+-- if n.next.next and n.next.next.id == glyph and n.next.next.subtype<256 and n.next.next.font == font and halant[n.next.next.char] then n = n.next.next end
+-- end
+-- if n.next and n.next.id == glyph and n.next.subtype<256 and n.next.font == font and consonant[n.next.char] then
+-- n = n.next
+-- if n.next and n.next.id == glyph and n.next.subtype<256 and n.next.font == font and nukta[n.next.char] then n = n.next end
+-- c = n
+-- else
+-- break
+-- end
+-- end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and anudatta[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and halant[c.next.char] then
+-- c = c.next
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and ( zwnj[c.next.char] or zwj[c.next.char] ) then c = c.next end
+-- else
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and dependent_vowel[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and nukta[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and halant[c.next.char] then c = c.next end
+-- end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and vowel_modifier[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and stress_tone_mark[c.next.char] then c = c.next end
+-- if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and stress_tone_mark[c.next.char] then c = c.next end
+-- current = c
+-- syllableend = c
+-- end
+-- end
+--
+-- if syllableend then
+-- syl_nr = syl_nr + 1
+-- c = syllablestart
+-- while c ~= syllableend.next do
+-- set_attribute(c,sylnr,syl_nr)
+-- c = c.next
+-- end
+-- end
+-- if syllableend and syllablestart ~= syllableend then
+-- head, current = dev2_reorder(head,syllablestart,syllableend,font,attr)
+-- end
+--
+-- if not syllableend and not has_attribute(current, state) and current.id == glyph and current.subtype<256 and current.font == font then -- Syntax error
+-- if pre_mark[current.char] or above_mark[current.char] or below_mark[current.char] or post_mark[current.char] then
+-- local n = node.copy(current)
+-- if pre_mark[current.char] then
+-- n.char = dotted_circle
+-- else
+-- current.char = dotted_circle
+-- end
+-- head, current = node.insert_after(head, current, n)
+-- end
+-- end
+--
+-- start = false
+-- current = current.next
+-- end
+--
+-- return head, done
+-- end
+--
+-- function otf.handlers.dev2_reorder_matras(start,kind,lookupname,replacement)
+-- return dev2_reorder_matras(start,kind,lookupname,replacement)
+-- end
+--
+-- function otf.handlers.dev2_reorder_reph(start,kind,lookupname,replacement)
+-- return dev2_reorder_reph(start,kind,lookupname,replacement)
+-- end
+--
+-- function otf.handlers.dev2_reorder_pre_base_reordering_consonants(start,kind,lookupname,replacement)
+-- return dev2_reorder_pre_base_reordering_consonants(start,kind,lookupname,replacement)
+-- end
+--
+-- function otf.handlers.remove_joiners(start,kind,lookupname,replacement)
+-- return remove_joiners(start,kind,lookupname,replacement)
+-- end