Xft字型庫:體系結構及使用者指南(轉)

post0發表於2007-08-09
Xft字型庫:體系結構及使用者指南(轉)[@more@]

Xft字型庫:體系結構及使用者指南

Keith Packard

XFree86 Core Team, SuSE Inc.

keithp@keithp.com

本文由本站會員麥氏賽揚翻譯,manux代為發表,原文排版非常漂亮,但是由於html程式碼問題,發到這裡後只能勉強看懂原意,後面評論裡面將會新增一個下載連線,感興趣的朋友可以下載回去瀏覽。

摘要

X渲染擴充套件(X Render Extension)提供了一個新的基於客戶方字形(glyph)和字型管理的字形渲染體系結構。這個擴充套件設計在解決了許多相關技術難題的同時,也把光柵化字型、配置字型以及定製字型使用的責任交給了每一個X客戶程式。

編寫Xft庫是為了給X應用程式提供一個能訪問FreeType字型光柵化引擎和X渲染擴充套件的、便於使用的介面,鑑於FreeType沒有提供配置和定製字型的功能,Xft也擔負了這一任務。Xft提供了新的字型命名約定、複雜而精密的字型匹配和選擇機制,並對相關功能進行充分的抽象,從而使得一般應用程式既能夠從使用X渲染擴充套件的文字輸出獲得益處,又能在不支援這一擴充套件的X伺服器上正常工作。

1 引言

X渲染擴充套件[Pac01]把訪問字型檔案和生成字形影像的功能從X伺服器移到了X客戶一方。採用客戶方字形管理的X應用程式在以下幾個方面有優勢:可以訪問字型檔案的所有細節,應用程式可以指定特有字型,漸增的光柵化處理(incremental rasterization),並且有可能與其他部件共享字型,例如印表機。此外,鑑於底層的渲染機制基於影像而非字形,字形的光柵化技術、乃至字型檔案格式本身都不再依賴於X伺服器的能力,所以現在新字型技術的整合速度可以跟得上獨立應用程式的開發,而不必遙遙無期地等待新的X伺服器增強技術。

當X伺服器不再負責管理字型檔案的訪問和字形生成,就需要一個新的函式庫在客戶方完成相應的任務。由於X渲染擴充套件在設計上支援消鋸齒(anti-aliased)圖形,這個新的函式庫需要支援高質量的消鋸齒字形光柵化。

FreeType專案[TT00]開發了一個完整的字型光柵化引擎,不僅支援大多數輪廓字型格式,還支援標準的X PCF點陣圖字型,X渲染擴充套件接收字形影像並使之在螢幕上顯現。為了讓應用程式能在螢幕上顯現高質量的文字,所需要做的就是在FreeType和X渲染擴充套件之間放置一層薄薄的“粘合”程式碼。

對於不支援渲染擴充套件的X伺服器,這個函式庫還需要提供訪問“核心”字型(使用原始X核心協議訪問的字型)的能力,這就使得應用程式能在轉向新函式庫時仍然支援老式X伺服器。

FreeType庫沒有指定如何定位字型檔案,而是需要應用程式提供字型檔名,這就把配置和定製可用字型集合的負擔放在了FreeType庫以外,因此,這個新的“粘合”層也需要提供一些配置功能以便在桌面環境中應用。

2 X渲染擴充套件字形管理

X渲染擴充套件提出了幾個簡單抽象供應用程式管理字形。每個Glyph結構包括一個覆蓋字形外形的alpha掩碼(一個描述不透明值的矩形映象)、從 alpha掩碼原點到名義字元原點的偏移量、到下一字形的位移(包括垂直和水平的偏移量),GlyphSet結構則包含了一個字形結構的集合,應用程式使用一個32位的索引對字形集進行編號。

應用程式繪製文字時,把一個GlyphSet識別符號以及一系列針對該GlyphSet的索引傳送到X伺服器,X伺服器透過對指定位置使用字形結構中的偏移量調整確定繪製位置,並渲染alpha掩碼來完成對每個字形的處理,後續字形的繪製位置則是透過在當前原點加上位移向量實現。正如X核心協議中的 PolyText請求,在同一個請求中可以對字形序列作出調整位置、改變GlyphSet等變動,從而使得一個複雜的字串在一次操作中完成渲染。

為了覆蓋世界上更多的民族,作業系統支援的語言和區域集合不斷擴充套件,伴隨這種擴充套件,大多數字體中包含的字形數也大大增加,當今流行的輪廓字型中會包含幾千個字形。十多年前,漸增式渲染字形被看作一種合理的最佳化,現在已成為各種字型機制中的基本組成部分,以儘可能減少每種字型佔用的記憶體,並縮短訪問一種新字型時所需的時間。X渲染擴充套件透過允許在需要時把一個Glyph加入已存在的GlyphSet,提供了這種漸增式渲染支援。由於在新增Glyph的過程中沒有任何從X伺服器到X客戶的資訊流,這一過程可以完全非同步進行。這種非同步性保證了即使面對一個高網路延遲的環境,仍有可接受的效能表現。

當應用程式傳送它們需要顯示的字形影像時,X伺服器透過在任何可能情況下共享相同字形來節省記憶體。

3 FreeType庫

FreeType專案的初衷是要構建一個自由的TrueType字型光柵化器。FreeType的第一版提供了與現有系統相當的高質量TrueType光柵化器,FreeType的第二版對內部結構進行了一般化以支援更多字型格式,除了支援Type-1、OpenType和CID等眾多輪廓字型格式, FreeType現在還支援X的標準PCF格式(可移植編譯格式)的點陣圖字型。

FreeType不僅提供光柵化以及度量字形的介面,還提供存取字型檔案內各種形式的字距調整和字形替換等表格的機制。這就在基礎字型含有相應表格的前提下,使應用程式能夠獲得在各種區域中定位字形所必需的資料。

既然FreeType專案明確地要構建一個通用的字型函式庫,在XFree86開發一個新函式庫的負擔就可以大大減輕,因為可以直接採用現有系統,並提供 “粘合程式碼”改變FreeType資料結構使之使用X渲染擴充套件的要求。這固然使得應用程式需要面對FreeType函式庫可能的變化,但考慮到 FreeType是一個成熟的專案,相對於完全由XFree86開發一個新函式庫的情形,這種變化的嚴重性大概會輕很多。

