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:
parent
87158047dd
commit
5c4e7641a7
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user