一个CoreText排版性能问题

2014-6-19

伊书的阅读器是用CoreText排版的,在中文字体的选择上,自带的字体中只有黑体,后来发现日文字体Hiragino也是可以用于中文,而且显示效果比黑体好很多,于是选用了这个字体。但在CoreText排版中遇到个问题,用Hiragino字体排版速度非常慢,几乎是默认黑体的100倍,以下是用Instrument Time Profiler查看排版同一章内容的时间消耗:

Hiragino:

1

黑体:

2

时间都消耗在CTFramesetterCreateWithAttributedString里,CoreText又不开源,看不到内部实现,在TimeProfiler里再继续展开,到最后只能看到时间分别耗在两个TRunGlue::ComputeEndIndex()里,看不出什么头绪。

后来用Instrument Allocation查看APP的内存分配时,发现用Hiragino字体排版生成的CTRun非常多,一章内容有2万多个CTRun。按理说,若一篇文章字体格式全部一样,渲染到frame之前CTRun只会有一个,渲染到frame后一行一个CTRun,怎样都不应该出现这么多CTRun。

3

再测了用黑体排版生成的CTRun次数,这次符合预期,只有70多个:

4

可以猜测到用Hiragino字体速度慢就是因为生成了大量的CTRun,那为什么会出现这样的情况?断点进入渲染处,打出其中一行CTLine数据,如下:

5

发现一些文字自动被转为黑体了。原因是Hiragino只支持部分中文字体,而那些不支持的中文字体就要用黑体代替,又因为一篇文章里会交错出现很多Hiragino支持和不支持的字,于是无法用一个CTRun表示一整段文字,每个交错都用一个新的CTRun,导致CTRun非常多,排版处理逻辑变复杂,耗时变高。

终于找到问题的原因,但如果想用Hiragino字体显示中文,这个问题还是无解的。其实在iOS4.x里是没有这个问题的,估计当时CoreText还没有为字体问题拆分多个CTRun,在5.0才开始这样做。除了我使用Hiragino字体会遇到这个问题外,在中英混杂的文字里用英文字体也有这样的问题,因为英文字体不支持中文显示,还是会被拆分成很多个CTRun,用CoreText注重性能的人可以注意下这个问题。

分类:技术文章 Tags:
评论

2014年6月25日 4:52

这样直接用日文字体 Hiragino Kaku Gothic 当然不行……正解是用苹果提供的字体下载 API 下载 Hiragino Sans GB 然后显示。

2015年8月31日 17:07

当使用的字体不包含当前文本字符时,就会使用系统默认的字体,而系统默认的字体中,中文字体与英文字体又是分开的(iOS7&8)