summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/font-ota.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-ota.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/font-ota.lua289
1 files changed, 173 insertions, 116 deletions
diff --git a/Master/texmf-dist/tex/context/base/font-ota.lua b/Master/texmf-dist/tex/context/base/font-ota.lua
index edf5996b3df..79fcf3fa200 100644
--- a/Master/texmf-dist/tex/context/base/font-ota.lua
+++ b/Master/texmf-dist/tex/context/base/font-ota.lua
@@ -8,11 +8,11 @@ if not modules then modules = { } end modules ['font-ota'] = {
-- this might become scrp-*.lua
-local type, tostring, match, format, concat = type, tostring, string.match, string.format, table.concat
+local type = type
if not trackers then trackers = { register = function() end } end
-local trace_analyzing = false trackers.register("otf.analyzing", function(v) trace_analyzing = v end)
+----- trace_analyzing = false trackers.register("otf.analyzing", function(v) trace_analyzing = v end)
local fonts, nodes, node = fonts, nodes, node
@@ -28,23 +28,19 @@ analyzers.initializers = initializers
analyzers.methods = methods
analyzers.useunicodemarks = false
+local a_state = attributes.private('state')
+
local nodecodes = nodes.nodecodes
local glyph_code = nodecodes.glyph
+local math_code = nodecodes.math
-local set_attribute = node.set_attribute
-local has_attribute = node.has_attribute
local traverse_id = node.traverse_id
local traverse_node_list = node.traverse
+local end_of_math = node.end_of_math
local fontdata = fonts.hashes.identifiers
-local state = attributes.private('state')
local categories = characters and characters.categories or { } -- sorry, only in context
-local tracers = nodes.tracers
-local colortracers = tracers and tracers.colors
-local setnodecolor = colortracers and colortracers.set or function() end
-local resetnodecolor = colortracers and colortracers.reset or function() end
-
local otffeatures = fonts.constructors.newfeatures("otf")
local registerotffeature = otffeatures.register
@@ -53,59 +49,94 @@ local registerotffeature = otffeatures.register
process features right.</p>
--ldx]]--
+-- never use these numbers directly
+
+local s_init = 1 local s_rphf = 7
+local s_medi = 2 local s_half = 8
+local s_fina = 3 local s_pref = 9
+local s_isol = 4 local s_blwf = 10
+local s_mark = 5 local s_pstf = 11
+local s_rest = 6
+
+local states = {
+ init = s_init,
+ medi = s_medi,
+ fina = s_fina,
+ isol = s_isol,
+ mark = s_mark,
+ rest = s_rest,
+ rphf = s_rphf,
+ half = s_half,
+ pref = s_pref,
+ blwf = s_blwf,
+ pstf = s_pstf,
+}
+
+local features = {
+ init = s_init,
+ medi = s_medi,
+ fina = s_fina,
+ isol = s_isol,
+ -- mark = s_mark,
+}
+
+analyzers.states = states
+analyzers.features = features
+
-- todo: analyzers per script/lang, cross font, so we need an font id hash -> script
-- e.g. latin -> hyphenate, arab -> 1/2/3 analyze -- its own namespace
-local state = attributes.private('state')
-
function analyzers.setstate(head,font)
local useunicodemarks = analyzers.useunicodemarks
local tfmdata = fontdata[font]
- local characters = tfmdata.characters
local descriptions = tfmdata.descriptions
local first, last, current, n, done = nil, nil, head, 0, false -- maybe make n boolean
while current do
local id = current.id
if id == glyph_code and current.font == font then
+ done = true
local char = current.char
local d = descriptions[char]
if d then
if d.class == "mark" or (useunicodemarks and categories[char] == "mn") then
done = true
- set_attribute(current,state,5) -- mark
+ current[a_state] = s_mark
elseif n == 0 then
first, last, n = current, current, 1
- set_attribute(current,state,1) -- init
+ current[a_state] = s_init
else
last, n = current, n+1
- set_attribute(current,state,2) -- medi
+ current[a_state] = s_medi
end
else -- finish
if first and first == last then
- set_attribute(last,state,4) -- isol
+ last[a_state] = s_isol
elseif last then
- set_attribute(last,state,3) -- fina
+ last[a_state] = s_fina
end
first, last, n = nil, nil, 0
end
elseif id == disc_code then
-- always in the middle
- set_attribute(current,state,2) -- midi
+ current[a_state] = s_midi
last = current
else -- finish
if first and first == last then
- set_attribute(last,state,4) -- isol
+ last[a_state] = s_isol
elseif last then
- set_attribute(last,state,3) -- fina
+ last[a_state] = s_fina
end
first, last, n = nil, nil, 0
+ if id == math_code then
+ current = end_of_math(current)
+ end
end
current = current.next
end
if first and first == last then
- set_attribute(last,state,4) -- isol
+ last[a_state] = s_isol
elseif last then
- set_attribute(last,state,3) -- fina
+ last[a_state] = s_fina
end
return head, done
end
@@ -117,14 +148,14 @@ end
local function analyzeinitializer(tfmdata,value) -- attr
local script, language = otf.scriptandlanguage(tfmdata) -- attr
local action = initializers[script]
- if action then
- if type(action) == "function" then
+ if not action then
+ -- skip
+ elseif type(action) == "function" then
+ return action(tfmdata,value)
+ else
+ local action = action[language]
+ if action then
return action(tfmdata,value)
- else
- local action = action[language]
- if action then
- return action(tfmdata,value)
- end
end
end
end
@@ -133,14 +164,14 @@ local function analyzeprocessor(head,font,attr)
local tfmdata = fontdata[font]
local script, language = otf.scriptandlanguage(tfmdata,attr)
local action = methods[script]
- if action then
- if type(action) == "function" then
+ if not action then
+ -- skip
+ elseif type(action) == "function" then
+ return action(head,font,attr)
+ else
+ action = action[language]
+ if action then
return action(head,font,attr)
- else
- action = action[language]
- if action then
- return action(head,font,attr)
- end
end
end
return head, false
@@ -163,19 +194,36 @@ registerotffeature {
methods.latn = analyzers.setstate
--- this info eventually will go into char-def and we will have a state
--- table for generic then
-
-local zwnj = 0x200C
-local zwj = 0x200D
-
-local isol = {
+-- This info eventually can go into char-def and we will have a state
+-- table for generic then (unicode recognized all states but in practice
+-- only has only
+--
+-- isolated : isol
+-- final : isol_fina
+-- medial : isol_fina_medi_init
+--
+-- so in practice, without analyzer it's rather useless info which is
+-- why having it in char-def makes only sense for special purposes (like)
+-- like tracing cq. visualizing.
+
+local tatweel = 0x0640
+local zwnj = 0x200C
+local zwj = 0x200D
+
+local isolated = { -- isol
[0x0600] = true, [0x0601] = true, [0x0602] = true, [0x0603] = true,
+ [0x0604] = true,
[0x0608] = true, [0x060B] = true, [0x0621] = true, [0x0674] = true,
- [0x06DD] = true, [zwnj] = true,
+ [0x06DD] = true,
+ -- mandaic
+ [0x0856] = true, [0x0858] = true, [0x0857] = true,
+ -- n'ko
+ [0x07FA] = true,
+ -- also here:
+ [zwnj] = true,
}
-local isol_fina = {
+local final = { -- isol_fina
[0x0622] = true, [0x0623] = true, [0x0624] = true, [0x0625] = true,
[0x0627] = true, [0x0629] = true, [0x062F] = true, [0x0630] = true,
[0x0631] = true, [0x0632] = true, [0x0648] = true, [0x0671] = true,
@@ -191,23 +239,26 @@ local isol_fina = {
[0x06D3] = true, [0x06D5] = true, [0x06EE] = true, [0x06EF] = true,
[0x0759] = true, [0x075A] = true, [0x075B] = true, [0x076B] = true,
[0x076C] = true, [0x0771] = true, [0x0773] = true, [0x0774] = true,
- [0x0778] = true, [0x0779] = true, [0xFEF5] = true, [0xFEF7] = true,
- [0xFEF9] = true, [0xFEFB] = true,
-
+ [0x0778] = true, [0x0779] = true,
+ [0x08AA] = true, [0x08AB] = true, [0x08AC] = true,
+ [0xFEF5] = true, [0xFEF7] = true, [0xFEF9] = true, [0xFEFB] = true,
-- syriac
-
[0x0710] = true, [0x0715] = true, [0x0716] = true, [0x0717] = true,
[0x0718] = true, [0x0719] = true, [0x0728] = true, [0x072A] = true,
[0x072C] = true, [0x071E] = true,
+ [0x072F] = true, [0x074D] = true,
+ -- mandaic
+ [0x0840] = true, [0x0849] = true, [0x0854] = true, [0x0846] = true,
+ [0x084F] = true
}
-local isol_fina_medi_init = {
+local medial = { -- isol_fina_medi_init
[0x0626] = true, [0x0628] = true, [0x062A] = true, [0x062B] = true,
[0x062C] = true, [0x062D] = true, [0x062E] = true, [0x0633] = true,
[0x0634] = true, [0x0635] = true, [0x0636] = true, [0x0637] = true,
[0x0638] = true, [0x0639] = true, [0x063A] = true, [0x063B] = true,
[0x063C] = true, [0x063D] = true, [0x063E] = true, [0x063F] = true,
- [0x0640] = true, [0x0641] = true, [0x0642] = true, [0x0643] = true,
+ [0x0641] = true, [0x0642] = true, [0x0643] = true,
[0x0644] = true, [0x0645] = true, [0x0646] = true, [0x0647] = true,
[0x0649] = true, [0x064A] = true, [0x066E] = true, [0x066F] = true,
[0x0678] = true, [0x0679] = true, [0x067A] = true, [0x067B] = true,
@@ -236,141 +287,147 @@ local isol_fina_medi_init = {
[0x0772] = true, [0x0775] = true, [0x0776] = true, [0x0777] = true,
[0x077A] = true, [0x077B] = true, [0x077C] = true, [0x077D] = true,
[0x077E] = true, [0x077F] = true,
-
+ [0x08A0] = true, [0x08A2] = true, [0x08A4] = true, [0x08A5] = true,
+ [0x08A6] = true, [0x0620] = true, [0x08A8] = true, [0x08A9] = true,
+ [0x08A7] = true, [0x08A3] = true,
-- syriac
-
- [0x0712] = true, [0x0713] = true, [0x0714] = true, [0x071A] = true,
- [0x071B] = true, [0x071C] = true, [0x071D] = true, [0x071F] = true,
- [0x0720] = true, [0x0721] = true, [0x0722] = true, [0x0723] = true,
- [0x0724] = true, [0x0725] = true, [0x0726] = true, [0x0727] = true,
- [0x0729] = true, [0x072B] = true,
-
- -- also
-
- [zwj] = true,
+ [0x0712] = true, [0x0713] = true, [0x0714] = true, [0x071A] = true,
+ [0x071B] = true, [0x071C] = true, [0x071D] = true, [0x071F] = true,
+ [0x0720] = true, [0x0721] = true, [0x0722] = true, [0x0723] = true,
+ [0x0724] = true, [0x0725] = true, [0x0726] = true, [0x0727] = true,
+ [0x0729] = true, [0x072B] = true, [0x072D] = true, [0x072E] = true,
+ [0x074E] = true, [0x074F] = true,
+ -- mandaic
+ [0x0841] = true, [0x0842] = true, [0x0843] = true, [0x0844] = true,
+ [0x0845] = true, [0x0847] = true, [0x0848] = true, [0x0855] = true,
+ [0x0851] = true, [0x084E] = true, [0x084D] = true, [0x084A] = true,
+ [0x084B] = true, [0x084C] = true, [0x0850] = true, [0x0852] = true,
+ [0x0853] = true,
+ -- n'ko
+ [0x07D7] = true, [0x07E8] = true, [0x07D9] = true, [0x07EA] = true,
+ [0x07CA] = true, [0x07DB] = true, [0x07CC] = true, [0x07DD] = true,
+ [0x07CE] = true, [0x07DF] = true, [0x07D4] = true, [0x07E5] = true,
+ [0x07E9] = true, [0x07E7] = true, [0x07E3] = true, [0x07E2] = true,
+ [0x07E0] = true, [0x07E1] = true, [0x07DE] = true, [0x07DC] = true,
+ [0x07D1] = true, [0x07DA] = true, [0x07D8] = true, [0x07D6] = true,
+ [0x07D2] = true, [0x07D0] = true, [0x07CF] = true, [0x07CD] = true,
+ [0x07CB] = true, [0x07D3] = true, [0x07E4] = true, [0x07D5] = true,
+ [0x07E6] = true,
+ -- also here:
+ [tatweel]= true,
+ [zwj] = true,
}
local arab_warned = { }
-
-- todo: gref
local function warning(current,what)
local char = current.char
if not arab_warned[char] then
- log.report("analyze","arab: character %s (U+%05X) has no %s class", char, char, what)
+ log.report("analyze","arab: character %C has no %a class",char,what)
arab_warned[char] = true
end
end
-function methods.nocolor(head,font,attr)
- for n in traverse_id(glyph_code,head) do
- if not font or n.font == font then
- resetnodecolor(n)
- end
- end
- return head, true
-end
+-- potential optimization: local medial_final = table.merged(medial,final)
local function finish(first,last)
if last then
if first == last then
local fc = first.char
- if isol_fina_medi_init[fc] or isol_fina[fc] then
- set_attribute(first,state,4) -- isol
- if trace_analyzing then setnodecolor(first,"font:isol") end
+ if medial[fc] or final[fc] then
+ first[a_state] = s_isol
else
warning(first,"isol")
- set_attribute(first,state,0) -- error
- if trace_analyzing then resetnodecolor(first) end
+ first[a_state] = s_error
end
else
local lc = last.char
- if isol_fina_medi_init[lc] or isol_fina[lc] then -- why isol here ?
- -- if laststate == 1 or laststate == 2 or laststate == 4 then
- set_attribute(last,state,3) -- fina
- if trace_analyzing then setnodecolor(last,"font:fina") end
+ if medial[lc] or final[lc] then
+ -- if laststate == 1 or laststate == 2 or laststate == 4 then
+ last[a_state] = s_fina
else
warning(last,"fina")
- set_attribute(last,state,0) -- error
- if trace_analyzing then resetnodecolor(last) end
+ last[a_state] = s_error
end
end
first, last = nil, nil
elseif first then
-- first and last are either both set so we never com here
local fc = first.char
- if isol_fina_medi_init[fc] or isol_fina[fc] then
- set_attribute(first,state,4) -- isol
- if trace_analyzing then setnodecolor(first,"font:isol") end
+ if medial[fc] or final[fc] then
+ first[a_state] = s_isol
else
warning(first,"isol")
- set_attribute(first,state,0) -- error
- if trace_analyzing then resetnodecolor(first) end
+ first[a_state] = s_error
end
first = nil
end
return first, last
end
-function methods.arab(head,font,attr) -- maybe make a special version with no trace
+function methods.arab(head,font,attr)
local useunicodemarks = analyzers.useunicodemarks
local tfmdata = fontdata[font]
local marks = tfmdata.resources.marks
local first, last, current, done = nil, nil, head, false
while current do
- if current.id == glyph_code and current.subtype<256 and current.font == font and not has_attribute(current,state) then
+ local id = current.id
+ if id == glyph_code and current.font == font and current.subtype<256 and not current[a_state] then
done = true
local char = current.char
if marks[char] or (useunicodemarks and categories[char] == "mn") then
- set_attribute(current,state,5) -- mark
- if trace_analyzing then setnodecolor(current,"font:mark") end
- elseif isol[char] then -- can be zwj or zwnj too
+ current[a_state] = s_mark
+ elseif isolated[char] then -- can be zwj or zwnj too
first, last = finish(first,last)
- set_attribute(current,state,4) -- isol
- if trace_analyzing then setnodecolor(current,"font:isol") end
+ current[a_state] = s_isol
first, last = nil, nil
elseif not first then
- if isol_fina_medi_init[char] then
- set_attribute(current,state,1) -- init
- if trace_analyzing then setnodecolor(current,"font:init") end
+ if medial[char] then
+ current[a_state] = s_init
first, last = first or current, current
- elseif isol_fina[char] then
- set_attribute(current,state,4) -- isol
- if trace_analyzing then setnodecolor(current,"font:isol") end
+ elseif final[char] then
+ current[a_state] = s_isol
first, last = nil, nil
else -- no arab
first, last = finish(first,last)
end
- elseif isol_fina_medi_init[char] then
+ elseif medial[char] then
first, last = first or current, current
- set_attribute(current,state,2) -- medi
- if trace_analyzing then setnodecolor(current,"font:medi") end
- elseif isol_fina[char] then
- if not has_attribute(last,state,1) then
+ current[a_state] = s_medi
+ elseif final[char] then
+ if not last[a_state] == s_init then
-- tricky, we need to check what last may be !
- set_attribute(last,state,2) -- medi
- if trace_analyzing then setnodecolor(last,"font:medi") end
+ last[a_state] = s_medi
end
- set_attribute(current,state,3) -- fina
- if trace_analyzing then setnodecolor(current,"font:fina") end
+ current[a_state] = s_fina
first, last = nil, nil
- elseif char >= 0x0600 and char <= 0x06FF then
- if trace_analyzing then setnodecolor(current,"font:rest") end
+ elseif char >= 0x0600 and char <= 0x06FF then -- needs checking
+ current[a_state] = s_rest
first, last = finish(first,last)
- else --no
+ else -- no
first, last = finish(first,last)
end
else
- first, last = finish(first,last)
+ if first or last then
+ first, last = finish(first,last)
+ end
+ if id == math_code then
+ current = end_of_math(current)
+ end
end
current = current.next
end
- first, last = finish(first,last)
+ if first or last then
+ finish(first,last)
+ end
return head, done
end
methods.syrc = methods.arab
+methods.mand = methods.arab
+methods.nko = methods.arab
directives.register("otf.analyze.useunicodemarks",function(v)
analyzers.useunicodemarks = v