such a long debugging session for such a silly error: the new hashed_escapements struct was never put into the width table when we grew the hash. The BWidthBufferTest now works. Simplified a bit the code.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24071 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stefano Ceccherini 2008-02-23 00:46:50 +00:00
parent 8dd5c3f974
commit 95c02f082c

View File

@ -1,9 +1,9 @@
/*
* Copyright 2003-2006, Haiku, Inc.
* Copyright 2003-2008, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stefano Ceccherini (burton666@libero.it)
* Stefano Ceccherini (stefano.ceccherini@gmail.com)
*/
//! Caches string widths in a hash table, to avoid a trip to the app server.
@ -83,7 +83,7 @@ float
_BWidthBuffer_::StringWidth(const char *inText, int32 fromOffset, int32 length,
const BFont *inStyle)
{
if (inText == NULL)
if (inText == NULL || length == 0)
return 0;
int32 index = 0;
@ -94,36 +94,35 @@ _BWidthBuffer_::StringWidth(const char *inText, int32 fromOffset, int32 length,
int32 numChars = 0;
int32 textLen = 0;
char *sourceText = (char *)inText + fromOffset;
const float fontSize = inStyle->Size();
float stringWidth = 0;
if (length > 0) {
for (int32 charLen = 0, currentOffset = fromOffset;
currentOffset < fromOffset + length;
currentOffset += charLen) {
charLen = UTF8NextCharLen(inText + currentOffset);
for (int32 charLen = 0;
sourceText < inText + length;
sourceText += charLen) {
charLen = UTF8NextCharLen(sourceText);
// End of string, bail out
if (charLen == 0)
break;
// End of string, bail out
if (charLen <= 0)
break;
// Some magic, to uniquely identify this charachter
const uint32 value = CharToCode(inText + currentOffset, charLen);
// Some magic, to uniquely identify this charachter
const uint32 value = CharToCode(sourceText, charLen);
float escapement;
if (GetEscapement(value, index, &escapement)) {
// Well, we've got a match for this charachter
stringWidth += escapement;
} else {
// Store this charachter into an array, which we'll
// pass to HashEscapements() later
int32 offset = textLen;
textLen += charLen;
numChars++;
text = (char *)realloc(text, textLen);
for (int32 x = 0; x < charLen; x++)
text[offset + x] = inText[currentOffset + x];
}
}
float escapement;
if (GetEscapement(value, index, &escapement)) {
// Well, we've got a match for this charachter
stringWidth += escapement;
} else {
// Store this charachter into an array, which we'll
// pass to HashEscapements() later
int32 offset = textLen;
textLen += charLen;
numChars++;
text = (char *)realloc(text, textLen);
for (int32 x = 0; x < charLen; x++)
text[offset + x] = sourceText[x];
}
}
if (text != NULL) {
@ -232,7 +231,6 @@ _BWidthBuffer_::GetEscapement(uint32 value, int32 index, float *escapement)
const hashed_escapement *widths = static_cast<hashed_escapement *>(table.widths);
uint32 hashed = Hash(value) & (table.tableCount - 1);
DEBUG_ONLY(uint32 iterations = 1;)
uint32 found;
while ((found = widths[hashed].code) != kInvalidCode) {
if (found == value)
@ -240,14 +238,11 @@ _BWidthBuffer_::GetEscapement(uint32 value, int32 index, float *escapement)
if (++hashed >= (uint32)table.tableCount)
hashed = 0;
DEBUG_ONLY(iterations++;)
}
if (found == kInvalidCode)
return false;
//PRINT(("Value found with %d iterations\n", iterations));
if (escapement != NULL)
*escapement = widths[hashed].escapement;
@ -283,76 +278,81 @@ float
_BWidthBuffer_::HashEscapements(const char *inText, int32 numChars, int32 textLen,
int32 tableIndex, const BFont *inStyle)
{
ASSERT(inText != NULL);
ASSERT(numChars > 0);
ASSERT(textLen > 0);
float *escapements = new float[numChars];
inStyle->GetEscapements(inText, numChars, escapements);
_width_table_ &table = fBuffer[tableIndex];
hashed_escapement *widths = static_cast<hashed_escapement *>(table.widths);
int32 offset = 0;
int32 charCount = 0;
char *text = (char *)inText;
const char *textEnd = inText + textLen;
// Insert the escapements into the hash table
do {
const int32 charLen = UTF8NextCharLen(inText + offset);
const int32 charLen = UTF8NextCharLen(text);
if (charLen == 0)
break;
const uint32 value = CharToCode(inText + offset, charLen);
const uint32 value = CharToCode(text, charLen);
uint32 hashed = Hash(value) & (table.tableCount - 1);
uint32 found = widths[hashed].code;
// Check if the value is already in the table
if (found != value) {
while ((found = widths[hashed].code) != kInvalidCode) {
if (found == value)
break;
if (++hashed >= (uint32)table.tableCount)
hashed = 0;
}
if (found == value) {
text += charLen;
continue;
}
while ((found = widths[hashed].code) != kInvalidCode) {
if (found == value)
break;
if (++hashed >= (uint32)table.tableCount)
hashed = 0;
}
if (found == kInvalidCode) {
// The value is not in the table. Add it.
widths[hashed].code = value;
widths[hashed].escapement = escapements[charCount];
table.hashCount++;
if (found == kInvalidCode) {
// The value is not in the table. Add it.
widths[hashed].code = value;
widths[hashed].escapement = escapements[charCount];
table.hashCount++;
// We always keep some free space in the hash table
// TODO: Not sure how much space, currently we double
// the current size when hashCount is at least 2/3 of
// the total size.
if (table.tableCount * 2 / 3 <= table.hashCount) {
table.hashCount = 0;
const int32 newSize = table.tableCount * 2;
// Create and initialize a new hash table
hashed_escapement *newWidths = new hashed_escapement[newSize];
// Rehash the values, and put them into the new table
for (int32 oldPos = 0; oldPos < table.tableCount; oldPos++) {
if (widths[oldPos].code != kInvalidCode) {
uint32 newPos = Hash(widths[oldPos].code) & (newSize - 1);
while (newWidths[newPos].code != kInvalidCode) {
if (++newPos >= (uint32)newSize)
newPos = 0;
}
newWidths[newPos].code = widths[oldPos].code;
newWidths[newPos].escapement = widths[oldPos].escapement;
table.hashCount++;
// We always keep some free space in the hash table:
// we double the current size when hashCount is 2/3 of
// the total size.
if (table.tableCount * 2 / 3 <= table.hashCount) {
const int32 newSize = table.tableCount * 2;
// Create and initialize a new hash table
hashed_escapement *newWidths = new hashed_escapement[newSize];
for (int32 i = 0; i < newSize; i++)
newWidths[i].code = kInvalidCode;
// Rehash the values, and put them into the new table
for (uint32 oldPos = 0; oldPos < (uint32)table.tableCount; oldPos++) {
if (widths[oldPos].code != kInvalidCode) {
uint32 newPos = Hash(widths[oldPos].code) & (newSize - 1);
while (newWidths[newPos].code != kInvalidCode) {
if (++newPos >= (uint32)newSize)
newPos = 0;
}
newWidths[newPos] = widths[oldPos];
}
table.tableCount = newSize;
// Delete the old table, and put the new pointer into the _width_table_
delete[] widths;
widths = newWidths;
}
table.tableCount = newSize;
// Delete the old table, and put the new pointer into the _width_table_
delete[] widths;
table.widths = widths = newWidths;
}
}
charCount++;
offset += charLen;
} while (offset < textLen);
text += charLen;
} while (text < textEnd);
// Calculate the width of the string
float width = 0;