由於中文字體設計的緣故,中文的引號、括號、書名號等標點符號,它們的左半部分,例如左引號,在字符圖形空間是靠右側的。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