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