CoreText编程指南(OverView)

CoreText是用来文字排版和处理字体的一个高级的底层技术。CoreText直接和CoreGraphics(CG)一起工作。CoreGraphics是一个高速的物理渲染引擎,它使用OSX和iOS的最底层技术处理二维图像。、

重要提示:CoreText是为开发高级文本处理框架而设计的。一般应用开发者应该使用TextKit in iOS(查看Text Programming Guide for iOS),或者Cocoa文本系统in OS X(查看 Cocoa Text Architecture Guide)。

CoreText协调文本布局、高级frameworks提供的字体支持和Quartz提供给所有文本和字体frameworks的低级能力。Quartz框架作用于字符和它们的位置。CoreText知道字符和字体之间的对应关系,并且在调用Quartz渲染文本之前计算样式信息、字体和其它属性。Quartz是在基础层面上唯一一种绘制字符的方法,并且,因为CoreText用一种Quartz可以直接使用的形式提供所有的数据,结果是高性能的文本渲染。

多线程:CoreText函数可能在多个线程同时调用,提供客户端不改变任何参数,比如被多个线程共享的attributed strings。

Multithreading: Core Text functions may be invoked from multiple threads simultaneously provided that the client is not mutating any parameters such as attributed strings that are shared between threads.

CoreText是一个基于C的平台无关的API

CoreText API在iOS和OSX上几乎是相同的,尽管OSX版本提供更丰富的字体管理API,包括mutable font collections。然而,当你在平台之间转换时,UIKitAppKit之间有一些不同之处你必须要考虑。举个例子:你必须要有一个Quartz graphic context来渲染CoreText生成的字符,但是在不同的平台上获取graphic context的方式不同。在iOS上你绘制的view是一个UIView的子类,OS X上是NSView的子类。你应该知道UIView的drawRect:方法接受一个CGRect类型的参数,而OS X版本的drawRect:方法接受一个NSRect类型的参数。(你可以在OS X使用NSRectToCGRect函数来把NSRect对象转换成CGRect对象。)

UIView里使用UIGraphicsGetCurrentContext函数返回的graphic context是上下翻转的,相对于未经修改的Quartz graphic context(就是说,UIView返回的context的原点在左上角),所以在iOS中你必须要重新翻转graphic context,而OS X你不需要这么做。这项技术的示例代码请查看表2-1。

CoreText尽可能的使用系统数据类型和服务,在iOS和OS X中你使用和其它core frameworks中相同的约定。例如,CoreText使用CoreFundation对象作为许多入参和出参,所以你可以把它们保存在CoreFoundation集合中。CoreText中的其它对象,例如CGPath,是Core Graphics框架提供的。

CoreText对象是C语言类型

为了简单和高效,OS X和iOS中的许多底层类库都是用纯C写的。使用CoreText的时候,你会使用许多函数,比如CTFramesetterCreateWithAttributedStringCTFramesetterCreateFrame,而不是Object-C类和方法。

CoreText类型

CoreText布局引擎经常和attributed strings (CFAttributedStringRef)graphics paths (CGPathRef)一起工作。一个attributed-string对象封装了一个字符串需要显示的文本和其它文体方面的属性—例如字体和颜色。CoreText的排版机制使用attributed string中的信息来把character转换成glyph。

Graphics path定义了一个文本框架的形状。在OS X v10.7和iOS 3.2之后,路径可以是非矩形的。

CFAttributedString引用类型,CFAttributedStringRef,和它的Foundation对象版本NSAttributedStringtoll-free bridged的,这意味着Core Foundation类型和Foundation在函数和方法中是可以互换的。因此,在一个参数是NSAttributedString *类型的方法中,你可以传CFAttributedStringRef类型。在一个参数是CFAttributedStringRef类型的方法中,你可以传NSAttributedString实例。(你可能需要转换一个类型到另一个类型来防止编译警告。)对于NSAttributedString的具体子类也是一样的。

属性是定义字符串中的字符的风格的键值对,它们按range分组分享相同的属性。属性使用CFDictionary对象类传递属性到字符串或者从字符串中获取属性。为了给glyph run (CTRun object)提供样式,创建一个CFDictionary对象来保存你需要的属性,然后创建一个attributed string,把这个dictionary作为参数传过去。或者,你可以给一个已经存在的CFMutableAttributedString对象提供属性。尽管CFDictionaryRefNSDictionarytoll-free bridged的,保存在dictionary中的个别属性可能不是。

CoreText在运行时形成一个结构体系,像图1-1中显示的那样。在这个结构的最顶层是framesetter objectCTFramesetterRef)。一个frame setter用一个attributed string和一个graphics path作为输入,来生成一个或更多的frames of textCTFrameRef)。每个CTFrame对象代表一个段落。

           Figure 1-1  Core Text layout engine的结构

为了生成framesframe setter调用一个typesetter objectCTTypesetterRef)。当它把文本摆放在frame上时,frame setter为它提供段落样式,包括一些属性:对齐方式、制表符设置、行间距、缩进和换行模式。typesetterattributed string中的characters转换成glyphs,并且把那些glyphs塞进lines来填满整个text frame

