Re: Typesetter - Fragment Generation
Re: Typesetter - Fragment Generation
- Subject: Re: Typesetter - Fragment Generation
- From: Seth Willits <email@hidden>
- Date: Thu, 14 Mar 2013 22:16:01 -0700
Responding to myself, here:
> 1) When I dump rich text into the text view, this method is called *twice* for each starting glyph index, and the proposed rect for the second call is the proposed rect I modify during the first call. For plain text it's only called once for each line. Any explanations for what's going on?
I still have no idea what the answer is.
> 2) Is simply modifying the proposed rect's origin the right approach?
> a) Does the proposed rect ever include lineFragmentPadding
> b) Is the proposed rect always a bazillion points wide?
Answers:
2) Yes.
2a) No.
2b) It *think* so.
> 3) Is it always going to be safe to ask the layout manage locationForGlyphAtIndex: for a glyph index < startingGlyphIndex or is there any possibility of an infinite loop?
Answer: yes it's possible to get in an infinite loop. There seems to be no solution other than not using locationForGlyphAtIndex. So rather than using the location of the first non-whitespace character to determine indentation, the answer is to calculate the width of the indentation "manually". I took a look at how Xcode does it, and it actually does this as well.
So here's what I've got:
- (void)getLineFragmentRect:(NSRectPointer)lineFragmentRect usedRect:(NSRectPointer)lineFragmentUsedRect remainingRect:(NSRectPointer)remainingRect forStartingGlyphAtIndex:(NSUInteger)startingGlyphIndex proposedRect:(NSRect)proposedRect lineSpacing:(CGFloat)lineSpacing paragraphSpacingBefore:(CGFloat)paragraphSpacingBefore paragraphSpacingAfter:(CGFloat)paragraphSpacingAfter
{
AGSourceTextStorage * textStorage = (AGSourceTextStorage *)self.layoutManager.textStorage;
if (![textStorage isKindOfClass:[AGSourceTextStorage class]]) {
[NSException raise:@"" format:@"AGSourceTypesetter's text storage is not an AGSourceTextStorage"];
}
if (textStorage.indentWrappedLines) {
NSString * string = textStorage.string;
NSUInteger characterIndex = [self.layoutManager characterIndexForGlyphAtIndex:startingGlyphIndex];
NSRange lineRange = [string lineRangeForRange:NSMakeRange(characterIndex, 0)];
// Find the line range for the line of text this glyph is a part of
characterIndex = [self.layoutManager characterIndexForGlyphAtIndex:startingGlyphIndex];
lineRange = [string lineRangeForRange:NSMakeRange(characterIndex, 0)];
// If the startingGlyphIndex's character is *after* the beginning of the line
// of text it's on, then the lineFragmentRect being asked for must be part
// of a wrapped line - which we want to indent.
if (characterIndex > lineRange.location) {
NSUInteger lineNumber = [textStorage lineNumberAtCharacterLocation:characterIndex];
CGFloat indentation = [textStorage indentationForWrappedLineNumber:lineNumber];
// TODO: Do we need to do anything special for lineFragmentPadding *here*?
// ...
// Modify the proposed rect to create that indentation
CGFloat maxX = NSMaxX(proposedRect);
proposedRect.origin.x = indentation;
proposedRect.size.width = maxX - indentation;
}
}
// After having possibly indented the proposed rect, let the standard class do its thing.
[super getLineFragmentRect:lineFragmentRect usedRect:lineFragmentUsedRect remainingRect:remainingRect forStartingGlyphAtIndex:startingGlyphIndex proposedRect:proposedRect lineSpacing:lineSpacing paragraphSpacingBefore:paragraphSpacingBefore paragraphSpacingAfter:paragraphSpacingAfter];
}
indentationForWrappedLineNumber in the text storage class counts the number of spaces at the beginning of the line, and multiplies that by a standard width for a space which was precalculated.
Seems to work, and it's reassuring to know that Xcode also apparently thinks this is a good solution and I think some smart folks work on that. ;-)
--
Seth Willits
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden