Get the fragmentRect used for layout from the text container

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@8061 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
FredKiefer 2000-11-06 22:11:26 +00:00
parent 856b6b4a6b
commit 0ca2537bc8

View file

@ -52,8 +52,8 @@
#define HUGE 1e7 #define HUGE 1e7
static NSCharacterSet *selectionWordGranularitySet;
static NSCharacterSet *newlines; static NSCharacterSet *newlines;
static NSCharacterSet *selectionWordGranularitySet;
static NSCharacterSet *invSelectionWordGranularitySet; static NSCharacterSet *invSelectionWordGranularitySet;
@interface _GNULineLayoutInfo: NSObject @interface _GNULineLayoutInfo: NSObject
@ -120,7 +120,6 @@ static NSCharacterSet *invSelectionWordGranularitySet;
- (NSRect) rectForCharacterIndex: (unsigned) index; - (NSRect) rectForCharacterIndex: (unsigned) index;
- (NSRange) lineRangeForRect: (NSRect) aRect; - (NSRange) lineRangeForRect: (NSRect) aRect;
- (NSSize) _sizeOfRange: (NSRange) range; - (NSSize) _sizeOfRange: (NSRange) range;
- (float) width;
// return value is identical to the real line number // return value is identical to the real line number
- (int) lineLayoutIndexForGlyphIndex: (unsigned) anIndex; - (int) lineLayoutIndexForGlyphIndex: (unsigned) anIndex;
@ -154,6 +153,14 @@ static NSCharacterSet *invSelectionWordGranularitySet;
[self setSelectionWordGranularitySet: whitespace]; [self setSelectionWordGranularitySet: whitespace];
} }
- (id) init
{
self = [super init];
_lineLayoutInformation = [[NSMutableArray alloc] init];
return self;
}
- (void) dealloc - (void) dealloc
{ {
RELEASE(_lineLayoutInformation); RELEASE(_lineLayoutInformation);
@ -163,7 +170,7 @@ static NSCharacterSet *invSelectionWordGranularitySet;
- (void) setTextStorage: (NSTextStorage*)aTextStorage - (void) setTextStorage: (NSTextStorage*)aTextStorage
{ {
DESTROY(_lineLayoutInformation); [_lineLayoutInformation removeAllObjects];
[super setTextStorage: aTextStorage]; [super setTextStorage: aTextStorage];
} }
@ -180,7 +187,7 @@ static NSCharacterSet *invSelectionWordGranularitySet;
for ((lineEnum = [_lineLayoutInformation objectEnumerator]); for ((lineEnum = [_lineLayoutInformation objectEnumerator]);
(currentInfo = [lineEnum nextObject]);) (currentInfo = [lineEnum nextObject]);)
{ {
retRect = NSUnionRect (retRect, currentInfo->lineRect); retRect = NSUnionRect (retRect, currentInfo->usedRect);
} }
return retRect; return retRect;
} }
@ -392,6 +399,17 @@ static NSCharacterSet *invSelectionWordGranularitySet;
return NSMakeRange(0, [_textStorage length]); return NSMakeRange(0, [_textStorage length]);
} }
- (void)invalidateGlyphsForCharacterRange:(NSRange)charRange
changeInLength:(int)delta
actualCharacterRange:(NSRange*)actualCharRange
{
// As we currenty dont have any glyph character mapping, we only have
// to ajust the ranges in the line layout infos
if (actualCharRange)
*actualCharRange = charRange;
}
- (void) invalidateLayoutForCharacterRange: (NSRange)aRange - (void) invalidateLayoutForCharacterRange: (NSRange)aRange
isSoft: (BOOL)flag isSoft: (BOOL)flag
actualCharacterRange: (NSRange*)actualRange actualCharacterRange: (NSRange*)actualRange
@ -421,6 +439,10 @@ static NSCharacterSet *invSelectionWordGranularitySet;
if (!mask) if (!mask)
return; return;
[self invalidateGlyphsForCharacterRange: invalidatedCharRange
changeInLength: delta
actualCharacterRange: NULL];
lineRange = [self rebuildForRange: aRange lineRange = [self rebuildForRange: aRange
delta: delta delta: delta
inTextContainer: aTextContainer]; inTextContainer: aTextContainer];
@ -495,21 +517,6 @@ static NSCharacterSet *invSelectionWordGranularitySet;
return [_textStorage sizeRange: aRange]; return [_textStorage sizeRange: aRange];
} }
- (NSRect) frame
{
if ([self firstTextView] == nil)
{
NSSize size = [[_textContainers objectAtIndex: 0] containerSize];
return NSMakeRect(0, 0, size.width, size.height);
}
return [[self firstTextView] frame];
}
- (float) width
{
return [[_textContainers objectAtIndex: 0] containerSize].width;
}
- (unsigned) lineLayoutIndexForPoint: (NSPoint)point - (unsigned) lineLayoutIndexForPoint: (NSPoint)point
{ {
int i; int i;
@ -620,7 +627,7 @@ static NSCharacterSet *invSelectionWordGranularitySet;
// rect to the end of line // rect to the end of line
- (NSRect) rectForCharacterIndex: (unsigned)index - (NSRect) rectForCharacterIndex: (unsigned)index
{ {
float width = [self width]; float width = [[_textContainers objectAtIndex: 0] containerSize].width;
_GNULineLayoutInfo *currentInfo; _GNULineLayoutInfo *currentInfo;
unsigned start; unsigned start;
NSRect rect; NSRect rect;
@ -700,8 +707,6 @@ static NSCharacterSet *invSelectionWordGranularitySet;
- (void) setNeedsDisplayForLineRange: (NSRange)redrawLineRange - (void) setNeedsDisplayForLineRange: (NSRange)redrawLineRange
inTextContainer:(NSTextContainer *)aTextContainer inTextContainer:(NSTextContainer *)aTextContainer
{ {
float width = [aTextContainer containerSize].width;
if ([_lineLayoutInformation count] if ([_lineLayoutInformation count]
&& redrawLineRange.location < [_lineLayoutInformation count] && redrawLineRange.location < [_lineLayoutInformation count]
&& redrawLineRange.length) && redrawLineRange.length)
@ -709,6 +714,7 @@ static NSCharacterSet *invSelectionWordGranularitySet;
_GNULineLayoutInfo *firstInfo _GNULineLayoutInfo *firstInfo
= [_lineLayoutInformation objectAtIndex: redrawLineRange.location]; = [_lineLayoutInformation objectAtIndex: redrawLineRange.location];
NSRect displayRect = firstInfo->lineRect; NSRect displayRect = firstInfo->lineRect;
float width = [aTextContainer containerSize].width;
if (redrawLineRange.length > 1) if (redrawLineRange.length > 1)
displayRect = NSUnionRect(displayRect, displayRect = NSUnionRect(displayRect,
@ -717,13 +723,13 @@ static NSCharacterSet *invSelectionWordGranularitySet;
(int)NSMaxRange(redrawLineRange) - 1] lineRect]); (int)NSMaxRange(redrawLineRange) - 1] lineRect]);
displayRect.size.width = width - displayRect.origin.x; displayRect.size.width = width - displayRect.origin.x;
[[self firstTextView] setNeedsDisplayInRect: displayRect]; [[aTextContainer textView] setNeedsDisplayInRect: displayRect];
} }
} }
- (BOOL) _relocLayoutArray: (NSMutableArray*)ghostArray - (BOOL) _relocLayoutArray: (NSMutableArray*)ghostArray
offset: (int)relocOffset offset: (int)relocOffset
floatTrift: (float*)yDisplacement floatTrift: (float*)yDisplacement
{ {
_GNULineLayoutInfo *lastInfo = [_lineLayoutInformation lastObject]; _GNULineLayoutInfo *lastInfo = [_lineLayoutInformation lastObject];
// The start character in the ghostArray // The start character in the ghostArray
@ -760,6 +766,7 @@ static NSCharacterSet *invSelectionWordGranularitySet;
if (yReloc) if (yReloc)
{ {
currReloc->lineRect.origin.y += yReloc; currReloc->lineRect.origin.y += yReloc;
currReloc->usedRect.origin.y += yReloc;
} }
[_lineLayoutInformation addObject: currReloc]; [_lineLayoutInformation addObject: currReloc];
} }
@ -790,42 +797,27 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
delta: (int)insertionDelta delta: (int)insertionDelta
inTextContainer:(NSTextContainer *)aTextContainer inTextContainer:(NSTextContainer *)aTextContainer
{ {
int aLine = 0;
NSPoint drawingPoint = NSZeroPoint; NSPoint drawingPoint = NSZeroPoint;
float width = [aTextContainer containerSize].width; float padding = [aTextContainer lineFragmentPadding];
unsigned startingIndex = 0; unsigned startingIndex = 0;
unsigned currentLineIndex; unsigned currentLineIndex;
// for optimization detection
NSMutableArray *ghostArray;
NSString *allText = [_textStorage string]; NSString *allText = [_textStorage string];
unsigned length = [allText length]; unsigned length = [allText length];
unsigned paraPos; unsigned paraPos;
int maxLines = [_lineLayoutInformation count];
int aLine = 0;
// for optimization detection
NSMutableArray *ghostArray = nil;
// sanity check that it is possible to do the layout if (maxLines)
if (width == 0.0)
{ {
NSLog(@"NSText formatting with empty frame"); int insertionLineIndex = [self lineLayoutIndexForGlyphIndex:
return NSMakeRange(0,0); aRange.location];
} int nextLine = [self lineLayoutIndexForGlyphIndex:
NSMaxRange(aRange) - insertionDelta] + 1;
if (_lineLayoutInformation == nil) if (nextLine < maxLines)
{ {
_lineLayoutInformation = [[NSMutableArray alloc] init];
aLine = 0;
ghostArray = nil;
}
else
{
int insertionLineIndex = [self lineLayoutIndexForGlyphIndex:
aRange.location];
int nextLine = [self lineLayoutIndexForGlyphIndex:
NSMaxRange(aRange)] + 1;
int maxLines = [_lineLayoutInformation count];
aLine = MAX(0, insertionLineIndex - 1);
if (nextLine < maxLines)
{
// remember old array for optimization purposes // remember old array for optimization purposes
ghostArray = AUTORELEASE([[_lineLayoutInformation ghostArray = AUTORELEASE([[_lineLayoutInformation
subarrayWithRange: subarrayWithRange:
@ -833,28 +825,27 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
maxLines - nextLine)] maxLines - nextLine)]
mutableCopy]); mutableCopy]);
} }
else
{ aLine = MAX(0, insertionLineIndex - 1);
ghostArray = nil; if (aLine)
} {
_GNULineLayoutInfo *lastValidLineInfo = [_lineLayoutInformation
if (aLine) objectAtIndex: aLine - 1];
{ NSRect aRect = lastValidLineInfo->lineRect;
_GNULineLayoutInfo *lastValidLineInfo = [_lineLayoutInformation
objectAtIndex: aLine - 1]; startingIndex = NSMaxRange(lastValidLineInfo->lineRange);
NSRect aRect = lastValidLineInfo->lineRect; drawingPoint = aRect.origin;
drawingPoint.y += aRect.size.height;
startingIndex = NSMaxRange(lastValidLineInfo->lineRange); }
drawingPoint = aRect.origin;
drawingPoint.y += aRect.size.height; [_lineLayoutInformation removeObjectsInRange:
} NSMakeRange (aLine, maxLines - aLine)];
[_lineLayoutInformation removeObjectsInRange:
NSMakeRange (aLine, [_lineLayoutInformation count] - aLine)];
} }
if (!length) if (!length)
{ {
float width = [aTextContainer containerSize].width;
// FIXME: This should be done via extra line fragment // FIXME: This should be done via extra line fragment
// If there is no text add one empty box // If there is no text add one empty box
[_lineLayoutInformation [_lineLayoutInformation
@ -877,6 +868,7 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
BOOL isBuckled = NO; BOOL isBuckled = NO;
NSString *paragraph; NSString *paragraph;
unsigned position; // Position in NSString. unsigned position; // Position in NSString.
NSRect remainingRect = NSZeroRect;
// Determine the range of the next paragraph of text (in 'para') and set // Determine the range of the next paragraph of text (in 'para') and set
// 'paraPos' to point after the terminating newline character (if any). // 'paraPos' to point after the terminating newline character (if any).
@ -898,12 +890,34 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
do do
{ {
NSRect currentLineRect = NSMakeRect (0, drawingPoint.y, 0, 0); NSRect fragmentRect;
NSRect usedLineRect;
float width;
NSRange currentLineRange; NSRange currentLineRange;
// starts with zero, do not confuse with startingLineCharIndex // starts with zero, do not confuse with startingLineCharIndex
unsigned localLineStartIndex = [lScanner scanLocation]; unsigned localLineStartIndex = [lScanner scanLocation];
unsigned scannerPosition = localLineStartIndex; unsigned scannerPosition = localLineStartIndex;
if (NSIsEmptyRect(remainingRect))
fragmentRect = NSMakeRect (0, drawingPoint.y, HUGE, HUGE);
else
fragmentRect = remainingRect;
fragmentRect = [aTextContainer lineFragmentRectForProposedRect: fragmentRect
sweepDirection: NSLineSweepRight
movementDirection: NSLineMoveDown
remainingRect: &remainingRect];
if (NSIsEmptyRect(fragmentRect))
{
// No more space in the text container, give up doing the layout
return NSMakeRange(aLine, MAX(1, [_lineLayoutInformation count] - aLine));
}
width = fragmentRect.size.width - 2 * padding;
usedLineRect = fragmentRect;
usedLineRect.origin.x += padding;
usedLineRect.size = NSZeroSize;
// scan the individual words to the end of the line // scan the individual words to the end of the line
while (![lScanner isAtEnd]) while (![lScanner isAtEnd])
{ {
@ -927,14 +941,13 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
currentStringRange = NSUnionRange(trailingSpacesRange, currentStringRange = NSUnionRange(trailingSpacesRange,
currentStringRange); currentStringRange);
// evaluate size of current word and line so far // evaluate size of current word
advanceSize = [self _sizeOfRange: advanceSize = [self _sizeOfRange:
NSMakeRange (currentStringRange.location + position, NSMakeRange (currentStringRange.location + position,
currentStringRange.length)]; currentStringRange.length)];
// handle case where single word is broader than width // handle case where single word is broader than width
// (buckle word) <!> unfinished and untested // (buckle word)
// for richText (absolute position see above)
if (advanceSize.width > width) if (advanceSize.width > width)
{ {
if (isBuckled) if (isBuckled)
@ -950,7 +963,7 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
startingLineCharIndex, lastVisibleCharIndex)]; startingLineCharIndex, lastVisibleCharIndex)];
} }
isBuckled = NO; isBuckled = NO;
currentLineRect.size = currentSize; usedLineRect.size = currentSize;
scannerPosition = localLineStartIndex + lastVisibleCharIndex +1; scannerPosition = localLineStartIndex + lastVisibleCharIndex +1;
[lScanner setScanLocation: scannerPosition]; [lScanner setScanLocation: scannerPosition];
break; break;
@ -966,7 +979,7 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
isBuckled = NO; isBuckled = NO;
// line to long // line to long
if (currentLineRect.size.width + advanceSize.width > width || if (usedLineRect.size.width + advanceSize.width > width ||
isBuckled) isBuckled)
{ {
// end of line -> word wrap // end of line -> word wrap
@ -976,7 +989,7 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
} }
// Add next word // Add next word
currentLineRect = NSUnionRect (currentLineRect, usedLineRect = NSUnionRect (usedLineRect,
NSMakeRect (drawingPoint.x, NSMakeRect (drawingPoint.x,
drawingPoint.y, drawingPoint.y,
advanceSize.width, advanceSize.width,
@ -992,21 +1005,23 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
{ {
// Add information for the line break // Add information for the line break
scannerPosition += eol.length; scannerPosition += eol.length;
currentLineRect.size.width += 1; usedLineRect.size.width += 1;
// FIXME: This should use the real font size!! // FIXME: This should use the real font size!!
if (!currentLineRect.size.height) if (!usedLineRect.size.height)
currentLineRect.size.height = 12; usedLineRect.size.height = 12;
} }
} }
currentLineRange = NSMakeRange (startingLineCharIndex, currentLineRange = NSMakeRange (startingLineCharIndex,
scannerPosition - localLineStartIndex); scannerPosition - localLineStartIndex);
[self setLineFragmentRect: currentLineRect // Adjust the height of the line fragment rect, as this will the to big
fragmentRect.size.height = usedLineRect.size.height;
[self setLineFragmentRect: fragmentRect
forGlyphRange: currentLineRange forGlyphRange: currentLineRange
usedRect: currentLineRect]; usedRect: usedLineRect];
currentLineIndex++; currentLineIndex++;
startingLineCharIndex = NSMaxRange(currentLineRange); startingLineCharIndex = NSMaxRange(currentLineRange);
drawingPoint.y += currentLineRect.size.height; drawingPoint.y += usedLineRect.size.height;
drawingPoint.x = 0; drawingPoint.x = 0;
if (ghostArray != nil) if (ghostArray != nil)
@ -1044,3 +1059,4 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
// end: central line formatting method------------------------------------ // end: central line formatting method------------------------------------
@end @end