由于中文字体设计的缘故,中文的引号、括号、书名号等标点符号,它们的左半部分,例如左引号,在字符图形空间是靠右侧的。node
按照中文排版惯例,段落首行缩进两个字符的宽度。可是,像左引号这样的标点符号,当它出如今段落之首时,所体现的段落缩进在视觉上就会大于两个字符的宽度。这样的标点符号出如今段落中任何一行的行首,都会致使相似的问题。segmentfault
在乎这样的问题,可能会被嘲笑或被不觉得然国。不过,我不只在乎,并且用了大概一天的时间把它解决了。app
解决方法很简单,就是在排版软件完成了段落分行以后,写个程序去检查引号、括号、书名号等标点符号的左半部分是否是出如今了段落中每一行的开始,而后对符合这一状况的文本行里的字符位置进行微调。固然,前提是这个排版软件支持这样的程序。大多数是不支持的,不过,TeX 能够。基于 TeX 的 ConTeXt MkIV 也能够。因此,我才有机会对这个问题的解决做一些记录。ide
既然出如今行首的标点会致使缩进宽度在视觉上增大,消除这个增量的最简单的办法是,将这一行文本总体向左偏移,直到标点与段落左边界对齐为止,段落首行的左引号算是与段落左边界近似齐平。字体
可是,将一行文本向作移动,确定会致使文本的右侧出现空缺,这在上面的图里能够看得出来。有一些拆东墙补西墙的意味。此时,因为段落分行工做已经结束,所以没有办法再从下一行里取字符去填补这一行右侧的微小空缺;即便有办法,也会产生连锁反应,从而波及整个段落再度从新分行,这样会让问题变得很是复杂,甚至无解。lua
须要换个角度去思考。一行文本向左移动而引发的右侧空缺,是由于最右侧的字符被「坑」了。民主的作法是,这一行文本里的每一个字符都应该承担一点空缺。能够想象为,将这行文本最右侧的空缺打碎,将碎片插入到这一行文本的每一个字符的后面,从而使得该行文本总体向右有所膨胀。因为每一个字符后面所分担的空缺碎片很小,足以欺骗个人眼睛。spa
下面给出一个具备通常性的例子以及完整的试验代码:设计
\usemodule[zhfonts] \setuppapersize[A5][A5] \setupindenting[first,always,2em] \setupinterlinespace[line=1.5em] \startluacode zhfonts = zhfonts or {} local hlist = nodes.nodecodes.hlist local glyph = nodes.nodecodes.glyph local insert_before = node.insert_before local insert_after = node.insert_after local new_kern = nodes.pool.kern local fonthashes = fonts.hashes local fontdata = fonthashes.identifiers local quaddata = fonthashes.quads local left_puncs = { [0x2018] = 0.35, -- ‘ [0x201C] = 0.35, -- “ [0x3008] = 0.35, -- 〈 [0x300A] = 0.35, -- 《 [0x300C] = 0.35, -- 「 [0x300E] = 0.35, -- 『 [0x3010] = 0.35, -- 【 [0x3014] = 0.35, -- 〔 [0x3016] = 0.35, -- 〖 [0xFF08] = 0.35, -- ( [0xFF3B] = 0.35, -- [ [0xFF5B] = 0.35 -- { } local function is_left_punc(n) if left_puncs[n.char] then return true end return false end local function quad_multiple(font, r) local quad = quaddata[font] return r * quad end function zhfonts.align_left_puncs(head) local it = head while it do if it.id == hlist then local e = it.head local neg_kern = nil local hit = nil while e do if e.id == glyph then if is_left_punc(e) then hit = e end break end e = e.next end if hit ~= nil then -- 文本行总体向左偏移 neg_kern = -left_puncs[hit.char] * quad_multiple(hit.font, 1) insert_before(head, hit, new_kern(neg_kern)) -- 统计字符个数 local w = 0 local x = hit while x do if x.id == glyph then w = w + 1 end x = x.next end if w == 0 then w = 1 end -- 将 neg_kern 分摊出去 x = it.head -- 从新遍历 av_neg_kern = -neg_kern/w local i = 0 while x do if x.id == glyph then i = i + 1 -- 最后一个字符以后不插入 kern if i < w then insert_after(head, x, new_kern(av_neg_kern)) end end x = x.next end end end it = it.next end return head, done end nodes.tasks.appendaction("finalizers", "after", "zhfonts.align_left_puncs") \stopluacode \starttext \quotation{很遗憾,}最高执政官说,\quotation{若是没有高级文明的培植,他们还要在亚光速和三维时空中被禁锢两千年,至少还需一千年时间才能掌握和使用湮灭能量,两千年后才能经过多维时空进行通信,至于经过超空间跃迁进行宇宙航行,多是五千年后的事了,至少要一万年,他们才具有加入银河系碳基文明你们庭的起码条件。} 参议员说:\quotation{文明的这种孤独进化,是银河系太古时代才有的事。若是那古老的记载正确,我那太古的祖先生活在一个海洋行星的深海中。在那黑暗世界中的无数个王朝后,一个庞大的探险计划开始了,他们发射了第一个外空飞船,那是一个透明浮力小球,通过漫长的路程浮上海面。当时正是深夜,小球中的先祖第一次看到了星空……大家可以想象,那对他们是怎样的壮丽和神秘啊!} 最高执政官说:\quotation{那是一个让人想往的时代,一粒灰尘样的行星对先祖都是一个无限广阔的世界,在那绿色的海洋和紫色的草原上,先祖敬畏地面对群星……这感受咱们已丢失千万年了。} \quotation{可我如今又找回了它!}参议员指着地球的影像说,她那蓝色的晶莹球体上浮动着雪白的云纹,他以为她真像一种来自他祖先星球海洋中的一种美丽的珍珠,\quotation{看这个小小的世界,她上面的生命体在过着本身的生活,作着本身的梦,对咱们的存在,对银河系中的战争和毁灭全然不知,宇宙对他们来讲,是但愿和梦想的无限源泉,这真象一首来自太古时代的歌谣。} 他真的吟唱了起来,他们三人的智能场合为一体,荡漾着玫瑰色的波纹。那从遥远得没法想象的太古时代传下来的歌谣听起来悠远、神秘、苍凉,经过超空间,它传遍了整个银河系,在这团由上千亿颗恒星组成的星云中,数不清的生命感到了一种久已消失的舒适和宁静。 \quotation{宇宙的最不可理解之处在于它是能够理解的。}最高执政官说。 \quotation{宇宙的最可理解之处在于它是不可理解的。}参议员说 \stoptext
如今,我已经将上述代码中处理标点符号与段落左边界对齐的代码合并到 zhfonts 模块 [1] 了,因此上例里 \startluacode ... \stopluacode
里的代码是不须要的。code