《The design of FreeType 2》中譯版

來源:互聯網
上載者:User

FreeType 2的設計

介紹
這份文檔提供了FreeType 2函數庫設計與實現的細節。本文檔的目標是讓開發人員更好的理解FreeType 2是如何組織的,並讓他們擴充、定製和調試它。
首先,我們先瞭解這個庫的目的,也就是說,為什麼會寫這個庫:
* 它讓客戶應用程式方便的訪問字型檔,無論字型檔儲存在哪裡,並且與字型格式無關。
* 方便的提取全域字型資料,這些資料在平常的字型格式中普遍存在。(例如:全域度量標準,字元編碼/字元對應表,等等)
* 方便的提取某個字元的字形資料(度量標準,映像,名字,其他任何東西)
* 訪問字型格式特定的功能(例如,SFNT表,多重控制,OpenType輪廓表)
Freetype 2的設計也受如下要求很大的影響:
* 高可移植性。這個庫必須可以運行在任何環境中。這個要求引入了一些非常激烈的選擇,這些是FreeType2的低級系統介面的一部分。
* 可擴充性。新特性應該可以在極少改動庫基礎代碼的前提下添加。這個要求引入了非常簡單的設計:幾乎所有操作都是以模組的形式提供的。
* 可定製。它應該能夠很容易建立一個只包含某個特定項目所需的特性的版本。當你需要整合它到一個嵌入式圖形庫的字型伺服器中時,這是非常重要的。
* 簡潔高效。這個庫的主要目標是只有很少cpu和記憶體資源的嵌入式系統。
這份文檔的其他部分分為幾個部分。首先,一些章節介紹了庫的基本設計以及Freetype 2內部對象/資料的管理。
接下來的章節專註於庫的定製和與這個話題相關的系統特定的介面,如何寫你自己的模組和如何按需裁減庫初始化和編譯。

一、組件和API
FT可以看作是一組組件,每個組件負責一部分任務,它們包括

* 客戶應用程式一般會調用FT高層API,它的功能都在一個組件中,叫做基礎層。
* 根據上下文和環境,基礎層會調用一個或多個模組進行工作,大多數情況下,客戶應用程式不知道使用那個模組。
* 基礎層還包含一組常式來進行一些共通處理,例如記憶體配置,列表處理、io流解析、固定點計算等等,這些函數可以被模組隨意調用,它們形成了一個底層基礎API。

如,表明它們的關係

  

另外,

* 為了一些特殊的構建,基礎層的有些部分可以替換掉,也可以看作組件。例如ftsystem組件,負責實現記憶體管理和輸入資料流訪問,還有ftinit,負責庫初始化。
* FT還有一些可選的組件,可以根據用戶端應用靈活使用,例如ftglyph組件提供一個簡單的API來管理字形映象,而不依賴它們內部標記法。或者是訪問特定格式的特性,例如ftmm組件用來訪問和管理Type1字型中Multiple Masters資料。
* 最後,一個模組可以調用其他模組提供的函數,這對在多個字型驅動模組中共用代碼和表非常有用,例如truetype和cff模組都使用sfnt模組提供的函數。

見,是對的一個細化。

 

請注意一些要點:

* 一個可選的組件可以用在高層API,也可以用在底層API,例如上面的ftglyph;
* 有些可選組件使用模組特定的介面,而不是基礎層的介面,上例中,ftmm直接存取Type1模組來訪問資料;
* 一個可替代的組件能夠提供一個高層API的函數,例如,ftinit提供FT_Init_FreeType()

二、公用對象和類

1、FT中的物件導向
雖然FT是使用ANSI C編寫,但是採用物件導向的思想,是這個庫非常容易擴充,因此,下面有一些代碼規約。

1. 每個物件類型/類都有一個對應的結構類型和一個對應的結構指標類型,後者稱為類型/類的控制代碼類型

設想我們需要管理FT中一個foo類的對象,可以定義如下

typedef struct FT_FooRec_* FT_Foo;

typedef struct FT_FooRec_

{

// fields for the foo class

}FT_FooRec;

依照規約,控制代碼類型使用簡單而有含義的標識符,並以FT_開始,如FT_Foo,而結構體使用相同的名稱但是加上Rec尾碼。Rec是記錄的縮寫。每個類類型都有對應的控制代碼類型;

2. 類繼承通過將基類封裝到一個新類中實現,例如,我們定義一個foobar類,從foo類繼承,可以實現為

typedef struct FT_FooBarRec_ * FT_FooBar;

