diff options
author | Karl Berry <karl@freefriends.org> | 2015-07-05 22:11:44 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2015-07-05 22:11:44 +0000 |
commit | 3ad37bd306bd38be21fe9082c369811140841075 (patch) | |
tree | 77565a4dc7ca4f67866507b4dbfed947c10d95fa /Master/texmf-dist/tex/luatex/luatexko/luatexko.lua | |
parent | 4fd06219c5cd91090c46103f063bc227ea27aa84 (diff) |
luatexko
git-svn-id: svn://tug.org/texlive/trunk@37775 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/luatex/luatexko/luatexko.lua')
-rw-r--r-- | Master/texmf-dist/tex/luatex/luatexko/luatexko.lua | 640 |
1 files changed, 357 insertions, 283 deletions
diff --git a/Master/texmf-dist/tex/luatex/luatexko/luatexko.lua b/Master/texmf-dist/tex/luatex/luatexko/luatexko.lua index c17f2b8ef83..9a076f151c0 100644 --- a/Master/texmf-dist/tex/luatex/luatexko/luatexko.lua +++ b/Master/texmf-dist/tex/luatex/luatexko/luatexko.lua @@ -1,6 +1,7 @@ -- luatexko.lua -- --- Copyright (c) 2013-2015 Dohyun Kim <nomos at ktug org> +-- Copyright (c) 2013-2015 Dohyun Kim <nomos at ktug org> +-- Soojin Nam <jsunam at gmail com> -- -- This work may be distributed and/or modified under the -- conditions of the LaTeX Project Public License, either version 1.3c @@ -12,10 +13,10 @@ local err,warn,info,log = luatexbase.provides_module({ name = 'luatexko', - date = '2015/05/10', - version = 1.8, + date = '2015/07/02', + version = 1.9, description = 'Korean linebreaking and font-switching', - author = 'Dohyun Kim', + author = 'Dohyun Kim, Soojin Nam', license = 'LPPL v1.3+', }) @@ -28,12 +29,8 @@ luatexko.rubynode = rubynode luatexko.ulinebox = ulinebox local stringbyte = string.byte -local stringgsub = string.gsub local stringchar = string.char -local stringfind = string.find -local stringmatch = string.match local stringformat = string.format -local string_sub = string.sub local mathfloor = math.floor local tex_round = tex.round local tex_sp = tex.sp @@ -94,15 +91,9 @@ local d_remove_node = nodedirect.remove local d_nodenew = nodedirect.new local d_nodecount = nodedirect.count local d_end_of_math = nodedirect.end_of_math -local d_nodeslide = nodedirect.slide local d_nodetail = nodedirect.tail local d_nodedimensions = nodedirect.dimensions - -local d_new_glue = d_nodenew(gluenode) -local d_new_glue_spec = d_nodenew(gluespecnode) -local d_new_penalty = d_nodenew(penaltynode) -local d_new_kern = d_nodenew(kernnode,1) -local d_new_rule = d_nodenew(rulenode) +local d_nodefree = nodedirect.free local emsize = 655360 @@ -473,30 +464,35 @@ local josa_code = { -- else 2 } -local function d_get_gluenode (w,st,sh) - local g = d_copy_node(d_new_glue) - local s = d_copy_node(d_new_glue_spec) - d_setfield(s,"width", w or 0) - d_setfield(s,"stretch", st or 0) - d_setfield(s,"shrink", sh or 0) - d_setfield(g,"spec", s) +local function d_get_gluespec (w, st, sh) + local s = d_nodenew(gluespecnode) + d_setfield(s, "width", w or 0) + d_setfield(s, "stretch", st or 0) + d_setfield(s, "shrink", sh or 0) + return s +end + +local function d_get_gluenode (...) + local g = d_nodenew(gluenode) + local s = d_get_gluespec(...) + d_setfield(g, "spec", s) return g end local function d_get_penaltynode (n) - local p = d_copy_node(d_new_penalty) + local p = d_nodenew(penaltynode) d_setfield(p,"penalty", n or 0) return p end local function d_get_kernnode (n) - local k = d_copy_node(d_new_kern) + local k = d_nodenew(kernnode,1) d_setfield(k,"kern", n or 0) return k end local function d_get_rulenode (w,h,d) - local r = d_copy_node(d_new_rule) + local r = d_nodenew(rulenode) d_setfield(r,"width", w or 0) d_setfield(r,"height", h or 0) d_setfield(r,"depth", d or 0) @@ -620,7 +616,7 @@ local function d_get_unicode_char(curr) if uni < 0xE000 or (uni > 0xF8FF and uni < 0xF0000) then -- no pua local uchr = get_font_char(d_getfont(curr), uni) uchr = uchr and uchr.tounicode - uchr = uchr and string_sub(uchr,1,4) -- seems ok for old hangul + uchr = uchr and uchr:sub(1,4) -- seems ok for old hangul if uchr then return tonumber(uchr,16) end end local uatt = d_has_attribute(curr, luakounicodeattr) @@ -647,12 +643,12 @@ local function d_get_hlist_char_first (hlist) end local function d_get_hlist_char_last (hlist,prevchar,prevfont) - local curr = d_nodeslide(d_getlist(hlist)) + local curr = d_nodetail(d_getlist(hlist)) while curr do local currid = d_getid(curr) if currid == glyphnode then local c,f = d_get_unicode_char(curr), d_getfont(curr) - if c then return c,f end + if c and not is_unicode_vs(c) then return c,f end -- bypass VS elseif currid == hlistnode or currid == vlistnode then local c,f = d_get_hlist_char_last(curr) if c then return c,f end @@ -820,20 +816,25 @@ local function cjk_insert_nodes(head,curr,currchar,currfont,prevchar,prevfont,wa end local function cjk_spacing_linebreak (head) - local prevchar,prevfont,was_penalty = nil,nil,nil + local prevchar,prevfont,was_penalty,prevfine = nil,nil,nil,nil local curr = head while curr do - if d_has_attribute(curr,finemathattr) then + local currfine = d_has_attribute(curr,finemathattr) + if currfine then local currid = d_getid(curr) if currid == gluenode then - prevchar,prevfont = nil,nil + prevchar,prevfont,prevfine = nil,nil,nil d_unset_attribute(curr,finemathattr) elseif currid == glyphnode then local currfont = d_getfont(curr) emsize = get_font_emsize(currfont) local uni = d_get_unicode_char(curr) - if uni then + if uni and not is_unicode_vs(uni) then -- bypass VS + if prevfine and prevfine > 0 and currfine == 0 then + d_set_attribute(curr, finemathattr, 1) + end prevchar,prevfont = cjk_insert_nodes(head,curr,uni,currfont,prevchar,prevfont,was_penalty) + prevfine = currfine end d_unset_attribute(curr,finemathattr) elseif currid == mathnode then @@ -846,7 +847,7 @@ local function cjk_spacing_linebreak (head) cjk_insert_nodes(head,curr,currchar,nil,prevchar,prevfont,was_penalty) curr = d_end_of_math(curr) if not curr then break end - prevchar,prevfont = currchar,nil + prevchar,prevfont,prevfine = currchar,nil,nil end d_unset_attribute(curr,finemathattr) elseif currid == hlistnode or currid == vlistnode then @@ -855,11 +856,17 @@ local function cjk_spacing_linebreak (head) cjk_insert_nodes(head,curr,firstchr,firstfid,prevchar,prevfont,was_penalty) end prevchar,prevfont = d_get_hlist_char_last(curr,prevchar,prevfont) + if d_getlist(curr) then prevfine = nil end -- empty box preserves prevfine. d_unset_attribute(curr,finemathattr) end was_penalty = currid == penaltynode else - prevchar,prevfont = 0,nil -- treat \verb as latin character. + if d_getid(curr) == glyphnode and prevfine and prevfine > 0 then -- fitst glyph in verb + d_set_attribute(curr, finemathattr, 1) + cjk_insert_nodes(head,curr,0,nil,prevchar,prevfont,was_penalty) + d_unset_attribute(curr,finemathattr) + end + prevchar,prevfont,prevfine = 0,nil,nil -- treat \verb as latin character. end curr = d_nodenext(curr) end @@ -888,8 +895,9 @@ local function remove_cj_spaceskip (head) prv = d_nodeprev(prv) end if prvid == glyphnode then - prevclass = get_cjk_class(d_get_unicode_char(prv), cjattr) prevchar, prevfont = d_getchar(prv), d_getfont(prv) + if is_unicode_vs(prevchar) then prv = d_nodeprev(prv) end -- bypass VS + prevclass = get_cjk_class(d_get_unicode_char(prv), cjattr) end end if nxtid == glyphnode then @@ -901,6 +909,8 @@ local function remove_cj_spaceskip (head) local subtype = currsubtype if subtype == 13 then -- do not touch on xspaceskip for now d_remove_node(head,curr) + d_nodefree(curr) + curr = nxt elseif subtype == 0 then -- before \text?? spaceskip is replaced by glue type 0 local spec = d_getfield(curr,"spec") local csp = spec and d_getfield(spec,"width") @@ -920,6 +930,8 @@ local function remove_cj_spaceskip (head) end if sp == csp and st == cst and sh == csh then d_remove_node(head,curr) + d_nodefree(curr) + curr = nxt end end end @@ -935,63 +947,104 @@ end local function compress_fullwidth_punctuations (head) for curr in d_traverse_id(glyphnode,head) do local currfont, currchar = d_getfont(curr), d_getchar(curr) - if get_font_feature(currfont,'halt') or get_font_feature(currfont,'vhal') then - else - local uni = d_get_unicode_char(curr) - local class = uni and get_cjk_class(uni, d_has_attribute(curr, cjtypesetattr)) - local chr = get_font_char(currfont, currchar) - if chr and class and class >= 1 and class <= 4 then - local width = d_getfield(curr,"width") or 655360 - emsize = get_font_emsize(currfont) - local ensize = emsize/2 - local oneoften = emsize/10 - local bbox = get_char_boundingbox(currfont, currchar) - bbox = bbox or {ensize-oneoften, ensize-oneoften, ensize+oneoften, ensize+oneoften} - if class == 2 or class == 4 then - local wd - if get_font_feature(currfont,'vertical') then - wd = ensize<width and ensize-width or 0 - else - wd = (bbox[3] < ensize) and ensize-width or bbox[3]-width+oneoften - end - if chr.right_protruding then - -- kern is a breakpoint if followed by a glue + local cjtype = d_has_attribute(curr, cjtypesetattr) + local uni = d_get_unicode_char(curr) + local class = uni and get_cjk_class(uni, cjtype or 0) -- include U+201C ... + local chr = get_font_char(currfont, currchar) + if chr and class and class >= 1 and class <= 4 then + local halt_on = get_font_feature(currfont,'halt') or get_font_feature(currfont,'vhal') + local width = d_getfield(curr,"width") or 655360 + emsize = get_font_emsize(currfont) + local ensize = emsize/2 + local oneoften = emsize/10 + local bbox = get_char_boundingbox(currfont, currchar) + bbox = bbox or {ensize-oneoften, ensize-oneoften, ensize+oneoften, ensize+oneoften} + if class == 2 or class == 4 then + local wd + if get_font_feature(currfont,'vertical') then + wd = ensize<width and ensize-width or 0 + else + wd = (bbox[3] < ensize) and ensize-width or bbox[3]-width+oneoften + if not cjtype and wd > 0 then wd = 0 end + end + if chr.right_protruding then + -- kern is a breakpoint if followed by a glue + if not halt_on then d_insert_after(head, curr, d_get_kernnode(wd)) - else - d_insert_after(head, curr, d_get_rulenode(wd)) end - elseif class == 1 then - local wd - if get_font_feature(currfont,'vertical') then - wd = ensize<width and ensize-width or 0 - else - wd = (width-bbox[1] < ensize) and ensize-width or -bbox[1]+oneoften + else + if halt_on then + -- gluph halt_kern glue -> glyph halt_kern rule glue (kern is a breakpoint if followed by a glue) + local nn = d_nodenext(curr) + if nn and d_getid(nn) == kernnode then + wd = 0 + curr = nn + end end - if chr.left_protruding then + d_insert_after(head, curr, d_get_rulenode(wd)) + end + elseif class == 1 then + local wd + if get_font_feature(currfont,'vertical') then + wd = ensize<width and ensize-width or 0 + else + wd = (width-bbox[1] < ensize) and ensize-width or -bbox[1]+oneoften + if not cjtype and wd > 0 then wd = 0 end + end + if chr.left_protruding then + if not halt_on then head = d_insert_before(head, curr, d_get_kernnode(wd)) - else - head = d_insert_before(head, curr, d_get_rulenode(wd)) end - elseif class == 3 then - local lwd, rwd - local quarter, thirdquarter, halfwd = ensize/2, ensize*1.5, width/2 - if get_font_feature(currfont,'vertical') then - rwd = quarter<halfwd and quarter-halfwd or 0 - lwd = rwd - else - rwd = (bbox[3] < thirdquarter) and quarter-halfwd or bbox[3]-width - lwd = (width-bbox[1] < thirdquarter) and quarter-halfwd or -bbox[1] + else + if halt_on then + local pn = d_nodeprev(curr) + if pn and d_getid(pn) == kernnode then + -- glue halt_kern glyph -> glue rule halt_kern glyph + wd = 0 + curr = pn + elseif pn and d_getid(pn) == gluenode and d_getfield(d_getfield(pn,"spec"),"width") == 0 then + -- halt_kern glue glyph -> glue rule halt_kern glyph + local ppn = d_nodeprev(pn) + if ppn and d_getid(ppn) == kernnode then + wd = 0 + head = d_remove_node(head, ppn) + head, curr = d_insert_before(head, curr, ppn) + end + end end - if chr.left_protruding then + head = d_insert_before(head, curr, d_get_rulenode(wd)) + end + elseif class == 3 then + local lwd, rwd + local quarter, thirdquarter, halfwd = ensize/2, ensize*1.5, width/2 + if get_font_feature(currfont,'vertical') then + rwd = quarter<halfwd and quarter-halfwd or 0 + lwd = rwd + else + rwd = (bbox[3] < thirdquarter) and quarter-halfwd or bbox[3]-width + lwd = (width-bbox[1] < thirdquarter) and quarter-halfwd or -bbox[1] + end + if chr.left_protruding then + if not halt_on then head = d_insert_before(head, curr, d_get_kernnode(lwd)) - else - head = d_insert_before(head, curr, d_get_rulenode(lwd)) end - if chr.right_protruding then + else + if halt_on then lwd = 0 end -- there's already penalty 10000 + head = d_insert_before(head, curr, d_get_rulenode(lwd)) + end + if chr.right_protruding then + if not halt_on then d_insert_after (head, curr, d_get_kernnode(rwd)) - else - d_insert_after (head, curr, d_get_rulenode(rwd)) end + else + if halt_on then + local nn = d_nodenext(curr) + if nn and d_getid(nn) == kernnode then + rwd = 0 + curr = nn + end + end + d_insert_after (head, curr, d_get_rulenode(rwd)) end end end @@ -1003,6 +1056,7 @@ end -- ruby: pre-linebreak routine ------------------------------ local function spread_ruby_box(head,extrawidth) + local to_free = {} for curr in d_traverse_id(gluenode,head) do local currspec = d_getfield(curr,"spec") if currspec then @@ -1012,9 +1066,13 @@ local function spread_ruby_box(head,extrawidth) else head = d_insert_before(head,curr,d_get_kernnode(wd+extrawidth)) head = d_remove_node(head,curr) + to_free[#to_free + 1] = curr end end end + if #to_free > 0 then + for _,v in ipairs(to_free) do d_nodefree(v) end + end return head end @@ -1045,7 +1103,11 @@ local function get_ruby_side_width (basewidth,rubywidth,adjacent) local width,margin = (rubywidth-basewidth)/2, 0 if adjacent then if d_getid(adjacent) == glyphnode then - if not is_hanja(d_get_unicode_char(adjacent)) then + local uni = d_get_unicode_char(adjacent) + if is_unicode_vs(uni) then -- bypass VS + uni = d_get_unicode_char(d_nodeprev(adjacent)) + end + if not is_hanja(uni) then width = (rubywidth-basewidth-emsize)/2 if width > 0 then margin = emsize/2 @@ -1295,10 +1357,13 @@ local function get_hanja_hangul_table (table,file,init) return table end -local hanja2hangul = { } -hanja2hangul = get_hanja_hangul_table(hanja2hangul,"hanja_hangul.tab",0x4E00) -hanja2hangul = get_hanja_hangul_table(hanja2hangul,"hanjaexa_hangul.tab",0x3400) -hanja2hangul = get_hanja_hangul_table(hanja2hangul,"hanjacom_hangul.tab",0xF900) +local hanja2hangul +local function initialize_hanja2hangul () + hanja2hangul = {} + hanja2hangul = get_hanja_hangul_table(hanja2hangul,"hanja_hangul.tab",0x4E00) + hanja2hangul = get_hanja_hangul_table(hanja2hangul,"hanjaexa_hangul.tab",0x3400) + hanja2hangul = get_hanja_hangul_table(hanja2hangul,"hanjacom_hangul.tab",0xF900) +end -- 1 : 리을, 2 : 중성, 3 : 종성 local function get_josacode (prevs) @@ -1311,6 +1376,7 @@ local function get_josacode (prevs) if is_jungjongsong(code) then return jamo2josacode(code) end if (code >= 0x3400 and code <= 0x9FA5) or (code >= 0xF900 and code <= 0xFA2D) then + if not hanja2hangul then initialize_hanja2hangul() end local _, _, T = syllable2jamo(hanja2hangul[code]) return jamo2josacode(T) end @@ -1345,6 +1411,7 @@ local function get_josaprevs(curr,josaprev,ignoreparens,halt) or inhibitxspcode[chr] or prebreakpenalty[chr] or postbreakpenalty[chr] + or is_unicode_vs(chr) -- bypass VS or chr == 0x302E -- tone mark or chr == 0x302F then -- tone mark --skip @@ -1352,7 +1419,7 @@ local function get_josaprevs(curr,josaprev,ignoreparens,halt) josaprev[#josaprev + 1] = chr end elseif currid == hlistnode or currid == vlistnode then - josaprev = get_josaprevs(d_nodeslide(d_getlist(curr)),josaprev,ignoreparens,halt) + josaprev = get_josaprevs(d_nodetail(d_getlist(curr)),josaprev,ignoreparens,halt) end if #josaprev == 3 then break end curr = d_nodeprev(curr) @@ -1361,6 +1428,7 @@ local function get_josaprevs(curr,josaprev,ignoreparens,halt) end local function korean_autojosa (head) + local to_free = {} for curr in d_traverse_id(glyphnode,head) do local josaattr = d_has_attribute(curr,autojosaattr) if josaattr and d_has_attribute(curr,finemathattr) then @@ -1380,7 +1448,13 @@ local function korean_autojosa (head) d_setfield(curr,"char", josa_list[thischar][josacode]) end end - if d_getchar(curr) < 0 then d_remove_node(head,curr) end + if d_getchar(curr) < 0 then + d_remove_node(head,curr) + to_free[#to_free + 1] = curr + end + end + if #to_free > 0 then + for _,v in ipairs(to_free) do d_nodefree(v) end end end @@ -1417,7 +1491,7 @@ local function nanumtype1font(curr) if series then series = series > 500 and "b" or "m" else - series = stringfind(fnt_t.name,"^cmb") and "b" or "m" + series = fnt_t.name:find("^cmb") and "b" or "m" end local shape = fnt_t.parameters.slant > 0 and "o" or "" local subfnt = stringformat("%s%s%s%02x",family,series,shape,currchar/256) @@ -1459,72 +1533,84 @@ local function font_substitute(head) while curr do local currid = d_getid(curr) if currid == mathnode and d_getsubtype(curr) == 0 then - curr = d_end_of_math(curr) + curr = d_end_of_math(curr) elseif currid == glyphnode then local currchar, currfont = d_getchar(curr), d_getfont(curr) - local eng = get_font_table(currfont) - local myfontchar = nil - if eng and eng.encodingbytes and eng.encodingbytes == 2 -- exclude type1 - and hangulpunctuations[currchar] - and d_has_attribute(curr, hangulpunctsattr) - and (d_has_attribute(curr, finemathattr) or 0) > 0 -- not ttfamily - and not get_font_char(currfont, 0xAC00) then -- exclude hangul font - else - myfontchar = get_font_char(currfont, currchar) - end - if currchar and not myfontchar then - local hangul = d_has_attribute(curr, hangulfntattr) - local hanja = d_has_attribute(curr, hanjafntattr) - local fallback = d_has_attribute(curr, fallbackfntattr) - local ftable = {hangul, hanja, fallback} - if luatexko.hanjafontforhanja then - local uni = d_get_unicode_char(curr) - uni = uni and get_cjk_class(uni) - if uni and uni < 7 then ftable = {hanja, hangul, fallback} end - end - for i = 1,3 do - local fid = ftable[i] - myfontchar = get_font_char(fid, currchar) - if myfontchar then - d_setfield(curr,"font",fid) - local nxt = d_nodenext(curr) - if eng and nxt then - local nxtid, nxtsubtype = d_getid(nxt), d_getsubtype(nxt) - -- adjust next glue by hangul font space - if nxtid == gluenode and nxtsubtype and nxtsubtype == 0 then - local nxtspec = d_getfield(nxt,"spec") - if nxtspec and d_getfield(nxtspec,"writable") and get_font_char(fid,32) then - local sp,st,sh = hangulspaceskip(eng, fid, nxtspec) - if sp and st and sh then - local hg = d_copy_node(nxtspec) - d_setfield(hg,"width", sp) - d_setfield(hg,"stretch",st) - d_setfield(hg,"shrink", sh) - d_setfield(nxt,"spec", hg) - end + if currchar then + if is_unicode_vs(currchar) then -- ideograph variation selectors + local prev = d_nodeprev(curr) + local prevfont = d_getid(prev) == glyphnode and d_getfont(prev) + if prevfont ~= currfont then + d_setfield(curr, "font", prevfont) -- sync font + end + else + local myfontchar + local eng = currfont and get_font_table(currfont) + if eng and eng.encodingbytes and eng.encodingbytes == 2 -- exclude type1 + and hangulpunctuations[currchar] and d_has_attribute(curr, hangulpunctsattr) + and (d_has_attribute(curr, finemathattr) or 0) > 0 -- not ttfamily + and not get_font_char(currfont, 0xAC00) then -- exclude hangul font + else + myfontchar = get_font_char(currfont, currchar) + end + if not myfontchar then + local hangul = d_has_attribute(curr, hangulfntattr) + local hanja = d_has_attribute(curr, hanjafntattr) + local fallback = d_has_attribute(curr, fallbackfntattr) + local ftable = {hangul, hanja, fallback} + if luatexko.hanjafontforhanja then + local uni = d_get_unicode_char(curr) + uni = uni and get_cjk_class(uni) + if uni and uni < 7 then ftable = {hanja, hangul, fallback} end + end + for i = 1,3 do + local fid = ftable[i] + myfontchar = fid and get_font_char(fid, currchar) + if myfontchar then + d_setfield(curr,"font",fid) + --- charraise option charraise + local charraise = get_font_feature(fid, "charraise") + if charraise then + charraise = tex_sp(charraise) + local curryoffset = d_getfield(curr,"yoffset") or 0 + d_setfield(curr,"yoffset", charraise + curryoffset) end - -- adjust next italic correction kern - elseif nxtid == kernnode and nxtsubtype == 1 and d_getfield(nxt,"kern") == 0 then - local ksl = get_font_table(fid).parameters.slant - if ksl and ksl > 0 then - d_setfield(nxt,"kern", myfontchar.italic or 0) + --- + local nxt = d_nodenext(curr) + local nxtid = nxt and d_getid(nxt) + if nxtid == glyphnode and is_unicode_vs(d_getchar(nxt)) then + nxt = d_nodenext(nxt) + nxtid = nxt and d_getid(nxt) end + if eng and nxtid then + local nxtsubtype = d_getsubtype(nxt) + -- adjust next glue by hangul font space + if nxtid == gluenode and nxtsubtype and nxtsubtype == 0 then + local nxtspec = d_getfield(nxt,"spec") + if nxtspec and d_getfield(nxtspec,"writable") and get_font_char(fid,32) then + local sp,st,sh = hangulspaceskip(eng, fid, nxtspec) + if sp and st and sh then + local s = d_get_gluespec(sp, st, sh) + d_setfield(nxt, "spec", s) + d_nodefree(nxtspec) + end + end + -- adjust next italic correction kern + elseif nxtid == kernnode and nxtsubtype == 1 and d_getfield(nxt,"kern") == 0 then + local ksl = get_font_table(fid).parameters.slant + if ksl and ksl > 0 then + d_setfield(nxt,"kern", myfontchar.italic or 0) + end + end + end + break end end - --- charraise option charraise - local charraise = get_font_feature(fid, "charraise") - if charraise then - charraise = tex_sp(charraise) - local curryoffset = d_getfield(curr,"yoffset") or 0 - d_setfield(curr,"yoffset", charraise + curryoffset) + if not myfontchar then + nanumtype1font(curr) end - --- - break end end - if not myfontchar then - nanumtype1font(curr) - end end end curr = d_nodenext(curr) @@ -1538,60 +1624,43 @@ local function assign_unicode_codevalue (head) for curr in d_traverse_id(glyphnode, head) do d_set_attribute(curr, luakounicodeattr, d_getchar(curr)) end - return head end ----------------------------- -- reorder hangul tone marks ----------------------------- local function reorderTM (head) - for curr in d_traverse_id(glyphnode, head) do - local uni = d_get_unicode_char(curr) - if uni and (uni == 0x302E or uni == 0x302F) then - local unichar = get_font_char(d_getfont(curr), uni) - if unichar and unichar.width > 0 then - local p = d_nodeprev(curr) - while p do - local pid = d_getid(p) - if pid == glyphnode then + local curr = d_nodetail(head) + while curr do + if d_getid(curr) == glyphnode then + local uni = d_get_unicode_char(curr) + if uni == 0x302E or uni == 0x302F then + local done = false + local unichar = get_font_char(d_getfont(curr), uni) + if unichar and unichar.width > 0 then + local p = d_nodeprev(curr) + while p and d_getid(p) == glyphnode do local pc = get_cjk_class(d_get_unicode_char(p)) - if pc == 7 or pc == 8 then - head = d_insert_before(head,p,d_copy_node(curr)) + if pc == 9 then + elseif pc == 7 or pc == 8 then head = d_remove_node(head,curr) + head, curr = d_insert_before(head,p,curr) + done = true + break + else break end - elseif unichar.commands and pid == kernnode then - -- kerns in vertical typesetting mode - else - break + p = d_nodeprev(p) end - p = d_nodeprev(p) end - end - end - end - return head -end - ------------------------------ --- ideographic variation selector ------------------------------ -local function hanja_vs_support (head) - for curr in d_traverse_id(glyphnode, head) do - local cc = d_getchar(curr) - if is_unicode_vs(cc) then - local prev = d_nodeprev(curr) - if prev and d_getid(prev) == glyphnode then - local f = get_font_table(d_getfont(prev)) - local ivs = f and f.resources and f.resources.variants - ivs = ivs and ivs[cc] and ivs[cc][d_getchar(prev)] - -- !!! ARRRG! the font table doesn't have variants for non-BMP chars. - if ivs then - d_setfield(prev,"char",ivs) - head = d_remove_node(head,curr) + if not done and get_font_char(d_getfont(curr), 0x25CC) then + local u_25CC = d_copy_node(curr) + d_setfield(u_25CC, "char", 0x25CC) + d_insert_after(head, curr, u_25CC) end end end + curr = d_nodeprev(curr) end return head end @@ -1605,7 +1674,6 @@ add_to_callback('hpack_filter', function(head) korean_autojosa(head) remove_cj_spaceskip(head) font_substitute(head) - head = hanja_vs_support(head) return d_tonode(head) end, 'luatexko.hpack_filter_first',1) @@ -1626,7 +1694,6 @@ add_to_callback('pre_linebreak_filter', function(head) korean_autojosa(head) remove_cj_spaceskip(head) font_substitute(head) - head = hanja_vs_support(head) return d_tonode(head) end, 'luatexko.pre_linebreak_filter_first',1) @@ -1636,7 +1703,7 @@ add_to_callback('pre_linebreak_filter', function(head) cjk_spacing_linebreak(head) if texcount["luakorubyattrcnt"]>0 then spread_ruby_base_box(head) end head = compress_fullwidth_punctuations(head) - discourage_char_widow(head, d_nodeslide(head)) + discourage_char_widow(head, d_nodetail(head)) if texcount["luakorubyattrcnt"]>0 then head = no_ruby_at_margin(head) end head = reorderTM(head) return d_tonode(head) @@ -1646,11 +1713,13 @@ end, 'luatexko.pre_linebreak_filter') -------------------------- -- dot emphasis (드러냄표) -------------------------- -local function after_linebreak_dotemph (head) +local function after_linebreak_dotemph (head, to_free) + local outer = not to_free + to_free = to_free or {} for curr in d_traverse(head) do local currid = d_getid(curr) if currid == hlistnode then -- hlist may be nested!!! - d_setfield(curr,"head", after_linebreak_dotemph(d_getlist(curr))) + d_setfield(curr,"head", after_linebreak_dotemph(d_getlist(curr), to_free)) elseif currid == glyphnode then local attr = d_has_attribute(curr,dotemphattr) if attr and attr > 0 then @@ -1671,18 +1740,23 @@ local function after_linebreak_dotemph (head) nn = d_nodenext(nn) end end - local d = d_copy_node(d_todirect(dotemphnode[attr])) + local dbox = d_todirect(dotemphnode[attr]) + local d = d_copy_node(dbox) local dwidth = d_getfield(d,"width") local dot = d_get_kernnode(basewd/2-dwidth/2) d_setfield(dot,"next", d_getlist(d)) d_setfield(d,"head", dot) d_setfield(d,"width", 0) head = d_insert_before(head,curr,d) + to_free[dbox] = true end d_unset_attribute(curr,dotemphattr) end end end + if outer then + for k in pairs(to_free) do d_nodefree(k) end + end return head end @@ -1723,10 +1797,9 @@ end --------------------- -- underline emphasis --------------------- -local function draw_underline(head,curr,width,ulinenum,ulstart) +local function draw_underline(head,curr,width,ubox,ulstart) if width and width > 0 then local glue = d_get_gluenode(width) - local ubox = d_todirect(ulinebox[ulinenum]) d_setfield(glue,"subtype", 101) -- cleaders d_setfield(glue,"leader", d_copy_node(ubox)) head = d_insert_before(head, ulstart, glue) @@ -1735,8 +1808,9 @@ local function draw_underline(head,curr,width,ulinenum,ulstart) for _,nd in ipairs({ulstart,curr}) do if d_getid(nd) == whatsitnode and d_getsubtype(nd) == whatsitspecial then local nddata = d_getfield(nd,"data") - if nddata and stringfind(nddata,"luako:uline") then + if nddata and nddata:find("luako:uline") then head = d_remove_node(head,nd) + d_nodefree(nd) end end end @@ -1762,21 +1836,23 @@ local function after_linebreak_underline(head,glueorder,glueset,gluesign,ulinenu elseif currid == whatsitnode and d_getsubtype(curr) == whatsitspecial then local currdata = d_getfield(curr,"data") if currdata then - if stringfind(currdata,"luako:ulinebegin=") then - ulinenum = tonumber(stringmatch(currdata,"(%d+)")) + if currdata:find("luako:ulinebegin=") then + ulinenum = tonumber(currdata:match("(%d+)")) ulstart = curr - elseif ulstart and ulinenum - and stringfind(currdata,'luako:ulineend') then + elseif ulstart and ulinenum and currdata:find('luako:ulineend') then + local ubox = d_todirect(ulinebox[ulinenum]) local wd = d_nodedimensions(glueset,gluesign,glueorder,ulstart,curr) - head = draw_underline(head,curr,wd,ulinenum,ulstart) + head = draw_underline(head,curr,wd,ubox,ulstart) + d_nodefree(ubox) ulinebox[ulinenum] = nil ulinenum = nil end end end if ulstart and ulinenum and curr == d_nodetail(head) then + local ubox = d_todirect(ulinebox[ulinenum]) local wd = d_nodedimensions(glueset,gluesign,glueorder,ulstart,curr) - head = draw_underline(head,curr,wd,ulinenum,ulstart) + head = draw_underline(head,curr,wd,ubox,ulstart) end end return head, ulinenum @@ -1805,34 +1881,34 @@ end, 'luatexko.post_linebreak_filter') ------------------------------------ -- vertical typesetting: EXPERIMENTAL ------------------------------------ -local tsbtable, mytime, currtime, cachedir, lfsattributes, lfstouch +local tsbtable, mytime, currtime, cachedir, fontloader, lfs, lfsattributes, lfstouch local function get_vwidth_tsb_table (filename,fontname) if tsbtable[fontname] then return tsbtable[fontname] end local cachefile = stringformat("%s/luatexko_vertical_metrics_%s.lua", - cachedir,stringgsub(fontname,"%W","_")) + cachedir,fontname:gsub("%W","_")) local cattr = lfs.isfile(cachefile) and lfsattributes(cachefile) local fonttime = lfsattributes(filename,"modification") if cattr and cattr.access > mytime and cattr.modification == fonttime then tsbtable[fontname] = dofile(cachefile) return tsbtable[fontname] end - local metrics = nil - local font = fontloader.open(filename,fontname) - if font then - metrics = fontloader.to_table(font) - fontloader.close(font) - local glyph_t = {} - if metrics.subfonts then - for _,v in ipairs(metrics.subfonts) do - for ii,vv in pairs(v.glyphs) do - glyph_t[ii] = { ht = vv.vwidth, tsb = vv.tsidebearing } + local fnt = fontloader.open(filename,fontname) + if fnt then + local fnt_t = fontloader.to_table(fnt) -- for tsidebearing + fontloader.close(fnt) + local glyph_t = {} + local subfonts = fnt_t.subfonts or {fnt_t} + for _,subfont in ipairs(subfonts) do + local glyphs = subfont.glyphs or {} + for i, gl in pairs(glyphs) do + local id = gl.orig_pos or i + local name = gl.name + if name then + glyph_t[id] = { ht = gl.vwidth, tsb = gl.tsidebearing, vk = gl.vkerns } + glyph_t[name] = id end end - else - for i,v in ipairs(metrics.glyphs) do - glyph_t[i] = { ht = v.vwidth, tsb = v.tsidebearing } - end end if lfstouch then table.tofile(cachefile,glyph_t,"return") @@ -1851,59 +1927,74 @@ local function cjk_vertical_font (vf) if not vf.shared.features["vertical"] then return end if vf.type == "virtual" then return end - -- load font (again) local tsbtable = get_vwidth_tsb_table(vf.filename,vf.fontname) if not tsbtable then return end - local tmp = table.copy(vf) -- fastcopy takes time too long. - local id = fontdefine(tmp) + local id = fontdefine(table.copy(vf)) -- fastcopy takes time too long. vf.type = 'virtual' vf.fonts = {{ id = id }} - local quad = vf.parameters and vf.parameters.quad or 655360 - local descriptions = vf.shared and vf.shared.rawdata and vf.shared.rawdata.descriptions - local ascender = vf.parameters and vf.parameters.ascender or quad*0.8 - local factor = vf.parameters and vf.parameters.factor or 655.36 - local xheight = vf.parameters and vf.parameters.x_height or quad/2 - local goffset = xheight/2 - quad/2 + local params = vf.parameters or {} + local shared = vf.shared or {} + local quad = params.quad or 655360 + local ascender = params.ascender or quad*0.8 + local factor = params.factor or 655.36 + local xheight = params.x_height or quad/2 + local goffset = xheight/2 - quad/2 + local descriptions = shared.rawdata and shared.rawdata.descriptions + local vkrn_tab, id2uni_tab = {}, {} for i,v in pairs(vf.characters) do - local dsc = descriptions[i] - local gl = v.index - -- from loaded font - local vw = tsbtable and tsbtable[gl] and tsbtable[gl].ht - vw = vw and vw * factor or quad - local tsb = tsbtable and tsbtable[gl] and tsbtable[gl].tsb - local bb4 = dsc and dsc.boundingbox and dsc.boundingbox[4] - local asc = bb4 and tsb and (bb4+tsb)*factor or ascender - local hw = v.width or quad - local offset = hw/2 + goffset - local vh = hw > 0 and hw/2 or nil + local dsc = descriptions[i] + local gl = v.index + local tsb_gl = tsbtable and tsbtable[gl] + local vw = tsb_gl and tsb_gl.ht; vw = vw and vw * factor or quad + local tsb = tsb_gl and tsb_gl.tsb + local bb4 = dsc and dsc.boundingbox and dsc.boundingbox[4] + local asc = bb4 and tsb and (bb4+tsb)*factor or ascender + local hw = v.width or quad + local offset = hw/2 + goffset + local vh = hw > 0 and hw/2 or nil v.commands = { - {'right', asc}, -- bbox4 + top_side_bearing - {'down', offset}, + {'right', asc}, -- bbox4 + top_side_bearing + {'down', offset}, {'special', 'pdf: q 0 1 -1 0 0 0 cm'}, {'push'}, - {'char', i}, + {'char', i}, {'pop'}, {'special', 'pdf: Q'}, } - v.width = vw - v.height = vh - v.depth = vh - v.italic = nil + v.width = vw + v.height = vh + v.depth = vh + v.italic = nil + -- for vkrn + local t = id2uni_tab[gl] or {} + t[#t + 1] = i + id2uni_tab[gl] = t + local vk = tsb_gl.vk + if vk then + for _,vv in ipairs(vk) do + local index, off = vv.char, vv.off + index = index and tsbtable and tsbtable[index] + if index and off then + vkrn_tab[i] = vkrn_tab[i] or {} + vkrn_tab[i][index] = off + end + end + end end --- vertical gpos local res = vf.resources or {} if res.verticalgposhack then return vf -- avoid multiple running end - local fea = vf.shared and vf.shared.features or {} + local fea = shared.features or {} fea.kern = nil -- only for horizontal typesetting fea.vert = true -- should be activated by default local vposkeys = {} local seq = res.sequences or {} for _,v in ipairs(seq) do - if v.type == "gpos_single" and v.subtables then -- todo: gpos_pair... + if (v.type == "gpos_single" or v.type == "gpos_pair") and v.subtables then local feature = v.features or {} if feature.vhal or feature.vkrn or feature.valt or feature.vpal or feature.vert then for _,vv in ipairs(v.subtables) do @@ -1921,6 +2012,20 @@ local function cjk_vertical_font (vf) vp[i] = { -vv[2], vv[1], vv[4], vv[3] } end end + else -- vkrn + local t = {} + for first,idofftab in pairs(vkrn_tab) do + for id,off in pairs(idofftab) do + local unis = id2uni_tab[id] + if unis then + for _,second in ipairs(unis) do + t[first] = t[first] or {} + t[first][second] = off + end + end + end + end + lookups[v] = t end end res.verticalgposhack = true @@ -1928,11 +2033,9 @@ local function cjk_vertical_font (vf) end local function activate_vertical_virtual (tfmdata,value) - local loaded = luatexbase.priority_in_callback("luaotfload.patch_font", - "luatexko.vertical_virtual_font") - if value and not loaded then - require "fontloader" - require "lfs" + if value and not tsbtable then + fontloader = require "fontloader" + lfs = require "lfs" lfstouch = lfs.touch lfsattributes = lfs.attributes tsbtable = {} @@ -1941,8 +2044,8 @@ local function activate_vertical_virtual (tfmdata,value) mytime = mytime and lfsattributes(mytime,"modification") cachedir = caches.getwritablepath("..","luatexko") add_to_callback("luaotfload.patch_font", - cjk_vertical_font, - "luatexko.vertical_virtual_font") + cjk_vertical_font, + "luatexko.vertical_virtual_font") end end @@ -1991,36 +2094,7 @@ local function fakeslant_itlc (tfmdata) end end ------------------------------------- --- tounicode for old hangul ------------------------------------- -local function tounicode_oldhangul (tfmdata) - local script = tfmdata.properties and tfmdata.properties.script - if script ~= "hang" then return end - local desc = tfmdata.shared and tfmdata.shared.rawdata and tfmdata.shared.rawdata.descriptions - local chrs = tfmdata.characters - if not desc or not chrs then return end - if not chrs[0x1100] then return end - for _,v in ipairs({{0x1100,0x11FF},{0xA960,0xA97C},{0xD7B0,0xD7FB}}) do - for i = v[1],v[2] do - local ds = desc[i] and desc[i].slookups - if ds then - for _,s in pairs(ds) do - if type(s) == "number" and s >= 0xF0000 and chrs[s] and not chrs[s].tounicode then - chrs[s].tounicode = stringformat("%04X",i) - end - end - end - end - end -end - -add_to_callback("luaotfload.patch_font", - function(tfmdata) - fakeslant_itlc(tfmdata) - tounicode_oldhangul(tfmdata) - end, "luatexko.font_patches") - +add_to_callback("luaotfload.patch_font", fakeslant_itlc, "luatexko.fakeslant_itlc") ------------------------------------ -- Actual Text |