每个CTFrame对象包含这个段落的line (CTLine) 对象。每个line object代表一行文字。一个CTFrame对象可能包含仅仅一个长的CTLine对象,或者夜可能包含很多linesLine对象是在一个framesetting操作中被typesetter创建的,像frames一样,可以直接把它们自己画到一个graphics context上。

每个CTLine对象包含一个glyph run (CTRun) objects的数组。一个glyph run是一个共享相同属性和方向的连贯的glyphs。当typesettercharacter stringsattributesfont objects里生成lines时,同时生成glyph runs。意思是一个line由一个或者更多glyphs runs组成。Glyph runs可以把它们自己绘制到graphic context上,如果你想着么做的话,然而大部分客户端不需要直接和glyph runs交互。

字体对象

字体为相对于另一个glyphs来摆放glyphs提供帮助,并用于建立在绘制到graphics context上时使用的字体。CoreText字体类型,CTFont,是一个封装了许多信息的具体字体实例。它的引用类型,CTFontRef,和iOS中的UIFont、OS X中的NSFonttoll-free bridged的。当你创建一个CTFont对象,你通常设置(或使用默认的)字号和变换矩阵,给字体提供具体的特征。然后你可以查询当前字号下字体对象的许多信息,比如character-to-glyph mappingencodingsfont metric dataglyph dataFont metrics是类似ascent、descent、leading、cap height、x-height等等之类的参数。Glyph data包含类似bounding rectanglesglyph advances的参数。

CoreText字体对象是不可变的,所以它们可以同时在不同的operations、work queues或者threads中使用。有许多方法来创建字体对象。首选的方法是用CTFontCreateWithFontDescriptor来葱一个font descriptor创建。你也可以用一些替换的APIs,取决于你有什么数据。举个例子,你可以使用PostScript字体的名称(CTFontCreateWithName)或者一个Core Graphics字体引用(CTFontCreateWithGraphicsFont)。还可以使用CTFontCreateUIFontForLanguage,创建一个你的程序的本地化使用的用户界面字体的引用。

Core Text字体引用提供了一个被称为font cascading的复杂的、自动的字体替换机制,它可以选择一个合适的字体来替代缺失字体,同时考虑字体特征。Font cascading基于cascade lists(许多有序的字体descriptors数组)。有一个系统默认的cascade list(多态的, 基于用户语言设置和当前字体),还有一个在字体床建时具像化的cascade list。使用font descriptors里的信息,cascading机制可以根据风格匹配字体,同时匹配字符。CTFontCreateForString函数使用cascade lists挑选一个合适的字体来编码一个给定的string。为了制定或恢复字体cascade lists,使用kCTFontCascadeListAttribute属性。

Font Descriptors

Font DescriptorsCTFontDescriptor),提供一个完全用一个字典描述字体的机制,和一个容易使用的创建新字体的字体匹配设置。你可以从一个font descriptor生成一个字体对象,你可以从一个字体对象中获取一个descriptor,你还可以改变一个descriptor并用它生成一个新的字体对象。你可以创建一个font descriptor来部分描述一个字体,例如,只描述一个family name或者宽度,然后可以从系统中找到所有符合给定特征的字体。CTFontDescriptorRef类型和iOS中的UIFontDescriptor、OS X中的NSFontDescriptortoll-free bridged的。

你可以创建一个字体属性的字典,这个字典包含类似PostScript name、font family and style、traits (for example, bold or italic) as a CTFontDescriptor object,而不是处理复杂的变换矩阵。你可以用font descriptor创建一个CTFont对象。Font descriptors可以被序列化并存储到文档里来为字体提供持久化。图1-2说明了字体系统用一个font descriptor创建一个具体的字体实例。

      Figure 1-2  Creating a font from a font descriptor

你可以把font descriptors想象成字体系统里的查询。你可以用一个不完整的描述创建一个font descriptor,就是说,用一个或者只是属性字典中的少数值,系统将会从可用字体中挑选出最匹配的字体。例如,如果你用一个family name descriptor查询,没有指定其它的特征,将会匹配family中所有的字体。但是如果你用一个kCTFontTraitsAttributekCTFontTraitBold的字典来指定字体特征,结果将会减少到family中复合bold特征的字体。通过CTFontDescriptorCreateMatchingFontDescriptors系统可以给你一个符合查询的font descriptors的完整列表。

在iOS6.0之后,应用可以根据需求使用CTFontDescriptorMatchFontDescriptorsWithProgressHandler函数下载所有没有安装的可用字体。用这种方式下载的字体不会永久安装,系统在特定情况下会移除它们。可以下载的字体在“Additional Information”中的 iOS 6: Font listiOS 7: Font list中列举。DownloadFont(in the iOS Developer Library)示范了下载技术。根据需求下载字体在OS X中是不必要的,因为所有的可以用字体都已经安装在系统中。

Font Collections

Font collections是一组font descriptors组成的一个单个对象。一个font collection用CTFontCollection类型来代表。Font collections提供字体美剧能力、全局和自定义font collections访问、访问组成collectionfont descriptors。例如,你可以用CTFontCollectionCreateFromAvailableFonts创建一个所有系统可用字体的font collection,然后你可以用这个collection来获取所有的成员font descriptors的数组。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容