字型命名和配置不屬於FreeType函式庫,這些“雜務”交給了應用程式。考慮到FreeType應用於各種環境,有些甚至沒有檔案系統,為保證 FreeType得到最大程度應用並獨立於系統策略,這種設計思想是適當的。提供這些支援成為Xft實現中最困難的部分,並且其中一部分可能很快就被替換。

4 XLFD命名

X核心協議規定了用非結構化字串命名字型的方法,X邏輯字型描述(XLFD)[SG92]用於在字串名格式中加入結構資訊。在開發X時,用於桌面計算的輪廓字型還是一個相對新奇的事務,所以X核心協議和XLFD都是基於點陣圖字型設計的,當圍繞縮放字型命名的語法和語義加入XLFD時,基於XLFD的開發已經進行了相當長的時期。

XLFD中字型命名語法的意圖在於僅透過名字就可以嚮應用程式提供足夠的字型資訊,這樣就可以在不訪問字型資料情況下,進行字型選擇和字型列表表示。

XLFD還提供了使用包含“?”和“*”的名字開啟字型的標準策略,使用這類名字時,選中的字型將是第一個匹配的字型,即使用相同模式請求列出字型時返回的第一個。不幸的是,X伺服器儲存字型名時為了高效搜尋,會在各字型目錄中進行內部排序,所以不能保證“*”的預設值是合理的。例如,當在字型名的 weight欄位使用“*”時,X伺服器會把bold字型列在normal字型之前。

這個策略真正失敗之處在從point(點值)尺寸到pixel(畫素)尺寸的對映。XLFD在字型名中分別提供了兩個軸向上的pixel尺寸、point 尺寸和resolution(解析度),標準的X字型按照解析度分別存放,“75dpi”和“100dpi”下各自存放著與該解析度匹配的各種點值尺寸的字型,其他字型目錄下一般是為了在75dpi螢幕光柵化。

協議指導X伺服器按照在字型路徑(譯註:font path,應指配置檔案中相應節)中出現的順序去搜尋字型目錄,這就使字型路徑決定了對解析度的傾向性。如果100dpi的目錄列在前面,當應用程式在字型名的resolution欄位用“*”時,只要在100dpi目錄下存在匹配字型就會使用該字型,否則才去嘗試75dpi的字型。

應用程式如果在字型名中僅指定point尺寸,而在resolution欄位使用“*”,那麼最終將會得到一組隨即尺寸的字型:那些在100dpi目錄下發現的字型按照100dpi螢幕光柵化,其他字型則按照75dpi螢幕光柵化從而會顯得小一些。

最終的結果是XLFD的字型匹配充滿了危險,應用程式經常列出所有可用字型(作出選擇)然後提交完整XLFD字型名(譯註:不含“?”和“*”)給X伺服器。

XLFD的另一個問題是在字型名中包含了字形的平均寬度欄位。對於需要在不同總體寬度的字型中進行選擇的應用程式而言,這是個非常有用的資訊,而且對點陣圖字型也很容易計算。但是對輪廓字型,除非在指定尺寸下對每個字形進行光柵化計算,該欄位值不能算出。僅僅列出一個特定尺寸下所有的可用字型就會導致光柵化每一個字型的每一個字形。

XLFD提供了關於可用字型的有用資訊,出列平均寬度,這些資訊都是容易計算並交付應用程式的。使用XLFD的應用程式應該在本地管理XLFD字型名,而不要依賴伺服器方字型匹配,也就是透過列出可用字型收集資訊,再利用這些資訊構造完整字型名。

鑑於XLFD沒有提供一種按照語義匹配的合理方案,需要有新方案允許在應用程式給定一組約束情況下,基礎的字型系統能夠定位一個適當的字型。這樣的系統需要有足夠的靈活性以便能夠包含現在不能預料的新字型特性,也不需要應用程式完全指定字型的方方面面。

5 設計一個新函式庫

Xft在三個方面與環境互動:透過程式設計介面與應用程式互動,透過配置檔案與系統互動,透過讓使用者指定字型名與使用者互動。雖然這三方面在函式庫中緊密相關,但從設計角度來說,它們是分離的。

5.1 應用程式介面設計

Xft的首要目標是把FreeType的輸出和X渲染擴充套件結合起來,但是,為了Xft能作為現有的Xlib文字輸出例程的替代物而被人接受,其次要目標包括支援核心X字型,儘管這樣做可能以損失應用程式功能為代價。

由於FreeType不提供字型選擇功能,所以Xft的一部分要進行字型匹配。採用現有的XLFD機制會極大地限制字型匹配地能力,所以Xft提出了一種新格式。這種選擇機制被設計為總能匹配某種字型,允許應用程式假設適當地字型存在,避免在每個級別上都要考慮失敗回落。

另一個要求是函式庫要提供合理地匹配,例如需要italic(斜體)字型時用oblique(傾斜)字型代替,在不指定weight要求時使用中等 weight的字型。這允許應用程式在指定字型時不必指定所有的特徵,而且可以期望得到合理的結果。當應用程式的請求存在相互矛盾時,決定哪些特徵更重要的政策能提供解決方案。

為了在函式庫級別上簡化可選的文字編碼,所有的文字輸出例程只接受Unicode編碼的資料。其他的編碼需要由應用程式負責轉換,無論是在作業系統邊界還是應用程式與Xft之間。由於大部分現存的字型一般都有Unicode編碼(譯註:指其內部檢索採用的編碼方式,可能有多種,置於不同表格結構,這取決於具體的字型檔案格式),或是某種易於轉換到Unicode的編碼,這個策略顯著地簡化了函式庫地內部結構,同時以一致的檢視呈現於應用程式之前。

另一個重要目標是儘可能避免把內部資料結構暴露給應用程式。X渲染擴充套件允許漸增式下載新字形,設計Xft時允許按需光柵化新字形,這就要求(字形的)度量資訊透過一個函式獲取,而不是象Xlib中那樣直接訪問相應資料結構。

最後,Xft被設計為一個完整的字型訪問函式庫,所以底層的FreeType資料型別未被隱藏,以便應用程式可以直接使用FreeType自身。這降低了Xft的複雜度,同時允許應用程式完全存取可用的字型資訊。