typedef struct FT_FooBarRec_
{
FT_FooRec root; //基類

}FT_FooBarRec;

可以看到,將一個FT_FooRec放在FT_FooBarRec定義的開始,並約定名為root,可以確保一個foobar對象也是一個foo對象。

在實際使用中,可以進行類型轉換。

後面

2、FT_Library類
這個類型對應一個庫的單一執行個體控制代碼,沒有定義相應的FT_LibraryRec,使客戶應用無法訪問它的內部屬性。

庫對象是所有FT其他對象的父親,你需要在做任何事情前建立一個新的庫執行個體,銷毀它時會自動銷毀他所有的孩子,如face和module等。

通常客戶程式應該調用FT_Init_FreeType()來建立新的庫對象,準備作其他動作時使用。

另一個方式是通過調用函數FT_New_Library()來建立一個新的庫對象,它在<freetype/ftmodule.h>中定義,這個函數返回一個空的庫,沒有任何模組註冊,你可以通過調用FT_Add_Module()來安裝模組。

調
用FT_Init_FreeType()更方便一些,因為他會預設地註冊一些模組。這個方式中,模組列表在構建時動態計算,並依賴ftinit組件的內
容。(見ftinit.c[l73]行,include
FT_CONFIG_MODULES_H,其實就是包含ftmodule.h,在ftmodule.h中定義預設的模組,所以模組數組
ft_default_modules的大小是在編譯時間動態確定的。)

3、FT_Face類
一個外觀對象對應單個字型外觀,即一個特定風格的特定外觀類型,例如Arial和Arial Italic是兩個不同的外觀。

一個外觀對象通常使用FT_New_Face()來建立,這個函數接受如下參數:一個FT_Library控制代碼,一個表示字型檔的C檔案路徑名,一個決定從檔案中裝載外觀的索引(一個檔案中可能有不同的外觀),和FT_Face控制代碼的地址,它返回一個錯誤碼。

FT_Error FT_New_Face( FT_Library library,
const char* filepathname,
FT_Long face_index,
FT_Face* face);

函數調用成功,返回0,face參數將被設定成一個非NULL值。

外觀對象包含一些用來描述全域字型資料的屬性,可以被客戶程式直接存取。例如外觀中字形的數量、外觀家族的名稱、風格名稱、EM大小等,詳見FT_FaceRec定義。

4、FT_Size類
每個FT_Face對象都有一個或多個FT_Size對象,一個尺寸對象用來存放指定字元寬度和高度的特定資料,每個新建立的外觀對象有一個尺寸,可以通過face->size直接存取。

尺寸對象的內容可以通過調用FT_Set_Pixel_Sizes()或FT_Set_Char_Size()來改變。

一個新的尺寸對象可以通過FT_New_Size()建立,通過FT_Done_Size()銷毀,一般客戶程式無需做這一步,它們通常可以使用每個FT_Face預設提供的尺寸對象。

FT_Size
公用屬性定義在FT_SizeRec中,但是需要注意的是有些字型驅動定義它們自己的FT_Size的子類,以儲存重要的內部資料,在每次字元大小改變時
計算。大多數情況下,它們是尺寸特定的字型hint。例如,TrueType驅動儲存CVT表,通過cvt程式執行將結果放入TT_Size結構體中,而
Type1驅動將scaled global metrics放在T1_Size對象中。

5、FT_GlyphSlot類

形槽的目的是提供一個地方,可以很容易地一個個地裝入字形映象,而不管它的格式(位元影像、向量輪廓或其他)。理想的,一旦一個字形槽建立了,任何字形映象可
以裝入,無需其他的記憶體配置。在實際中,只對於特定格式才如此,像TrueType,它顯式地提供資料來計算一個槽地最大尺寸。

另一個字形槽地原因是他用來為指定字形儲存格式特定的hint,以及其他為正確裝入字形的必要資料。

基本的FT_GlyphSlotRec結構體只向客戶程式展現了字形metics和映象,而真正的實現回包含更多的資料。

例如,TrueType特定的TT_GlyphSlotRec結構包含附加的屬性,存放字形特定的位元組碼、在hint過程中暫時的輪廓和其他一些東西。

最後,每個外觀對象有一個單一字形槽,可以用face->glyph直接存取。

6、FT_CharMap類
FT_CharMap類型用來作為一個字元地圖對象的控制代碼,一個字元圖是一種表或字典,用來將字元碼從某種編碼轉換成字型的字形索引。

