阅读器的进度显示与估计

对电子书阅读器来说,提示当前阅读进度是一项很自然的功能,习惯用电脑的人都常看到进度条 (progress bar) 和滚动条 (scroll bar),如右图是 Textus 中使用的右侧滚动条。

然而在实际实现中,进度计算是一件伤脑筋的事情,比如 Textus 的实现其实很简单:在打开文件时读入整个文件,然后整个交给 Core Text 去排版,将排版后的结果分解为行 (CTLineRef) 记录下来,并将所有行总的高度设置为整个文本视图的高度,这样,每当滚动视图 (NSScrollView) 移动到某个位置时,重绘函数 (-drawRect:) 被调用到,我们根据该位置来判断应该绘制从第几行到第几行的内容,再调用 Core Text 把这些行画出来。

这么做看似很简单直接,结果也很容易保证正确,带来的问题是,每次用户修改设置 (比如调整字体大小、窗口尺寸) 时,就得把整个文件重新排版一遍,即使此时我们只需要看到当前一页的内容。为什么这种方法这么低效,我还一直使用它呢?因为这个实现严格依赖滚动视图给出的位置来判断当前阅读进度,所以总的高度估计必须非常精确,不然随便滚动一下就可能出现错位,而一次算给出整个高度的方法最准确,不容易出错。

Continue reading “阅读器的进度显示与估计”

闲聊文本渲染技术的近期发展

在今年 7 月的 GUADEC 上 Behdad Esfahbod 做了一个题为 State of Text Rendering 的讲座,系统地综述了当前文本渲染技术的现状,顺带强调主要由他开发的 harfbuzz-ng 是未来发展的方向,4 个月过去了,最近文本渲染技术有了什么发展呢?这里谈谈我的一些印象和见解。

首先,harfbuzz-ng 到底想做成什么样子?我们知道底层的字体格式支持,开放的有 FreeType 一枝独秀,各平台私有的有 Win32 的 GDI font, Mac OS X 有 ATS 和 CGFont,上层的文本布局排版引擎,现在各家自有一套到两套:Windows 的 DirectWrite 和 Uniscribe;Mac OS X 有 Core Text 和 ATSUI,有 NSLayoutManager;GTK+ 有 pango,都是比较成熟的接口了,那 harfbuzz-ng 是要取代他们吗?

不是,也完全说不通,毕竟 pango 就是 Behdad Esfahbod 自己维护的,没理由拆自己的台。但是开放的 pango 等平台一直缺失的部分是 OpenType 复杂排版特性的支持,这一点 FreeType 没来得及解决,也因为和排版引擎关系太紧密,所以没法完全靠 FreeType 这种“字体格式解析库”来解决。harfbuzz-ng 要做的,正是在原来的 FreeType OpenType 排版代码的基础上,构建一个类似 ICU LayoutEngine 的、有简洁的 C API 的、支持 OpenType 特性的,而且还要比 pango 底层一些的库。

那不是和 ICU 重合了吗?ICU 一来是 C++ 的 API 用着比较累,而来确实也比较笨重,移植的时候够受的。ICU 虽然在近期版本里也开始提供 C 的排版引擎 API,但也只是试验性的。

所以总的看起来,Linux 下的文本渲染层次还真是够多的:GTK+ → pango/cairo → harfbuzz-ng → FreeType,同时 harfbuzz-ng 还可能用到 ICU, Graphite,在 Mac OS X 上还要用到 Core Text 和 Core Graphics。

细分层带来的好处就是不同的需求可以选择合适的 API 来实现:比如你要在图形界面上显示一段文字,就用 GTK+ 的 label;要绘制小段的文本,就用 cairo 和 pango;要高效率的、轻量地绘制大量的文本,就用 harfbuzz-ng 来自己攒一个排版引擎 — 大部分浏览器都是这样,只不过在没有 harfbuzz-ng 的情况下,或者要直接用 FreeType,不得不多写很多代码,或者就用 pango 这种重量级的,性能又得不到保证。

在 8 月份,harfbuzz-ng 的 API 提议已经出现,并在不断讨论中完善 (要我说,本来这个星球上有经验参与讨论的也最多不超过 20 个人,不如大家到一个屋子里开个会搞定得了)。

XeTeX 的作者 Jonathan Kew 虽然仍然在开发 TeXworks,但工作的重心已经放到了 Mozilla Firefox 3.6 的 WOFF 格式和 OpenType 复杂排版支持上,最近的一个视频里 Jonathan 提供了一个很棒的概览,有这样的一些特性之后,在浏览器里做一些认真的文本排版才可能成为现实 — 可惜浏览器仍然缺乏好的断行算法实现。这部分工作其实就是基于 harfbuzz-ng 的。而 WebKit-GTK 版本也开始了基于 harfbuzz-ng 的实现。

当然了,畅想了一番美好未来之后还是要回到现实,目前我想做的一个项目,是开发一套能跨 iPhone OS 和 Mac OS X 的、轻量级的排版引擎,专门给文本阅读器用。这个工作的出发点是:

  1. iPhone 上缺少 (按我的标准) 足够好的文本阅读器,而既然我已经开始写 Textus 了,不如把它移植到 iPhone 上;
  2. iPhone 上没有 Core Text 这个层次的框架,要渲染文本要么用 NSAttributedString,要么用 WebView,他们的额外开销都太多,太重量级了;
  3. 轻量的方法有神秘的 private API CGFontGetGlyphsForUnichars,如果不愿意用 private API 呢,就只好像 cocos2d-iphone 那样自己去实现 cmap 载入的代码,非常痛苦;
  4. 即使这样,也不支持复杂的 OpenType 排版特性,甚至简单一点的连字 (ligature) 都不支持,对于一个文本阅读器这是不能忍受的。

所以觉得写个这样的引擎会比较有用:

  • 做到后端独立,比如可以选用 ICU (iPhone OS 上), Core Text (Mac OS X 上), harfbuzz-ng
  • 能够支持 OpenType 复杂排版特性
  • 至少支持好大部分西方字符和 CJK 字符
  • API 尽可能的简单

最近刚刚开始做一些试验,比如用 Core Graphics 完成了一个简单的 CGFontInstance 给 ICU 用,这在目前还没看到类似的工作。

vim-cocoa 0.3 beta 1 released

After two days of work, here is the first beta of the 0.3 series of vim-cocoa.

vim-cocoa 0.3b1 screenshot

What’s New?

  • Updated vim to 7.2.49
  • Use Core Text to replace ATSUI for text rendering
  • Optimize program startup
  • Support transparency option to control background transparency
  • Fix cursor redraw on right clicking
  • Fix CTRL + SHIFT + ? key handling ( Issue 35 )
  • Mac OS X 10.5 only (Since Core Text is a 10.5 only framework)

Download

View Source