5.2 字型命名設計

Xft字型命名設計方案最初源於這樣的觀念,即字型名應該反映字型屬性,不管是應用程式想要的屬性還是字型自身的屬性。由於應用程式的需求並不固定,而字型的特性也不斷得到增強,下述想法逐漸形成:字型名應該用一個可變的指定屬性列表表示,每個屬性有一組相關值。允許屬性有多個值,提供了為字型的家族(family)名或風格(style)等屬性指定可接受的替代值的能力。

這一設計統一了應用程式的字型請求和可用字型的表示。一個XftPattern是一組指定屬性,每個屬性有一個或多個值。每個可用字型用一個給出了該字型特性的XftPattern來描述。應用程式構造一個描述了其請求的XftPattern,該XftPattern其後將與所有描述可用字型的 XftPattern進行匹配,與應用程式請求最匹配的可用字型將被選中。這種“最近匹配”機制保證每個應用程式字型請求都能匹配一個字型,雖然該字型的精確特性可能與應用程式的請求有一定差別。

一種XftPattern的文字表示方法最終被設計出來,這就允許應用程式在很大程度上象當前一樣使用字串去選擇字型。

XftPattern提供了一種簡單但可擴充套件的機制,供應用程式與所使用的字型之間傳達請求和能力,具體的用法在第6節描述。

5.3 字型列表設計

X核心協議提供了支援查詢可用字型集合的原語,簡單的、shell風格的模式(Pattern)傳送到X伺服器,匹配該模式的字型名集合被返回。只有獲得幾乎包括系統中所有字型的列表,才能發現可用的字型家族集合。應用程式要負責從這些大量資料中提取有用資訊。

真正需要的是能向系統請求特定的相關資訊,並由系統丟棄多餘資料。應用程式可以專注於檢驗和操作資訊,而不是花費很大氣力去解析XLFD字串。

Xft把用於返回可用字型資料的資訊分為兩部分,第一部分是從可用字型中做選擇所需的模式,第二部分是決定應用程式有興趣接收資訊的一組屬性名。匹配字型的列表將被修剪,以消除在所選屬性中重複的項。

最後需要說明的是,“最好匹配”的觀念在列出字型時沒有用,應用程式用字型列表為使用者產生對話方塊,或者用來發現字型家族的能力。這時,需要對模式中的每個元素做精確匹配,而不是測量可用字型與請求模式的差距(以尋找最好匹配——譯註)。

5.4 配置設計

為避免可能在字型配置和定製機制出現互不相容的分支,需要一個標準。鑑於沒有可用的現有標準,在Xft中加入字型配置至少能保證X應用程式使用相同方式共享和命名字型。

一個基本的定製需求是允許一種字型作為另一種字型的替代,這種“別名”機制能在某種字型不可用時,選擇擁有近似特性的字型來維護文字的外觀統一。另一個有用的任務是支援一般的“mono”、“sans”和“serif”字型,應用程式可以在大多數情況下按照使用者偏好選用。

另一個目標是要使新增字型儘可能容易。核心X字型配置機制使用X伺服器字型路徑列出所有查詢字型的目錄集合,在每個目錄下,需要生成兩個單獨的配置檔案來進行字型名到檔名的對映。如果這些檔案丟失或損壞,就不能正確地進行字型選擇。不再使用這些配置檔案,會使系統總體上更加健壯。

最後,使用者和管理員需要定製特定字型的光柵化。一些使用者希望避免對某些字型、或是某些尺寸範圍內的字型使用消鋸齒功能,另一些需要對某些字型調整尺寸和間距。

實際上,Xft並非放置所有這些配置功能的正確場所,因為X應用程式並不是唯一對訪問字型和字型資訊感興趣的程式。把這些配置機制移出Xft,放在一個能被非X應用程式使用的函式庫,將是近期開發的焦點(譯註:該功能已經移到FontConfig函式庫。)

6 Xft字型名

Xft的字型名用一個指定屬性的列表表示,其中每個屬性帶有一個有型別值的列表,這個屬性集合存放在XftPattern資料結構中。有一些例程用於建立、編輯XftPattern以及進行與可用字型列表進行匹配的操作。Xft有一些內部支援的屬性,如表1中所示;但是並不限制應用程式僅使用這些屬性, Xft會忽略所有不理解的屬性。

為了讓XftPattern能夠傳輸和儲存,一個模式的結構能用一個字串表示。這些字串的格式如圖1所示。每一個支援的(屬性)名字有一個隱含型別,以便解析相關值,這樣就避免使用引號或其它詞法機制來區分不同型別。一些指定常量可以取代一些值或者完整的“name=value”對,因為常量唯一確定了相關屬性名字,沒有必要再顯式給出名字。表2給出了可用的常量列表。這些常量中的每一個在內部都用一個值表示,這就允許在應用程式請求的值和可用字型的值之間進行相似匹配。例如,一個應用程式請求“demibold”時,會選中“bold”而不是“medium”。這有助於達成應用程式的意圖,即使在開發和測試過程中沒有與之匹配的可用字型。

名字 型別 C語言名

family String XFT_FAMILY

style String XFT_STYLE

slant Int XFT_SLANT

weight Int XFT_WEIGHT

size Double XFT_SIZE

pixelsize Double XFT_PIXEL SIZE

encoding String XFT_ENCODING

spacing Int XFT_SPACING

foundry String XFT_FOUNDRY

core Bool XFT_CORE

antialias Bool XFT_ANTIALIAS

xlfd String XFT_XLFD

file String XFT_FILE

index Int XFT_INDEX

rasterizer String XFT_RASTERIZER

outline Bool XFT_OUTLINE

scalable Bool XFT_SCALABLE

rgba Int XFT_RGBA

scale Double XFT_SCALE

render Bool XFT_RENDER

minspace Bool XFT_MINSPACE

dpi Double XFT_DPI

charwidth Int XFT_CHAR WIDTH

charheight Int XFT_CHAR HEIGHT

matrix Matrix XFT_MATRIX

表1 Xft字型名屬性

name : families sizes properties

families : family-names

|

family-names : family-names ,string

| string

sizes : -size-list

|

size-list : size-list ,number

| number

