diff options
Diffstat (limited to 'Master/texmf-dist/tex/luatex/luaotfload/luaotfload-case-el.lua')
-rw-r--r-- | Master/texmf-dist/tex/luatex/luaotfload/luaotfload-case-el.lua | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-case-el.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-case-el.lua new file mode 100644 index 00000000000..1b329c4a65b --- /dev/null +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-case-el.lua @@ -0,0 +1,294 @@ +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, + }, +} |