Widow / Orphan protection in text layout
Widow / Orphan protection in text layout
- Subject: Widow / Orphan protection in text layout
- From: Gideon King <email@hidden>
- Date: Tue, 21 May 2013 00:26:29 +1000
Hi, I have inherited some code which has a subclass of NSATSTypesetter in it, and in the -willSetLineFragmentRect:forGlyphRange:usedRect:baselineOffset: method it works out whether it needs to put a page break in, and directly sets the currentTextContainer, currentTextContainerIndex, and currentTextContainerSize instance variables.
This is completely undocumented and presumably a very bad way to handle the pagination, so I want to fix it.
The problem is that I am not clear whether the typesetter is the place to do the pagination or whether it should be in the layout manager, and if so exactly how to handle the processing. Any advice on how best to handle the pagination would be most welcome.
Here's what got handed to me (in a subclass of NSATSTypesetter):
- (void)willSetLineFragmentRect:(NSRect *)lineRect forGlyphRange:(NSRange)glyphRange usedRect:(NSRect *)usedRect baselineOffset:(CGFloat *)baselineOffset {
NSRange characterRange = [self characterRangeForGlyphRange:glyphRange actualGlyphRange:NULL];
NSString *string = [[[[self layoutManager] textStorage] string] substringWithRange:characterRange];
NSSize size = [[self currentTextContainer] containerSize];
// This is more like the forecast maximum y which is the line height plus the origin y.
CGFloat forecastedHeight = ((*lineRect).size.height*2.0) + (*lineRect).origin.y;
// If the last character of the line fragment is not a paragraph marker, and the text is on the last line, then put the text on the next page. This is so the
// text is not split so that the character name is on one page and the dialog is on another etc
if ([string characterAtIndex:characterRange.length-1] != NSParagraphSeparatorCharacter) {
if (forecastedHeight > size.height) {
NSFont *font = [[[self layoutManager] textStorage] attribute:NSFontAttributeName atIndex:[self paragraphCharacterRange].location effectiveRange:NULL];
NSDictionary *attrs = [[[self layoutManager] textStorage] attributesAtIndex:[self paragraphCharacterRange].location effectiveRange:NULL];
NSString *temp = [[[[self layoutManager] textStorage] string] substringWithRange:[self paragraphCharacterRange]];
NSSize stringSize = [temp sizeWithAttributes:attrs];
lineRect->origin.y = 0.0;
lineRect->size.height = stringSize.height;
usedRect->origin.y = 0.0;
usedRect->size.height = stringSize.height;
*baselineOffset = [[self layoutManager] defaultBaselineOffsetForFont:font];
if (currentTextContainer == [[self textContainers] lastObject]) {
currentTextContainerIndex = NSNotFound;
currentTextContainer = nil;
currentTextContainerSize = NSZeroSize;
} else {
unsigned indexOfOldTC = [[self textContainers] indexOfObjectIdenticalTo:currentTextContainer];
currentTextContainerIndex = indexOfOldTC+1;
currentTextContainer = [[self textContainers] objectAtIndex:currentTextContainerIndex];
currentTextContainerSize = [currentTextContainer containerSize];
}
}
}
// If the line is a character name, then we will always put it down a line below whatever section was above it.
NSString *section = [self.screenwriterLayoutManager.screenwriterView sectionFromRange:[self paragraphCharacterRange]];
if (section == SWCharacterSectionIdentifier) {
if (forecastedHeight > size.height) {
if (lineRect->origin.y > 0.001) {
NSFont *font = [[[self layoutManager] textStorage] attribute:NSFontAttributeName atIndex:[self paragraphCharacterRange].location effectiveRange:NULL];
NSDictionary *attrs = [[[self layoutManager] textStorage] attributesAtIndex:[self paragraphCharacterRange].location effectiveRange:NULL];
NSString *temp = [[[[self layoutManager] textStorage] string] substringWithRange:[self paragraphCharacterRange]];
NSSize stringSize = [temp sizeWithAttributes:attrs];
lineRect->origin.y = 0.0;
lineRect->size.height = stringSize.height;
usedRect->origin.y = 0.0;
usedRect->size.height = stringSize.height;
*baselineOffset = [[self layoutManager] defaultBaselineOffsetForFont:font];
if (currentTextContainer == [[self textContainers] lastObject]) {
currentTextContainerIndex = NSNotFound;
currentTextContainer = nil;
currentTextContainerSize = NSZeroSize;
} else {
unsigned indexOfOldTC = [[self textContainers] indexOfObjectIdenticalTo:currentTextContainer];
currentTextContainerIndex = indexOfOldTC+1;
currentTextContainer = [[self textContainers] objectAtIndex:currentTextContainerIndex];
currentTextContainerSize = [currentTextContainer containerSize];
}
}
}
}
}
PS Sorry about the number of questions at once - just seem to have run into multiple issues at once tonight.
Regards
Gideon
_______________________________________________
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