properties : properties :property

|

property : string =value

| named-constant

value : string

| number

| boolean

| named-constant

| matrix

matrix : number number number number

Examples:

times,serif-12:italic

courier,mono-14:matrix=1 .1 0 1

圖1: Xft字型名語法.

另外,雖然XLFD字型名不理想,但是它在現有的X應用程式中很常見,而且也表達了一組期望的字型特性。Xft能夠把XLFD字型名轉換成XftPattern,以便能使用Xft匹配規則選擇字型,而不用第4節中所述的XLFD匹配規則。

名字 常量 值

weight light 0

medium 100

demibold 180

bold 200

black 210

slant roman 0

italic 100

oblique 110

spacing proportional 0

mono 100

charcell 110

rgba rgb 1

bgr 2

vrgb 3

vbgr 4

表2 Xft字型名常量

Xft字型名被設計為可擴充套件,以便即使Xft/FreeType2介面繼續成長併為新系統提供模式元素情況下,現有應用程式依然能夠正確運轉。

7 Xft配置檔案

使用核心協議,應用程式保證可以存取所有可用字型,因為由X伺服器負責定位字型;現在字型管理移到了客戶方,定位字型成為應用程式的責任。沒有了可以共享的集中配置機制,每個應用程式可用的字型集合都可能有很大不同,安裝和選擇字型就可能有問題或者出錯。

Xft配置檔案的主要作用是指定可用字型檔案的位置,其次是調整字型選擇以及定製光柵化引數。

預設情況下,Xft的配置檔案“XftConfig”在/usr/X11R6/lib/X11目錄下,但可以透過在XFT_CONFIG環境變數中指定一個不同的檔名來改變。

檔案中任何地方都可以放置註釋,“#”字元將使其後直到行尾的部分成為註釋。其他的語法將在下面幾節說明。

7.1 字型目錄

在配置字型所在位置時,Xft使用了一種極為簡單的方法。指定一個目錄的列表,Xft在這些目錄中查詢字型檔案,所有找到的字型檔案將被加入用於匹配的可以字型列表。(字型)在目錄中的位置是無關緊要的,因為Xft總是在所有字型中進行最佳匹配。在配置檔案中,用如下格式的行來指定目錄:

dir "/usr/X11R6/lib/X11/fonts/Type1"

在目錄下不再需要其他配置,Xft自動掃描目錄來發現字型。

7.2 巢狀配置檔案

為了把配置檔案劃分為便於管理的部分,也為了允許基於使用者的函式庫定製,Xft配置檔案中允許出現如下格式的行:

include "/usr/local/lib/XftAliases"

includeif "~/.xftconfig"

兩種格式的唯一區別在於:使用第一種格式,當被引用的檔案找不到時,會發出警告訊息。“~”字元指的是使用者的主目錄。因為Xft配置檔案由使用者的應用程式自己進行解析,這就能在不管X的顯示(display)情況下,實現基於使用者的定製。

7.3 字型模式編輯

為了能在字型匹配過程中實現字型替換以及其他的調整,也為了能配置光柵化過程,Xft配置檔案中可以包含一些操作,這些操作能在匹配過程結束前修改Xft模式。這些操作被稱為“編輯命令”(editing commands),與模式匹配時執行以修改模式,每個命令按照它們在配置檔案中出現的順序執行。這些命令的語法示於圖2。

command : match tests edit edits

tests : test tests

|

test : any | all name compare value

compare : == | != | < | <= | > | >=

edits : edit edits

|

edit : name eqop expr ;

eqop : = | += | =+

expr : value

| name

| expr binop expr

| !expr

| expr ?expr :expr

binop : || | && | == | != | < | <= | > | >= | + | - | * | /

Examples:

# Use LuciduxSerif as default serif’ed font

match any family == "serif"

edit family += "LuciduxSerif";

# Avoid using anti-aliasing at some sizes for LuciduxSerif face

match any family == "LuciduxSerif" any size < 14 any size > 8

edit antialias = false;

圖2 Xft模式編輯語法

match子句用來選擇待編輯的模式,其值為“真”時才會進行編輯。如果表示式使用“any”字首,那麼當與指定欄位相關的任何值符合條件時,子句取“真”值;如果表示式使用“all”字首,那麼只有當所有值符合條件時,子句才取“真”值。

edit子句在模式的欄位上操作,可以替換或者修正相關值。如果在match子句中引用模式中同一元素,則匹配值將被標記。

在edit子句中,“+=”運算子把值插入標記值之前,“=+”運算子把值插入標記值之後,“=”運算子則替換標記值。如果沒有值被標記,“+=”和“=+”運算子分別把值加入整個值列表的頭和尾,“=”運算子將會替換所有的值。

表示式中的運算子的含義都很明顯,一種可能有些意外的情況,是“+”運算子可以用於連線字串。表示式中可能引用字型中的某些欄位,這種情況下,使用該欄位的第一個值。

使用此機制幾個月後,發現這種機制很複雜,並且完成不了一些預期的任務。缺陷之一是編輯隻影響進入的模式,而不對匹配的字型進行任何操作。這使得禁止 LuciduxSerif字型消鋸齒效果的例子(譯註:圖2中的第二個例子)產生非預期的結果,例如,當以如下名字指定字型時,

Times,LuciduxSerif,serif-10

match子句將會成功匹配該模式,從而導致Times字型在顯示時失去了消鋸齒效果。

另一個問題是字型別名含義不清,目前還沒有提供精確語義。關於字型別名,有兩種可能的語義:一種是在任何情況下都用一種字型替換其它,另一種是隻有當某些字型不存在時,才用特定字型替換。關於這一點的明確宣告既能澄清檔案格式,也有助於改進匹配的語義。(譯註:本段中的“字型”對應原文的face)

8 字型匹配

Xft中字型匹配的目標是從應用程式接收一組字型特性的描述,然後從所有可用字型中返回最好的。應用程式呼叫XftFontMatch函式,並提供 XftPattern形式的字型規格說明。模式按照7.3節中所描述的方式進行編輯,表3所示的X資源可以用來修改模式。如果應用程式沒有指定畫素尺寸,將根據指定的點值尺寸(如果也沒有指定,使用12.0)乘以縮放因子,再利用指定的dpi值將點值轉換為畫素。其他的X資源用作相關模式元素的預設值。

