From d6b2eaba6fe47c24603040934903c73535ff09ba Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Fri, 11 Jun 2021 03:00:56 +0000 Subject: CTAN sync 202106110300 --- macros/luatex/generic/luatexko/luatexko.lua | 195 ++++++++++++++++++---------- 1 file changed, 126 insertions(+), 69 deletions(-) (limited to 'macros/luatex/generic/luatexko/luatexko.lua') diff --git a/macros/luatex/generic/luatexko/luatexko.lua b/macros/luatex/generic/luatexko/luatexko.lua index d0360a8b72..aa1aa4149f 100644 --- a/macros/luatex/generic/luatexko/luatexko.lua +++ b/macros/luatex/generic/luatexko/luatexko.lua @@ -13,8 +13,8 @@ luatexbase.provides_module { name = 'luatexko', - date = '2021/04/20', - version = '3.1', + date = '2021/06/10', + version = '3.2', description = 'typesetting Korean with LuaTeX', author = 'Dohyun Kim, Soojin Nam', license = 'LPPL v1.3+', @@ -72,6 +72,7 @@ local attributes = luatexbase.attributes local call_callback = luatexbase.call_callback local create_callback = luatexbase.create_callback local module_warning = luatexbase.module_warning +local new_attribute = luatexbase.new_attribute local new_user_whatsit = luatexbase.new_user_whatsit local registernumber = luatexbase.registernumber @@ -85,6 +86,7 @@ local glueid = node.id"glue" local glyphid = node.id"glyph" local hlistid = node.id"hlist" local kernid = node.id"kern" +local localparid = node.id"local_par" local mathid = node.id"math" local penaltyid = node.id"penalty" local ruleid = node.id"rule" @@ -98,6 +100,7 @@ local italcorr = 3 local lua_number = 100 local lua_value = 108 local spaceskip = 13 +local indentbox = 3 local nohyphen = registernumber"l@nohyphenation" or -1 -- verbatim local langkor = registernumber"koreanlanguage" or 16383 @@ -107,11 +110,12 @@ local fallbackfontattr = attributes.luatexkofallbackfontattr local autojosaattr = attributes.luatexkoautojosaattr local classicattr = attributes.luatexkoclassicattr local dotemphattr = attributes.luatexkodotemphattr -local ulineattr = attributes.luatexkoulineattr local rubyattr = attributes.luatexkorubyattr local hangulbyhangulattr = attributes.luatexkohangulbyhangulattr local hanjabyhanjaattr = attributes.luatexkohanjabyhanjaattr +local unicodeattr = new_attribute"luatexkounicodeattr" + local stretch_f = 5/100 -- should be consistent for ruby local function get_font_data (fontid) @@ -537,12 +541,15 @@ local special_classes = { [0xFF01] = 4, [0xFF1A] = 2, [0xFF1B] = 2, [0xFF1F] = 4, }, { __index = charclass }), setmetatable({ -- TC - [0x3001] = 3, [0x3002] = 3, [0xFF0C] = 3, [0xFF0E] = 3, + [0x3001] = 3, [0x3002] = 5, [0xFF0C] = 3, [0xFF0E] = 5, }, { __index = charclass }), setmetatable({ -- TC vert - [0x3001] = 3, [0x3002] = 3, [0xFF0C] = 3, [0xFF0E] = 3, + [0x3001] = 3, [0x3002] = 5, [0xFF0C] = 3, [0xFF0E] = 5, [0xFF1A] = 7, [0xFF1B] = 7, -- 0xFE13, 0xFE14 }, { __index = charclass }), + setmetatable({ -- JP vert + [0xFF1B] = 7, -- 0xFE14 + }, { __index = charclass }), } local function get_char_class (c, classic) @@ -684,8 +691,8 @@ local function process_fonts (head) while curr do local id = curr.id if id == glyphid then - local props = my_node_props(curr) - if not props.unicode then + if curr.font ~= 0 -- exclude nullfont + and not has_attribute(curr, unicodeattr) then local c = curr.char @@ -735,7 +742,7 @@ local function process_fonts (head) end end - props.unicode = c + set_attribute(curr, unicodeattr, c) end elseif id == discid then curr.pre = process_fonts(curr.pre) @@ -779,11 +786,11 @@ local function hbox_char_font (box, init, glyfonly) while curr do local id = curr.id if id == glyphid then - local c = my_node_props(curr).unicode or curr.char + local c = has_attribute(curr, unicodeattr) or curr.char if c and not is_cjk_combining(c) then return c, curr.font end - elseif id == hlistid and curr.list then + elseif curr.list then return hbox_char_font(curr, init, glyfonly) elseif not glyfonly and is_blocking_node(curr) then return @@ -858,7 +865,7 @@ local function process_linebreak (head, par) while curr do local id = curr.id if id == glyphid then - local c = my_node_props(curr).unicode or curr.char + local c = has_attribute(curr, unicodeattr) or curr.char if c and not is_unicode_var_sel(c) then local old = has_attribute(curr, classicattr) head, pc, pcl = maybe_linebreak(head, curr, pc, pcl, c, old, curr.font, par) @@ -913,7 +920,7 @@ local function process_interhangul (head, par) while curr do local id = curr.id if id == glyphid then - local c = my_node_props(curr).unicode or curr.char + local c = has_attribute(curr, unicodeattr) or curr.char if c and not is_unicode_var_sel(c) then head, pc = do_interhangul_option(head, curr, pc, c, curr.font, par) @@ -975,7 +982,7 @@ local function process_interlatincjk (head, par) while curr do local id = curr.id if id == glyphid then - local c = my_node_props(curr).unicode or curr.char + local c = has_attribute(curr, unicodeattr) or curr.char if c and not is_unicode_var_sel(c) then head, pc, pf, pcl = do_interlatincjk_option(head, curr, pc, pf, pcl, c, curr.font, par) pc = breakable_after[c] and pc or 0 @@ -1033,7 +1040,7 @@ local function process_glyph_width (head) if curr.lang ~= nohyphen and fontoptions.compresspunctuations[curr.font] then - local cc = my_node_props(curr).unicode or curr.char + local cc = has_attribute(curr, unicodeattr) or curr.char local old = has_attribute(curr, classicattr) local class = get_char_class(cc, old) if class >= 1 and class <= 4 and @@ -1087,11 +1094,11 @@ local function process_remove_spaces (head) local vchar, vfont if id == glyphid and v.lang ~= nohyphen then - local c = my_node_props(v).unicode or v.char or 0 + local c = has_attribute(v, unicodeattr) or v.char or 0 if is_unicode_var_sel(c) then v = getprev(v) or v end - vchar, vfont = my_node_props(v).unicode or v.char, v.font + vchar, vfont = has_attribute(v, unicodeattr) or v.char, v.font elseif id == hlistid and v.list then vchar, vfont = hbox_char_font(v, k == "n") end @@ -1131,6 +1138,23 @@ local josa_table = { [0xC774] = {0xC774, nil, 0xC774}, -- 이(라) = 이, , 이 } +local hanja2hangul = { } + +local function add_to_hanja2hangul (filename, i, last) + local f = kpse.find_file(filename) + if f then + for c in io.lines(f) do + hanja2hangul[i] = tonumber(c) + i = i + 1 + end + else + warning("cannot find %s", filename) + for c = i, last do + hanja2hangul[c] = c + end + end +end + local josa_code = setmetatable({ [0x30] = 3, [0x31] = 1, [0x33] = 3, [0x36] = 3, [0x37] = 1, [0x38] = 1, [0x4C] = 1, [0x4D] = 3, @@ -1156,16 +1180,37 @@ local josa_code = setmetatable({ [0xFF13] = 3, [0xFF16] = 3, [0xFF17] = 1, [0xFF18] = 1, [0xFF2C] = 1, [0xFF2D] = 3, [0xFF2E] = 3, [0xFF4C] = 1, [0xFF4D] = 3, [0xFF4E] = 3, -},{ __index = function(_,c) +},{ __index = function(t, cc) + local c = cc + -- xetexko에 포함된 .tab 파일들을 이용해 한자를 한글로 변환 + if c >= 0x4E00 and c <= 0x9FA5 then + if not hanja2hangul[c] then + add_to_hanja2hangul("hanja_hangul.tab", 0x4E00, 0x9FA5) + end + c = hanja2hangul[c] + elseif c >= 0xF900 and c <= 0xFA2D then + if not hanja2hangul[c] then + add_to_hanja2hangul("hanjacom_hangul.tab", 0xF900, 0xFA2D) + end + c = hanja2hangul[c] + elseif c >= 0x3400 and c <= 0x4DB5 then + if not hanja2hangul[c] then + add_to_hanja2hangul("hanjaexa_hangul.tab", 0x3400, 0x4DB5) + end + c = hanja2hangul[c] + end if is_hangul(c) then c = (c - 0xAC00) % 28 + 0x11A7 end if is_chosong(c) then - return c == 0x1105 and 1 or 3 + c = c == 0x1105 and 1 or 3 + t[cc] = c; return c elseif is_jungsong(c) then - return c ~= 0x1160 and 2 + c = c ~= 0x1160 and 2 + t[cc] = c; return c elseif is_jongsong(c) then - return c == 0x11AF and 1 or 3 + c = c == 0x11AF and 1 or 3 + t[cc] = c; return c elseif is_noncjk_char(c) and c <= 0x7A or c >= 0x2160 and c <= 0x217F -- roman or c >= 0x2460 and c <= 0x24E9 -- ① @@ -1175,11 +1220,13 @@ local josa_code = setmetatable({ or c >= 0xFF10 and c <= 0xFF19 -- 0 or c >= 0xFF21 and c <= 0xFF3A -- A or c >= 0xFF41 and c <= 0xFF5A -- a - then return 2 + then + t[cc] = 2; return 2 elseif c >= 0x3131 and c <= 0x314E or c >= 0x3165 and c <= 0x3186 -- ㄱ or c >= 0x3200 and c <= 0x320D -- ㈀ or c >= 0x3260 and c <= 0x326D -- ㉠ - then return 3 + then + t[cc] = 3; return 3 end end }) @@ -1188,7 +1235,7 @@ local function prevjosacode (n, parenlevel, ignore_parens) while n do local id = n.id if id == glyphid then - local c = my_node_props(n).unicode or n.char -- beware hlist/vlist + local c = has_attribute(n, unicodeattr) or n.char -- beware hlist/vlist if ignore_parens and c == 0x29 then -- ) parenlevel = parenlevel + 1 elseif ignore_parens and c == 0x28 then -- ( @@ -1287,8 +1334,8 @@ local function process_dotemph (head) elseif curr.id == glyphid then local dotattr = has_attribute(curr, dotemphattr) - if dotattr then - local c = my_node_props(curr).unicode or curr.char + if dotattr and dotemphbox[dotattr] then + local c = has_attribute(curr, unicodeattr) or curr.char if is_hangul(c) or is_compat_jamo(c) or is_chosong(c) or @@ -1425,7 +1472,7 @@ end local ulitems = {} local function process_uline (head, parent, level) - local curr, level, attr = head, level or 0 + local curr, level = head, level or 0 while curr do if curr.list then curr.list = process_uline(curr.list, curr, level+1) @@ -1439,33 +1486,28 @@ local function process_uline (head, parent, level) list = list, subtype = subtype, level = level, + start = getnext(curr) or curr, } else local item = ulitems[value] if item then head = draw_uline(head, curr, parent, item, true) ulitems[value] = nil - attr = nil end end - else - local currattr = has_attribute(curr, ulineattr) - if currattr then - local item = ulitems[currattr] - if item and not item.start then - item.start = curr - attr = currattr - end - end + local to_free = curr + head, curr = noderemove(head, curr) + nodefree(to_free) + goto nextnode end curr = getnext(curr) + ::nextnode:: end - if attr then - local item = ulitems[attr] - if item and item.level == level then + for _, item in pairs(ulitems) do + if item.level == level then head = draw_uline(head, nodeslide(head), parent, item) item.start = nil end @@ -1496,13 +1538,23 @@ local function process_ruby_pre_linebreak (head) local rubyid = has_attribute(curr, rubyattr) if rubyid then local ruby_t = rubybox[rubyid] - if ruby_t[3] then -- rubyoverlap + if ruby_t and ruby_t[3] then -- rubyoverlap local side = (ruby_t[1].width - curr.width)/2 if side > 0 then -- ruby is wide local k, r = nodenew(kernid), nodenew(ruleid) k.subtype, k.kern = userkern, -side r.width, r.height, r.depth = side, 0, 0 local k2, r2 = nodecopy(k), nodecopy(r) + + local prev = curr.prev -- 문단 첫머리에 루비 돌출 방지 + if prev then + if prev.id == localparid or + prev.id == hlistid and prev.subtype == indentbox and prev.width == 0 + then + k.kern = 0 + end + end + head = insert_before(head, curr, k) head = insert_before(head, curr, r) head, curr = insert_after(head, curr, r2) @@ -1540,17 +1592,19 @@ local function process_ruby_post_linebreak (head) -- consider charraise local shift = shift_put_top(curr, ruby) - local _, f = hbox_char_font(curr, true, true) - local ascender = tableunpack(fontoptions.asc_desc[f]) or curr.height - ruby.shift = shift - ascender - ruby.depth - ruby_t[2] -- rubysep + local f, ascender, descender + _, f = hbox_char_font(curr, true, true) + ascender = fontoptions.asc_desc[f][1] or curr.height + _, f = hbox_char_font(ruby, true, true) + descender = fontoptions.asc_desc[f][2] or ruby.depth + + ruby.shift = shift - ascender - descender - ruby_t[2] -- rubysep head = insert_before(head, curr, ruby) end - ruby_t = nil - elseif curr.list then - curr.list = process_ruby_post_linebreak(curr.list) + rubybox[rubyid] = nil end - elseif curr.list then - curr.list = process_ruby_post_linebreak(curr.list) + elseif id == mathid then + curr = end_of_math(curr) end curr = getnext(curr) end @@ -1600,7 +1654,7 @@ local function process_reorder_tonemarks (head) fontoptions.is_not_harf[curr.font] and fontoptions.is_hangulscript[curr.font] then - local uni = my_node_props(curr).unicode or curr.char + local uni = has_attribute(curr, unicodeattr) or curr.char if is_hangul(uni) or is_chosong(uni) or uni == 0x25CC then init = curr elseif is_jungsong(uni) or is_jongsong(uni) then @@ -1609,7 +1663,7 @@ local function process_reorder_tonemarks (head) local n, syllable = init, { init = init } while n do if n.id == glyphid then - local u = my_node_props(n).unicode or n.char + local u = has_attribute(n, unicodeattr) or n.char if u then tableinsert(syllable, u) end end if n == curr then break end @@ -1912,7 +1966,7 @@ end -- charraise -local raiseattr = luatexbase.new_attribute"luatexkoraiseattr" +local raiseattr = new_attribute"luatexkoraiseattr" local function process_charraise (head) local curr = head @@ -1957,7 +2011,7 @@ local function process_fake_slant_corr (head) -- for font fallback tableinsert(t, char_in_font(p.font, p.char).italic or 0) end - local c = my_node_props(p).unicode or p.char + local c = has_attribute(p, unicodeattr) or p.char if is_jungsong(c) or is_jongsong(c) or hangul_tonemark[c] then else break @@ -2034,13 +2088,6 @@ end, local pass_fun = function(...) return ... end create_callback("luatexko_prelinebreak_first", "data", pass_fun) create_callback("luatexko_prelinebreak_second", "data", pass_fun) -create_callback("luatexko_do_atbegshi", "data", pass_fun) - -function luatexko.process_atbegshi (box) - if box and box.list then - box.list = call_callback("luatexko_do_atbegshi", box.list) - end -end add_to_callback("pre_shaping_filter", function(h, gc) local par = gc == "" @@ -2250,14 +2297,20 @@ otfregister { local auxiliary_procs = { dotemph = { - luatexko_do_atbegshi = process_dotemph, + post_linebreak_filter = process_dotemph, + hpack_filter = process_dotemph, }, uline = { - luatexko_do_atbegshi = process_uline, + post_linebreak_filter = function(h) return process_uline(h) end, + hpack_filter = function(h) return process_uline(h) end, }, ruby = { - pre_linebreak_filter = process_ruby_pre_linebreak, - luatexko_do_atbegshi = process_ruby_post_linebreak, + pre_linebreak_filter = function(h) + h = process_ruby_pre_linebreak(h) + h = process_ruby_post_linebreak(h) + return h + end, + hpack_filter = process_ruby_post_linebreak, }, autojosa = { luatexko_prelinebreak_first = process_josa, @@ -2267,9 +2320,16 @@ local auxiliary_procs = { }, } +-- dotemph 등을 수식 한글에서도 작동하게 하려면 +-- post_mlist_to_hlist_filter 콜백을 이용해야 한다. + function luatexko.activate (name) for cbnam, cbfun in pairs( auxiliary_procs[name] ) do - add_to_callback(cbnam, cbfun, "luatexko."..cbnam.."."..name) + local prior + if cbnam == "hpack_filter" then + prior = luatexbase.priority_in_callback(cbnam, "luaotfload.color_handler") or nil + end + add_to_callback(cbnam, cbfun, "luatexko."..cbnam.."."..name, prior) end active_processes[name] = true end @@ -2281,8 +2341,9 @@ function luatexko.deactivateall (str) for _, name in ipairs{ "pre_shaping_filter", "post_shaping_filter", "pre_linebreak_filter", + "hpack_filter", "hyphenate", - "luatexko_do_atbegshi", -- might not work properly + "post_linebreak_filter", } do local t = {} for i, v in ipairs( luatexbase.callback_descriptions(name) ) do @@ -2304,7 +2365,3 @@ function luatexko.reactivateall () luatexko.deactivated = nil end -function luatexko.currenthashangulchars (cnt) - texcount[cnt] = char_in_font(fontcurrent(), 0xAC00) and 1 or 0 -end - -- cgit v1.2.3