summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/luatex/luatexko/luatexko.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/luatex/luatexko/luatexko.lua')
-rw-r--r--Master/texmf-dist/tex/luatex/luatexko/luatexko.lua640
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