_NSFastFillAllLayoutHolesUpToGlyphIndex crash in NSLayoutManager
_NSFastFillAllLayoutHolesUpToGlyphIndex crash in NSLayoutManager
- Subject: _NSFastFillAllLayoutHolesUpToGlyphIndex crash in NSLayoutManager
- From: Keith Blount <email@hidden>
- Date: Sun, 29 Jul 2007 17:28:51 -0700 (PDT)
Hello,
I have a printing text view that avoids widows and
orphans when it prints. It works a little like
TextEdit's wrap-to-page view in that it adds and
removes pages in NSLayoutManager's
-layoutManager:didCompleteLayoutForTextContainer:atEnd:
method. It also checks for widows and orphans in this
method by getting the index of the glyph right at the
end of the last full text container, getting the
paragraph that contains that glyph, counting the
number of lines contained in that paragraph and then
deciding whether or not any lines need pushing over
onto the next page.
This means that I have created my own method that gets
called from inside the
-layoutManager:didCompleteLayoutForTextContainer:atEnd:
method in order to count the number of lines in a
paragraph. Unfortunately, my method seems - in some
very particular but seemingly random circumstances -
to be causing a crash. This is the method that gets
called from
-layoutManager:didCompleteLayoutForTextContainer:atEnd:
in order to count the number of lines in a paragraph:
// Convenience methods for helping avoid widows and
orphans
-
(unsigned)numberOfLinesInParagraphContainingGlyphRange:(NSRange)glyphRange
inLayoutManager:(NSLayoutManager *)lm
lineForRange:(unsigned *)lineNo lineHeights:(NSArray
**)lineHeights
{
NSRange paragraphCharacterRange, paragraphGlyphRange;
paragraphCharacterRange = [layoutManager
characterRangeForGlyphRange:glyphRange
actualGlyphRange:nil];
paragraphCharacterRange = [[[layoutManager
attributedString] string]
paragraphRangeForRange:paragraphCharacterRange];
paragraphGlyphRange = [layoutManager
glyphRangeForCharacterRange:paragraphCharacterRange
actualCharacterRange:nil];
// Offset glyphRange to account for the fact that the
paragraph range will be placed at the beginning of a
text view.
glyphRange.location -= paragraphGlyphRange.location;
// Create a temporary text view and make sure it has
the same width as the original. Our text has not
finished layout out in the multiple page view,
// so to get an accurate line count of the paragraph,
we need to place it in a text view that finishes
layout before we count.
NSRect frame = NSZeroRect;
frame.size = [[self firstTextView] frame].size;
frame.size.height = FLT_MAX;
NSTextView *tempTextView = [[NSTextView alloc]
initWithFrame:frame];
[tempTextView setTextContainerInset:NSMakeSize(0,0)];
[[tempTextView textContainer]
setLineFragmentPadding:0.0];
// Place the paragraph into our temporary text view.
[[tempTextView textStorage] beginEditing];
[[tempTextView textStorage]
replaceCharactersInRange:NSMakeRange(0,0)
withAttributedString:[textStorage
attributedSubstringFromRange:paragraphCharacterRange]];
[[tempTextView textStorage] endEditing];
// Now use the layout manager o the temporary text
view to count how many lines the paragraph takes up in
our view, and also to find out how high each line will
be.
NSLayoutManager *tempLayoutManager = [tempTextView
layoutManager];
// Set paragraphGlyphRange.location to 0 as it is now
at the beginning of our text view.
paragraphGlyphRange.location = 0;
NSMutableArray *heights = [NSMutableArray array];
unsigned index, numberOfLines;
NSRange lineRange;
for (numberOfLines = 0, index =
paragraphGlyphRange.location; index <
NSMaxRange(paragraphGlyphRange); numberOfLines++)
{
// Save the height of the current line and get the
its range.
// THIS next line, with the call to
-lineFragmentRectForGlyphAtIndex..., can cause a
crash, apparently because of the layout caused.
[heights addObject:[NSNumber
numberWithFloat:[tempLayoutManager
lineFragmentRectForGlyphAtIndex:index
effectiveRange:&lineRange].size.height]];
// Does the current line contain the range we passed
in? If so, save the line number (we have to add 1,
because numberOfLines has not yet been advanced).
if (lineNo &&
NSIntersectionRange(lineRange,glyphRange).length > 0)
*lineNo = numberOfLines+1;
index = NSMaxRange(lineRange);
}
[tempTextView release];
if (lineHeights) *lineHeights = [NSArray
arrayWithArray:heights];
return numberOfLines;
}
The crash comes when that method causes layout in the
tempLayoutManager, when I get this backtrace:
Exception: EXC_BAD_ACCESS (0x0001)
Codes: KERN_INVALID_ADDRESS (0x0001) at
0xbf7ffdec
Thread 0 Crashed:
0 com.apple.AppKit 0x933437f2
-[NSConcreteGlyphGenerator
generateGlyphsForGlyphStorage:desiredNumberOfCharacters:glyphIndex:characterIndex:]
+ 12
1 com.apple.AppKit 0x933437b5
-[NSGlyphGenerator
generateGlyphsForLayoutManager:range:desiredNumberOfCharacters:startingAtGlyphIndex:completedRange:nextGlyphIndex:]
+ 81
2 com.apple.AppKit 0x9334310a
-[NSLayoutManager(NSPrivate)
_fillGlyphHoleAtIndex:desiredNumberOfCharacters:] +
1216
3 com.apple.AppKit 0x932e3aff
_NSFastFillAllGlyphHolesUpToGlyphIndex + 311
4 com.apple.AppKit 0x9332ed68
_NSFastFillAllLayoutHolesUpToGlyphIndex + 367
5 com.apple.AppKit 0x933b0519
-[NSLayoutManager
lineFragmentRectForGlyphAtIndex:effectiveRange:] + 26
6 ...iteratureandlatte.scrivener 0x000d2a61
-[KBTextPagePrintingView
numberOfLinesInParagraphContainingGlyphRange:inLayoutManager:lineForRange:lineHeights:]
+ 722
7 ...iteratureandlatte.scrivener 0x000d25de
-[KBTextPagePrintingView
layoutManager:didCompleteLayoutForTextContainer:atEnd:]
If anyone can see what I am doing wrong in the above
method (bearing in mind that it gets called from the
NSLayoutManager delegate method), I would be very
grateful; I have now spent days on this to no avail.
Thanks in advance and all the best,
Keith
____________________________________________________________________________________
Sick sense of humor? Visit Yahoo! TV's
Comedy with an Edge to see what's on, when.
http://tv.yahoo.com/collections/222
_______________________________________________
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