單個外觀可能包含若干字元圖,每個對應一個指定的字元指令系統,例如Unicode、Apple Roman、Windows codepages等等。

每個FT_CharMap對象包含一個platform和encoding屬性,用來標識它對應的字元指令系統。每個字型格式都提供它們自己的FT_CharMapRec的繼承類型並實現它們。

7、對象關係
正好概述了我們之前所說的關於庫裡的公用類託管,除此之外還明確描述了它們之前的關係。

三、內部對象和類
1、記憶體管理

有記憶體管理操作通過基礎層中3個特定常式完成,叫做FT_Alloc、FT_Realloc、 FT_Free,每個函數需要一個
FT_Memory控制代碼作為它的第一個參數。它是一個用來描述當前記憶體池/管理器對象的指標。在庫初始化時,在FT_Init_FreeType中調用函
數FT_New_Memory建立一個記憶體管理器,這個函數位於ftsystem組件當中。

預設情況下,這個管理器使用ANSI
malloc、realloc和free函數,不過ftsystem是基礎層中一個可替換的部分,庫的特定構建可以提供不同的記憶體管理器。即使使用預設的
版本,客戶程式仍然可以提供自己的記憶體管理器,通過如下的步驟,調用FT_Init_FreeType實現:

1. 手工建立一個FT_Memory對象,FT_MemoryRec位於公用檔案<freetype/ftsystem.h>中。

2. 使用你自己的記憶體管理器,調用FT_New_Library()建立一個新的庫執行個體。新的庫沒有包含任何登入的模組。

3. 通過調用函數FT_Add_Default_Modules()(在ftinit組件中)註冊預設的模組,或者通過反覆調用FT_Add_Module手工註冊你的驅動。

2、輸入資料流

體檔案總是通過FT_Stream對象讀取,FT_StreamRec的定義位於公用檔案<freetype/ftsystem.h>中,可
以允許客戶開發人員提供自己的流實現。FT_New_Face()函數會自動根據他第二個參數,一個C路徑名建立一個新的流對象。它通過調用由
ftsystem組件提供的FT_New_Stream()完成,後者時可替換的,在不同平台上,流的實現可能大不一樣。

舉例來說,流的預設實現位於檔案src/base/ftsystem.c並使用ANSI fopen/fseek和fread函數。不過在FT2的Unix版本中,提供了另一個使用記憶體對應檔的實現,對於主機系統來說,可以大大提高速度。

FT區分基於記憶體和基於磁碟的流,對於前者,所有資料在記憶體直接存取(例如ROM、唯寫待用資料和記憶體對應檔),而後者,使用幀(frame)的概念從字型檔中讀出一部分,使用典型的seek/read操作並暫時緩衝。

FT_New_Memory_Face
函數可以用來直接從記憶體中可讀取的資料建立/開啟一個FT_Face對象。最後,如果需要客戶輸入資料流,客戶程式能夠使用FT_Open_Face()函數
接受客戶輸入資料流。這在壓縮或遠程字型檔的情況下,以及從特定文檔抽取嵌入式字型檔非常有用。

注意每個外觀擁有一個流,並且通過FT_Done_Face被銷毀。總的來說,保持多個FT_Face在開啟狀態不是一個很好的主意。

3、模組
FT2
模組本身是一段代碼,庫調用FT_Add_Moudle()函數註冊模組,並為每個模組建立了一個FT_Module對象。FT_ModuleRec的定
義對客戶程式不是公開的,但是每個模組類型通過一個簡單的公用結構FT_Module_Class描述,它定義在<
freetype/ftmodule.h>中,後面將詳述。

當調用FT_Add_Module是,需要指定一個FT_Module_Class結構的指標,它的聲明如下:

FT_Error FT_Add_Module( FT_Library library,

const FT_Module_Class* clazz);

調用這個函數將作如下操作:

* 檢查庫中是否已經有對應FT_Module_Class指名的模組對象;

* 如果是,比較模組的版本號碼看是否可以升級,如果模組類的版本號碼小於已裝入的模組,函數立即返回。當然,還要檢查正在啟動並執行FT版本是否滿足待裝模組所需FT的版本。

* 建立一個新的FT_Module對象,使用模組類的資料的標誌決定它的大小和如何初始化;

* 如果在模組類中有一個模組初始器,它將被調用完成模組對象的初始化;

* 新的模組加入到庫的“登入”模組列表中,對升級的情況,先前的模組對象只要簡單的銷毀。

