reworked BFont::GetStringWidths and BFont::StringWidth

implemented BFont::GetEdges


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14057 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval 2005-08-24 14:50:41 +00:00
parent 2185eed6d2
commit 2b1263bedf
5 changed files with 135 additions and 49 deletions

View File

@ -124,7 +124,6 @@ enum {
AS_COUNT_FONT_FAMILIES,
AS_COUNT_FONT_STYLES,
AS_GET_STRING_WIDTH,
AS_GET_STRING_WIDTHS,
AS_GET_EDGES,
AS_GET_ESCAPEMENTS,

View File

@ -131,10 +131,13 @@ class ServerFont {
{ return fStyle->CharMapCount(); }
BShape** GetGlyphShapes(const char charArray[],
int32 numChars) const;
int32 numChars) const;
void GetHasGlyphs(const char charArray[],
int32 numChars, bool hasArray[]) const;
int32 numChars, bool hasArray[]) const;
void GetEdges(const char charArray[],
int32 numChars, edge_info edgeArray[]) const;
BPoint* GetEscapements(const char charArray[],
int32 numChars,

View File

@ -860,8 +860,12 @@ BFont::GetTruncatedStrings(const char *stringArray[], int32 numStrings,
float
BFont::StringWidth(const char *string) const
{
if (!string)
return 0.0;
int32 length = strlen(string);
return StringWidth(string, length);
float width;
GetStringWidths(&string, &length, 1, &width);
return width;
}
@ -870,24 +874,9 @@ BFont::StringWidth(const char *string, int32 length) const
{
if (!string || length < 1)
return 0.0;
int32 code;
BPrivate::AppServerLink link;
link.StartMessage(AS_GET_STRING_WIDTH);
link.AttachString(string);
link.Attach<int32>(length);
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(fStyleID);
link.Attach<float>(fSize);
link.Attach<uint8>(fSpacing);
if (link.FlushWithReply(code) != B_OK
|| code != SERVER_TRUE)
return 0.0;
float width;
link.Read<float>(&width);
GetStringWidths(&string, &length, 1, &width);
return width;
}
@ -903,11 +892,15 @@ BFont::GetStringWidths(const char *stringArray[], const int32 lengthArray[],
BPrivate::AppServerLink link;
link.StartMessage(AS_GET_STRING_WIDTHS);
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(fStyleID);
link.Attach<float>(fSize);
link.Attach<uint8>(fSpacing);
link.Attach<int32>(numStrings);
for (int32 i = 0; i < numStrings; i++) {
link.AttachString(stringArray[i]);
link.Attach<int32>(lengthArray[i]);
link.AttachString(stringArray[i]);
}
if (link.FlushWithReply(code) != B_OK
@ -1013,23 +1006,26 @@ BFont::GetEscapements(const char charArray[], int32 numChars, escapement_delta *
void
BFont::GetEdges(const char charArray[], int32 numBytes, edge_info edgeArray[]) const
BFont::GetEdges(const char charArray[], int32 numChars, edge_info edgeArray[]) const
{
if (!charArray || numBytes < 1 || !edgeArray)
if (!charArray || numChars < 1 || !edgeArray)
return;
int32 code;
BPrivate::AppServerLink link;
link.StartMessage(AS_GET_EDGES);
link.Attach<int32>(numBytes);
link.Attach(charArray, numBytes);
link.Attach<int32>(numChars);
uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
link.Attach<int32>(bytesInBuffer);
link.Attach(charArray, bytesInBuffer);
if (link.FlushWithReply(code) != B_OK
|| code != SERVER_TRUE)
return;
link.Read(edgeArray, sizeof(edge_info) * numBytes);
link.Read(edgeArray, sizeof(edge_info) * numChars);
}

View File

@ -1348,53 +1348,68 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
// gFontServer->Unlock();
break;
}
case AS_GET_STRING_WIDTH:
case AS_GET_STRING_WIDTHS:
{
FTRACE(("ServerApp %s: AS_GET_STRING_WIDTH\n", Signature()));
FTRACE(("ServerApp %s: AS_GET_STRING_WIDTHS\n", Signature()));
// Attached Data:
// 1) string String to measure
// 2) int32 string length to measure
// 3) uint16 ID of family
// 4) uint16 ID of style
// 5) float point size of font
// 6) uint8 spacing to use
// 1) uint16 ID of family
// 2) uint16 ID of style
// 3) float point size of font
// 4) uint8 spacing to use
// 5) int32 numStrings
// 6) int32 string length to measure (numStrings times)
// 7) string String to measure (numStrings times)
// Returns:
// 1) float - width of the string in pixels
char *string = NULL;
int32 length;
// 1) float - width of the string in pixels (numStrings times)
uint16 family, style;
float size, width = 0;
float size;
uint8 spacing;
link.ReadString(&string);
link.Read<int32>(&length);
link.Read<uint16>(&family);
link.Read<uint16>(&style);
link.Read<float>(&size);
link.Read<uint8>(&spacing);
int32 numStrings;
link.Read<int32>(&numStrings);
float widthArray[numStrings];
int32 lengthArray[numStrings];
char *stringArray[numStrings];
for(int32 i=0; i<numStrings; i++) {
link.Read<int32>(&lengthArray[i]);
stringArray[i] = new char[lengthArray[i]];
link.ReadString(&stringArray[i]);
}
ServerFont font;
if (length > 0 && font.SetFamilyAndStyle(family, style) == B_OK
&& size > 0 && string) {
if (font.SetFamilyAndStyle(family, style) == B_OK
&& size > 0) {
font.SetSize(size);
font.SetSpacing(spacing);
width = fDesktop->GetDisplayDriver()->StringWidth(string, length, font);
for (int32 i=0; i<numStrings; i++)
if (!stringArray[i] || lengthArray[i] <= 0)
widthArray[i] = 0.0;
else
widthArray[i] = fDesktop->GetDisplayDriver()->StringWidth(stringArray[i], lengthArray[i], font);
// NOTE: The line below will return the exact same thing. However,
// the line above uses the AGG rendering backend, for which glyph caching
// actually works. It is about 20 times faster!
//width = font.StringWidth(string, length);
fLink.StartMessage(SERVER_TRUE);
fLink.Attach<float>(width);
fLink.Attach(widthArray, sizeof(widthArray));
} else
fLink.StartMessage(SERVER_FALSE);
fLink.Flush();
free(string);
for(int32 i=0; i<numStrings; i++) {
delete[] stringArray[i];
}
break;
}
case AS_GET_FONT_BOUNDING_BOX:
@ -1766,6 +1781,38 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
fLink.Flush();
break;
}
case AS_GET_EDGES:
{
FTRACE(("ServerApp %s: AS_GET_EDGES\n", Signature()));
// Attached Data:
// 1) uint16 - family ID
// 2) uint16 - style ID
// 3) int32 - numChars
// 4) int32 - numBytes
// 5) char - the char buffer with size numBytes
uint16 famid, styid;
link.Read<uint16>(&famid);
link.Read<uint16>(&styid);
int32 numChars;
link.Read<int32>(&numChars);
uint32 numBytes;
link.Read<uint32>(&numBytes);
char* charArray = new char[numBytes];
link.Read(charArray, numBytes);
ServerFont font;
if (font.SetFamilyAndStyle(famid, styid) == B_OK) {
edge_info edgeArray[numChars];
font.GetEdges(charArray, numChars, edgeArray);
fLink.StartMessage(SERVER_TRUE);
fLink.Attach(edgeArray, sizeof(edgeArray));
} else
fLink.StartMessage(SERVER_FALSE);
fLink.Flush();
break;
}
case AS_GET_ESCAPEMENTS:
{
FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS\n", Signature()));

View File

@ -370,11 +370,52 @@ ServerFont::GetHasGlyphs(const char charArray[], int32 numChars, bool hasArray[]
}
}
delete[] convertedBuffer;
}
/*for (int i = 0; i < numChars; i++) {
hasArray[i] = true;
}*/
// GetEdges
void
ServerFont::GetEdges(const char charArray[], int32 numChars, edge_info edgeArray[]) const
{
if (!fStyle || !charArray || numChars <= 0 || !edgeArray)
return;
FT_Face face = fStyle->GetFTFace();
if (!face)
return;
FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72);
// UTF8 handling...this can probably be smarter
// Here is what I do in the AGGTextRenderer to handle UTF8...
// It is probably highly inefficient, so it should be reviewed.
int32 numBytes = UTF8CountBytes(charArray, numChars);
int32 convertedLength = numBytes * 2;
char* convertedBuffer = new char[convertedLength];
int32 state = 0;
status_t ret;
if ((ret = convert_from_utf8(B_UNICODE_CONVERSION,
charArray, &numBytes,
convertedBuffer, &convertedLength,
&state, B_SUBSTITUTE)) >= B_OK
&& (ret = swap_data(B_INT16_TYPE, convertedBuffer, convertedLength,
B_SWAP_BENDIAN_TO_HOST)) >= B_OK) {
uint16* glyphIndex = (uint16*)convertedBuffer;
// just to be sure
numChars = min_c((uint32)numChars, convertedLength / sizeof(uint16));
for (int i = 0; i < numChars; i++) {
FT_Load_Char(face, glyphIndex[i], FT_LOAD_NO_BITMAP);
if (face->glyph) {
edgeArray[i].left = float(face->glyph->metrics.horiBearingX /64) / fSize;
edgeArray[i].right = float((face->glyph->metrics.horiBearingX
+ face->glyph->metrics.width - face->glyph->metrics.horiAdvance)/64) /fSize;
}
}
}
delete[] convertedBuffer;
}