Archive for the ‘Mac OS X’ Category

Mac OS X的字体

2009/06/26

经常听到有人说“Mac挺好用的,就是字体有点发虚”;或者“就冲Mac的字体效果我也不买”。老是听到这些不免有些迷惑——我原来是Windows和Linux的用户,从Windows转向OS X 50%因为UNIX,50%是因为字体;从Linux转向OS X 那就90%以上是因为字体了。莫非自己的感觉太神秘,太不理性,太孤僻?

今日在网上看到一篇《Vista puts Mac OS X font rendering to shame》。从题目看觉得阅读它又要体会一番道不同的煎熬。不过进去才发现自己并不孤单——虽然作者对Mac OS X的字体渲染口诛笔伐,但是文章下面的调查里62%的人认为Mac OS X的渲染效果最好。评论更是精彩。

关于字体之争,大家有一点是赞同的:Windows把字体形状根据显示器的像素进行变形,使字体尽量和显示器像素吻合,称为注重可读性;Mac OS X即使在低像素下仍然尽量通过反走样算法最大可能接近字体的原始数学描述的形状,称为注重准确度。最大的争议在于到底是可读性还是准确度才是大多数人需要的?(说道这里插一句。Windows里面对于某些字体(比如宋体)的小号字干脆图省事使用了点阵字库。)

上面从左到右就是Windows下的点阵(宋体),Windows ClearType,和Mac OS X的效果。从最下面一行的“听”字可以看出,Mac OS X的“听”的“口”和“斤”的比例是最匀称的。Windows的雅黑和宋体为了硬性的适应显示器像素,“斤”的最上面一撇的斜度有很大变形,”口“的位置和高度也和原始字型的设计有出入。这种情况在”通“字的”甬“与“走之”的相对位置,”话“的”言字旁“和”舌“的位置也有体现。另外就是字体大小变化的比例线性,如下图(左为Windows,右为Mac OS X),OS X的字体大小是符合线性的。

谈到这里可以得出一个大多数人都同意的结论。做出版印刷的专业人士必用Mac。接下来就是常见的反驳——”喂,我每天都对着屏幕阅读,但是不会打印一张纸。OS X对我根本没用!”  如果是这样,那么我也属于整天对着屏幕的人,我对Mac OS X显示效果的偏爱难道是一种不合逻辑的病态吗?

还好,那62%的人也并非都是每天消耗一叠A4纸的人。他们给出了对我的直觉的解释。语言不是单个字或者字母的简单组合,字组成词,词组成句,句组成段落。当我们阅读的时候,解释语言的速度远远高于我们的大脑分辨每个单独的字是否清晰的速度(更加高于分辨每个笔画的清晰的速度)。我们的思维更多的落在词或者句上面。这时,注重准确性的渲染方式对于词或者句子的整体表现效果更好。也就是说,Windows注重的”可读性“是对于字母的可分辨性的过分注重,反而牺牲了人真正的能够感受的可读性。从上面中文字体例子也能看出,单个字体的显示越匀称,整行字也就显得越整洁。相对的,为了笔画清晰而牺牲匀称度,整行字也会有些许里出外进的感觉。

另一个问题是显示器的分辨率必然越来越高。在这个过程中,Mac OS X的显示算法不用做任何调整就能自动适应,而且其边缘不够清晰的缺陷也随之越来越不明显。Windows的ClearType技术则必然要经历调整。

Windows算法更大的问题是它对单个字母的可读性的注重其实也仅限于拉丁字母。用日文字体的对比来比较一下,就能够看出擅自改变字型的渲染算法对于复杂的字体渲染是多么不友好。当然用繁体中文(尤其实斜体效果)比较更好。不过我懒得自己截图了。

最后再说说一位字体专家在评论中提到的关于字体的,但与渲染无关的话题。Windows的字体管理仍然比Mac OS X混乱无数倍。直到Office 2007,Windows的大多数应用仍然不是根据font family和font face两级来管理字体,而是把所有字体混为一级让用户选择。这和Windows提供的字体管理API有很大关系。而OS X的字体管理服务天然的让一般应用按照两级来管理字体。

