简体   繁体   English

CTFrameGetLineOrigin令人难以置信的奇怪错误

[英]CTFrameGetLineOrigin unbelievably strange bug

I'm working on text selection with core text. 我正在使用核心文本进行文本选择。 The selection mechanism itself is working, except for one very strange thing. 选择机制本身正在起作用,除了一件非常奇怪的事情。 I can select fine on the final line of the text view only . 我可以选择在文本视图的最后一行的罚款。 All previous lines snap to either all selected or not selected at all. 先前的所有行都将捕捉到所有选定或根本未选定的位置。 Here is the logic (taken from Apple's sample code): 这是逻辑(摘自Apple的示例代码):

 NSArray *lines = (NSArray *) CTFrameGetLines(_frame);
for (int i = 0; i < [lines count]; i++) {
    CTLineRef line = (CTLineRef) [lines objectAtIndex:i];
    CFRange lineRange = CTLineGetStringRange(line);
    NSRange range = NSMakeRange(lineRange.location, lineRange.length);
    NSRange intersection = [self RangeIntersection:range withSecond:selectionRange];
    if (intersection.location != NSNotFound && intersection.length > 0) {
        // The text range for this line intersects our selection range
        CGFloat xStart = CTLineGetOffsetForStringIndex(line, intersection.location, NULL);
        CGFloat xEnd = CTLineGetOffsetForStringIndex(line, intersection.location + intersection.length, NULL);
        CGPoint origin;
        // Get coordinate and bounds information for the intersection text range
        CTFrameGetLineOrigins(_frame, CFRangeMake(i, 0), &origin);
        CGFloat ascent, descent;
        CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
        // Create a rect for the intersection and draw it with selection color
        CGRect selectionRect = CGRectMake(xStart, origin.y - descent, xEnd - xStart, ascent + descent);
        UIRectFill(selectionRect);
    }
}    

I noticed one very strange thing. 我注意到一件非常奇怪的事情。 Calls to CTFrameGetLineOrigin seem to destroy the values inside of xStart and xEnd. 调用CTFrameGetLineOrigin似乎会破坏xStart和xEnd内部的值。 I inserted logs as in the following: 我插入了如下日志:

NSLog(@"BEFORE: xStart (%p) = %f, xEnd (%p) = %f, origin (%p) = %@", &xStart, xStart, &xEnd, xEnd, &origin, NSStringFromCGPoint(origin));
CTFrameGetLineOrigins(_frame, CFRangeMake(i, 0), &origin);
NSLog(@"AFTER: xStart (%p) = %f, xEnd (%p) = %f, origin (%p) = %@", &xStart, xStart, &xEnd, xEnd, &origin, NSStringFromCGPoint(origin));

The output for the lines that don't work is as follows 无效行的输出如下

2012-09-19 12:08:39.831 SimpleTextInput[1172:11603] BEFORE: xStart (0xbfffcefc) = 18.000000, xEnd (0xbfffcef8) = 306.540009, origin (0xbfffcef0) = {0, -0} 2012-09-19 12:08:39.831 SimpleTextInput [1172:11603]之前:xStart(0xbfffcefc)= 18.000000,xEnd(0xbfffcef8)= 306.540009,原点(0xbfffcef0)= {0,-0}

2012-09-19 12:08:39.831 SimpleTextInput[1172:11603] AFTER: xStart (0xbfffcefc) = 370.000000, xEnd (0xbfffcef8) = 0.000000, origin (0xbfffcef0) = {0, 397} 2012-09-19 12:08:39.831 SimpleTextInput [1172:11603]之后:xStart(0xbfffcefc)= 370.000000,xEnd(0xbfffcef8)= 0.000000,原点(0xbfffcef0)= {0,397}

If I do the following, it will fix itself...but I have no idea why: 如果执行以下操作,它将自动修复...但是我不知道为什么:

CGFloat xStart = CTLineGetOffsetForStringIndex(line, intersection.location, NULL);
CGFloat xEnd = CTLineGetOffsetForStringIndex(line, intersection.location + intersection.length, NULL);
CGFloat xStart2 = 0.f; //HACK, not used at all except to pad memory
CGPoint origin;

It seems like CTFrameGetLineOrigin doesn't respect the memory boundaries of origin (Logging xStart2 shows that its value gets corrupted in the same way), but if that is the case then why would the last line of text work as expected? 这似乎是CTFrameGetLineOrigin不尊重的内存边界origin (记录xStart2显示,其价值被以同样的方式损坏),但如果是这样的话,那么为什么会如预期文字工作的最后一行? Can someone explain this to me? 谁可以给我解释一下这个?

No strange bug in CTFrameGetLineOrigins. CTFrameGetLineOrigins中没有奇怪的错误。

In CTFrameGetLineOrigins 2nd parameter: CFRange is range of line origins you wish to copy. 在CTFrameGetLineOrigins第二个参数中: CFRange是要复制的线原点的范围。 If the range length of the range is 0, then the copy operation continues from the start index of the range to the last line origin. 如果范围的范围长度为0,则复制操作将从范围的起始索引继续到最后的行原点。

You are passing CFRangeMake(i, 0) . 您正在传递CFRangeMake(i, 0) Here in first loop iteration (i=0), it will try to fill &origin with all lines origins (0 to end line) and override some other memory. 在这里,在第一次循环迭代(i = 0)中,它将尝试用所有行的原点(从0到结束行)填充&origin,并覆盖其他一些内存。

Try following code, this will solve the problem. 尝试下面的代码,这将解决问题。

NSArray *lines = (NSArray *) CTFrameGetLines(_frame);
CGPoint origins[lines.count]; //allocate enough space for buffer.
// Get all line origins...
CTFrameGetLineOrigins(_frame, CFRangeMake(0, 0), origins);

for (int i = 0; i < [lines count]; i++) {
    CTLineRef line = (CTLineRef) [lines objectAtIndex:i];
    CFRange lineRange = CTLineGetStringRange(line);
    NSRange range = NSMakeRange(lineRange.location, lineRange.length);
    NSRange intersection = [self RangeIntersection:range withSecond:selectionRange];
    if (intersection.location != NSNotFound && intersection.length > 0) {
        // The text range for this line intersects our selection range
        CGFloat xStart = CTLineGetOffsetForStringIndex(line, intersection.location, NULL);
        CGFloat xEnd = CTLineGetOffsetForStringIndex(line, intersection.location + intersection.length, NULL);
        
        CGFloat ascent, descent;
        CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
        // Create a rect for the intersection and draw it with selection color
        CGRect selectionRect = CGRectMake(xStart + origins[i].x, origins[i].y - descent, xEnd - xStart, ascent + descent);
        UIRectFill(selectionRect);
    }
}    

This looks like it's the drawRangeAsSelection from the SimpleTextInput example. 看起来就像SimpleTextInput示例中的drawRangeAsSelection If that's the case you can do: 如果是这样,您可以执行以下操作:

CTFrameGetLineOrigins(_frame, CFRangeMake(i, 1), &origin);

Which will simply retrieve the origin for just the one line that you need (which is what is intended in this method). 这将仅检索您需要的一行的原点(这就是此方法的目的)。 I also noticed they made the same mistake in: cursorRectForIndex and firstRectForNSRange . 我还注意到它们在以下方面犯了相同的错误: cursorRectForIndexfirstRectForNSRange Credit goes to @RobNapier for helping me figure this one out. 感谢@RobNapier帮助我弄清楚了这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM