diff options
author | Karl Berry <karl@freefriends.org> | 2020-12-31 21:51:56 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2020-12-31 21:51:56 +0000 |
commit | 0d3cb8095777faa6f0790ce9f2a73c08882b775e (patch) | |
tree | 11ece030bd8bdf6557675f8e58ce847552035e84 /Master/texmf-dist/tex/luatex/luaotfload/luaotfload-harf-plug.lua | |
parent | 0cbf90fb1d02a12129a697341cdc3dcf1ca63789 (diff) |
luaotfload (31dec20)
git-svn-id: svn://tug.org/texlive/trunk@57274 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/luatex/luaotfload/luaotfload-harf-plug.lua')
-rw-r--r-- | Master/texmf-dist/tex/luatex/luaotfload/luaotfload-harf-plug.lua | 563 |
1 files changed, 330 insertions, 233 deletions
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-harf-plug.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-harf-plug.lua index 6759747fbf3..c40aa3b72e4 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-harf-plug.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-harf-plug.lua @@ -3,19 +3,15 @@ -- DESCRIPTION: part of luaotfload / HarfBuzz / fontloader plugin ----------------------------------------------------------------------- do -- block to avoid to many local variables error - local ProvidesLuaModule = { + assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-harf-plug", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / HarfBuzz shaping", license = "GPL v2.0", author = "Khaled Hosny, Marcel Krüger", copyright = "Luaotfload Development Team", } - - if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) - end end local hb = luaotfload.harfbuzz @@ -36,6 +32,7 @@ local direct = node.direct local tonode = direct.tonode local todirect = direct.todirect local traverse = direct.traverse +local traverse_list = direct.traverse_list local insertbefore = direct.insert_before local insertafter = direct.insert_after local protectglyph = direct.protect_glyph @@ -46,6 +43,7 @@ local removenode = direct.remove local copynodelist = direct.copy_list local ischar = direct.is_char local uses_font = direct.uses_font +local length = direct.length local getattrs = direct.getattributelist local setattrs = direct.setattributelist @@ -78,13 +76,15 @@ local getsubtype = direct.getsubtype local setsubtype = direct.setsubtype local getwidth = direct.getwidth local setwidth = direct.setwidth +local setlist = direct.setlist local is_char = direct.is_char local tail = direct.tail +local getboth = direct.getboth +local setlink = direct.setlink local properties = direct.get_properties_table() -local imgnode = img.node - +local hlist_t = node.id("hlist") local disc_t = node.id("disc") local glue_t = node.id("glue") local glyph_t = node.id("glyph") @@ -94,7 +94,10 @@ local localpar_t = node.id("local_par") local whatsit_t = node.id("whatsit") local pdfliteral_t = node.subtype("pdf_literal") +local line_t = 1 local explicitdisc_t = 1 +local firstdisc_t = 4 +local seconddisc_t = 5 local fontkern_t = 0 local italiccorr_t = 3 local regulardisc_t = 3 @@ -179,8 +182,12 @@ local function itemize(head, fontid, direction) local currdir = direction or 0 local lastskip, lastdir = true local lastrun = {} + local lastdisc + local in_disc - for n, id, subtype in direct.traverse(head) do + for n, id, subtype in traverse(head) do + if in_disc == n then in_disc = nil end + local disc local code = 0xFFFC -- OBJECT REPLACEMENT CHARACTER local skip = lastskip local props = properties[n] @@ -189,8 +196,9 @@ local function itemize(head, fontid, direction) code = 0x200C -- skip = false -- Not sure about this, but lastskip should be a bit faster elseif id == glyph_t then - if is_char(n) and getfont(n) == fontid then - code = getchar(n) + local char = is_char(n, fontid) + if char then + code = char skip = false else skip = true @@ -199,8 +207,28 @@ local function itemize(head, fontid, direction) code = 0x0020 -- SPACE elseif id == disc_t then if uses_font(n, fontid) then - code = 0x00AD -- SOFT HYPHEN + local _, _, rep, _, _, rep_tail = getdisc(n, true) + setfield(n, 'replace', nil) + local prev, next = getboth(n) + in_disc = next + disc = { + disc = n, + anchor_cluster = #codes - (lastrun.start or 0) + 1, + after_cluster = #codes - (lastrun.start or 0) + 1 + length(rep), + } + if rep then + setlink(rep_tail, next) + setnext(n, rep) -- This one is just to keep the loop going + n = rep + else + n = next + end + setlink(prev, n) + code = nil skip = false + if not prev then + head = n + end else skip = true end @@ -220,26 +248,39 @@ local function itemize(head, fontid, direction) currdir = getdirection(n) end - codes[#codes + 1] = code + local ncodes = #codes -- Necessary to count discs correctly + codes[ncodes + 1] = code - if lastdir ~= currdir or lastskip ~= skip then + if (disc or not in_disc) and (lastdir ~= currdir or lastskip ~= skip) then + if disc then + disc.after_cluster = disc.after_cluster - disc.anchor_cluster + disc.anchor_cluster = 0 + end lastrun.after = n lastrun = { - start = #codes, - len = 1, + start = ncodes + 1, + len = code and 1 or 0, font = fontid, dir = currdir == 1 and dir_rtl or dir_ltr, skip = skip, codes = codes, + discs = disc, } runs[#runs + 1] = lastrun - lastdir, lastskip = currdir, skip - else + lastdir, lastskip, lastdisc = currdir, skip, disc + elseif code then lastrun.len = lastrun.len + 1 + elseif disc then + if lastdisc then + lastdisc.next = disc + lastdisc = disc + else + lastrun.discs, lastdisc = disc, disc + end end end - return runs + return head, runs end @@ -260,7 +301,6 @@ local function makesub(run, codes, nodelist) font = run.font, dir = run.dir, fordisc = true, - node = nodelist, codes = codes, } local glyphs @@ -294,14 +334,12 @@ end function shape(head, firstnode, run) local node = firstnode local codes = run.codes - local offset = run.start - local nodeindex = offset - run.start = offset + local offset = run.start - 1 -- -1 because we want the cluster local len = run.len local fontid = run.font local dir = run.dir - local fordisc = run.fordisc - local cluster = offset - 2 + local cluster + local discs = (not run.fordisc) and run.discs local fontdata = font.getfont(fontid) local hbdata = fontdata.hb @@ -323,7 +361,7 @@ function shape(head, firstnode, run) buf:set_script(script) buf:set_language(lang) buf:set_cluster_level(buf.CLUSTER_LEVEL_MONOTONE_CHARACTERS) - buf:add_codepoints(codes, offset - 1, len) + buf:add_codepoints(codes, offset, len) local hscale = hbdata.hscale local vscale = hbdata.vscale @@ -333,7 +371,7 @@ function shape(head, firstnode, run) features = table.merged(features) -- We don't want to modify the global features local current_features = {} local n = node - for i = offset-1, offset+len-2 do + for i = offset, offset+len-1 do local props = properties[n] or empty_table if props then local local_feat = props.glyph_features or empty_table @@ -371,187 +409,260 @@ function shape(head, firstnode, run) local glyphs = buf:get_glyphs() + local break_glyph, break_cluster, break_node = 1, offset, node + local disc_glyph, disc_cluster, disc_node + local disc_cluster local i = 0 - while i < #glyphs do - i = i + 1 - local glyph = glyphs[i] - - -- Calculate the Unicode code points of this glyph. If cluster did not - -- change then this is a glyph inside a complex cluster and will be - -- handled with the start of its cluster. - if cluster ~= glyph.cluster then - cluster = glyph.cluster - for i = nodeindex, cluster do node = getnext(node) end - nodeindex = cluster + 1 - local hex = "" - local str = "" - local nextcluster - for j = i+1, #glyphs do - nextcluster = glyphs[j].cluster - if cluster ~= nextcluster then - glyph.nglyphs = j - i - goto NEXTCLUSTERFOUND -- break - end - end -- else -- only executed if the loop reached the end without - -- finding another cluster - nextcluster = offset + len - 1 - glyph.nglyphs = #glyphs + 1 - i - ::NEXTCLUSTERFOUND:: -- end - glyph.nextcluster = nextcluster - do - local node = node - for j = cluster,nextcluster-1 do - local id = getid(node) - if id == glyph_t or (id == glue_t and getsubtype(node) == spaceskip_t) then - local code = codes[j + 1] - hex = hex..to_utf16_hex(code) - str = str..utf8.char(code) - end + local glyph + -- The following is a repeat {...} while glyph {...} loop. + while true do + repeat + i = i+1 + glyph = glyphs[i] + until not glyph or glyph.cluster ~= cluster + do + local oldcluster = cluster + cluster = glyph and glyph.cluster or offset + len + if oldcluster then + for _ = oldcluster+1, cluster do + node = getnext(node) end - glyph.tounicode = hex - glyph.string = str end - if not fordisc then - local discindex = nil - local disc = node - for j = cluster + 1, nextcluster do - local props = properties[disc] - if (not (props and props.zwnj)) and getid(disc) == disc_t then - discindex = j - break + end + + -- Is this a safe breakpoint? + if discs and ((not glyph) or codes[cluster] == 0x20 or codes[cluster+1] == 0x20 or codes[cluster+1] == 0xFFFC + or not unsafetobreak(glyph)) then + -- Should we change the discretionary state? + local anchor_cluster, after_cluster = offset + discs.anchor_cluster, offset + discs.after_cluster + local saved_anchor, saved_after = (discs.next and discs.next.anchor_cluster or math.huge) + offset + while disc_cluster and after_cluster <= cluster + or not disc_cluster and anchor_cluster <= cluster do + if disc_cluster then + if not saved_after and saved_anchor < cluster then + saved_after = discs.next.after_cluster + offset + if saved_after > cluster then + saved_after, after_cluster = after_cluster, saved_after + break + end + elseif saved_after then + saved_after, after_cluster = after_cluster, saved_after end - disc = getnext(disc) - end - if discindex then - -- Discretionary found. - local startindex, stopindex = nil, nil - local startglyph, stopglyph = nil, nil - - -- Find the previous glyph that is safe to break at. - local startglyph = i - while startglyph > 1 - and codes[glyphs[startglyph - 1].cluster + 1] ~= 0x20 - and codes[glyphs[startglyph - 1].cluster + 1] ~= 0xFFFC - and (unsafetobreak(glyphs[startglyph]) - or glyphs[startglyph].cluster == glyphs[startglyph-1].cluster) do - startglyph = startglyph - 1 + local rep_glyphs = table.move(glyphs, disc_glyph, i - 1, 1, {}) + for j = 1, #rep_glyphs do + local glyph = rep_glyphs[j] + glyph.cluster = glyph.cluster - disc_cluster + glyph.nextcluster = glyph.nextcluster - disc_cluster end - -- Get the corresponding character index. - startindex = glyphs[startglyph].cluster + 1 - - -- Find the next glyph that is safe to break at. - stopglyph = i + 1 - local lastcluster = glyphs[i].cluster - while stopglyph <= #glyphs - and codes[glyphs[stopglyph].cluster + 1] ~= 0x20 - and codes[glyphs[stopglyph].cluster + 1] ~= 0xFFFC - and (unsafetobreak(glyphs[stopglyph]) - or lastcluster == glyphs[stopglyph].cluster) do - lastcluster = glyphs[stopglyph].cluster - stopglyph = stopglyph + 1 + do + local cluster_offset = disc_cluster - cluster + (saved_after and 2 or 1) -- The offset the glyph indices will move + for j = i, #glyphs do + local glyph = glyphs[j] + glyph.cluster = glyph.cluster + cluster_offset + end + len = len + cluster_offset + table.move(glyphs, i, #glyphs + i - disc_glyph, disc_glyph + (saved_after and 2 or 1)) + + local discs = discs.next + while discs do + discs.anchor_cluster = discs.anchor_cluster + cluster_offset + discs.after_cluster = discs.after_cluster + cluster_offset + discs = discs.next + end end - stopindex = stopglyph <= #glyphs and glyphs[stopglyph].cluster + 1 - or offset + len - - local startnode, stopnode = node, node - for j=nodeindex - 1, startindex, -1 do - startnode = getprev(startnode) + local pre, post, _, _, lastpost, _ = getdisc(discs.disc, true) + local precodes, postcodes, repcodes = {}, {} + table.move(codes, disc_cluster + 1, anchor_cluster, 1, precodes) + for n in traverse(pre) do + precodes[#precodes + 1] = is_char(n, fontid) or 0xFFFC end - for j=nodeindex + 1, stopindex do - stopnode = getnext(stopnode) + for n in traverse(post) do + postcodes[#postcodes + 1] = is_char(n, fontid) or 0xFFFC end + table.move(codes, after_cluster + 1, cluster, #postcodes + 1, postcodes) - glyphs[startglyph] = glyph - glyph.cluster = startindex - 1 - glyph.nextcluster = startindex - for j = stopglyph, #glyphs do - local glyph = glyphs[j] - glyph.cluster = glyph.cluster - (stopindex - startindex) + 1 + if saved_after then + repcodes = table.move(codes, disc_cluster + 1, cluster, 1, {}) + table.move(codes, cluster + 1, #codes + cluster - disc_cluster, disc_cluster + 3) + codes[disc_cluster + 1], codes[disc_cluster + 2] = 0xFFFC, 0xFFFC + else + table.move(codes, cluster + 1, #codes + cluster - disc_cluster, disc_cluster + 2) + codes[disc_cluster + 1] = 0xFFFC end - len = len - (stopindex - startindex) + 1 - table.move(glyphs, stopglyph, #glyphs + stopglyph - startglyph - 1, startglyph + 1) - local subcodes, subindex = {} do - local node = startnode - while node ~= stopnode do - if node == disc then - subindex = #subcodes - startindex = startindex + 1 - node = getnext(node) - elseif getid(node) == disc_t then - local oldnode = node - startnode, node = removenode(startnode, node) - freenode(oldnode) - tableremove(codes, startindex) - else - subcodes[#subcodes + 1] = tableremove(codes, startindex) - node = getnext(node) - end + local iter = disc_node + for _ = disc_cluster, anchor_cluster-1 do iter = getnext(iter) end + if iter ~= disc_node then + local newpre = copynodelist(disc_node, iter) + setlink(tail(newpre), pre) + pre = newpre + end + for _ = anchor_cluster, after_cluster-1 do iter = getnext(iter) end + if post then + setlink(lastpost, copynodelist(iter, node)) + else + post = copynodelist(iter, node) end end - - local pre, post, rep, lastpre, lastpost, lastrep = getdisc(disc, true) - local precodes, postcodes, repcodes = {}, {}, {} - table.move(subcodes, 1, subindex, 1, repcodes) - for n, id, subtype in traverse(rep) do - repcodes[#repcodes + 1] = getfont(n) == fontid and getchar(n) or 0xFFFC - end - table.move(subcodes, subindex + 1, #subcodes, #repcodes + 1, repcodes) - table.move(subcodes, 1, subindex, 1, precodes) - for n, id, subtype in traverse(pre) do - precodes[#precodes + 1] = getfont(n) == fontid and getchar(n) or 0xFFFC - end - for n, id, subtype in traverse(post) do - postcodes[#postcodes + 1] = getfont(n) == fontid and getchar(n) or 0xFFFC - end - table.move(subcodes, subindex + 1, #subcodes, #postcodes + 1, postcodes) - if startnode ~= disc then - local newpre = copynodelist(startnode, disc) - setnext(tail(newpre), pre) - pre = newpre + local prev = getprev(disc_node) + if disc_cluster ~= cluster then + setprev(disc_node, nil) + setnext(getprev(node), nil) end - if post then - setnext(lastpost, copynodelist(getnext(disc), stopnode)) - else - post = copynodelist(getnext(disc), stopnode) + setlink(prev, discs.disc, node) + if disc_node == firstnode then + firstnode = discs.disc + if head == disc_node then + head = firstnode + end end - if startnode ~= disc then - local predisc = getprev(disc) - setnext(predisc, rep) - setprev(rep, predisc) - if firstnode == startnode then - firstnode = disc + glyphs[disc_glyph] = { + replace = { + glyphs = rep_glyphs, + head = disc_node ~= node and disc_node or nil, + run = { + start = 1, + font = run.font, + dir = run.dir, + }, + }, + pre = makesub(run, precodes, pre), + post = makesub(run, postcodes, post), + cluster = disc_cluster, + nextcluster = disc_cluster + 1, + codepoint = 0xFFFC, + } + if saved_after then + local next_disc = discs.next + setlink(discs.disc, next_disc.disc, node) + local next_pre, next_post, _, _, next_lastpost, _ = getdisc(next_disc.disc, true) + local next_rep = copynodelist(next_pre) + -- Let's play the game again. We need three parts: + -- The pre and post branches in the outer post branch + local next_precodes, next_postcodes, next_repcodes = {}, {}, {} + do + local saved_offset = length(post) - cluster + local saved_anchor, saved_after = saved_anchor + saved_offset, saved_after + saved_offset + table.move(postcodes, 1, saved_anchor, 1, next_precodes) + for n in traverse(next_pre) do + next_precodes[#next_precodes + 1] = is_char(n, fontid) or 0xFFFC + end + for n in traverse(next_post) do + next_postcodes[#next_postcodes + 1] = is_char(n, fontid) or 0xFFFC + end + table.move(postcodes, saved_after + 1, #postcodes, #next_postcodes + 1, next_postcodes) + + local iter = post + for _ = 1, saved_anchor do iter = getnext(iter) end + if iter ~= post then + local newpre = copynodelist(post, iter) + setlink(tail(newpre), next_pre) + next_pre = newpre + end + for _ = saved_anchor, saved_after - 1 do iter = getnext(iter) end + if next_post then + setlink(next_lastpost, copynodelist(iter)) + else + next_post = copynodelist(iter) + end end - if startnode == head then - head = disc - else - local before = getprev(startnode) - setnext(before, disc) - setprev(disc, before) + -- The pre branch in the outer replace branch. The post branch is implicitly the same as the previous one + do + local saved_anchor = saved_anchor - disc_cluster + table.move(repcodes, 1, saved_anchor, 1, next_repcodes) + for n in traverse(next_rep) do + next_repcodes[#next_repcodes + 1] = is_char(n, fontid) or 0xFFFC + end + + local rep = glyphs[disc_glyph].replace.head + local iter = rep + for _ = 1, saved_anchor do iter = getnext(iter) end + if iter ~= rep then + local newpre = copynodelist(rep, iter) + setlink(tail(newpre), next_rep) + next_rep = newpre + end end - setprev(startnode, nil) - rep = startnode - lastrep = lastrep or predisc + setsubtype(discs.disc, firstdisc_t) + setsubtype(next_disc.disc, seconddisc_t) + discs = discs.next + disc_glyph = disc_glyph + 1 + disc_cluster = disc_cluster + 1 + glyphs[disc_glyph] = { + replace = makesub(run, next_repcodes, next_rep), + pre = makesub(run, next_precodes, next_pre), + post = makesub(run, next_postcodes, next_post), + cluster = disc_cluster, + nextcluster = disc_cluster + 1, + codepoint = 0xFFFC, + } + end + i = disc_glyph + 1 + assert(node == getnext(discs.disc)) + cluster = disc_cluster + 1 + + disc_cluster = nil + discs = discs.next + while discs and discs.anchor_cluster + offset < cluster do + freenode(discs.disc) + discs = discs.next end - if getnext(disc) ~= stopnode then - setnext(getprev(stopnode), nil) - setprev(stopnode, disc) - setprev(getnext(disc), lastrep) - setnext(lastrep, getnext(disc)) - rep = rep or getnext(disc) - setnext(disc, stopnode) + if not discs then break end + anchor_cluster, after_cluster = offset + discs.anchor_cluster, offset + discs.after_cluster + saved_anchor, saved_after = (discs.next and discs.next.anchor_cluster or math.huge) + offset + elseif anchor_cluster == cluster then + disc_glyph, disc_cluster, disc_node = i, cluster, node + else + disc_glyph, disc_cluster, disc_node = break_glyph, break_cluster, break_node + end + end + break_glyph, break_cluster, break_node = i, cluster, node + end + + if not glyph then break end + + local nextcluster + for j = i+1, #glyphs do + nextcluster = glyphs[j].cluster + if cluster ~= nextcluster then + glyph.nglyphs = j - i + goto NEXTCLUSTERFOUND -- break + end + end -- else -- only executed if the loop reached the end without + -- finding another cluster + nextcluster = offset + len + glyph.nglyphs = #glyphs + 1 - i + ::NEXTCLUSTERFOUND:: -- end + glyph.nextcluster = nextcluster + + local disc, discindex + -- Calculate the Unicode code points of this glyph. If cluster did not + -- change then this is a glyph inside a complex cluster and will be + -- handled with the start of its cluster. + do + local hex = "" + local str = "" + local node = node + for j = cluster+1,nextcluster do + local char, id = is_char(node, fontid) + if char then + -- assert(char == codes[j]) + hex = hex .. to_utf16_hex(char) + str = str .. utf8.char(char) + elseif not discindex and id == disc_t then + local props = properties[disc] + if not (props and props.zwnj) then + disc, discindex = node, j end - glyph.replace = makesub(run, repcodes, rep) - glyph.pre = makesub(run, precodes, pre) - glyph.post = makesub(run, postcodes, post) - i = startglyph - node = disc - cluster = glyph.cluster - nodeindex = cluster + 1 end + node = getnext(node) end + glyph.tounicode = hex + glyph.string = str + end + if not fordisc and discindex then end end return head, firstnode, glyphs, run.len - len @@ -587,7 +698,7 @@ local function color_to_rgba(color) end end --- Cache of color glyph PNG data for bookkeeping, only because I couldn’t +-- Cache of color glyph PNG data for bookkeeping, only because I couldn't -- figure how to make the engine load the image from the binary data directly. local pngcache = {} local pngcachefiles = {} @@ -672,7 +783,7 @@ local function tonodes(head, node, run, glyphs) end local gid = glyph.codepoint local char = nominals[gid] or gid_offset + gid - local id = getid(node) + local orig_char, id = is_char(node, fontid) if glyph.replace then -- For discretionary the glyph itself is skipped and a discretionary node @@ -681,17 +792,12 @@ local function tonodes(head, node, run, glyphs) setdisc(node, tonodes(pre.head, pre.head, pre.run, pre.glyphs), tonodes(post.head, post.head, post.run, post.glyphs), - tonodes(rep.head, rep.head, rep.run, rep.glyphs)) + (tonodes(rep.head, rep.head, rep.run, rep.glyphs))) node = getnext(node) nodeindex = nodeindex + 1 - elseif glyph.skip then - local oldnode = node - head, node = removenode(head, node) - freenode(oldnode) - nodeindex = nodeindex + 1 else if lastprops and lastprops.zwnj and nodeindex == glyph.cluster + 1 then - elseif id == glyph_t then + elseif orig_char then local done local fontglyph = fontglyphs[gid] local character = characters[char] @@ -717,7 +823,7 @@ local function tonodes(head, node, run, glyphs) character.depth = layerchar.depth end -- color_index has a special value, 0x10000, that mean use text - -- color, we don’t check for it here explicitly since we will + -- color, we don't check for it here explicitly since we will -- get nil anyway. local color = palette[layer.color_index] if not color or color.alpha ~= 0 then @@ -787,7 +893,7 @@ local function tonodes(head, node, run, glyphs) -- Color bitmap font with no glyph outlines (like Noto -- Color Emoji) but has no bitmap for current glyph (most likely -- `.notdef` glyph). The engine does not know how to embed such - -- fonts, so we don’t want them to reach the backend as it will cause + -- fonts, so we don't want them to reach the backend as it will cause -- a fatal error. We use `nullfont` instead. That is a hack, but I -- think it is good enough for now. We could make the glyph virtual -- with empty commands suh that LuaTeX ignores it, but we still want @@ -799,7 +905,7 @@ local function tonodes(head, node, run, glyphs) end end if not done then - local oldcharacter = characters[getchar(node)] + local oldcharacter = characters[orig_char] -- If the glyph index of current font character is the same as shaped -- glyph, keep the node char unchanged. Helps with primitives that -- take characters as input but actually work on glyphs, like @@ -824,7 +930,7 @@ local function tonodes(head, node, run, glyphs) -- overfull messages, otherwise it will be trying to print our -- invalid pseudo Unicode code points. -- If the string is empty it means this glyph is part of a larger - -- cluster and we don’t to print anything for it as the first glyph + -- cluster and we don't to print anything for it as the first glyph -- in the cluster will have the string of the whole cluster. local props = properties[node] if not props then @@ -837,7 +943,7 @@ local function tonodes(head, node, run, glyphs) -- * Find how many characters in this cluster and how many glyphs, -- * If there is more than 0 characters -- * One glyph: one to one or one to many mapping, can be - -- represented by font’s /ToUnicode + -- represented by font's /ToUnicode -- * More than one: many to one or many to many mapping, can be -- represented by /ActualText spans. -- * If there are zero characters, then this glyph is part of complex @@ -883,7 +989,7 @@ local function tonodes(head, node, run, glyphs) end elseif id == kern_t and getsubtype(node) == italiccorr_t then -- If this is an italic correction node and the previous node is a - -- glyph, update its kern value with the glyph’s italic correction. + -- glyph, update its kern value with the glyph's italic correction. local prevchar, prevfontid = ischar(getprev(node)) if prevfontid == fontid and prevchar and prevchar > 0 then local italic = characters[prevchar].italic @@ -919,8 +1025,8 @@ local function shape_run(head, current, run) end function process(head, font, _attr, direction) - local newhead, current = head, head - local runs = itemize(head, font, direction) + local newhead, runs = itemize(head, font, direction) + local current = newhead local offset = 0 for i = 1,#runs do @@ -954,29 +1060,39 @@ local function post_process(head) if startactual then local actualtext = "/Span<</ActualText<FEFF"..startactual..">>>BDC" head = insertbefore(head, n, pageliteral(actualtext)) + props[startactual_p] = nil end if endactual then head = insertafter(head, n, pageliteral("EMC")) + props[endactual_p] = nil end local replace = getfield(n, "replace") if replace then setfield(n, "replace", post_process(replace)) end + end + return head +end - local subhead = getfield(n, "head") - if subhead then - setfield(n, "head", post_process(subhead)) +local function post_process_vlist(head) + for n, id, subtype, list in traverse_list(head) do + if id == hlist_t and subtype == line_t then + setlist(n, post_process(list)) end end - return head + return true end -local function post_process_nodes(head, groupcode) +local function post_process_nodes(head) return tonode(post_process(todirect(head))) end +local function post_process_vlist_nodes(head) + return tonode(post_process_vlist(todirect(head))) +end + local function run_cleanup() -- Remove temporary PNG files that we created, if any. -- FIXME: It would be nice if we wouldn't need this @@ -1032,29 +1148,10 @@ end fonts.handlers.otf.registerplugin('harf', process) --- luatexbase does not know how to handle `wrapup_run` callback, teach it. --- TODO: Move these into ltluatex -luatexbase.callbacktypes.wrapup_run = 1 -- simple -luatexbase.callbacktypes.glyph_info = 1 -- simple - -local base_callback_descriptions = luatexbase.callback_descriptions -local base_add_to_callback = luatexbase.add_to_callback -local base_remove_from_callback = luatexbase.remove_from_callback - --- Remove all existing functions from given callback, insert ours, then --- reinsert the removed ones, so ours takes a priority. -local function add_to_callback(name, func) - local saved_callbacks = {}, ff, dd - for k, v in next, base_callback_descriptions(name) do - saved_callbacks[k] = { base_remove_from_callback(name, v) } - end - base_add_to_callback(name, func, "Harf "..name.." callback") - for _, v in next, saved_callbacks do - base_add_to_callback(name, v[1], v[2]) - end -end +local add_to_callback = luatexbase.add_to_callback -add_to_callback('pre_output_filter', post_process_nodes) -- FIXME: Wrong callback, but I want to get rid of the whole function anyway -add_to_callback('wrapup_run', run_cleanup) -add_to_callback('finish_pdffile', set_tounicode) -add_to_callback('glyph_info', get_glyph_info) +add_to_callback('post_linebreak_filter', post_process_vlist_nodes, 'luaotfload.harf.finalize_vlist') +add_to_callback('hpack_filter', post_process_nodes, 'luaotfload.harf.finalize_hlist') +add_to_callback('wrapup_run', run_cleanup, 'luaotfload.cleanup_files') +add_to_callback('finish_pdffile', set_tounicode, 'luaotfload.harf.finalize_unicode') +add_to_callback('glyph_info', get_glyph_info, 'luaotfload.glyphinfo') |