Current File : //usr/share/texlive/texmf-dist/tex/luatex/luaotfload/luaotfload-case-el.lua |
local unicode_data = require'luaotfload-unicode'
local has_accent = 1
local has_combining_dialytika = 2
local has_ypogegrammeni = 4
local has_other_diacritic = 8
local has_vowel = 16
local vowels = {
[0x03B1] = true,
[0x0391] = true,
[0x03B5] = true,
[0x0395] = true,
[0x03B7] = true,
[0x0397] = true,
[0x03B9] = true,
[0x0399] = true,
[0x03BF] = true,
[0x039F] = true,
[0x03C9] = true,
[0x03A9] = true,
[0x03C5] = true,
[0x03A5] = true,
[0x03F5] = true,
}
local diacritic_data = {
[0x0300] = has_accent,
[0x0301] = has_accent,
[0x0302] = has_accent,
[0x0303] = has_accent,
[0x0311] = has_accent,
[0x0342] = has_accent,
[0x0308] = has_combining_dialytika,
[0x0344] = has_accent | has_combining_dialytika,
[0x0345] = has_ypogegrammeni,
[0x0304] = has_other_diacritic,
[0x0306] = has_other_diacritic,
[0x0313] = has_other_diacritic,
[0x0314] = has_other_diacritic,
[0x0343] = has_other_diacritic,
}
local mapping_tables = unicode_data.casemapping
local soft_dotted = unicode_data.soft_dotted
local ccc = unicode_data.ccc
local uppercase = mapping_tables.uppercase
local lowercase = mapping_tables.lowercase
local cased = mapping_tables.cased
local case_ignorable = mapping_tables.case_ignorable
local otfregister = fonts.constructors.features.otf.register
local direct = node.direct
local is_char = direct.is_char
local has_glyph = direct.has_glyph
local uses_font = direct.uses_font
local getnext = direct.getnext
local setchar = direct.setchar
local setdisc = direct.setdisc
local getdisc = direct.getdisc
local getfield = direct.getfield
local remove = direct.remove
local copy = direct.copy
local insert_after = direct.insert_after
local traverse = direct.traverse
local disc = node.id'disc'
local nfd = {} -- FIXME: Data
local data do
for cp = 1, 0xFF, 1 do -- FIXME: Correct limits
local decomposed = nfd[cp]
local first = decomposed and decomposed[1] or cp
local upper = uppercase[first]
local data = vowels[first] and has_vowel or 0
if decomposed then
for i=1, #decomposed do
data = data | (diacritic_data[decomposed[i]] or 0)
end
end
end
end
--[[ We make some implicit assumptions about contexts in SpecialCasing.txt here which happened to be true when I wrote the code:
--
-- * Before_Dot only appears as Not_Before_Dot
-- * No other context appears with Not_
-- * Final_Sigma is never language dependent
-- * Other contexts are always language dependent
-- * The only languages with special mappings are Lithuanian (lt/"LTH "/lit), Turkish (tr/"TRK "/tur), and Azeri/Azerbaijani (az/"AZE "/aze)
]]
local font_lang = setmetatable({}, {__index = function(t, fid)
local f = font.getfont(fid)
local lang = f.specification.features.normal.language
lang = lang == 'lth' and 'lt' or lang == 'trk' and 'tr' or lang == 'aze' and 'az' or false
t[fid] = lang
return lang
end})
local function is_Final_Sigma(font, mapping, n, after)
mapping = mapping.Final_Sigma
if not mapping then return false end
mapping = mapping._
if not mapping then return false end
n = getnext(n)
repeat
while n do
local char, id = is_char(n, font)
if id == disc then
after = getnext(n)
n = getfield(n, 'replace')
char, id = is_char(n, font)
elseif char then
if not case_ignorable[char] then
return not cased[char] and mapping
end
n = getnext(n)
else
return mapping
end
end
n, after = after
until not n
return mapping
end
local function is_More_Above(font, mapping, n, after)
mapping = mapping.More_Above
if not mapping then return false end
mapping = mapping._
if not mapping then return false end
n = getnext(n)
repeat
while n do
local char, id = is_char(n, font)
if id == disc then
after = getnext(n)
n = getfield(n, 'replace')
char, id = is_char(n, font)
elseif char then
local char_ccc = ccc[char]
if not char_ccc then
return false
elseif char_ccc == 230 then
return mapping
end
n = getnext(n)
else
return false
end
end
n, after = after
until not n
return false
end
local function is_Not_Before_Dot(font, mapping, n, after)
mapping = mapping.Not_Before_Dot
if not mapping then return false end
mapping = mapping._
if not mapping then return false end
n = getnext(n)
repeat
while n do
local char, id = is_char(n, font)
if id == disc then
after = getnext(n)
n = getfield(n, 'replace')
char, id = is_char(n, font)
elseif char then
local char_ccc = ccc[char]
if not char_ccc then
return mapping
elseif char_ccc == 230 then
return char ~= 0x0307 and mapping
end
n = getnext(n)
else
return mapping
end
end
n, after = after
until not n
return mapping
end
local function is_Language_Mapping(font, mapping, n, after, seen_soft_dotted, seen_I)
if not mapping then return false end
if seen_soft_dotted then
local mapping = mapping.After_Soft_Dotted
mapping = mapping and mapping._
if mapping then
return mapping
end
end
if seen_I then
local mapping = mapping.After_I
mapping = mapping and mapping._
if mapping then
return mapping
end
end
return is_More_Above(font, mapping, n, after) or is_Not_Before_Dot(font, mapping, n, after) or mapping._ -- Might be nil
end
local function process(table)
local function processor(head, font, after, seen_cased, seen_soft_dotted, seen_I)
local lang = font_lang[font]
local n = head
while n do
do
local new = has_glyph(n)
if n ~= new then
seen_cased, seen_soft_dotted, seen_I = nil
end
n = new
end
if not n then break end
local char, id = is_char(n, font)
if char then
local mapping = table[char]
if mapping then
if tonumber(mapping) then
setchar(n, mapping)
else
mapping = seen_cased and is_Final_Sigma(font, mapping, n, after)
or lang and is_Language_Mapping(font, mapping[lang], n, after, seen_soft_dotted, seen_I)
or mapping._
if #mapping == 0 then
head, n = remove(head, n)
goto continue
else
setchar(n, mapping[1])
for i=2, #mapping do
head, n = insert_after(head, n, copy(n))
setchar(n, mapping[i])
end
end
end
end
if not case_ignorable[char] then
seen_cased = cased[char] or nil
end
local char_ccc = ccc[char]
if not char_ccc or char_ccc == 230 then
seen_I = char == 0x49 or nil
seen_soft_dotted = soft_dotted[char]
end
elseif id == disc and uses_font(n, font) then
local pre, post, rep = getdisc(n)
local after = getnext(n)
pre, post, rep, seen_cased, seen_soft_dotted, seen_I =
processor(pre, font, nil, seen_cased, seen_soft_dotted, seen_I),
processor(post, font, after),
processor(rep, font, after, seen_cased, seen_soft_dotted, seen_I)
setdisc(n, pre, post, rep)
else
seen_cased, seen_soft_dotted, seen_I = nil
end
n = getnext(n)
::continue::
end
return head, seen_cased, seen_soft_dotted, seen_I
end
return function(head, font) return (processor(head, font)) end
end
local upper_process = process(uppercase)
otfregister {
name = 'upper',
description = 'Map to uppercase',
default = false,
processors = {
position = 1,
plug = upper_process,
node = upper_process,
base = upper_process,
},
}
local lower_process = process(lowercase)
otfregister {
name = 'lower',
description = 'Map to lowercase',
default = false,
processors = {
position = 1,
plug = lower_process,
node = lower_process,
base = lower_process,
},
}