diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-ota.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/font-ota.lua | 289 |
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 |