好了,这个话题由ZDNET上一篇吹捧Vista的文章开始。中间有统计数字,也有专家的评述,还有大量外部引用。我很高兴有如此多的人和我感觉相同,并且从专业角度说明了我的自觉(而且广博到我没法完全详细读完)。而身边一些人接触过Mac OS X之后仍然执着于Windows的字体渲染也让我心存迷惑——是否能完全用习惯的惰性来解释他们不能欣赏Mac OS X的字体呢?现在下此结论未免轻率。不过从这些专业的评论来看,即使我们尊重个人的选择,也只能说对Windows清晰边缘渲染的偏爱是一种更加神秘的无法用理性解释的感情渊源。

界面开发中的DSL

2009/06/01

没有NIB文件的Cocoa应用是可行的,但是非常困难。⋯⋯在开始接触Cocoa的20年间,我几乎每过3个月就会看到有人讨论这样的问题。

三个阵营欢迎你的加入:
1. IB一开始是令人痛苦的,但是你会渐渐离不开它。
2. IB起码聊胜于无,不要白不要。
3. IB有利有弊,逆来顺受吧。

上面是从一次关于Cocoa XIB(以前称为NIB)的长篇邮件列表讨论中摘出来的两段。尽管这个题为《Writing Cocoa apps w/o using Interface Builder》的问题错误的发到了Xcode列表(本该是Cocoa-dev列表),而且其间也不断的有人指出这一点,但是没有阻止每个回信者(包括第一句就指出问题发错了地方的)都慷慨的发表对XIB的看法。最终有30人次发言,不说Xcode列表本来就没有Cocoa-dev热闹,即使是Cocoa-dev列表也少有这么吸引人的话题。这种情景让我想到专用语言(domain-specific language)在界面设计中应该如何应用仍然是一个未有定论的话题。

我的早期接触

我接触的第一种DSL是Windows的资源文件(.rc文件)。当时看来——现在也多少如此——在纯粹的C/C++环境中引入一个语言异类把开发过程搞得非常难以理解,令人厌恶而恐惧。直到发现资源文件描述的东西用C API也统统能实现,对它的恐惧心理稍减,厌恶感更甚。这种DSL简直是毫无用处,多此一举。

除了SQL和IDL之外,我接触的第二种DSL是北电内部开发的一种把一种类型的Java对象转换成另一种Java对象的语言。当时的研发中心还不正式属于北电,开发过程也不太严格,程序员可以对很多事情自作主张。在发现Java的代码也能提供这个DSL的功能之后,我马上下定决心不使用这个DSL(因为没有办法完全绕过,最终写了一个非常小的不做任何转换的DSL文件)。结果是非常令我满意的,那些用了这个DSL的同事除了无穷无尽的bug,什么也没得到,因为这个DSL不光需要编译,而且要先编译成Java代码,再编译成bytecode,既失去了调试所需的透明度,又没有节省任何编译时间。

这就是DSL在我的早期开发生活中给我留下的印象。严格的说,引起我反感的不是全部的DSL,仅仅是具有下面特征的:首先,这种DSL是声明式(declarative)语言,而不是命令式的(imperative)。它们不是图灵完备的,只能根据预先定义的一些规则(rules)来粗糙的描述使用者要达到的目的,而无法精细的控制每一步(step);其次,它们的所有功能,至少是绝大部分功能,都能被某种命令式语言替代。比如Windows资源文件的功能能够被直接调用Win32 API的C代码完全替代。从这个方面来说,我并不反感像SQL或者IDL这样的DSL。因为它们是为了完成命令式语言无法很好完成的工作而设计的独有接口,并非仅仅是命令式语言的某种速写符。

