diff options
author | Karl Berry <karl@freefriends.org> | 2013-04-08 00:43:40 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2013-04-08 00:43:40 +0000 |
commit | 824f7b0903de8ad7f6ee3d7656005e4c59155e06 (patch) | |
tree | abfc8673ef9916f3ab7074e811207384c301492b /Master/texmf-dist/tex/context/base/font-otx.lua | |
parent | 689aefb0727676ed3cddf331337b4be226495e72 (diff) |
context import for TL13, from www.pragma-ade.com/context/beta/cont-tmf.zip
git-svn-id: svn://tug.org/texlive/trunk@29731 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-otx.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/font-otx.lua | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/font-otx.lua b/Master/texmf-dist/tex/context/base/font-otx.lua new file mode 100644 index 00000000000..d276b8a1524 --- /dev/null +++ b/Master/texmf-dist/tex/context/base/font-otx.lua @@ -0,0 +1,393 @@ +if not modules then modules = { } end modules ['font-otx'] = { + version = 1.001, + comment = "companion to font-otf.lua (analysing)", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- context only + +local type = type + +if not trackers then trackers = { register = function() end } end + +----- trace_analyzing = false trackers.register("otf.analyzing", function(v) trace_analyzing = v end) + +local fonts, nodes, node = fonts, nodes, node + +local allocate = utilities.storage.allocate + +local otf = fonts.handlers.otf + +local analyzers = fonts.analyzers +local initializers = allocate() +local methods = allocate() + +analyzers.initializers = initializers +analyzers.methods = methods +---------.useunicodemarks = false + +local a_state = attributes.private('state') + +local nodecodes = nodes.nodecodes +local glyph_code = nodecodes.glyph +local math_code = nodecodes.math + +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 categories = characters and characters.categories or { } -- sorry, only in context +local chardata = characters and characters.data + +local otffeatures = fonts.constructors.newfeatures("otf") +local registerotffeature = otffeatures.register + +--[[ldx-- +<p>Analyzers run per script and/or language and are needed in order to +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 + +function analyzers.setstate(head,font) + local useunicodemarks = analyzers.useunicodemarks + local tfmdata = fontdata[font] + 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 + current[a_state] = s_mark + elseif n == 0 then + first, last, n = current, current, 1 + current[a_state] = s_init + else + last, n = current, n+1 + current[a_state] = s_medi + end + else -- finish + if first and first == last then + last[a_state] = s_isol + elseif last then + last[a_state] = s_fina + end + first, last, n = nil, nil, 0 + end + elseif id == disc_code then + -- always in the middle + current[a_state] = s_midi + last = current + else -- finish + if first and first == last then + last[a_state] = s_isol + elseif last then + 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 + last[a_state] = s_isol + elseif last then + last[a_state] = s_fina + end + return head, done +end + +-- in the future we will use language/script attributes instead of the +-- font related value, but then we also need dynamic features which is +-- somewhat slower; and .. we need a chain of them + +local function analyzeinitializer(tfmdata,value) -- attr + local script, language = otf.scriptandlanguage(tfmdata) -- attr + local action = initializers[script] + 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) + end + end +end + +local function analyzeprocessor(head,font,attr) + local tfmdata = fontdata[font] + local script, language = otf.scriptandlanguage(tfmdata,attr) + local action = methods[script] + 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) + end + end + return head, false +end + +registerotffeature { + name = "analyze", + description = "analysis of (for instance) character classes", + default = true, + initializers = { + node = analyzeinitializer, + }, + processors = { + position = 1, + node = analyzeprocessor, + } +} + +-- latin + +methods.latn = analyzers.setstate + +local arab_warned = { } + +local function warning(current,what) + local char = current.char + if not arab_warned[char] then + log.report("analyze","arab: character %C has no %a class",char,what) + arab_warned[char] = true + end +end + +local mappers = { + l = s_init, -- left + d = s_medi, -- double + c = s_medi, -- joiner + r = s_fina, -- right + u = s_isol, -- nonjoiner +} + +local classifiers = { } -- we can also use this trick for devanagari + +local first_arabic, last_arabic = characters.blockrange("arabic") +local first_syriac, last_syriac = characters.blockrange("syriac") +local first_mandiac, last_mandiac = characters.blockrange("mandiac") +local first_nko, last_nko = characters.blockrange("nko") + +table.setmetatableindex(classifiers,function(t,k) + local c = chardata[k] + local v = false + if c then + local arabic = c.arabic + if arabic then + v = mappers[arabic] + if not v then + log.report("analyze","error in mapping arabic %C",k) + -- error + v = false + end + elseif k >= first_arabic and k <= last_arabic or k >= first_syriac and k <= last_syriac or + k >= first_mandiac and k <= last_mandiac or k >= first_nko and k <= last_nko then + if categories[k] == "mn" then + v = s_mark + else + v = s_rest + end + else + end + end + t[k] = v + return v +end) + +function methods.arab(head,font,attr) + local first, last = nil, nil + local c_first, c_last = nil, nil + local current, done = head, false + while current do + 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 + local classifier = classifiers[char] + if not classifier then + if last then + if c_last == s_medi or c_last == s_fina then + last[a_state] = s_fina + else + warning(last,"fina") + last[a_state] = s_error + end + first, last = nil, nil + elseif first then + if c_first == s_medi or c_first == s_fina then + first[a_state] = s_isol + else + warning(first,"isol") + first[a_state] = s_error + end + first = nil + end + elseif classifier == s_mark then + current[a_state] = s_mark + elseif classifier == s_isol then + if last then + if c_last == s_medi or c_last == s_fina then + last[a_state] = s_fina + else + warning(last,"fina") + last[a_state] = s_error + end + first, last = nil, nil + elseif first then + if c_first == s_medi or c_first == s_fina then + first[a_state] = s_isol + else + warning(first,"isol") + first[a_state] = s_error + end + first = nil + end + current[a_state] = s_isol + elseif classifier == s_medi then + if first then + last = current + c_last = classifier + current[a_state] = s_medi + else + current[a_state] = s_init + first = current + c_first = classifier + end + elseif classifier == s_fina then + if last then + if last[a_state] ~= s_init then + last[a_state] = s_medi + end + current[a_state] = s_fina + first, last = nil, nil + elseif first then + -- if first[a_state] ~= s_init then + -- -- needs checking + -- first[a_state] = s_medi + -- end + current[a_state] = s_fina + first = nil + else + current[a_state] = s_isol + end + else -- classifier == s_rest + current[a_state] = s_rest + if last then + if c_last == s_medi or c_last == s_fina then + last[a_state] = s_fina + else + warning(last,"fina") + last[a_state] = s_error + end + first, last = nil, nil + elseif first then + if c_first == s_medi or c_first == s_fina then + first[a_state] = s_isol + else + warning(first,"isol") + first[a_state] = s_error + end + first = nil + end + end + else + if last then + if c_last == s_medi or c_last == s_fina then + last[a_state] = s_fina + else + warning(last,"fina") + last[a_state] = s_error + end + first, last = nil, nil + elseif first then + if c_first == s_medi or c_first == s_fina then + first[a_state] = s_isol + else + warning(first,"isol") + first[a_state] = s_error + end + first = nil + end + if id == math_code then -- a bit duplicate as we test for glyphs twice + current = end_of_math(current) + end + end + current = current.next + end + if last then + if c_last == s_medi or c_last == s_fina then + last[a_state] = s_fina + else + warning(last,"fina") + last[a_state] = s_error + end + elseif first then + if c_first == s_medi or c_first == s_fina then + first[a_state] = s_isol + else + warning(first,"isol") + first[a_state] = s_error + end + 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 +-- end) |