X資源 型別 效果 預設值

Xft.render Bool 指導Xft使用客戶方字型 HasRender

Xft.core Bool 指導Xft使用伺服器方字型 !HasRender

Xft.antialias Bool 選擇字形是否需要消鋸齒 True

Xft.rgba Number 指定LCD螢幕上的子畫素順序 0

Xft.minspace Bool 消除行間的額外間距 False

Xft.scale Number 所有字型點值尺寸的縮放因子 1.0

Xft.dpi Number 用於從點值尺寸轉換為畫素尺寸 螢幕的垂直dpi

表3 用X資源調整Xft值

完整的模式隨後將用於與所有可用字型進行比較,只有表4中所示的欄位在比較中有用。表中欄位的順序是有意義的,表中靠前的元素不匹配將使後面元素的匹配變得無效。如果模式或字型缺少某一元素,將預設為匹配。數字值按照其差值的大小進行度量,這就是為什麼指定“oblique”將選擇“italic”,而不是“roman”。(譯註:參見表2的常量定義。)

Order Name Type

1 foundry String

2 encoding String

3 antialias Bool

4 family String

5 spacing Number

6 pixelsize Number

7 style String

8 slant Number

9 weight Number

10 rasterizer String

11 outline Bool

表4 Xft欄位比較的匹配順序

有多個值的欄位傾向於匹配列表中靠前項的字型,按照這種方式,下面名字將相對於“LuciduxSerif”優先匹配“Times”。

Times,LuciduxSerif,serif-10

一但選中了某一字型,將會構造一個能精確描述該字型的XftPattern,以便應用程式知道究竟選用了什麼字型。這個模式包括底層字型檔案的資訊,從而允許應用程式直接透過FreeType訪問未獲得的資訊。在模式中有、而字型中沒有的欄位也被加上,這就允許應用程式之間交換字型模式的資訊,這種通訊既可以在應用程式與光柵化器之間,也可以在應用程式自身發生。

9 X核心字型處理

雖然Xft的主要目標是在FreeType和X渲染擴充套件基礎上,提供客戶方字型支援,但是為了在X渲染擴充套件不可用時提供應用程式相容性,同時X核心字型支援也是合理的。這必然限制函式庫的能力,但即使這樣,很多應用程式無論使用X核心字型或基於渲染擴充套件字型機制時,不加修改地使用Xft函式,另一些則只需作一些小小的改動以便注意到何時不能使用FreeType函式。

核心字型處理有兩個部分:字型選擇和渲染。字型選擇是透過列出可用的X字型,將其轉換為XftPattern結構,然後從應用程式接收模式進行匹配。由於按照接近程度進行匹配,而不是採用簡單的shell模式匹配,一般情況下,這種匹配得到的結果要比用XLFD指定更有用。這有助於簡化應用程式的設計,因為在此之前它們需要包含可觀的、用於X核心字型匹配的機制。

一但選定某種核心字型,渲染就成為簡單的事情:可以讓Xft例程呼叫標準Xlib中文字繪製例程。唯一的困難是把應用程式提供的Unicode字形對映到字型所支援的編碼。

這種合併的效果之一是Xft渲染例程只提供那些渲染擴充套件和核心字型都支援的能力。應用程式可以為繪製指定半透明的顏色值,但是如果使用的是核心字型,該指定將被忽略。類似地,Xft不提供選擇光柵化操作或者組合操作(譯註:X渲染擴充套件在伺服器方的基本設計思想是基於影像組合操作),因為它們都只被底層的一種渲染機制支援。最終的結果是一種新的使用核心字型的方式,相對於Xlib中的對應物,在許多方面更容易使用,並且功能更強大。

10 Xft介面總覽

Xft程式設計介面很容易劃分到三個單獨區域:處理XftPattern以及匹配字型、在螢幕上繪製字形、用於提供底層FreeType函式庫介面的一小部分。

10.1 Xft資料結構

XftValue

typedef enum _XftType {

XftTypeVoid,

XftTypeInteger,

XftTypeDouble,

XftTypeString,

XftTypeBool,

XftTypeMatrix

} XftType;

typedef struct _XftValue {

XftType type;

union {

char *s;

int i;

Bool b;

double d;

XftMatrix *m;

} u;

} XftValue;

一個XftValue存放一個XftPattern元素的一個值,應該作為一個加了標籤的聯合來對待:使用聯合前應該先設定或檢查“type”欄位。字串或者矩陣元素單獨存放,Xft從應用程式接收XftValue結構後,總是根據這些指標複製資料,這就使得應用程式自由地決定使用靜態或是堆疊中的儲存。

XftPattern

typedef struct _XftPattern

XftPattern;

XftPattern是一個不透明地資料結構,用於存放一個指定元素的列表,而每個元素又有一個XftValue的列表。Xft為構建和查詢這些模式提供了介面。

XftFont

typedef struct _XftFont {

int ascent;

int descent;

int height;

int max_advance_width;

Bool core;

XftPattern *pattern;

union {

struct {

XFontStruct *font;

} core;

struct {

XftFontStruct *font;

} ft;

} u;

} XftFont;

當開啟字型時,返回XftFont資料結構,並用於繪製字形。其可見成員提供了關於字型的少量資訊。如果core的值為真,底層使用X核心字型,這時u.core.font 指向一個 XfontStruct結構;否則底層使用FreeType字型而u.ft.font欄位引用XftFontStruct結構。

XftFontStruct

typedef struct _XftFontStruct

XftFontStruct;

struct _XftFontStruct {

FT_Face face;

GlyphSet glyphset;

int min_char;

int max_char;

FT_F26Dot6 size;

int ascent;

int descent;

int height;

int max_advance_width;

int spacing;

int rgba;

Bool antialias;

int charmap;

XRenderPictFormat *format;

XGlyphInfo **realized;

int nrealized;

Bool transform;

FT_Matrix matrix;

};

也許這個結構將來會隱藏起來,用一些適當的函式訪問某些內部欄位。最有用的欄位當屬“face”,用於引用底層的FreeType物件,但是在記憶體中儲存這類物件開銷太大,所以這些應該被緩衝並且按需調入。應用程式在使用該欄位時,明智的方法是透過宏包裝,以備將來該欄位不再可見。關於該結構其他欄位的可見性還需進一步核查。

