核心文字中的行距如何工作? (为什么它与NSLayoutManager不同?) [英] How does line spacing work in Core Text? (and why is it different from NSLayoutManager?)

查看:147
本文介绍了核心文字中的行距如何工作? (为什么它与NSLayoutManager不同?)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Core Text函数绘制文本,其行距尽可能接近使用NSTextView时的行距.

I'm trying to draw text using Core Text functions, with a line spacing that's as close as possible to what it would be if I used NSTextView.

以这种字体为例:

NSFont *font = [NSFont fontWithName:@"Times New Roman" size:96.0];

如果我要在NSTextView中使用此字体,则其行高为111.0.

The line height of this font, if I would use it in an NSTextView is 111.0.

NSLayoutManager *lm = [[NSLayoutManager alloc] init];
NSLog(@"%f", [lm defaultLineHeightForFont:font]); // this is 111.0

现在,如果我对Core Text执行相同的操作,结果为110.4(假设您可以通过添加上升,下降和前导来计算行高).

Now, if I do the same thing with Core Text, the result is 110.4 (assuming you can calculate the line height by adding the ascent, descent and leading).

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,我将无法使用ascent + descent +来计算线间距.

This is very close to 111.0, but for some fonts the difference is much bigger. E.g. for Helvetica, NSLayoutManager gives 115.0 whereas CTFont ascent + descent + leading = 96.0. Clearly, for Helvetica, I wouldn't be able to use ascent + descent + leading to calculate the spacing between lines.

因此,我想我将使用CTFrame和CTFramesetter来布局几行并从中获取行距.但这也给出了不同的值.

So I thought I'd use CTFrame and CTFramesetter to layout a few lines and get the linespacing from that. But that also gives different values.

CTFontRef cFont = CTFontCreateWithName(CFSTR("Times New Roman"), 96.0, NULL);
NSDictionary *attrs = [NSDictionary dictionaryWithObject:(id)cFont forKey:(id)kCTFontAttributeName];
NSAttributedString *threeLines = [[NSAttributedString alloc] initWithString:@"abcdefg\nabcdefg\nabcdefg" 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).

So the line spacing is now even more different from the 111.0 that was used in my NSTextView, and not every line is equal. It seems that the line breaks add some extra space (even though the default value for paragraphSpacingBefore is 0.0).

我现在通过NSLayoutManager获取线高,然后分别绘制每条CTLine来解决此问题,但是我想知道是否有更好的方法来做到这一点.

I'm working around this problem now by getting the line height via NSLayoutManager and then individually drawing each CTLine, but I wonder if there's a better way to do this.

推荐答案

好,所以我很好地了解了NSLayoutManager的内在情况,根据我对反汇编的阅读,它看起来像它使用归结为这样的东西:

OK, so I took a good look at what goes on in the guts of NSLayoutManager, and it appears, based on my reading of the disassembly, that the code it uses boils down to something like this:

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值.

This will get you the 111.0 and 115.0 values for the two fonts you mention above.

我应该补充一点,根据OpenType规范,正确的方法是添加三个值(请注意,如果您使用的API不能使它们全都为正,请获取下降值正确).

I should add that the correct way, according to the OpenType specification, is just to add the three values (being careful, if you’re using an API that doesn’t make them all positive, to get the sign of the descent value correct).

这篇关于核心文字中的行距如何工作? (为什么它与NSLayoutManager不同?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