LuaTeX 的字体加载器库的奇怪输出

LuaTeX 的字体加载器库的奇怪输出

我正在尝试调试一个更大的问题,但确凿的证据是 LuaTeX 的字体加载器库存在一些(显然)奇怪的行为。

最小示例

这是文件backmap.tex

\directlua { tex.enableprimitives('',tex.extraprimitives()) }
\directlua { dofile('define_font.lua') }
\font\noto={../../fonts/amiri-regular.ttf}
\bye

这是文件define_font.lua

function read_font (name, size, fontid)
  -- Load file using fontloader.open
  local f = fontloader.open (name)
  local fonttable = fontloader.to_table(f)
  fontloader.close(f)

  for char, glyph in pairs(fonttable.map.map) do
    if char == 0x0020      -- SPACE
    or char == 0x110300    -- Some ‘character’ in Amiri font
    or char == 0x06A9 then -- ARABIC LETTER KEHEH
      local backmap = fonttable.map.backmap[glyph]      
      texio.write_nl(string.format("\n\nGLYPH: 0x%x, CHAR: 0x%x, BACKMAP: 0x%x", glyph, char, backmap))
      if char ~= backmap then
        texio.write_nl("char and backmap value DIFFERENT")
        texio.write_nl(string.format("fonttable.map.map[0x%x]: 0x%x", char, fonttable.map.map[char]))
        texio.write_nl(string.format("fonttable.map.map[0x%x]: 0x%x", char, fonttable.map.map[backmap]))
      else
        texio.write_nl("char and backmap value SAME")
      end
    end
  end

  return { }
end

-- Register OpenType font loader in define_font callback.
callback.register('define_font', read_font, "font loader")

运行后的输出如下luatex --fmt=plain backmap.tex

This is LuaTeX, Version beta-0.87.1 (TeX Live 2016/dev)
(./backmap.tex


GLYPH: 0x3, CHAR: 0x20, BACKMAP: 0xa0
char and backmap value DIFFERENT
fonttable.map.map[0x20]: 0x3
fonttable.map.map[0xa0]: 0x3


GLYPH: 0x206, CHAR: 0x6a9, BACKMAP: 0x6a9
char and backmap value SAME


GLYPH: 0x987, CHAR: 0x110300, BACKMAP: 0x110300
char and backmap value SAME
! error  (font): lua-loaded font '51' has no name!
!  ==> Fatal error occurred, bad output DVI file produced!
No pages of output.
(

解释

我正在尝试读取中的所有字符和字形fonttable.map.map,然后将的值char与的相应值进行比较fonttable.map.backmap[glyph]

我的期望是,该fonttable.map.backmap表应将字形映射回与该特定字形相同的字符。但是,正如您从上面的输出中看到的那样,与 U+0020(空格)对应的字形的反向映射反而映射到 U+00A0(无间断空格)。

这给我带来问题的原因是,我正在使用外部整形引擎(Harfbuzz)来获取段落中字符的字形,然后尝试检查反向映射以查看字形是否映射回 U+0020(SPACE)字符,然后拦截它以添加粘合节点。

我的问题:

  1. 字体这样是否有效,即反向映射与字形不匹配回到相同的字符?
  2. 关于如何拦截空格,有什么建议吗?我应该寻找任何类型的空格并将其替换为胶水吗?

答案1

  1. 这没问题,返回的代码点位于 PUA(私有使用区域)中,因为它们应该与输入文件中使用的其他字形一起显示。这种情况发生在非标准连字符、各种脚本(例如阿拉伯语)以及由整形过程生成的其他字形(未定义为普通 Unicode 字符)中。

  2. 您还可以只塑造单词,并将原始粘连保留在节点列表中。这样,您将保留用户插入的非中断空格和其他类型的空格。另一种方法是使用带有 Unicode 字符信息的表来检测各种空格类型并相应地采取行动。但是,当塑造器生成的所有空格都是非喙状空格时,它对我来说似乎不太有用。特别是在乌尔都语的情况下,我们在 LuaTeX 中没有功能性连字

有一个例子可以说明各种空间的问题:

\documentclass{article}
\usepackage{luacode}
\begin{luacode*}
local glue_id = node.id "glue"
local glyph_id = node.id "glyph"
local penalty_id = node.id "penalty"
local kern_id = node.id "kern"
local utfchar = unicode.utf8.char
local onept = tex.sp "1pt"
local function clb(head)
  local t = {}
  local function printword()
    print(table.concat(t))
    t = {}
  end
  for n in node.traverse(head) do
    if n.id == glyph_id then
      t[#t+1] = utfchar(n.char)
    elseif n.id == glue_id then
      printword()
      local spec = n.spec
      local width = spec.width / onept
      local stretch = spec.stretch / onept
      local shrink = spec.shrink /onept
      print("glue type: ",n.subtype, width, stretch, shrink)
    elseif n.id == penalty_id then
      print("penalty", n.penalty / onept)
    elseif n.id == kern_id and n.subtype == 1 then 
      printword()
      print("kern", n.kern / onept)
    end
  end
  return head
end
luatexbase.add_to_callback("pre_linebreak_filter", clb, "print spaces")
\end{luacode*}
\begin{document}

hello world~there\,are\quad various\qquad space\ types

\end{document}

这会在控制台中产生以下输出:

hello
glue type:      0       3.3333282470703 1.6666564941406 1.1111145019531
penalty 0.152587890625
world
glue type:      0       3.3333282470703 1.6666564941406 1.1111145019531
there
kern    1.6667175292969
are
glue type:      0       10.000015258789 0       0
various
glue type:      0       20.000030517578 0       0
space
glue type:      0       3.3333282470703 1.6666564941406 1.1111145019531
penalty 0.152587890625
types
glue type:      15      0       1       0

为了支持这些情况,我会保存表格中单词之间的粘连、惩罚和字距节点,然后将它们插回到正确的位置。我猜在 BiDi 中这可能很难。

相关内容