XftDraw

typedef struct _XftDraw

XftDraw;

XftDraw封裝了在X可畫物上渲染字形所需的狀態。對於使用渲染擴充套件的情況,需要Picture,對於使用X核心協議情況,需要GC和相關畫素值。(譯註:可畫物,drawable,是Xlib程式設計基本概念,包括window和pixmap)

XftColor

typedef struct _XftColor {

unsigned long pixel;

XRenderColor color;

} XftColor;

渲染擴充套件需要RGBA,而X核心需要畫素值;XftColor儲存了二者,並有相應例程來初始化以及釋放相關資源。對於真彩色可視型別,分配例程為了避免往返傳遞的開銷,在本地計算畫素值,這樣來消除效能下降。如果已知將使用渲染擴充套件,“color”成員可以手動初始化而不去設定“pixel”的值。(譯註:可視型別,visual type,是Xlib程式設計基本概念,可以是StaticGray, StaticColor,TrueColor, GrayScale, PseudoColor, 或DirectColor之一)

XftObjectSet

typedef struct _XftObjectSet

XftObjectSet;

Xft的字型列示機制使用XftObjectSet來限制返回給應用程式的資料總量,XftObjectSet用於存放一個欄位名的列表。

XftFontSet

typedef struct

_XftFontSet {

int nfont;

int sfont;

XftPattern **fonts;

} XftFontSet;

XftFontSets指向一組模式集合,用作字型列示函式的返回值。

XftResult

typedef enum _XftResult {

XftResultMatch,

XftResultNoMatch,

XftResultTypeMismatch,

XftResultNoId

} XftResult;

需要返回搜尋結果的函式使用這個資料型別來表示它們的發現,XftResultMatch表示發現了物件XftResultNoMatch說明沒有發現匹配物件,XftResultTypeMismatch說明發現了某個物件,但是型別不對,XftResultNoId說明發現了物件,但是比請求的值少。

10.2 字型模式操作

許多Xft操作涉及XftPattern物件,鑑於應用程式不應該直接訪問這些物件,有一組例程用於操作它們。

XftPatternCreate

XftPattern *

XftPatternCreate (

void)

建立一個空的模式。

XftPatternDuplicate

XftPattern *

XftPatternDuplicate (

XftPattern *p)

建立一個新模式,其所有值源自“p”所指物件。如果值引用其他儲存(字串和矩陣),相關儲存將被複制到新分配儲存區中。

XftPatternDestroy

void

XftPatternDestroy (

XftPattern *p)

釋放所有相關的儲存,包括模式中引用的字串和矩陣。

XftPatternAdd

Bool

XftPatternAdd (

XftPattern *p,

const char *object,

XftValue value,

Bool append)

把“value”加入“object”欄位的值列表中。如果“append”為True,值將被加到列表尾部,否則插入到頭部。如果 “value”引用字串或者矩陣,XftPatternAdd將分配新儲存區並複製,只有在分配空間失敗時,XftPatternAdd才返回 False。此函式是其他XftPatternAdd函式的基礎。

Bool

XftPatternAddInteger (

XftPattern *p,

const char *object,

int i)

Bool

XftPatternAddDouble (

XftPattern *p,

const char *object,

double d)

Bool

XftPatternAddString (

XftPattern *p,

const char *object,

const char *s)

Bool

XftPatternAddMatrix (

XftPattern *p,

const char *object,

const XftMatrix *s)

Bool

XftPatternAddBool (

XftPattern *p,

const char *object,

Bool b)

這些函式中的每一個都會建立適當型別的臨時XftValue,並作為引數傳遞給XftPatternAdd,呼叫時“append”設為True。

XftPatternGet

XftResult

XftPatternGet (

XftPattern *p,

const char *object,

int id,

XftValue *v)

XftPatternGet搜尋指定的模式,找到名字與“object”匹配的元素,然後在值列表中找到第“id”個(從0開始計數)個元素,把結果值存入“v”。此函式不為字串和矩陣分配儲存區,所以應用程式必須確保不在XftPattern自身的生存期之外引用該值。此函式是其他 XftPatternGet函式的基礎。

XftResult

XftPatternGetInteger (

XftPattern *p,

const char *object,

int n,

int *i)

XftResult

XftPatternGetDouble (

XftPattern *p,

const char *object,

int n,

double *d)

XftResult

XftPatternGetString (

XftPattern *p,

const char *object,

int n,

char **s)

XftResult

XftPatternGetMatrix (

XftPattern *p,

const char *object,

int n,

XftMatrix **s)

XftResult

XftPatternGetBool (

XftPattern *p,

const char *object,

int n,

Bool *b)

這些函式中的每一個都呼叫XftPatternGet。如果結果的資料型別與函式不匹配,函式將返回XftResultTypeMismatch,否則與XftPatternGet的返回值相同。

XftPatternBuild

XftPattern *

XftPatternBuild (

XftPattern *orig,

...)

“orig”之後的引數構成了一個用於加入到指定模式的名字、型別和值的列表,如果“orig”為空,將分配一個新模式。模式引數的格式如下:

char *object,

XftType type,

union {

char *s;

int i;

Bool b;

double d;

XftMatrix *m;

} u

列表用一個空物件結束,例如:

p = XftPatternBuild (

0,

XFT_FAMILY,

XftTypeString,

"mono",

XFT_SIZE,

XftTypeDouble,

12.0,

0);

這個函式是一個便捷函式,它把若干XftPatternAdd呼叫封裝到一個語句,其語義與作一組相當的XftPatternAdd呼叫是一樣的。

XftPattern *

XftPatternVaBuild (

XftPattern *orig,

va_list va)

這個函式使用變參列表,其引數格式與XftPatternBuild 一致,產生結果也一樣。

10.3 字型選擇

Xft的字型選擇函式分若干級別,所用到的模式既可以由簡單的字型名字串隱含生成,也可以由應用程式顯式管理,在交付下層匹配介面前進行操作。作為最基本的級別,Xft提供:

XftFontMatch

XftPattern *

XftFontMatch (

Display *dpy,

int screen,

XftPattern *pattern,

XftResult *result)

