MS RFC 98:标签/文本呈现大修¶
- 日期
2013/06
- 作者
托马斯堡
- 联系方式
- 状态
采用
- 版本
MAPServer 7
1。现状¶
1.1文本呈现管道¶
当需要标记某个特性时,执行以下(简化)步骤:
字符串最终通过iconv转换为utf8
字符串通过fribidi将glyph从“逻辑顺序”重新排序为“视觉顺序”,以支持从右向左编写的语言。例如,假设大写字母是阿拉伯字母,则存储在特征中的文本为
this is some ARABIC text
转化为this is some CIBARA text
为了向渲染器透明地输入当前从左到右布局glyph的内容字符串通过换行符,对于RTL脚本来说,换行符当前是断开的(对于
arabic \n text
)TXET CIBARA
而不是所需的
CIBARA TXET
我们尝试通过填充空格,而不是每行使用精确偏移来实现字符串对齐,这目前还是不精确的(感谢您的使用)。
然后,字符串按原样传递给渲染器,渲染器负责每个glyph的整个布局
1.2个局限性¶
虽然目前的情况很容易理解,而且对于拉丁语来说效果也很好,但是这个RFC的目标是解决一些缺点:
所有渲染器都在复制布局逻辑:
将utf8字符串拆分为单个glyph
在字体文件中查找给定的字形
相对于前一个设置标志符号(这包括后续字符之间的间距,或确定遇到换行符时应垂直添加多少像素)
虽然拉丁语言在字符串字符和字体glyph之间有一个1对1的映射,但对于复杂语言则不是这样,因为需要根据上下文插入连字glyph(请参见 wikipedia complex text layout page 更完整的解释)。虽然这部分由fribidi for arabic(它有一个为我们插入连接符的成形算法)负责,但我们目前在其他复杂的文本语言中很难做到。
我们根本不支持双间距或行距,而且我们的文本对齐方式(中间、右侧)不精确,因为这些方法的实现需要添加到每个渲染器中。
2。拟大修¶
大局见 the state of text rendering .
简而言之,我们不向渲染器传递文本字符串和起始位置,而是传递一个glyph列表(即glyph是特定字体文件中的特定条目)及其精确定位,这与我们当前在渲染时所做的非常相似。 FOLLOW
标签,如中所述 bug 3611 . 实际的形状和布局发生在一个mapserver函数中,渲染器只是简单地将glyph放置在它们被告知的位置。
2.1架构影响¶
在体系结构上,这种修改非常重要,因为需要重构整个标签呈现链,以便考虑到定位glyph列表,而不仅仅是纯文本字符串。
2.1.1依赖性¶
freetype成为了一个中心mapserver依赖项,因为我们需要比当前更高级别的glyph大小信息(其中freetype是单个渲染器的依赖项)。我们还需要一个单一的中央glyph缓存来跨harfbuzz和渲染器使用。
fontsetObj
可能需要扩展到一个简单的文件名哈希表之外。fribidi(它有一些线程安全问题)被保存为为为我们处理bidi算法的库。我们不再用它来塑形。
引入harfbuzz以支持复杂的脚本变形(简化:在字符之间插入连接符的工具)。HarfBuzz算法将应用于已确定为非拉丁语的文本字符串(即,HarfBuzz导致的速度减慢仅限于那些实际需要整形的语言)。
uthash(http://troydhanson.github.io/uthash/)是一个只实现包含哈希表的头文件,可与任意键和值一起使用,并用于访问缓存的字体和glyph。考虑到一些性能测试,我们可能希望有一天用这个来替换我们自己的哈希表。
请注意,fribidi和harfbuzz依赖项仍然是可选的,并且可以在编译时对那些只处理拉丁脚本的人禁用。Harfbuzz和Fribidi需要一起启用或禁用。
2.1.2字体和字形缓存¶
(font cache.c)全局(如果需要,线程保护)glyph和字体缓存将确保缓存的glyph可在fastcgi案例的多个请求中重用,但反过来需要一些线程级保护,可能还需要一些修剪,以使其保持合理的大小。为了让fontcache可访问,一些API已经更改。fontcache包含以下缓存:
字体(即TrueType文件的表示)
字形(即给定大小的单个字形的度量)
2.1.2将文本字符串转换为定位glyph列表¶
此步骤将添加到MapServer,包括协调freetype、bidi算法、harfbuzz、换行、文本对齐以及未来的文本和行距的输出。这个步骤在很大程度上可以通过pango透明地实现,但是pango很难跨平台支持,据我所知,它对fontconfig有着严格的依赖性,这与我们的fontset方法不兼容。
文本由“textpathobj”表示,它基本上是定位glyph的列表。(例如,对于Arial字体,大小为10的单词“l a b e l”由位置(x,y)=(0,0)处的Arial字体的glyph“l”、位置(10,0)处的glyph“a”、位置(18,0)处的“b”等表示)。多行文本通过在不同的Y值处放置glyph透明地处理。文本路径可以是“绝对”(即glyph位置在绝对图像坐标中,用于定位角度跟随标签的glyph)或“相对”(在这种情况下,它们必须被其标签点偏移)。
所有的变形都发生在textlayout.c中,其主要角色是接受一个文本字符串作为输入,并返回一个定位glyph列表作为输出。输入字符串经过多个步骤,并被拆分为多个运行。每次运行都有一个不同的行号、bidi方向和脚本“language”。
例如,我们将使用输入的Unicode字符串“这是一些英语、阿拉伯语和日语文本”。大写字母用于表示非拉丁字母,还请注意,阿拉伯语按逻辑(=阅读)顺序存储,而它将呈现为cibara。
将字符串转换为Unicode的ICONV编码转换
run1 = "this is some text in english, ARABIC and JAPANESE", line=0
换行:换行符换行,空格换行
run1 = "this is some text in english,", line=0
run2 = "ARABIC and JAPANESE", line=1
bidi级别,每个运行都有一个bidi方向(即从左到右或从右到左)
run1 = "this is some text in english,", line=0, direction=LTR
run2 = "ARABIC" line=1, direction=RTL
run3 = " and JAPANESE", line=1, direction = LTR
脚本检测应用于启用依赖于语言的形状,并优化将使用的字体(稍后将详细介绍)
run1 = "this is some text in english,", line=0, direction=LTR, script=latin
run2 = "ARABIC" line=1, direction=RTL, script=arabic
run3 = " and " line=1, direction=LTR, script=latin
run4 = "JAPANESE" line=1, direction=LTR, script=hiragana
对于每个运行,我们选择应该使用的字体,以便在给定的运行中使用相同的字体。 MS RFC 80:字体回退支持 允许为一个标签指定多个字体,这已扩展到能够微调哪些字体最好用于给定脚本:
FONT "arialuni,arial,cjk,arabic"
现在可以用脚本标识符,即:
FONT "arialuni,en:arial,ja:cjk,ar:arabic"
This is needed as there is and will be overlap between font glyph
coverages, and it should be possible to prioritize which font is used
for which language.
然后将每次运行输入harfbuzz,该函数返回定位glyph的列表。返回的glyph的数目并不意味着与Unicode字符串中的glyph数目相同,而是从左到右排列。作为加速,run who的脚本是“拉丁语”不是通过harfbuzz提供的,而是使用缓存的glyph高级。
重新组装每个运行的标志符号,以说明行号和运行位置(例如,运行3向下偏移一行,并放置在运行2的右侧)。
每一行水平地加上括号,以便于对齐。标签对齐现在停止默认为左对齐,因此从右向左的运行将是右对齐的,而不是现在的左对齐。
2.1.3渲染阶段处理glyph¶
需要更新labelcache和渲染器才能使用glyph列表。这里的变化是广泛的,但在概念上应该保持简单。单个渲染器被大大简化。
已尽可能减少labelcache计算:
将功能插入labelcache时:
如果labelobj及其子StyleObj不包含任何绑定,我们将插入对原始labelobj的引用,而不是副本。当属性绑定不在使用时,这会减少内存使用的DOW。
我们不会插入永远无法呈现的功能(例如,超出比例,对其功能而言太大(minFeatureSize关键字))。
在msdrawlabelcache阶段:
我们将标签文本边界框的计算延迟到,在我们检查了可能导致它无法呈现的条件之后,即。
如果他们有一个思维定势和一个相同文本的相邻标签已经呈现
对于没有标记的标签,我们首先检查LabelPoint是否与现有标签冲突。
碰撞检测已优化:
我们保留一个呈现标签的列表,并遍历这些标签,而不是检查每个成员的labelcache中所有标签的状态
标签的边界度量已从完整的shapeobj缩减为包含边界rect和可选lineobj的结构。对于非旋转标签,不需要任何信息,只需要边界框,这使得这样的两个标签更容易进行交叉检测(即,这两个标签的重叠与边界框的重叠相同,无需进入更多的几何交叉基本体)。
这些变化的加速对于杂乱的地图非常重要,c.f.https://plus.google.com/u/0/118271009221580171800/posts/prwhfyskhea(例如,500.000个标签的渲染时间从800秒到1秒)。
2.2向后兼容性¶
在高(mapfile)级别,不需要。
某些mapscript API可能会更改,或者可能需要打包。(TBD)
角色位置的一些细微但广泛的变化。
MS RFC 99:删除对gd渲染器的支持 是这些变化的附带因素
2.3性能影响¶
可能很多:
通过检测和缩短这些案例,仅拉丁语文本的现有性能需要保持在当前水平。如果做得正确,我们实际上可以加快拉丁文本渲染的速度。
对于其他脚本,通过哈夫布兹的成本 will 带上一个性能惩罚。