summaryrefslogtreecommitdiff
path: root/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua')
-rw-r--r--macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua138
1 files changed, 88 insertions, 50 deletions
diff --git a/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua b/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua
index c1d87de312..726aaaea7e 100644
--- a/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua
+++ b/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua
@@ -5,8 +5,8 @@
do -- block to avoid to many local variables error
local ProvidesLuaModule = {
name = "luaotfload-harf-plug",
- version = "3.12", --TAGVERSION
- date = "2020-02-02", --TAGDATE
+ version = "3.13", --TAGVERSION
+ date = "2020-05-01", --TAGDATE
description = "luaotfload submodule / database",
license = "GPL v2.0",
author = "Khaled Hosny, Marcel Krüger",
@@ -105,6 +105,8 @@ local fl_unsafe = hb.Buffer.GLYPH_FLAG_UNSAFE_TO_BREAK
local startactual_p = "luaotfload_startactualtext"
local endactual_p = "luaotfload_endactualtext"
+local empty_table = {}
+
-- "Copy" properties as done by LuaTeX: Make old properties metatable
local function copytable(old)
local new = {}
@@ -164,22 +166,11 @@ end
local process
--- Legacy TeX Input Method Disguised as Font Ligatures hack.
---
--- Single replacements, keyed by character to replace. Handled separately
--- because TeX ligaturing mechanism does not support one-to-one replacements.
-local trep = {
- [0x0022] = 0x201D, -- ["]
- [0x0027] = 0x2019, -- [']
- [0x0060] = 0x2018, -- [`]
-}
-
local function itemize(head, fontid, direction)
local fontdata = font.getfont(fontid)
local hbdata = fontdata and fontdata.hb
local spec = fontdata and fontdata.specification
local options = spec and spec.features.raw
- local texlig = options and options.tlig
local runs, codes = {}, {}
local dirstack = {}
@@ -189,20 +180,25 @@ local function itemize(head, fontid, direction)
for n, id, subtype in direct.traverse(head) do
local code = 0xFFFC -- OBJECT REPLACEMENT CHARACTER
- local skip = false
+ local skip = lastskip
+ local props = properties[n]
- if id == glyph_t then
+ if props and props.zwnj then
+ 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)
+ skip = false
else
skip = true
end
elseif id == glue_t and subtype == spaceskip_t then
code = 0x0020 -- SPACE
- skip = lastskip
elseif id == disc_t then
if uses_font(n, fontid) then
code = 0x00AD -- SOFT HYPHEN
+ skip = false
else
skip = true
end
@@ -217,17 +213,8 @@ local function itemize(head, fontid, direction)
-- Pop the last direction from the stack.
currdir = tableremove(dirstack)
end
- skip = lastskip
elseif id == localpar_t then
currdir = getdir(n)
- skip = lastskip
- end
-
- if not skip and texlig then
- local replacement = trep[code]
- if replacement then
- code = replacement
- end
end
codes[#codes + 1] = code
@@ -277,7 +264,7 @@ local function makesub(run, codes, nodelist)
if nodelist == 0 then -- FIXME: This shouldn't happen
nodelist = nil
end
- nodelist, glyphs = shape(nodelist, nodelist, subrun)
+ nodelist, nodelist, glyphs = shape(nodelist, nodelist, subrun)
return { glyphs = glyphs, run = subrun, head = nodelist }
end
@@ -300,7 +287,8 @@ local function printnodes(label, head, after)
end
-- Main shaping function that calls HarfBuzz, and does some post-processing of
-- the output.
-function shape(head, node, run)
+function shape(head, firstnode, run)
+ local node = firstnode
local codes = run.codes
local offset = run.start
local nodeindex = offset
@@ -313,7 +301,7 @@ function shape(head, node, run)
local fontdata = font.getfont(fontid)
local hbdata = fontdata.hb
- local spec = hbdata.spec
+ local spec = fontdata.specification
local features = spec.hb_features
local options = spec.features.raw
local hbshared = hbdata.shared
@@ -324,6 +312,9 @@ function shape(head, node, run)
local shapers = options.shaper and { options.shaper } or {}
local buf = hb.Buffer.new()
+ if buf.set_flags then
+ buf:set_flags(hbdata.buf_flags)
+ end
buf:set_direction(dir)
buf:set_script(script)
buf:set_language(lang)
@@ -334,6 +325,41 @@ function shape(head, node, run)
local vscale = hbdata.vscale
hbfont:set_scale(hscale, vscale)
+ do
+ 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
+ local props = properties[n] or empty_table
+ if props then
+ local local_feat = props.glyph_features or empty_table
+ if local_feat then
+ for tag, value in next, current_features do
+ local loc = local_feat[tag]
+ loc = loc ~= nil and (tonumber(loc) or (loc and 1 or 0)) or nil
+ if value.value ~= loc then -- This includes loc == nil
+ value._end = i
+ features[#features + 1] = value
+ current_features[tag] = nil
+ end
+ end
+ for tag, value in next, local_feat do
+ if not current_features[tag] then
+ local feat = hb.Feature.new(tag)
+ feat.value = tonumber(value) or (value and 1 or 0)
+ feat.start = i
+ current_features[tag] = feat
+ end
+ end
+ end
+ end
+ n = getnext(n)
+ end
+ for _, feat in next, current_features do
+ features[#features + 1] = feat
+ end
+ end
+
if hb.shape_full(hbfont, buf, features, shapers) then
-- The engine wants the glyphs in logical order, but HarfBuzz outputs them
-- in visual order, so we reverse RTL buffers.
@@ -372,7 +398,7 @@ function shape(head, node, run)
local node = node
for j = cluster,nextcluster-1 do
local id = getid(node)
- if id == glyph_t or id == glue_t then
+ 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)
@@ -385,7 +411,8 @@ function shape(head, node, run)
local discindex = nil
local disc = node
for j = cluster + 1, nextcluster do
- if codes[j] == 0x00AD then
+ local props = properties[disc]
+ if (not (props and props.zwnj)) and getid(disc) == disc_t then
discindex = j
break
end
@@ -489,6 +516,9 @@ function shape(head, node, run)
local predisc = getprev(disc)
setnext(predisc, rep)
setprev(rep, predisc)
+ if firstnode == startnode then
+ firstnode = disc
+ end
if startnode == head then
head = disc
else
@@ -519,10 +549,10 @@ function shape(head, node, run)
end
end
end
- return head, glyphs, run.len - len
+ return head, firstnode, glyphs, run.len - len
end
- return head, {}, 0
+ return head, firstnode, {}, 0
end
local function color_to_rgba(color)
@@ -583,8 +613,10 @@ local function tonodes(head, node, run, glyphs)
local dir = run.dir
local fontid = run.font
local fontdata = font.getfont(fontid)
+ local space = fontdata.parameters.space
local characters = fontdata.characters
local hbdata = fontdata.hb
+ local hfactor = (fontdata.extend or 1000) / 1000
local palette = hbdata.palette
local hbshared = hbdata.shared
local hbface = hbshared.face
@@ -596,7 +628,6 @@ local function tonodes(head, node, run, glyphs)
local lastprops
local scale = hbdata.scale
- local letterspace = hbdata.letterspace
local haspng = hbshared.haspng
local fonttype = hbshared.fonttype
@@ -640,7 +671,8 @@ local function tonodes(head, node, run, glyphs)
freenode(oldnode)
nodeindex = nodeindex + 1
else
- if id == glyph_t then
+ if lastprops and lastprops.zwnj and nodeindex == glyph.cluster + 1 then
+ elseif id == glyph_t then
local done
local fontglyph = fontglyphs[gid]
local character = characters[char]
@@ -749,8 +781,14 @@ local function tonodes(head, node, run, glyphs)
-- glyph, keep the node char unchanged. Helps with primitives that
-- take characters as input but actually work on glyphs, like
-- `\rpcode`.
- if character.commands or not oldcharacter
- or character.index ~= oldcharacter.index then
+ if not oldcharacter then
+ if gid == 0 then
+ local new = copynode(node)
+ head, node = insertafter(head, node, new)
+ end
+ setchar(node, char)
+ elseif character.commands
+ or character.index ~= oldcharacter.index then
setchar(node, char)
end
local xoffset = (rtl and -glyph.x_offset or glyph.x_offset) * scale
@@ -795,8 +833,8 @@ local function tonodes(head, node, run, glyphs)
if glyph.endactual then
setprop(node, endactual_p, true)
end
- local x_advance = glyph.x_advance + letterspace
- local width = fontglyph.width
+ local x_advance = glyph.x_advance
+ local width = fontglyph.width * hfactor
if width ~= x_advance then
-- The engine always uses the glyph width from the font, so we need
-- to insert a kern node if the x advance is different.
@@ -807,14 +845,18 @@ local function tonodes(head, node, run, glyphs)
elseif id == glue_t and getsubtype(node) == spaceskip_t then
-- If the glyph advance is different from the font space, then a
-- substitution or positioning was applied to the space glyph changing
- -- it from the default, so reset the glue using the new advance.
+ -- it from the default. We try to maintain as much as possible from the
+ -- original value because we assume that we want to keep spacefactors and
+ -- assume that we got mostly positioning applied. TODO: Handle the case that
+ -- we became a glyph in the process.
-- We are intentionally not comparing with the existing glue width as
-- spacing after the period is larger by default in TeX.
- local width = (glyph.x_advance + letterspace) * scale
- if fontdata.parameters.space ~= width then
- setwidth(node, width)
- setfield(node, "stretch", width / 2)
- setfield(node, "shrink", width / 3)
+ local width = glyph.x_advance * scale
+ -- if space > width + 2 or width > space + 2 then
+ if space ~= width then
+ setwidth(node, getwidth(node) - space + width)
+ -- setfield(node, "stretch", width / 2)
+ -- setfield(node, "shrink", width / 3)
end
elseif id == kern_t and getsubtype(node) == italiccorr_t then
-- If this is an italic correction node and the previous node is a
@@ -844,19 +886,15 @@ local function shape_run(head, current, run)
if not run.skip then
-- Font loaded with our loader and an HarfBuzz face is present, do our
-- shaping.
- local fontid = run.font
- local fontdata = font.getfont(fontid)
- local options = fontdata.specification.features.raw
-
local glyphs, offset
- head, glyphs, offset = shape(head, current, run)
+ head, current, glyphs, offset = shape(head, current, run)
return offset, tonodes(head, current, run, glyphs)
else
return 0, head, run.after
end
end
-function process(head, font, direction)
+function process(head, font, _attr, direction)
local newhead, current = head, head
local runs = itemize(head, font, direction)