此函式用應用程式生成的XftPattern進行配置檔案編輯和X資源替換(譯註:見第7、8節),然後把得到的模式在可用字型集合中匹配,最接近的字型名以另一個XftPattern的形式返回,該模式包含足夠的資訊以使用XftFontOpenPattern函式開啟字型。如果失敗,返回值為0,並且在“result”中放置錯誤指示。

XftFontOpenPattern

XftFont *

XftFontOpenPattern (

Display *dpy,

XftPattern *pattern)

XftFontOpenPattern接受匹配的字型模式,為字型建立XftFont結構。返回的XftFont包含一個對傳入模式的引用,該模式將在以該XftFont為引數呼叫XftFontClose時被銷燬。

XftFontOpen

XftFont *

XftFontOpen (

Display *dpy,

int screen,

...)

“screen”之後的引數構成了一個暗含的XftPattern,如同10.2節對XftPatternBuild引數的描述。下面是一個例子:

f = XftFontOpen (

dpy,

DefaultScreen(dpy),

XFT_FAMILY,

XftTypeString,

"mono",

XFT_SIZE,

XftTypeDouble,

12.0,

0);

根據這些引數可以建立一個模式,將其作為引數呼叫XftFontMatch,返回結果有傳遞給XftFontOpenPattern,最終產生本函式的返回值。

XftFontOpenName

XftFont *

XftFontOpenName (

Display *dpy,

int screen,

const char *name)

與XftFontOpen類似,“name”引數構成暗含的XftPattern,XftFontMatcn和XftFontOpenPattern以同樣方式被呼叫以最終得到匹配的XftFont。

XftFontOpenXlfd

XftFont *

XftFontOpenXlfd (

Display *dpy,

int screen,

const char *xlfd)

除了透過解析“xlfd”指向的XLFD字型名得到XftPattern以外,此函式與XftFontOpenName完全相同。

XftFontClose

void

XftFontClose (

Display *dpy,

XftFont *font)

下層的核心或者FreeType字型物件被關閉,字型引用的模式被銷燬。

10.4 XftDraw操作

Xft提供了可以遮蔽X核心和渲染擴充套件這兩種不同渲染機制之間差異的一種抽象,XftDraw物件提供了兩種模式的操作物件,幷包裝了兩種渲染模型所需的適當資訊。

XftDrawCreate

XftDraw *

XftDrawCreate (

Display *dpy,

Drawable drawable,

Visual *visual,

Colormap colormap)

此例程建立一個XftDraw物件,引用所涉及的可畫物以及相關的可視型別及顏色圖。即便使用指定了最終畫素的畫素圖(pixmap)進行渲染,也需要指定visual引數。

XftDrawCreateBitmap

XftDraw *

XftDrawCreateBitmap (

Display *dpy,

Pixmap bitmap)

如果渲染目標是1位的點陣圖,應使用此函式,而非XftDrawCreate。

XftDrawChange

void

XftDrawChange (

XftDraw *draw,

Drawable drawable)

此函式切換下層的渲染目標,但不會影響XftDraw物件的其他屬性。應用程式應負責保證新的可畫物與原來的可畫物有相同的可視型別。

XftDrawDisplay,XftDrawDrawable,

XftDrawColormap,XftDrawVisual

Display *

XftDrawDisplay (

XftDraw *draw)

Drawable

XftDrawDrawable (

XftDraw *draw)

Colormap

XftDrawColormap (

XftDraw *draw)

Visual *

XftDrawVisual (

XftDraw *draw)

這些函式簡單地從不透明地XftDraw結構中返回相關值。

XftDrawDestroy

void

XftDrawDestroy (

XftDraw *draw)

此函式將銷燬XftDraw物件及其分配的任何私有資料,但引用的X可畫物並不銷燬。

10.5 字形渲染

有了XftFont和XftDraw,下一步就是使用它們在螢幕上顯示文字。這相對簡單,因為只用Unicode編碼,唯一需要改變的是如何儲存字形。在這一節中還給出了一些便利函式,讓應用程式能使用與其他操作類似的資料結構。

XftTextExtents

void

XftTextExtents<8,16,32,Utf8> (

Display *dpy,

XftFont *font,

XftChar<8,16,32,8> *string,

int len,

XGlyphInfo *extents)

這些函式測量指定字串的顯示寬度,並在“extents”結構中返回。

XftDrawString

void

XftDrawString<8,16,32,Utf8> (

XftDraw *d,

XftColor *color,

XftFont *font,

int x,

int y,

XftChar<8,16,32,8> *string,

int len)

這些函式中的每一個顯示一個字串。若用渲染擴充套件,使用Over操作繪製字串;若用核心機制,使用GXcopy繪製並且作用於所有平面。(譯註:原文最後一句為it is painted with GXcopy and a full planemask,plane指特定可視型別下的顏色平面,planemask是GC的成員,按位標記平面,說明繪製操作影響哪些平面;with a full planemask意味著影響所有平面)

XftDrawRect

void

XftDrawRect (

XftDraw *d,

XftColor *color,

int x,

int y,

unsigned int width,

unsigned int height)

這個簡單的函式用指定的顏色畫一個矩形。

XftDrawSetClip

Bool

XftDrawSetClip (

XftDraw *d,

Region r)

透過指定區域來設定XftDraw的裁減區(clip)列表,以後可能會增加使用矩形列表來指定區域的等同函式。

10.6 字型列示

Xft提供一套相對複雜的機制來列示可用字型,此機制不僅可以列出可用的字型face,還可以在不返回無關資料的前提下列出某種特定face的可用風格。為達到這個目標,應用程式在提供用於字型匹配的模式外,還要說明字型模式中哪些欄位是重要的;對每種匹配的字型,都會根據應用程式提供的 XftObjectList選中的欄位生成返回列表中的一項,由這些項構成的無重複集合將返回給應用程式。

列出字型是一個獨立於開啟字型的基本過程,此過程中模式如何匹配字型的語義與10.3節中有所不同。在這種上下文中,匹配要求模式中每個元素必有值與相關字型元素精確匹配。

XftObjectSetCreate

XftObjectSet *

XftObjectSetCreate (

void)

建立一個空的XftObjectSet。

XftObjectSetAdd

Bool

