¿Cómo funciona el interlineado en Core Text? (¿y por qué es diferente de NSLayoutManager?)

Estoy tratando de dibujar texto usando las funciones de Core Text, con un espaciado de línea lo más cercano posible a lo que sería si usara NSTextView.

Tome esta fuente como ejemplo:

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

La altura de la línea de esta fuente, si la usaría en un NSTextView es 111.0.

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

Ahora, si hago lo mismo con Core Text, el resultado es 110.4 (suponiendo que pueda calcular la altura de la línea agregando el ascenso, el descenso y el avance).

CTFontRef cFont = CTFontCreateWithName(CFSTR("Times New Roman"), 96.0, NULL);
NSLog(@"%f", CTFontGetDescent(cFont) + CTFontGetAscent(cFont) + 
             CTFontGetLeading(cFont)); // this is 110.390625

Esto está muy cerca de 111.0, pero para algunas fuentes la diferencia es mucho mayor. P.ej. para Helvetica, NSLayoutManager da 115.0 mientras que CTFont ascenso + descenso + líder = 96.0. Claramente, para Helvetica, no podría usar ascenso + descenso + dirección para calcular el espacio entre líneas.

Así que pensé en usar CTFrame y CTFramesetter para diseñar algunas líneas y obtener el espacio entre ellas. Pero eso también da valores diferentes.

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

Así que el espacio entre líneas ahora es aún más diferente del 111.0 que se usó en mi NSTextView, y no todas las líneas son iguales. Parece que los saltos de línea agregan algo de espacio adicional (aunque el valor predeterminado paraparagraphSpacingBefore es 0.0).

Estoy trabajando en este problema ahora obteniendo la altura de la línea a través de NSLayoutManager y luego dibujando individualmente cada CTLine, pero me pregunto si hay una mejor manera de hacerlo.

Respuestas a la pregunta(3)

Su respuesta a la pregunta