zooey+mmlr:

* Large cleanup in _FindLineBreak(), be a bit more clever by storing the found
  offsets instead of calculating them multiple times, use
  _TabExpandedStyledWidth() instead of _StyledWidth() and manual tab calculation
  which was also broken (it assumed tabs were consequtive which was possibly not
  the case).
* Modified CanEndLine() to also return true when going from non-whitespace to
  whitespace and the other way around which is more logical (so we'd break after
  the word and not after word + whitespace, even though we actually do that
  in the end by eating whitespace after words in _FindLineBreak()).
* The TextGapBuffer is not necessarily 0 terminated, so RealCharAt() needs to
  check if the index is at the end of the string and return 0 in that case.
  Before it would access the buffer "out by one" which could've lead to a crash.
* Simplified the gap moving calculations by removing some no-op calculations.
* Added debugger calls in TextGapBuffer in case of invalid use.
* Some minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36304 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2010-04-15 16:12:16 +00:00
parent 87158047dd
commit 5c4e7641a7
3 changed files with 48 additions and 84 deletions

View File

@ -1144,7 +1144,7 @@ BTextView::SetText(const char *inText, int32 inLength,
// remove data from buffer
if (fText->Length() > 0)
DeleteText(0, fText->Length()); // TODO: was fText->Length() - 1
DeleteText(0, fText->Length());
if (inText != NULL && inLength > 0)
InsertText(inText, inLength, 0, inRuns);
@ -1944,6 +1944,9 @@ BTextView::FindWord(int32 inOffset, int32 *outFromOffset, int32 *outToOffset)
bool
BTextView::CanEndLine(int32 offset)
{
if (offset < 0 || offset > fText->Length())
return false;
// TODO: This should be improved using the LocaleKit.
uint32 classification = _CharClassification(offset);
@ -1961,6 +1964,13 @@ BTextView::CanEndLine(int32 offset)
return false;
}
if ((classification == CHAR_CLASS_WHITESPACE
&& nextClassification != CHAR_CLASS_WHITESPACE)
|| (classification != CHAR_CLASS_WHITESPACE
&& nextClassification == CHAR_CLASS_WHITESPACE)) {
return true;
}
// allow wrapping after whitespace, unless more whitespace (except for
// newline) follows
if (classification == CHAR_CLASS_WHITESPACE
@ -3869,15 +3879,13 @@ BTextView::_FindLineBreak(int32 fromOffset, float *outAscent, float *outDescent,
float descent = 0.0;
int32 delta = 0;
float deltaWidth = 0.0;
float tabWidth = 0.0;
float strWidth = 0.0;
uchar theChar;
// wrap the text
do {
bool foundTab = false;
while (offset < limit && !done) {
// find the next line break candidate
for ( ; (offset + delta) < limit ; delta++) {
for (; (offset + delta) < limit; delta++) {
if (CanEndLine(offset + delta)) {
theChar = fText->RealCharAt(offset + delta);
if (theChar != B_SPACE && theChar != B_TAB
@ -3890,11 +3898,10 @@ BTextView::_FindLineBreak(int32 fromOffset, float *outAscent, float *outDescent,
break;
}
}
// now skip over trailing whitespace, if any
for ( ; (offset + delta) < limit; delta++) {
if (!CanEndLine(offset + delta))
break;
int32 deltaBeforeWhitespace = delta;
// now skip over trailing whitespace, if any
for (; (offset + delta) < limit; delta++) {
theChar = fText->RealCharAt(offset + delta);
if (theChar == B_ENTER) {
// found a newline, we're done!
@ -3904,85 +3911,36 @@ BTextView::_FindLineBreak(int32 fromOffset, float *outAscent, float *outDescent,
} else if (theChar != B_SPACE && theChar != B_TAB) {
// stop at anything else than trailing whitespace
break;
} else {
// include all trailing spaces and tabs,
// but not spaces after tabs
if (theChar == B_TAB)
foundTab = true;
}
}
delta = max_c(delta, 1);
deltaWidth = _StyledWidth(offset, delta, &ascent, &descent);
deltaWidth = _TabExpandedStyledWidth(offset, delta, &ascent, &descent);
strWidth += deltaWidth;
if (!foundTab)
tabWidth = 0.0;
else {
int32 tabCount = 0;
for (int32 i = delta - 1; fText->RealCharAt(offset + i) == B_TAB;
i--) {
tabCount++;
}
tabWidth = _ActualTabWidth(strWidth);
if (tabCount > 1)
tabWidth += ((tabCount - 1) * fTabWidth);
strWidth += tabWidth;
}
if (strWidth >= *inOutWidth) {
// we've found where the line will wrap
bool foundNewline = done;
done = true;
// we have included trailing whitespace in the width computation
// above, but that is not being shown anyway, so we try again
// without the trailing whitespace
int32 pos = delta - 1;
theChar = fText->RealCharAt(offset + pos);
if (theChar != B_SPACE && theChar != B_TAB && theChar != B_ENTER) {
if (delta == deltaBeforeWhitespace) {
// there is no trailing whitespace, no point in trying
break;
}
// reset string width to start of current run ...
strWidth -= (deltaWidth + tabWidth);
// ... skip back all trailing whitespace ...
while (offset + pos > offset) {
theChar = fText->RealCharAt(offset + pos);
if (theChar != B_SPACE && theChar != B_TAB
&& theChar != B_ENTER)
break;
pos--;
}
strWidth -= deltaWidth;
// ... and compute the resulting width (of visible characters)
strWidth += _StyledWidth(offset, pos + 1, &ascent, &descent);
strWidth += _StyledWidth(offset, deltaBeforeWhitespace, NULL, NULL);
if (strWidth >= *inOutWidth) {
// width of visible characters exceeds line, we need to wrap
// before the current "word"
break;
}
// we can include the current "word" on this line, but we need
// to eat the trailing whitespace, such that we do not encounter
// it again during the next run
// TODO: can this ever be entered?
if (!foundNewline) {
while (offset + delta < limit) {
const char realChar = fText->RealCharAt(offset + delta);
if (realChar != B_SPACE && realChar != B_TAB)
break;
delta++;
}
if (offset + delta < limit
&& fText->RealCharAt(offset + delta) == B_ENTER)
delta++;
}
// get the ascent and descent of the current word, including all
// trailing whitespace
_StyledWidth(offset, delta, &ascent, &descent);
}
*outAscent = max_c(ascent, *outAscent);
@ -3990,8 +3948,7 @@ BTextView::_FindLineBreak(int32 fromOffset, float *outAscent, float *outDescent,
offset += delta;
delta = 0;
} while (offset < limit && !done);
}
if (offset - fromOffset < 1) {
// there weren't any words that fit entirely in this line

View File

@ -129,21 +129,22 @@ TextGapBuffer::MoveGapTo(int32 toIndex)
{
if (toIndex == fGapIndex)
return;
if (toIndex > fItemCount) {
debugger("MoveGapTo: invalid toIndex supplied");
return;
}
long gapEndIndex = fGapIndex + fGapCount;
long srcIndex = 0;
long dstIndex = 0;
long count = 0;
int32 srcIndex = 0;
int32 dstIndex = 0;
int32 count = 0;
if (toIndex > fGapIndex) {
long trailGapCount = fBufferCount - gapEndIndex;
srcIndex = toIndex + (gapEndIndex - toIndex);
dstIndex = fGapIndex;
count = fGapCount + (toIndex - srcIndex);
count = (count > trailGapCount) ? trailGapCount : count;
srcIndex = fGapIndex + fGapCount;
dstIndex = fGapIndex;
count = toIndex - fGapIndex;
} else {
srcIndex = toIndex;
dstIndex = toIndex + (gapEndIndex - fGapIndex);
count = gapEndIndex - dstIndex;
dstIndex = toIndex + fGapCount;
count = fGapIndex- toIndex;
}
if (count > 0)

View File

@ -33,11 +33,11 @@ virtual ~TextGapBuffer();
bool FindChar(char inChar, int32 fromIndex, int32 *ioDelta);
const char *Text();
const char *RealText();
const char *Text();
const char *RealText();
int32 Length() const;
const char *GetString(int32 fromOffset, int32 *numBytes);
const char *GetString(int32 fromOffset, int32 *numBytes);
void GetString(int32 offset, int32 length, char *buffer);
char RealCharAt(int32 offset) const;
@ -50,11 +50,11 @@ virtual ~TextGapBuffer();
protected:
int32 fExtraCount; // when realloc()-ing
int32 fItemCount; // logical count
char *fBuffer; // allocated memory
char * fBuffer; // allocated memory
int32 fBufferCount; // physical count
int32 fGapIndex; // gap position
int32 fGapCount; // gap count
char *fScratchBuffer; // for GetString
char * fScratchBuffer; // for GetString
int32 fScratchSize; // scratch size
bool fPasswordMode;
};
@ -68,9 +68,15 @@ TextGapBuffer::Length() const
inline char
TextGapBuffer::RealCharAt(long index) const
TextGapBuffer::RealCharAt(int32 index) const
{
return (index < fGapIndex) ? fBuffer[index] : fBuffer[index + fGapCount];
if (index < 0 || index >= fItemCount) {
if (index != fItemCount)
debugger("RealCharAt: invalid index supplied");
return 0;
}
return index < fGapIndex ? fBuffer[index] : fBuffer[index + fGapCount];
}
} // namespace BPrivate