LuaTeX它是由什么構(gòu)成的?
我的朋友之中,有曾經(jīng)研究過(guò)ConTeXt的。所以他們一度順理成章地研究過(guò)LuaTeX。和XeTeX相比,LuaTeX曾經(jīng)在理論上有非常高的自由度和開(kāi)放性。
LuaTeX項(xiàng)目的起源,大概是要從一個(gè)大學(xué)的阿拉伯語(yǔ)項(xiàng)目說(shuō)起。但是,從排版技術(shù)難度上來(lái)說(shuō),其實(shí)是不必專門造一個(gè)引擎的。因?yàn)榘⒗Z(yǔ)排版,固然是復(fù)雜語(yǔ)言排版(Complex Text Layout),但是它只比西文和漢字排版復(fù)雜一點(diǎn)的。簡(jiǎn)單的說(shuō)(以后有機(jī)會(huì)詳細(xì)說(shuō),做成視頻應(yīng)該更有意思),阿拉伯語(yǔ)的字符只有一個(gè)排版輸出方向上的變化和字符的位置變體,說(shuō)人話就是,阿拉伯語(yǔ)是從右往左排字,字在詞中的位置會(huì)有變體。
所以呢,“騙”經(jīng)費(fèi)這事,大概是的。但是呢,我們可以看Knuth在TeXbook里面寫的:
My work at Stanford has been generously supported by the National Science Foundation, the Office of Naval Research, the IBM Corporation, and the System Development Foundation.
所以說(shuō)啊,立項(xiàng)了,基本上就是走流程了,能出結(jié)果就好。
LuaTeX它做了些什么呢?我們先從最簡(jiǎn)單的說(shuō)起:

\directlua整個(gè)東西實(shí)際上和TeX的擴(kuò)展很相似,即\input的管道輸入,舉例:

但是呢,\directlua實(shí)際上是在LuaTeX內(nèi)部創(chuàng)建一個(gè)buffer,所有計(jì)算的結(jié)果,只要想存到這里面,都需要使用類似tex.print的函數(shù)調(diào)用。當(dāng)然,你在\directlua里面也使用io.popen,這也是使用管道。
\directlua的應(yīng)用,使用最廣泛的例子其實(shí)是TiKZ的LuaTeX后端,比如說(shuō)它實(shí)現(xiàn)了一些圖形學(xué)的算法來(lái)排布特定格式的圖的元素(如譜系樹(shù)的排法)。
除此之外,LuaTeX的核心排版部分,加了不少允許掛Lua代碼鉤子的地方,這是LuaTeX的迷人之處,當(dāng)然也是腦瓜仁疼的來(lái)源。畢竟,能做出一些好玩的排版效果但是效率低。這個(gè)效率低體現(xiàn)在:他們最后不得不上了LuaJIT。但是用LuaJIT也沒(méi)緩解慢的問(wèn)題。非要強(qiáng)加一個(gè)理由的話,那可能是排版這事,就是那么復(fù)雜,掛鉤子的效率就是不高。
更重要的,現(xiàn)在人講的很少的,其實(shí)是Omega部分。這個(gè)東西,我以前水文章的時(shí)候?qū)戇^(guò)一點(diǎn)。這個(gè)引擎做了三件事,第一個(gè)是把8位支持直接修改成了十六位;第二個(gè)是增加了多方向排版(就是“騙”經(jīng)費(fèi)的公能);第三個(gè)是OTP或者OCP。
但實(shí)際上,很長(zhǎng)時(shí)間里面,LuaTeX的多方向排版,是假的?;蛘哒f(shuō),它的這一部分功能實(shí)際上是處于不怎么維護(hù)的狀態(tài)。也就是這幾年,這一塊的代碼是進(jìn)入了可用狀態(tài)的。當(dāng)然,不可用的話,可以強(qiáng)行可用,比如LuaTeX-ja用代碼模擬的:

這里面順便提一句,有人說(shuō)XeTeX也支持豎排。這是不確切的。XeTeX支持的功能很簡(jiǎn)單,就是把glyph轉(zhuǎn)90度,看起來(lái)像是豎排,但其實(shí)不是。豎排這事,如果是輸出到圖上,那還好說(shuō)。但是稍微想要帶一些語(yǔ)義,可能還得做特殊處理,比如在PDF中要控制嵌入的字體的CMAP。所以說(shuō),豎排這事,也是分層的,圖像上看著像只是第一步,但是還有幾步走。
這里該輪到將OTP和OCP了。這里熟悉Erlang的朋友不要誤會(huì),Omega中的OTP不是Open Telecom Platform的意思,而是Omega Translation Processes。OCP就是編譯之后的OTP。在Omege的語(yǔ)境下,這個(gè)translation其實(shí)包含了transliteration,也就是轉(zhuǎn)寫。那么什么是轉(zhuǎn)寫呢?比如我們見(jiàn)到泰語(yǔ)的??????,用拉丁字母寫可以是sa wa dee。這就是一種直接的轉(zhuǎn)寫。轉(zhuǎn)寫這東西,在輸入法比較難搞定的情況下,其實(shí)能解決不少事情。在九十年代,Omega面對(duì)的就是類似的情況。所以O(shè)mega的強(qiáng)項(xiàng)其實(shí)也是這個(gè),所以社區(qū)做了阿拉伯語(yǔ),梵語(yǔ),孟加拉語(yǔ),高棉語(yǔ)等等的OTP文件。
OTP這東西,語(yǔ)法很像flex,但是不太支持復(fù)雜的正則表達(dá)式,也能做編碼轉(zhuǎn)換。這也就是我很久之前提到的,Omega的純文本文件可以輸入多種不同的編碼文本塊。OTP技術(shù)雖然很強(qiáng),但是技術(shù)太強(qiáng)有時(shí)候也是包袱,就會(huì)導(dǎo)致難學(xué)。就像我在別的地方揶揄Apple的AAT技術(shù),強(qiáng)是強(qiáng),但是設(shè)計(jì)師看了想打人。
話說(shuō)回到LuaTeX這邊。LuaTeX直接把OTP部分功能刪掉了。這有幾方面的考慮,比如說(shuō)LuaTeX只支持Unicode,那么編碼轉(zhuǎn)換之類的東西其實(shí)就沒(méi)用了。這確實(shí)沒(méi)什么遺憾的。不過(guò),OTP這東西確實(shí)依舊很好玩。因?yàn)樗脑O(shè)計(jì)模式在一定程度上,和Harfbuzz相似。但是顯而易見(jiàn)的是,OTP比Harfbuzz要出現(xiàn)的早。所以,OTP曾經(jīng)是我在思考復(fù)雜語(yǔ)言處理時(shí)候,研究的一個(gè)具體對(duì)象。
LuaTeX的核心鉤子的那部分,太龐雜了。我暫時(shí)就不講了。