核心文本中的行间距如何工作? (为什么它不同于NSLayoutManager?)
我试图使用核心文本函数绘制文本,行间距尽可能地接近如果我使用NSTextView。
以此字体为例:
NSFont *font = [NSFont fontWithName:@"Times New Roman" size:96.0];
如果我在NSTextView中使用它,该字体的行高为111.0。
NSLayoutManager *lm = [[NSLayoutManager alloc] init];
NSLog(@"%f", [lm defaultLineHeightForFont:font]); // this is 111.0
现在,如果我用Core Text做同样的事情,结果是110.4(假设你可以通过增加上升,下降和领先来计算行高)。
CTFontRef cFont = CTFontCreateWithName(CFSTR("Times New Roman"), 96.0, NULL);
NSLog(@"%f", CTFontGetDescent(cFont) + CTFontGetAscent(cFont) +
CTFontGetLeading(cFont)); // this is 110.390625
这与111.0非常接近,但对于某些字体,差异要大得多。 例如Helvetica,NSLayoutManager给出115.0,而CTFont上升+下降+领导= 96.0。 显然,对于Helvetica,我不能使用上升+下降+来计算行间距。
所以我想我会使用CTFrame和CTFramesetter来布局几行,并从中获得行距。 但是这也给了不同的价值。
CTFontRef cFont = CTFontCreateWithName(CFSTR("Times New Roman"), 96.0, NULL);
NSDictionary *attrs = [NSDictionary dictionaryWithObject:(id)cFont forKey:(id)kCTFontAttributeName];
NSAttributedString *threeLines = [[NSAttributedString alloc] initWithString:@"abcdefgnabcdefgnabcdefg" attributes:attrs];
CTFramesetterRef threeLineFramesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)threeLines);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0.0, 0.0, 600.0, 600.0));
CTFrameRef threeLineFrame = CTFramesetterCreateFrame(threeLineFramesetter, CFRangeMake(0, 0), path, NULL);
CGPoint lineOrigins[3];
CTFrameGetLineOrigins(threeLineFrame, CFRangeMake(0, 0), lineOrigins);
NSLog(@"space between line 1 and 2: %f", lineOrigins[0].y - lineOrigins[1].y); // result: 119.278125
NSLog(@"space between line 2 and 3: %f", lineOrigins[1].y - lineOrigins[2].y); // result: 113.625000
所以行距现在与我在NSTextView中使用的111.0更加不同,并不是每行都是相等的。 看来换行符会添加一些额外的空间(即使paragraphSpacingBefore
的默认值为0.0)。
现在我正在通过NSLayoutManager获取行高,然后单独绘制每个CTLine来解决这个问题,但是我想知道是否有更好的方法来实现这一点。
好的,所以我仔细研究了NSLayoutManager的内涵,看来,根据我对反汇编的理解,它使用的代码归结为如下所示:
CGFloat ascent = CTFontGetAscent(theFont);
CGFloat descent = CTFontGetDescent(theFont);
CGFloat leading = CTFontGetLeading(theFont);
if (leading < 0)
leading = 0;
leading = floor (leading + 0.5);
lineHeight = floor (ascent + 0.5) + floor (descent + 0.5) + leading;
if (leading > 0)
ascenderDelta = 0;
else
ascenderDelta = floor (0.2 * lineHeight + 0.5);
defaultLineHeight = lineHeight + ascenderDelta;
这将为您提供上述两种字体的111.0和115.0值。
我应该补充一点,根据OpenType规范,正确的方法就是添加三个值(如果你使用的API不能使它们全部为正值,则要小心,以获得正确的下降值的符号)。
简单。 设置一个测试字符串和框架,并比较两行字体的原点。 然后,如果你想计算领先只使用线高度重音下降做计算。
- (float)getLineHeight {
CFMutableAttributedStringRef testAttrString;
testAttrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
NSString *testString = @"testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest";
CFAttributedStringReplaceString (testAttrString, CFRangeMake(0, 0), (CFStringRef)testString);
CTFontRef myFont1 = CTFontCreateWithName((CFStringRef)@"Helvetica", 30, NULL);
CFRange range = CFRangeMake(0,testString.length);
CFAttributedStringSetAttribute(testAttrString, range, kCTFontAttributeName, myFont1);
CGMutablePathRef path = CGPathCreateMutable();
CGRect bounds;
if ([model isLandscape]) {
bounds = CGRectMake(0, 10, 1024-20, 768);
}
else {
bounds = CGRectMake(0, 10, 768-20, 1024);
}
CGPathAddRect(path, NULL, bounds);
CTFramesetterRef testFramesetter = CTFramesetterCreateWithAttributedString(testAttrString);
CTFrameRef testFrameRef = CTFramesetterCreateFrame(testFramesetter,CFRangeMake(0, 0), path, NULL);
CGPoint origins1,origins2;
CTFrameGetLineOrigins(testFrameRef, CFRangeMake(0, 1), &origins1);
CTFrameGetLineOrigins(testFrameRef, CFRangeMake(1, 1), &origins2);
return origins1.y-origins2.y;
}
你看看CTFontGetDescent()
返回值的符号是什么吗? 一个常见的错误是假设下降值是正值,实际上它们往往是负值(以反映它们低于字体基线的下降值)。
因此,行间距应该设置为
ascent - descent + leading
链接地址: http://www.djcxy.com/p/81917.html
上一篇: How does line spacing work in Core Text? (and why is it different from NSLayoutManager?)