XftObjectSetAdd (

XftObjectSet *os,

const char *object)

在XftObjectSet中新增一個欄位名。會分配新的儲存區,並從引數中複製欄位名,這樣就允許應用程式能釋放或重用其儲存空間。

XftObjectSetDestroy

void

XftObjectSetDestroy (

XftObjectSet *os)

The XftObjectSet is destroyed along with any other

referenced storage.

XftObjectSetBuild, XftObjectSetVaBuild

XftObjectSet *

XftObjectSetBuild (

const char *first,

...)

XftObjectSet *

XftObjectSetVaBuild (

const char *first,

va_list va)

XftObjectSetBuild透過NULL結束的物件名列表建立XftObjectSet,使用此函式能快速構建一個名字的常量集合而避免一長串函式呼叫,其語義效果等同於一系列呼叫。XftObjectSetVaBuild使用一個可變引數列表完成同樣的工作。

XftListFontsPatternObjects

XftFontSet *

XftListFontsPatternObjects (

Display *dpy,

int screen,

XftPattern *pattern,

XftObjectSet *os)

對匹配“pattern”的每種字型生成一個新的模式,其中僅包括“os”所指定的元素;此函式把得到的新模式合併後返回,以保證其中沒有重複的模式。

XftListFonts

XftFontSet *

XftListFonts (

Display *dpy,

int screen,

...)

可變引數包括一個NULL結束的模式元素列表,與10.2節中關於XftPatternBuild的描述一致,其後還有一個NULL結束的欄位名列表,與本節中關於XftObjectSetBuild的描述一致。根據引數生成模式和物件集合後,此函式呼叫 XftListFontPatternObjects並直接返回撥用結果。

10.7 訪問FreeType

在需要與底層的FreeType函式庫或渲染擴充套件需要更復雜互動的地方,Xft提供一些函式以便直接訪問。

XftFreeTypeGet

XftFontStruct *

XftFreeTypeGet (

XftFont *font)

此函式返回給定字型的底層XftFontStruct物件,當底層字型不是FreeType時返回NULL。

XftRenderString

void

XftRenderString<8,16,32,Utf8> (

Display *dpy,

Picture src,

XftFontStruct *font,

Picture dst,

int srcx, int srcy,

int x, int y,

XftChar<8,16,32,8> *string,

int len)

這四個相關函式都提供相對於使用渲染擴充套件畫文字更強的控制,它們提供一個任意源圖片(picture),用於填充文字。應用程式使用這些例程,還能更有效地緩衝源圖片。(譯註:Picture可能是FreeType引入的資料結構)

11 字型資訊緩衝

如同7.1節所述,函式庫透過掃描配置檔案中列出的目錄生成可用字型集合。要發現字型的特性需要使用FreeType開啟字型檔案,一大批檔案需要處理,這可能會花費相當長的時間,尤其是字型很多的情況。

為提高此操作的效能,Xft在兩個地方快取搜尋結果。每個目錄下可能有一個名為XftCache的檔案,其中每一行列出了字型檔名、字型在檔案的索引以及用XftPattern字串格式表示的字型資訊。如果一種字型沒有在任何XftCache檔案中發現其資訊,Xft會在使用者主目錄下生成一個. xftcache檔案,其中包含字型檔名、字型索引、檔案修改時間和XftPattern。

XftCache檔案由xftcache程式建立,該程式是Xfree86釋出的一個標準部件。鼓勵使用者在要加入Xft配置檔案的其他目錄下執行此程式,並且每當目錄內容改變時重新執行。Xft會自動管理每使用者的.xftcache檔案內容,僅存放那些不在任何XftCache檔案中的未知字型。

Xft仍然會在開始時掃描每個目錄,但是會在使用FreeType開啟檔案前先檢查每目錄和每使用者緩衝中是否有相應檔名,這能在保持查詢字型目錄方法得到的精確性前提下,極大地減少應用程式的啟動時間。

12 未來的研究方向

Xft始於把X渲染擴充套件和FreeType光柵化器結合在一起的簡單努力,為了支援更多的應用程式,加入了一些新的能力。這些新功能都是必須的,但其中的一些已經超出了以X為中心的函式庫。特別是字型配置機制,應該從Xft中提出來放入一個單獨的函式庫,以便列印驅動程式和其他非X的字型使用者能共享該機制。這樣能確保所有應用程式,而不僅是那些在螢幕上顯示資訊的程式,都能受惠於字型更易安裝、管理。

Xft還需要支援國際化的額外能力。目前,XftFont物件引用單一FreeType字型,如果該字型沒有包括渲染特定文件所需的全部字形,缺少的字形不會正確顯示。需要增加某種發現替換字形的機制,XftFont結構也應擴充套件以便使用多個底層FreeType字型face進行自動字形替換。

對於那些不希望自動替換的應用程式,可能應該基於所需的Unicode字形子集匹配字型。字型檔案中有字形覆蓋範圍的資訊,應用程式應該能指定所需的字形範圍,而Xft應該基於該指定進行字型匹配。

13 結論

Xft的開發模型與大多數X開發不同,函式庫早期在其他專案中釋出和整合,其他X專案等到基本穩定了才提交給社群中進行詳細評判。

隨著對此函式庫的使用逐步增長,在沒有太多影響其他專案的情況下,一些主要的提高被加入。未來的增強可能需要改變現有應用程式,這應被視作發展過程的正常部分。此函式庫在很大程度上為Xfree86社群開闢了新天地,只有透過大範圍的使用和評判,才能開發出適當的體系結構。

Xft的設計與實現進展很快,雖然僅在一年前啟動,Xft已經成為許多現在的X專案的基本組成部分。(譯註:原文發表於2001年11月在Oakland, California, USA舉行的Proceedings of the XFree86 Technical Conference)

參考文獻

[Pac01] Keith Packard. Design and Implementation of the X Rendering Extension. In FREENIX Track, 2001 Usenix Annual Technical Conference, Boston, MA, June 2001. USENIX.

[SG92] Robert W. Scheifler and James Gettys. X Window System. Digital Press, third edition, 1992.

[TT00] David Turner and The FreeType Development Team. The design of FreeType 2, 2000.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-938294/,如需轉載,請註明出處,否則將追究法律責任。

相關文章