Bug in CTFrameGetLineOrigins?

I'm using the following code from Apple's SimpleTextInput example to determine the frame for the cursor. I am using CTFrameGetLineOrigins and I noticed the y value it's returning for it is incorrect (it displays .336 no matter which line is at). My app is a little different than the SimpleTextInput in that I'm vertically centering my text so the text frame isn't starting directly at the origin. But still, why is it giving me this value for everyline? Is this a bug?

for (int i = 0; i < [lines count]; i++) 
{
    CTLineRef line = (CTLineRef) [lines objectAtIndex:i];
    CFRange range = CTLineGetStringRange(line);
    NSInteger localIndex = index - range.location;

    if (localIndex >= 0 && localIndex <= range.length) 
    {
        CGPoint origin;
        CGFloat ascent, descent;
        CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
        CTFrameGetLineOrigins(self.textFrame, CFRangeMake(i, 0), &origin);
        CGFloat xPos = origin.x + CTLineGetOffsetForStringIndex(line, index, NULL);
        return CGRectMake(xPos, origin.y - descent, 3, ascent + descent);
    }
}

- (void) drawRect:(CGRect)rect
{
    CTFramesetterRef textFramesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)self.text);
    CGMutablePathRef textFrameMutablePath = CGPathCreateMutable();
    CGPathAddRect(textFrameMutablePath, NULL, self.bounds);
    self.textFrame = CTFramesetterCreateFrame(textFramesetter, CFRangeMake(0, 0), textFrameMutablePath, NULL);

    CGFloat textFrameHeight = [self calculateHeightForTextFrame];
    CGRect textFrameRect = CGRectMake(0, (self.bounds.size.height / 2) - (textFrameHeight / 2), self.bounds.size.width, textFrameHeight);

    CGPathRelease(textFrameMutablePath);
    textFrameMutablePath = NULL;

    CFRelease(self.textFrame);
    self.textFrame = NULL;

    textFrameMutablePath = CGPathCreateMutable();
    CGPathAddRect(textFrameMutablePath, NULL, textFrameRect);
    self.textFrame = CTFramesetterCreateFrame(textFramesetter, CFRangeMake(0, 0), textFrameMutablePath, NULL);

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetTextMatrix(context, CGAffineTransformIdentity);
    CGContextTranslateCTM(context, 0, self.bounds.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    CTFrameDraw(self.textFrame, context); 

    CGPathRelease(textFrameMutablePath);
    CFRelease(textFramesetter);

    [self cursorPositionChanged];
}

Take out CTFrameGetLineOrigins() out of loop to get all line origins like :

NSArray *lines = (__bridge id)CTFrameGetLines(frame);
CGPoint origins[lines.count];
CTFrameGetLineOrigins(frame, CFRangeMake(0, lines.count), origins); //this will fill all line origins in origins[] buffer.

for (int i = 0; i < [lines count]; i++)
{
    CTLineRef line = (__bridge CTLineRef) [lines objectAtIndex:i];
    CFRange range = CTLineGetStringRange(line);

    // CGPoint origin; // moved out of loop
    CGFloat ascent, descent;
    CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
    // CTFrameGetLineOrigins(frame, CFRangeMake(i, 1), &origin); // moved to out of loop
    CGFloat xPos = origins[i].x; //  + CTLineGetOffsetForStringIndex(line, index, NULL);
    NSLog(@"%@", NSStringFromCGRect(CGRectMake(xPos + origins[i].x, origins[i].y - descent, 3, ascent + descent)));
}

Your range is 0 elements long:

CFRangeMake(i, 0)

You meant to make it 1 element long:

CFRangeMake(i, 1)

EDIT:

I just tried the following code and had no problem getting different origins for each line. I took out your "index" code because I didn't know what index was supposed to be set to, and I wanted to demonstrate that I could get all the line origins (which I could).

CTFramesetterRef
      framesetter = CTFramesetterCreateWithAttributedString(attrString);


  CFArrayRef paths = [self copyPaths];
  CFIndex pathCount = CFArrayGetCount(paths);
  CFIndex charIndex = 0;
  for (CFIndex pathIndex = 0; pathIndex < pathCount; ++pathIndex) {
    CGPathRef path = CFArrayGetValueAtIndex(paths, pathIndex);

    CTFrameRef
        frame = CTFramesetterCreateFrame(framesetter,
                                         CFRangeMake(charIndex, 0),
                                         path,
        NULL);

    NSArray *lines = (__bridge id)CTFrameGetLines(frame);
    for (int i = 0; i < [lines count]; i++)
    {
      CTLineRef line = (__bridge CTLineRef) [lines objectAtIndex:i];
      CFRange range = CTLineGetStringRange(line);

      CGPoint origin;
      CGFloat ascent, descent;
      CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
      CTFrameGetLineOrigins(frame, CFRangeMake(i, 1), &origin);
      CGFloat xPos = origin.x; //  + CTLineGetOffsetForStringIndex(line, index, NULL);
      NSLog(@"%@", NSStringFromCGRect(CGRectMake(xPos, origin.y - descent, 3, ascent + descent)));
    }

It outputs in my case:

2012-03-21 18:28:19.834 Columns[9370:f803] {{0, 929.24}, {3, 12}}
2012-03-21 18:28:19.835 Columns[9370:f803] {{0, 914.24}, {3, 12}}
2012-03-21 18:28:19.835 Columns[9370:f803] {{0, 899.24}, {3, 12}}
2012-03-21 18:28:19.836 Columns[9370:f803] {{0, 884.24}, {3, 12}}
2012-03-21 18:28:19.836 Columns[9370:f803] {{0, 869.24}, {3, 12}}
2012-03-21 18:28:19.836 Columns[9370:f803] {{0, 854.24}, {3, 12}}
2012-03-21 18:28:19.837 Columns[9370:f803] {{0, 839.24}, {3, 12}}
2012-03-21 18:28:19.837 Columns[9370:f803] {{0, 824.24}, {3, 12}}
2012-03-21 18:28:19.838 Columns[9370:f803] {{0, 809.24}, {3, 12}}
2012-03-21 18:28:19.838 Columns[9370:f803] {{0, 794.24}, {3, 12}}
2012-03-21 18:28:19.838 Columns[9370:f803] {{0, 779.24}, {3, 12}}
2012-03-21 18:28:19.839 Columns[9370:f803] {{0, 764.24}, {3, 12}}
...

Oddly enough I seem to have fixed this problem by replacing:

CGPathAddRect(textFrameMutablePath, NULL, self.bounds);

with

CGPathAddRect(textFrameMutablePath, NULL, CGRectInset(self.bounds, self.horizontalInset, self.verticalInset));

No clue why but it works.

链接地址: http://www.djcxy.com/p/81940.html

上一篇: Emoji和CTFramesetterCreateWithAttributedString错误

下一篇: CTFrameGetLineOrigins中的错误?