摘要
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提出了一种新格式。这种选择机制被设计为总能匹配某种字体,答应应用程序假设适当地字体存在,避免在每个级别上都要考虑失败回落。
另一个要求是函数库要提供