CSS Text 3: Segment Break Transformation Rules

去年年底,我利用閒暇時間1修好了 Firefox 的 Segment Break Transformation Rules 實做 (Bug 1081858)。從 Firefox 52 開始,HTML 裡面中文與中文之 間的換行,瀏覽器排版時不會顯示為空白。

Source
Chromium 59
Firefox 56

使用純文字編輯器撰寫文檔時,為了閱讀的舒適性,常常我們會在行寬 80 個字元的時候換行,這個寬度可以容納四十個中文字,剛好也是可以舒 適閱讀中文的寬度。隨著軟體硬體的進步,顯示內容不再侷限於固定的寬度, 很多排版軟體都可以把內文重新排版後顯示在不一樣的環境。

從原始文檔轉換為螢幕顯示內容的排版過程,這些軟體會把同一段落的文字重組 為文字流,移除換行或是插入新的換行,重新排版於新的容器寬度內;問題在於 很多拼音文字使用空白作為字與字之間的分隔,排版軟體的演算法也如此假設, 結果原本文檔內被移除的換行就預設被取代為空白。

現在很多網路上的內容都是用 Markdown 語法編寫的,大部分的 Markdown 轉譯 程式都會保留原本內文的換行2,所以很多網路上的中文內容都會發 現這樣的問題。不仔細看的話也許不會注意到,但是一旦注意到了就很難忽略這 個排版的瑕疵,如果網頁使用齊頭齊尾排版的話尤其明顯。

這個問題不只出現在網頁上,也出現在很多會自動重新排版文字流的應用程式中, 例如 XeLaTeX 的中文套件 XeCJK 也要處理類似的問題。過去我經常修改程式後 端來解決這個問題,但是也一直在尋找一勞永逸的,直接在瀏覽器裡面修正的方法。

後來找到 CSS Text 3 有這方面的規範。實際開始修改後我發現其實 Firefox 在很早就有針對中文做些處理,但是這段程式碼錯誤判斷中文字的邊界,使得這 段程式碼從寫完開始就沒有任何作用。這段程式原本的寫法就比較難懂(使用負 的陣列索引),缺乏相關的測試導致一直沒有人發現這個錯誤3,結果 甚至在我修好這段程式碼之後還暴露了原本排版引擎的一 些 bug

同事 Jeremy 後來進一步修改了 Gecko 的演算法,符合目前 spec 規範的行為。

4.1.2. Segment Break Transformation Rules

When white-space is pre, pre-wrap, or pre-line, segment breaks are not collapsible and are instead transformed into a preserved line feed (U+000A).

For other values of white-space, segment breaks are collapsible. As with spaces, any collapsible segment break immediately following another collapsible segment break is removed. Then the remaining segment breaks are either transformed into a space (U+0020) or removed depending on the context before and after the break:

其他瀏覽器的話,IE 原本就有部份支援,只要在 Blink/Webkit 也實做同樣的 spec,這樣大部分的網頁就都不會有問題了。Servo 目前在這部份也是只有簡單 的演算法,也是貢獻的機會!

1

之前這個 Bug 一直在我的「如果我有時間」清單裡,通常就是不會有時間做啦 😆

2

原本的 Markdown 是用 perl 做簡單的文字取代

3

所以說 test coverage 很重要!