在接触DSL很久之后才了解DSL,decalratvie和imperative这样的名词。一开始的概念就是“只有程序代码最好”。

DSL与UI

Java Swing是众多UI framework里面完全不使用DSL的一个罕见的例子。这是Sun追求100%纯Java的副作用。这样做的好处在于程序员不用再学习专门的DSL。 程序的编译和分发也更加简单统一。带来的问题是定义UI的代码十分冗长。特别是命令式语言和UI定义的对应方式不直观,这样用可视化工具产生的UI代码除 了本身比手工编写的代码更为冗长之外,每种可视化工具产生代码的方式也不相同。用命令式的步骤来理解产生的UI效果,让程序的可读性很差。

用命令式语言表示UI的问题,也就是引入UI DSL的初衷。尽管有类似北电那种情况的特例,DSL的绝大部分都是在图形界面设计方面的。这是由图形界面设计的本质决定的。UI的布局部分很适合声明式语言。

Windows的资源文件有了20多年的历史。作为UI开发还不为人们熟悉的时代的产物,当它出现的时候,人们把使用它作为一种新奇的技能,还来不及权衡其利弊。20多年之后,资源文件已经很少使用。它的语法和功能都过于陈旧,只能用来偶尔声明一些比较简单的对话框。对于复杂的国际化和本地化需求,资源文件也是疲于应付。资源文件无法提供具有很强动态特性的UI。后来的framwork一般都拥有运行时的自动化布局功能。自动化布局让纯粹代码表示的UI变得勉强可以接受,不致可读性非常差。这也是Java能够完全放弃DSL的一个必要条件。

现代的UI framework基本都使用DSL,大多采用基于XML的语法。比如GTK和Cocoa。这些DSL从本质上说仍然是代码的速记符——完全脱离这些DSL用纯代码实现的UI是理论上可行的。但是就像一开头说的,完全脱离DSL是不建议的,实际上非常困难的。

DSL的利弊

DSL让程序的代码量,尤其是大体类似的冗余代码量大大减少。减少代码量就意味着减少引入错误的机会和减少维护量。但是同时,DSL让程序失去了一部分透明度。由于失去透明度带来的维护开销是否能够被代码量减少带来的收益抵消是一个很难衡量的问题。

DSL对于版本控制也不是很友好。UI DSL一般由可视化工具生成而很少手工编写。通过可视化工具做出的很小的改动往往造成DSL文件的很大变化。这种“雪崩效应”给版本控制和历史改动的跟踪带来了很大的麻烦。两个方面可以解决这个问题。第一,可视化工具尽可能消除“雪崩效应”;第二,可视化工具支持DSL的双向修改,即经过手工修改的合法的DSL文件可以被可视化工具正常操作,这样开发者在做出很小的改动时可以直接手工修改,出现“雪崩效应”时也可以用手工补救。

DSL对于跨平台开发非常不利。跨平台开发使用的语言绝大多数是命令式的。其一般的策略是把各个平台特有的API封装起来,对上提供统一的接口。由于跨平台部分采用命令式语言,接口本身和支持接口的平台特有API也最好是命令式的才能让整个架构的集成更为自然。所以跨平台开发中对于跨平台接口以下层次中DSL的使用总是极力避免。像Cocoa这样的framework并没有成为跨平台的接口,通常作为平台特有的API处于跨平台接口之下,这种情景中对绕过XIB的需求最为强烈。而对于GTK这种本身支持多平台的framework,这种需求就小得多。

DSL适合中等程度UI定制化。对于UI控制度极高的场合,比如游戏设计,UI DSL没有什么市场,整体UI都是用命令式语言编写。对于一些prototype UI,人们往往习惯用命令式语言调用预设定的alert popup或者简单可控的对话框。

对DSL是否利大于弊我仍然持怀疑态度。但是Java Swing遭到了失败(尽管有其它原因),越来越多的framework采用DSL,可视化工具的更多应用,人们不可避免的越来越习惯和无法脱离UI DSL。