summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/luatex/luatexko/luatexko.lua
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2014-05-13 22:13:08 +0000
committerKarl Berry <karl@freefriends.org>2014-05-13 22:13:08 +0000
commit8ed901e81f474c7cf2946183f99b5836d40ffcd7 (patch)
tree0022083d26affb19815426f497b91ad443d74ebe /Master/texmf-dist/tex/luatex/luatexko/luatexko.lua
parentbd7687e8abb5975905db822498e640ca7e2e1b2c (diff)
luatexko (11may14)
git-svn-id: svn://tug.org/texlive/trunk@34018 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.lua524
1 files changed, 317 insertions, 207 deletions
diff --git a/Master/texmf-dist/tex/luatex/luatexko/luatexko.lua b/Master/texmf-dist/tex/luatex/luatexko/luatexko.lua
index 8ef25e1f439..aa14bbc249f 100644
--- a/Master/texmf-dist/tex/luatex/luatexko/luatexko.lua
+++ b/Master/texmf-dist/tex/luatex/luatexko/luatexko.lua
@@ -1,6 +1,6 @@
-- luatexko.lua
--
--- Copyright (c) 2013 Dohyun Kim <nomos at ktug org>
+-- Copyright (c) 2013-2014 Dohyun Kim <nomos at ktug org>
--
-- This work may be distributed and/or modified under the
-- conditions of the LaTeX Project Public License, either version 1.3c
@@ -12,8 +12,8 @@
local err,warn,info,log = luatexbase.provides_module({
name = 'luatexko',
- date = '2014/01/06',
- version = 1.4,
+ date = '2014/05/11',
+ version = 1.5,
description = 'Korean linebreaking and font-switching',
author = 'Dohyun Kim',
license = 'LPPL v1.3+',
@@ -26,21 +26,21 @@ local dotemphnode,rubynode,ulinebox = {},{},{}
luatexko.dotemphnode = dotemphnode
luatexko.rubynode = rubynode
luatexko.ulinebox = ulinebox
-luatexko.hanjafontforhanja = luatexko.hanjafontforhanja or false
local stringbyte = string.byte
local stringgsub = string.gsub
local stringchar = string.char
local stringfind = string.find
local stringmatch = string.match
-local stringgmatch = string.gmatch
local stringformat = string.format
local string_sub = string.sub
local mathfloor = math.floor
local tex_round = tex.round
local tex_sp = tex.sp
+local texcount = tex.count
local fontdefine = font.define
-local utf8char = unicode.utf8.char
+
+local kpse_find_file = kpse.find_file
local fontdata = fonts.hashes.identifiers
@@ -57,14 +57,17 @@ local nodecount = node.count
local nodeslide = node.slide
local nodedimensions = node.dimensions
local nodetail = node.tail
+local end_of_math = node.end_of_math
+local nodenext = node.next
+local nodeprev = node.prev
local finemathattr = luatexbase.attributes.finemathattr
local cjtypesetattr = luatexbase.attributes.cjtypesetattr
local dotemphattr = luatexbase.attributes.dotemphattr
local autojosaattr = luatexbase.attributes.autojosaattr
local luakorubyattr = luatexbase.attributes.luakorubyattr
-local hangfntattr = luatexbase.attributes.hangfntattr
-local hanjfntattr = luatexbase.attributes.hanjfntattr
+local hangulfntattr = luatexbase.attributes.hangulfntattr
+local hanjafntattr = luatexbase.attributes.hanjafntattr
local fallbackfntattr = luatexbase.attributes.fallbackfntattr
local hangulpunctsattr = luatexbase.attributes.hangulpunctsattr
local luakoglueattr = luatexbase.new_attribute("luakoglueattr")
@@ -552,7 +555,6 @@ local function get_cjk_class (ch, cjtype)
end
return c
end
- return nil
end
local function get_font_table (fid)
@@ -597,8 +599,8 @@ end
local function get_unicode_char(curr)
local uni = curr.char
- if (uni > 0 and uni < 0xE000) or (uni > 0xF8FF and uni < 0xF0000) then
- return uni -- no pua
+ if (uni > 0xFF and uni < 0xE000) or (uni > 0xF8FF and uni < 0xF0000) then
+ return uni -- no pua. no nanumgtm??
end
-- tounicode is now reliable. backend is fixed
uni = get_font_char(curr.font, curr.char)
@@ -622,7 +624,7 @@ local function get_hlist_class_first (hlist)
elseif curr.id == gluenode then
if curr.spec and curr.spec.width ~= 0 then return end
end
- curr = curr.next
+ curr = nodenext(curr)
end
end
@@ -638,7 +640,7 @@ local function get_hlist_class_last (hlist,prevchar,prevfont)
elseif curr.id == gluenode then
if curr.spec and curr.spec.width ~= 0 then return end
end
- curr = curr.prev
+ curr = nodeprev(curr)
end
return prevchar, prevfont
end
@@ -679,7 +681,7 @@ end
local function koreanlatinskip (head,curr,currfont,prevfont,was_penalty)
local width = 0 -- default: 0em
- if has_attribute(curr,finemathattr) == 1 then -- not ttfamily
+ if (has_attribute(curr,finemathattr) or 0) > 0 then -- not ttfamily
local latincjk = get_font_feature(currfont, "interlatincjk")
if not latincjk then
latincjk = get_font_feature(prevfont, "interlatincjk")
@@ -700,8 +702,8 @@ local function cjk_insert_nodes(head,curr,currchar,currfont,prevchar,prevfont)
local p = get_cjk_class(prevchar, currentcjtype)
local c = get_cjk_class(currchar, currentcjtype)
---[[raise latin puncts
- if curr.id == glyphnode and has_attribute(curr,finemathattr) == 1 and c < 10 then -- not ttfamily
- local nn, raise = curr.next, nil
+ if curr.id == glyphnode and (has_attribute(curr,finemathattr) or 0) > 0 and c < 10 then -- not ttfamily
+ local nn, raise = nodenext(curr), nil
while nn do
if nn.id == glyphnode and latin_fullstop[nn.char] then
if not raise then
@@ -709,12 +711,11 @@ local function cjk_insert_nodes(head,curr,currchar,currfont,prevchar,prevfont)
raise = raise and tex_sp(raise)
end
if raise then
- nn.yoffset = nn.yoffset or 0
- nn.yoffset = nn.yoffset + raise
+ nn.yoffset = (nn.yoffset or 0) + raise
end
- nn = nn.next
+ nn = nodenext(nn)
elseif nn.id == kernnode then
- nn = nn.next
+ nn = nodenext(nn)
else
break
end
@@ -796,7 +797,8 @@ end
local function cjk_spacing_linebreak (head)
local prevchar,prevfont = nil,nil
- for curr in traverse(head) do
+ local curr = head
+ while curr do
if has_attribute(curr,finemathattr) then
if curr.id == gluenode then
prevchar,prevfont = nil,nil
@@ -815,8 +817,8 @@ local function cjk_spacing_linebreak (head)
end
if curr.subtype == 0 then
cjk_insert_nodes(head,curr,currchar,nil,prevchar,prevfont)
- prevchar,prevfont = nil,nil
- else
+ curr = end_of_math(curr)
+ if not curr then break end
prevchar,prevfont = currchar,nil
end
unset_attribute(curr,finemathattr)
@@ -831,6 +833,7 @@ local function cjk_spacing_linebreak (head)
else
prevchar,prevfont = 0,nil -- treat \verb as latin character.
end
+ curr = nodenext(curr)
end
end
@@ -838,55 +841,61 @@ end
-- remove japanese/chinese spaceskip
------------------------------------
local function remove_cj_spaceskip (head)
- for curr in traverse_id(gluenode,head) do
- local cjattr = has_attribute(curr,cjtypesetattr)
- local prv, nxt = curr.prev, curr.next
- if cjattr and cjattr > 0 and prv and nxt then
- local prevclass, prevchar, prevfont, nextclass
- if prv.id == hlistnode or prv.id == vlistnode then
- prevclass = get_hlist_class_last(prv)
- else
- -- what is this strange kern before \text??
- if prv.id == kernnode and prv.kern == 0 then
- prv = prv.prev
+ local curr, prevfont = head, nil
+ while curr do
+ if curr.id == mathnode and curr.subtype == 0 then
+ curr = end_of_math(curr)
+ elseif curr.id == gluenode then
+ local cjattr = has_attribute(curr,cjtypesetattr)
+ local prv, nxt = nodeprev(curr), nodenext(curr)
+ if cjattr and cjattr > 0 and prv and nxt then
+ local prevclass, prevchar, nextclass
+ if prv.id == hlistnode or prv.id == vlistnode then
+ prevclass = get_hlist_class_last(prv)
+ else
+ -- what is this strange kern before \text??
+ if prv.id == kernnode and prv.kern == 0 then
+ prv = nodeprev(prv)
+ end
+ if prv.id == glyphnode then
+ prevclass = get_cjk_class(get_unicode_char(prv), cjattr)
+ prevchar, prevfont = prv.char, prv.font
+ end
end
- if prv.id == glyphnode then
- prevclass = get_cjk_class(get_unicode_char(prv), cjattr)
- prevchar, prevfont = prv.char, prv.font
+ if nxt.id == glyphnode then
+ nextclass = get_cjk_class(get_unicode_char(nxt), cjattr)
+ elseif nxt.id == hlistnode or nxt.id == vlistnode then
+ nextclass = get_hlist_class_first(nxt)
end
- end
- if nxt.id == glyphnode then
- nextclass = get_cjk_class(get_unicode_char(nxt), cjattr)
- elseif nxt.id == hlistnode or nxt.id == vlistnode then
- nextclass = get_hlist_class_first(nxt)
- end
- if (prevclass and prevclass < 10) or (nextclass and nextclass < 10) then
- local subtype = curr.subtype
- if subtype == 13 then -- do not touch on xspaceskip for now
- remove_node(head,curr)
- else -- before \text?? spaceskip is replaced by glue type 0
- local spec = curr.spec
- local csp = spec and spec.width
- local cst = spec and spec.stretch
- local csh = spec and spec.shrink
- local fp = get_font_table(prevfont)
- fp = fp and fp.parameters
- local sp = fp and fp.space
- local st = fp and fp.space_stretch
- local sh = fp and fp.space_shrink
- sp = sp and tex_round(sp)
- st = st and tex_round(st)
- sh = sh and tex_round(sh)
- if prevchar and prevchar >= 65 and prevchar <= 90 then
- st = st and mathfloor(st*(999/1000))
- sh = sh and mathfloor(sh*(1001/1000))
- end
- if sp == csp and st == cst and sh == csh then
+ if (prevclass and prevclass < 10) or (nextclass and nextclass < 10) then
+ local subtype = curr.subtype
+ if subtype == 13 then -- do not touch on xspaceskip for now
remove_node(head,curr)
+ else -- before \text?? spaceskip is replaced by glue type 0
+ local spec = curr.spec
+ local csp = spec and spec.width
+ local cst = spec and spec.stretch
+ local csh = spec and spec.shrink
+ local fp = get_font_table(prevfont)
+ fp = fp and fp.parameters
+ local sp = fp and fp.space
+ local st = fp and fp.space_stretch
+ local sh = fp and fp.space_shrink
+ sp = sp and tex_round(sp)
+ st = st and tex_round(st)
+ sh = sh and tex_round(sh)
+ if prevchar and prevchar >= 65 and prevchar <= 90 then
+ st = st and mathfloor(st*(999/1000))
+ sh = sh and mathfloor(sh*(1001/1000))
+ end
+ if sp == csp and st == cst and sh == csh then
+ remove_node(head,curr)
+ end
end
end
end
end
+ curr = nodenext(curr)
end
end
@@ -906,7 +915,7 @@ local function compress_fullwidth_punctuations (head)
local ensize = emsize/2
local oneoften = emsize/10
local bbox = get_char_boundingbox(curr.font, curr.char)
- if not bbox then return head end --
+ bbox = bbox or {ensize-oneoften, ensize-oneoften, ensize+oneoften, ensize+oneoften}
if class == 2 or class == 4 then
local wd
if get_font_feature(curr.font,'vertical') then
@@ -1025,14 +1034,14 @@ local function get_ruby_side_kern (head)
if curr.width < rubywidth then
local _,fid = get_hlist_class_first(curr)
emsize = get_font_emsize(fid)
- local leftwidth,leftmargin = get_ruby_side_width(basewidth,rubywidth,curr.prev)
+ local leftwidth,leftmargin = get_ruby_side_width(basewidth,rubywidth,nodeprev(curr))
if leftwidth > 0 then
curr.width = curr.width + leftwidth
end
if leftmargin > 0 then
rubynode[attr].leftmargin = leftmargin
end
- local rightwidth,rightmargin = get_ruby_side_width(basewidth,rubywidth,curr.next)
+ local rightwidth,rightmargin = get_ruby_side_width(basewidth,rubywidth,nodenext(curr))
if rightwidth > 0 then
curr.width = curr.width + rightwidth
end
@@ -1079,13 +1088,14 @@ local function no_ruby_at_margin(head)
end
margin = rubynode[attr].rightmargin
if margin then
- if curr.next then
- if curr.next.id == gluenode then
+ local nn = nodenext(curr)
+ if nn then
+ if nn.id == gluenode then
insert_after(head,curr,get_kernnode(-margin))
head = zero_width_rule_with_dir(head,curr)
insert_after(head,curr,get_kernnode(margin))
- elseif curr.next.id == penaltynode and curr.next.penalty < 10000 then
- insert_after(head,curr.next,get_kernnode(-margin))
+ elseif nn.id == penaltynode and nn.penalty < 10000 then
+ insert_after(head,nn,get_kernnode(-margin))
head = zero_width_rule_with_dir(head,curr)
insert_after(head,curr,get_kernnode(margin))
end
@@ -1104,14 +1114,15 @@ local function inject_char_widow_penalty (head,curr,uni,cjattr)
local class = get_cjk_class(uni, cjattr)
if class and class < 9 then
local pv = cjattr and 500 or 5000
- if curr.prev and curr.prev.id == rulenode then
- curr = curr.prev
+ local np = nodeprev(curr)
+ if np and np.id == rulenode then
+ curr = np; np = nodeprev(curr)
end
- if curr.prev and curr.prev.id == gluenode then
- curr = curr.prev
+ if np and np.id == gluenode then
+ curr = np; np = nodeprev(curr)
end
- if curr.prev and curr.prev.id == penaltynode then
- curr = curr.prev
+ if np and np.id == penaltynode then
+ curr = np
if curr.penalty < pv then
curr.penalty = pv
end
@@ -1141,7 +1152,7 @@ local function discourage_char_widow (head,curr)
local cjattr = has_attribute(curr,cjtypesetattr)
curr = inject_char_widow_penalty(head,curr,uni,cjattr)
end
- curr = curr.prev
+ curr = nodeprev(curr)
end
end
@@ -1228,7 +1239,7 @@ end
local function get_hanja_hangul_table (table,file,init)
local i = 0
- local file = kpse.find_file(file)
+ local file = kpse_find_file(file)
if not file then return table end
file = io.open(file, "r")
if not file then return table end
@@ -1301,7 +1312,7 @@ local function get_josaprevs(curr,josaprev,ignoreparens,halt)
josaprev = get_josaprevs(nodeslide(curr.head),josaprev,ignoreparens,halt)
end
if #josaprev == 3 then break end
- curr = curr.prev
+ curr = nodeprev(curr)
end
return josaprev
end
@@ -1311,13 +1322,12 @@ local function korean_autojosa (head)
if has_attribute(curr,autojosaattr) and has_attribute(curr,finemathattr) then
local ignoreparens = has_attribute(curr,autojosaattr) > 1 and true or false
local josaprev = {}
- josaprev = get_josaprevs(curr.prev,josaprev,ignoreparens)
+ josaprev = get_josaprevs(nodeprev(curr),josaprev,ignoreparens)
local josacode = get_josacode(josaprev)
local thischar = get_unicode_char(curr)
if thischar == 0xC774 then
- if curr.next
- and curr.next.id == glyphnode
- and get_unicode_char(curr.next) == 0xB77C then
+ local nn = nodenext(curr)
+ if nn and nn.id == glyphnode and get_unicode_char(nn) == 0xB77C then
curr.char = josa_list[0xC774][josacode]
else
curr.char = josa_list[0xAC00][josacode]
@@ -1353,30 +1363,65 @@ local function hangulspaceskip (engfont, hfontid, spec)
return tex_round(hsp), tex_round(hst), tex_round(hsh)
end
+local type1fonts = {} -- due to too verbose log
+local function nanumtype1font(curr)
+ if curr.char > 0xFFFF then return end
+ local fnt_t = get_font_table(curr.font)
+ local family = (has_attribute(curr,finemathattr) or 0) > 1 and not is_hanja(curr.char) and "nanummj" or "nanumgt"
+ local series = fnt_t.shared and fnt_t.shared.rawdata.metadata.pfminfo.weight
+ if series then
+ series = series > 500 and "b" or "m"
+ else
+ series = stringfind(fnt_t.name,"^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,curr.char/256)
+ local fsize = fnt_t.size or 655360
+ local fspec = stringformat("%s@%d",subfnt,fsize)
+ local newfnt = type1fonts[fspec]
+ local newchr = curr.char % 256
+ local function ital_corr (curr,chr_t)
+ if shape ~= "o" then return end
+ local nxt = nodenext(curr)
+ if nxt and nxt.id == kernnode and nxt.subtype == 1 and nxt.kern == 0 then
+ nxt.kern = chr_t.italic or 0
+ end
+ end
+ if newfnt then
+ local fntchr = get_font_char(newfnt,newchr)
+ if fntchr then
+ curr.font, curr.char = newfnt, newchr
+ ital_corr(curr,fntchr)
+ end
+ else
+ local ft, id = fonts.constructors.readanddefine(subfnt,fsize)
+ local fntchr = ft and ft.characters[newchr]
+ if id and fntchr then
+ type1fonts[fspec], curr.font, curr.char = id, id, newchr
+ ital_corr(curr,fntchr)
+ end
+ end
+end
+
local function font_substitute(head)
- local noinmath = true
- for curr in traverse(head) do
- if curr.id == mathnode then
- if curr.subtype == 0 then
- noinmath = false
- else
- noinmath = true
- end
- elseif noinmath and curr.id == glyphnode then
+ local curr = head
+ while curr do
+ if curr.id == mathnode and curr.subtype == 0 then
+ curr = end_of_math(curr)
+ elseif curr.id == glyphnode then
local eng = get_font_table(curr.font)
- local engfontchar = nil
+ local myfontchar = nil
if eng and eng.encodingbytes and eng.encodingbytes == 2 -- exclude type1
and hangulpunctuations[curr.char]
and has_attribute(curr, hangulpunctsattr)
- and has_attribute(curr, finemathattr) == 1
+ and (has_attribute(curr, finemathattr) or 0) > 0 -- not ttfamily
and not get_font_char(curr.font, 0xAC00) then -- exclude hangul font
else
- engfontchar = get_font_char(curr.font, curr.char)
+ myfontchar = get_font_char(curr.font, curr.char)
end
- if curr.char and not engfontchar then
- local korid = false
- local hangul = has_attribute(curr, hangfntattr)
- local hanja = has_attribute(curr, hanjfntattr)
+ if curr.char and not myfontchar then
+ local hangul = has_attribute(curr, hangulfntattr)
+ local hanja = has_attribute(curr, hanjafntattr)
local fallback = has_attribute(curr,fallbackfntattr)
local ftable = {hangul, hanja, fallback}
if luatexko.hanjafontforhanja then
@@ -1384,17 +1429,15 @@ local function font_substitute(head)
uni = uni and get_cjk_class(uni)
if uni and uni < 7 then ftable = {hanja, hangul, fallback} end
end
- for i=1,#ftable do
+ for i = 1,3 do
local fid = ftable[i]
- if fid then
- local c = get_font_char(fid, curr.char)
- if c then
- korid = true
- curr.font = fid
+ myfontchar = get_font_char(fid, curr.char)
+ if myfontchar then
+ curr.font = fid
+ local nxt = nodenext(curr)
+ if eng and nxt then
-- adjust next glue by hangul font space
- local nxt = curr.next
- if eng
- and nxt and nxt.id == gluenode
+ if nxt.id == gluenode
and nxt.subtype and nxt.subtype == 0
and nxt.spec and nxt.spec.writable
and get_font_char(fid,32) then
@@ -1404,25 +1447,32 @@ local function font_substitute(head)
hg.width, hg.stretch, hg.shrink = sp, st, sh
nxt.spec = hg
end
+ -- adjust next italic correction kern
+ elseif nxt.id == kernnode
+ and nxt.subtype == 1 and nxt.kern == 0 then
+ local ksl = get_font_table(fid).parameters.slant
+ if ksl and ksl > 0 then
+ nxt.kern = myfontchar.italic or 0
+ end
end
- --- charraise option charraise
- local charraise = get_font_feature(fid, "charraise")
- if charraise then
- charraise = tex_sp(charraise)
- curr.yoffset = curr.yoffset and (curr.yoffset + charraise) or charraise
- end
- ---
- break
end
+ --- charraise option charraise
+ local charraise = get_font_feature(fid, "charraise")
+ if charraise then
+ charraise = tex_sp(charraise)
+ curr.yoffset = charraise + (curr.yoffset or 0)
+ end
+ ---
+ break
end
end
- if not korid and not is_unicode_vs(curr.char) then
- warn("!Missing character: %s U+%04X", utf8char(curr.char),curr.char)
+ if not myfontchar then
+ nanumtype1font(curr)
end
end
end
+ curr = nodenext(curr)
end
- return head
end
-----------------------------
@@ -1440,19 +1490,25 @@ end
-----------------------------
local function reorderTM (head)
for curr in traverse_id(glyphnode, head) do
- if curr.width > 0 then -- old hangul vertical typesetting is broken?
- local uni = get_unicode_char(curr)
- if uni and (uni == 0x302E or uni == 0x302F) then
- local p = curr.prev
+ local uni = get_unicode_char(curr)
+ if uni and (uni == 0x302E or uni == 0x302F) then
+ local unichar = get_font_char(curr.font, uni)
+ if unichar.width > 0 then
+ local p = nodeprev(curr)
while p do
- if p.id ~= glyphnode then break end
- local pc = get_cjk_class(get_unicode_char(p))
- if pc == 7 or pc == 8 then
- head = insert_before(head,p,copy_node(curr))
- head = remove_node(head,curr)
+ if p.id == glyphnode then
+ local pc = get_cjk_class(get_unicode_char(p))
+ if pc == 7 or pc == 8 then
+ head = insert_before(head,p,copy_node(curr))
+ head = remove_node(head,curr)
+ break
+ end
+ elseif unichar.commands and p.id == kernnode then
+ -- kerns in vertical typesetting mode
+ else
break
end
- p = p.prev
+ p = nodeprev(p)
end
end
end
@@ -1467,7 +1523,7 @@ local function hanja_vs_support (head)
for curr in traverse_id(glyphnode, head) do
local cc = curr.char
if is_unicode_vs(cc) then
- local prev = curr.prev
+ local prev = nodeprev(curr)
if prev and prev.id == glyphnode then
local f = get_font_table(prev.font)
local ivs = f and f.resources and f.resources.variants
@@ -1496,9 +1552,9 @@ add_to_callback('hpack_filter', function(head)
end, 'luatexko.hpack_filter_first',1)
add_to_callback('hpack_filter', function(head)
- get_ruby_side_kern(head)
+ if texcount["luakorubyattrcnt"]>0 then get_ruby_side_kern(head) end
cjk_spacing_linebreak(head)
- spread_ruby_base_box(head)
+ if texcount["luakorubyattrcnt"]>0 then spread_ruby_base_box(head) end
head = compress_fullwidth_punctuations(head)
-- head = no_ruby_at_margin(head)
head = reorderTM(head)
@@ -1515,12 +1571,12 @@ add_to_callback('pre_linebreak_filter', function(head)
end, 'luatexko.pre_linebreak_filter_first',1)
add_to_callback('pre_linebreak_filter', function(head)
- get_ruby_side_kern(head)
+ if texcount["luakorubyattrcnt"]>0 then get_ruby_side_kern(head) end
cjk_spacing_linebreak(head)
- spread_ruby_base_box(head)
+ if texcount["luakorubyattrcnt"]>0 then spread_ruby_base_box(head) end
head = compress_fullwidth_punctuations(head)
discourage_char_widow(head, nodeslide(head))
- head = no_ruby_at_margin(head)
+ if texcount["luakorubyattrcnt"]>0 then head = no_ruby_at_margin(head) end
head = reorderTM(head)
return head
end, 'luatexko.pre_linebreak_filter')
@@ -1540,7 +1596,7 @@ local function after_linebreak_dotemph (head)
if cc and (cc == 0 or cc == 7 or cc == 8) then
local basewd = curr.width or 0
if cc == 8 then -- check next char for old hangul jung/jongseong
- local nn = curr.next
+ local nn = nodenext(curr)
while nn do
if nn.id ~= glyphnode then break end
local uni = get_unicode_char(nn)
@@ -1550,7 +1606,7 @@ local function after_linebreak_dotemph (head)
else
break
end
- nn = nn.next
+ nn = nodenext(nn)
end
end
local d = copy_node(dotemphnode[attr])
@@ -1623,7 +1679,7 @@ end
local function after_linebreak_underline(head,glueorder,glueset,gluesign,ulinenum)
local ulstart = ulinenum and head or false
- if ulstart and ulstart.id == gluenode then ulstart = ulstart.next end
+ if ulstart and ulstart.id == gluenode then ulstart = nodenext(ulstart) end
for curr in traverse(head) do
if curr.id == hlistnode then
curr.head,ulinenum = after_linebreak_underline(curr.head,curr.glue_order,curr.glue_set,curr.glue_sign,ulinenum)
@@ -1652,48 +1708,61 @@ end
-- add to callback : post-linebreak
-----------------------------------
add_to_callback('vpack_filter', function(head)
- head = after_linebreak_dotemph(head)
- after_linebreak_ruby(head)
- head = after_linebreak_underline(head)
+ if texcount["luakodotemphcnt"]>0 then head = after_linebreak_dotemph(head) end
+ if texcount["luakorubyattrcnt"]>0 then after_linebreak_ruby(head) end
+ if texcount["luakoulineboxcnt"]>0 then head = after_linebreak_underline(head) end
return head
end, 'luatexko.vpack_filter')
add_to_callback("post_linebreak_filter", function(head)
- head = after_linebreak_dotemph(head)
- after_linebreak_ruby(head)
- head = after_linebreak_underline(head)
+ if texcount["luakodotemphcnt"]>0 then head = after_linebreak_dotemph(head) end
+ if texcount["luakorubyattrcnt"]>0 then after_linebreak_ruby(head) end
+ if texcount["luakoulineboxcnt"]>0 then head = after_linebreak_underline(head) end
return head
end, 'luatexko.post_linebreak_filter')
------------------------------------
--- vertical typesetting: EXPERIMENTAL -- don't use this
+-- vertical typesetting: EXPERIMENTAL
------------------------------------
----[[no vwidth in luaotfload v2
-local tsbtable = {}
-
-local function read_tsb_table(filename)-- for ttx-generated vmtx table
- if tsbtable[filename] then
- return tsbtable[filename]
+local tsbtable, mytime, currtime, cachedir, 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","_"))
+ 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 filepath = kpse.find_file(filename)
- if not filepath then return end
- local file = io.open(filepath, "r")
- if not file then return end
- local tsbtb = {}
- local patt = 'name="(.-)" height="(.-)" tsb="(.-)"'
- while true do
- local l = file:read("*line")
- if not l then break end
- for name, height, tsb in stringgmatch(l,patt) do
- tsbtb[name] = {}
- tsbtb[name].height = height
- tsbtb[name].tsb = tsb
+ 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 }
+ 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")
+ if not lfstouch(cachefile,currtime,fonttime) then
+ warn("Writing cache file '%s' failed!",cachefile)
+ end
+ end
+ tsbtable[fontname] = glyph_t
+ return glyph_t
end
- file:close()
- tsbtable[filename] = tsbtb
- return tsbtb
end
local function cjk_vertical_font (vf)
@@ -1702,25 +1771,13 @@ local function cjk_vertical_font (vf)
if not vf.shared.features["vertical"] then return end
if vf.type == "virtual" then return end
- ---[[ for read-ttx
- local filename = vf.filename
- filename = stringgsub(filename,".*/","")
- filename = stringgsub(filename,"[tToO][tT][fF]$","ttx")
- local tsbtable = read_tsb_table(filename)
- if not tsbtable then
- warn("Cannot read %s. Aborting vertical typesetting.",filename)
- 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 hash = vf.properties and vf.properties.hash and vf.properties.hash..' @ vertical'
- hash = hash or (vf.name and vf.size and vf.name..' @ '..vf.size..' @ vertical')
-
- vf.properties = vf.properties or {}
- vf.properties.hash = hash
vf.type = 'virtual'
vf.fonts = {{ id = id }}
local quad = vf.parameters and vf.parameters.quad or 655360
@@ -1728,31 +1785,21 @@ local function cjk_vertical_font (vf)
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 halfxht = xheight/2
+ local goffset = xheight/2 - quad/2
for i,v in pairs(vf.characters) do
local dsc = descriptions[i]
- local gname = dsc.name
- -- local vw = dsc and dsc.vwidth
- ---[[ for read-ttx
- local vw = tsbtable and tsbtable[gname] and tsbtable[gname].height
- local tsb = tsbtable and tsbtable[gname] and tsbtable[gname].tsb
- if not vw and dsc.index then
- local cid = stringformat("cid%05d", dsc.index)
- vw = tsbtable and tsbtable[cid] and tsbtable[cid].height
- tsb = tsbtable and tsbtable[cid] and tsbtable[cid].tsb
- end
- tsb = tsb and factor and tsb*factor
- --]]
+ 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 hw = v.width or quad
- local offset = hw/2 - quad/2 + halfxht
- local vh = (hw > 0) and hw/2 or nil
+ local tsb = tsbtable and tsbtable[gl] and tsbtable[gl].tsb
local bb4 = dsc and dsc.boundingbox and dsc.boundingbox[4]
- bb4 = bb4 and bb4*factor
- local asc = bb4 and tsb and (bb4 + tsb)
- asc = asc or ascender
+ 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! But, tsb not available!
+ {'right', asc}, -- bbox4 + top_side_bearing
{'down', offset},
{'special', 'pdf: q 0 1 -1 0 0 0 cm'},
{'push'},
@@ -1800,6 +1847,15 @@ 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"
+ lfstouch = lfs.touch
+ lfsattributes = lfs.attributes
+ tsbtable = {}
+ currtime = os.time()
+ mytime = kpse_find_file("luatexko.lua")
+ mytime = mytime and lfsattributes(mytime,"modification")
+ cachedir = caches.getwritablepath("..","luatexko")
add_to_callback("luaotfload.patch_font",
cjk_vertical_font,
"luatexko.vertical_virtual_font")
@@ -1814,7 +1870,6 @@ otffeatures.register {
node = activate_vertical_virtual,
}
}
---no vwidth in luaotfload v2]]
------------------------------------
-- italic correction for fake-slant font
@@ -1834,7 +1889,62 @@ 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
+ local last = 0
+ 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)
+ last = s > last and s or last
+ end
+ end
+ end
+ end
+ end
+ if stringfind(tfmdata.fontname,"^HCR.+LVT") then
+ local touni = "1112119E"
+ for i = last+1, last+2 do
+ local dsc,chr = desc[i],chrs[i]
+ if dsc and chr and dsc.class == "ligature" and not chr.tounicode then
+ chr.tounicode = touni
+ end
+ touni = touni.."11AB"
+ end
+ end
+end
+
add_to_callback("luaotfload.patch_font",
- fakeslant_itlc,
- "luatexko.fakeslant_itlc")
+ function(tfmdata)
+ fakeslant_itlc(tfmdata)
+ tounicode_oldhangul(tfmdata)
+ end, "luatexko.font_patches")
+
+------------------------------------
+-- Actual Text
+------------------------------------
+local function actualtext (str)
+ local t = {}
+ for uni in string.utfvalues(str) do
+ if uni < 0x10000 then
+ t[#t+1] = stringformat("%04X",uni)
+ else -- surrogate
+ uni = uni - 0x10000
+ t[#t+1] = stringformat("%04X%04X", uni/0x400+0xD800, uni%0x400+0xDC00)
+ end
+ end
+ tex.sprint(stringformat("<FEFF%s>", table.concat(t)))
+end
+luatexko.actualtext = actualtext