注意這個函數並不返回FT_Module控制代碼,它完全是庫內部的事情,客戶程式不應該擺弄他。最後,要知道FT2識別和管理若干種模組,這在後面將有詳述,這裡列舉如下:

* 渲染器模組用來將原始字形映象轉換成位元影像或象素圖。FT2內建兩個渲染器,一個是產生單色位元影像,另一個產生高品質反走樣的象素圖。

* 字型驅動模組用來支援多種字型格式,典型的字型驅動需要提供特定的FT_Face、FT_Size、FT_GlyphSlot和FT_CharMap的實現;

* 助手模組被多個字型驅動共用,例如sfnt模組分析和管理基於SFNT字型格式的表,用於TrueType和OpenType字型驅動;

* 最後,auto-hinter模組在庫設計中有特殊位置,它不管原始字型格式,處理向量字形輪廓,使之產生優質效果。

注意每個FT_Face對象依據原始字型檔格式,都屬於相應的字型驅動。這就是說,當一個模組從一個庫執行個體移除/取消註冊後,所有的外觀對象都被銷毀(通常是調用FT_Remove_Module()函數)。

因此,你要注意當你升級或移除一個模組時,沒有開啟FT_Face對象,因為這會導致不預期的對象刪除。

4、庫
現在來說說FT_Library對象,如上所述,一個庫執行個體至少包含如下:

* 一個記憶體管理對象(FT_Memory),用來在執行個體中分配、釋放記憶體;

* 一個FT_Module對象列表,對應“已安裝”或“登入”的模組,它可以隨時通過FT_Add_Module()和FT_Remove_Module()管理;

* 記住外觀對象屬於字型驅動,字型驅動模組屬於庫。

還有一個對象屬於庫執行個體,但仍未提到:raster pool

光柵池是一個固定大小的一塊記憶體,為一些記憶體需要大的操作作為內部的“草稿地區”,避免記憶體配置。例如,它用在每個渲染器轉換一個向量字形輪廓到一個位元影像時(這其實就是它為何叫光柵池的原因)。

光柵池的大小在初始化的時候定下來的(預設為16k位元組),運行期不能修改。當一個瞬時操作需要的記憶體超出這個池的大小,可以另外分配一塊作為例外條件,或者是遞迴細分任務,以確保不會超出池的極限。

這種極度的記憶體保守行為是為了FT的效能考慮,特別在某些地方,如字形渲染、掃描線轉換等。

5、總結
最後,展示的上面所述內容,他表示FT基本設計的對象圖


四、模組類

在FT中有若干種模組

* 渲染模組,用來管理可縮放的字形映象。這意味這轉換它們、計算邊框、並將它們轉換成單色和反走樣位元影像。FT可以處理任何類型的字形映像,只要為它提供了一個渲染模組,FT預設帶了兩個渲染器

raster 支援從向量輪廓(由FT_Outline對象描述)到單色位元影像的轉換

smooth 支援同樣的輪廓轉換到高品質反走樣的象素圖,使用256級灰階。這個渲染器也支援直接產生span。

* 字型驅動模組,用來支援一種或多種特定字型格式,預設情況下,FT由下列字型驅動

truetype 支援TrueType字型檔

type1 支援PostScript Type1字型,可以是二進位(.pfb)和ASCII(.pfa)格式,包括Multiple Master字型

cid 支援Postscript CID-keyed字型

cff 支援OpenType、CFF和CEF字型(CEF是CFF的一個變種,在Adobe的SVG Viewer中使用

winfonts 支援Windows位元影像字型,.fon和.fnt

字型驅動可以支援位元影像和可縮放的字形映象,一個特定支援Bezier輪廓的字型驅動通過FT_Outline可以提供他自己的hinter,或依賴FT的autohinter模組。

* 助手模組,用來處理一些共用代碼,通常被多個字型驅動,甚至是其他模組使用,預設的助手如下

sfnt 用來支援基於SFNT儲存綱要的字型格式,TrueType和OpenType字型和其他變種

psnames 用來提供有關字形名稱排序和Postscript編碼/字元集的函數。例如他可以從一個Type1字形名稱字典中自動合成一個Unicode字元圖。

psaux 用來提供有關Type1字元解碼的函數,type1、cid和cff都需要這個特性

* 最後,autohinter模組在FT中是特殊角色,當一個字型驅動沒有提供自己的hint引擎時,他可以在字形裝載時處理各自的字形輪廓。

我們現在來學習模組是如何描述以及如何被FreeType2庫管理的。
1 FT_Module_Class結構

2 FT_Module類型

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.