More work on the BFont special functions.

* Reworked functions like GetEscapements(), GetBoundingBoxesAsString() and GetGlyphShapes() completely
* Made the ServerFont functions uniform in their prototypes and cleaned out unnecessary arguments
* Added new UTF8 handling functions to moreUTF8.h that are now used by ServerFont
* Put the common transformations of the FT_Face into an own GetTransformedFace() to lessen code duplication

In other words, ServerFont is now cleaned and handles UTF8 pretty efficiently. Some ToDo's are still left though.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16241 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2006-02-05 23:36:59 +00:00
parent 2bdbc03a1d
commit db5734a452
5 changed files with 384 additions and 347 deletions

View File

@ -98,4 +98,112 @@ UTF8CountChars(const char *text, int32 numBytes)
}
/* UTF8ToCharCode converts the input that includes potential multibyte chars
to UTF-32 char codes that can be used by FreeType. The string pointer is
then advanced to the next character in the string. In case the terminating
0 is reached, the string pointer is not advanced anymore and spaces are
returned. This makes it safe to overruns and enables streamed processing
of UTF8 strings. */
static inline uint32
UTF8ToCharCode(const char **bytes)
{
register uint32 result = 0;
if ((*bytes)[0] & 0x80) {
if ((*bytes)[0] & 0x40) {
if ((*bytes)[0] & 0x20) {
if ((*bytes)[0] & 0x10) {
if ((*bytes)[0] & 0x08) {
/* A five byte char?!
Something's wrong, substitue. */
result += 0x20;
(*bytes)++;
return result;
}
/* A four byte char */
result += (*bytes)[0] & 0x07;
result <<= 6;
result += (*bytes)[1] & 0x3f;
result <<= 6;
result += (*bytes)[2] & 0x3f;
result <<= 6;
result += (*bytes)[3] & 0x3f;
(*bytes) += 3;
return result;
}
/* A three byte char */
result += (*bytes)[0] & 0x0f;
result <<= 6;
result += (*bytes)[1] & 0x3f;
result <<= 6;
result += (*bytes)[2] & 0x3f;
(*bytes) += 3;
return result;
}
/* A two byte char */
result += (*bytes)[0] & 0x1f;
result <<= 6;
result += (*bytes)[1] & 0x3f;
(*bytes) += 2;
return result;
}
/* This (10) is not a startbyte.
Substitute with a space. */
result += 0x20;
(*bytes)++;
return result;
}
if ((*bytes)[0] == 0) {
/* We do not advance beyond the terminating 0. Just pad any further
request with spaces. */
result += 0x20;
return result;
}
result += (*bytes)[0];
(*bytes)++;
return result;
}
/* UTF8ToLength works like strlen() but takes UTF8 encoded multibyte chars
into account. It's a quicker version of UTF8CountChars above. */
static inline int32
UTF8ToLength(const char *bytes)
{
int32 length = 0;
while (*bytes) {
length++;
if (bytes[0] & 0x80) {
if (bytes[0] & 0x40) {
if (bytes[0] & 0x20) {
if (bytes[0] & 0x10) {
bytes += 4;
continue;
}
bytes += 3;
continue;
}
bytes += 2;
continue;
}
/* Not a startbyte - skip */
}
bytes += 1;
}
return length;
}
#endif

View File

@ -107,33 +107,39 @@ class ServerFont {
uint16 CharMapCount() const
{ return fStyle->CharMapCount(); }
BShape** GetGlyphShapes(const char charArray[],
int32 numChars) const;
void GetHasGlyphs(const char charArray[],
FT_Face GetTransformedFace(bool rotate, bool shear) const;
void PutTransformedFace(FT_Face face) const;
status_t GetGlyphShapes(const char charArray[],
int32 numChars, BShape *shapeArray[]) const;
status_t GetHasGlyphs(const char charArray[],
int32 numChars, bool hasArray[]) const;
void GetEdges(const char charArray[],
status_t GetEdges(const char charArray[],
int32 numChars, edge_info edgeArray[]) const;
BPoint* GetEscapements(const char charArray[],
int32 numChars,
BPoint offsetArray[]) const;
bool GetEscapements(const char charArray[],
int32 numChars,
int32 numBytes,
float widthArray[],
escapement_delta delta) const;
status_t GetEscapements(const char charArray[],
int32 numChars, escapement_delta delta,
BPoint escapementArray[],
BPoint offsetArray[]) const;
bool GetBoundingBoxesAsString(const char charArray[],
int32 numChars, BRect rectArray[], bool string_escapement,
font_metric_mode mode, escapement_delta delta);
status_t GetEscapements(const char charArray[],
int32 numChars, escapement_delta delta,
float widthArray[]) const;
bool GetBoundingBoxesForStrings(char *charArray[], int32 lengthArray[],
int32 numStrings, BRect rectArray[],
font_metric_mode mode, escapement_delta deltaArray[]);
status_t GetBoundingBoxesAsString(const char charArray[],
int32 numChars, BRect rectArray[],
bool stringEscapement, font_metric_mode mode,
escapement_delta delta);
float StringWidth(const char* string, int32 numBytes) const;
status_t GetBoundingBoxesForStrings(char *charArray[],
int32 lengthArray[], int32 numStrings,
BRect rectArray[], font_metric_mode mode,
escapement_delta deltaArray[]);
float StringWidth(const char *string, int32 numChars) const;
bool Lock() const { return fStyle->Lock(); }
void Unlock() const { fStyle->Unlock(); }

View File

@ -1048,10 +1048,9 @@ BFont::GetEscapements(const char charArray[], int32 numChars, escapement_delta *
link.Attach<float>(delta ? delta->nonspace : 0.0);
link.Attach<float>(delta ? delta->space : 0.0);
// TODO: Should we not worry about the port capacity here?!?
link.Attach<int32>(numChars);
// TODO: Should we not worry about the port capacity here?!?
uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
link.Attach<int32>(bytesInBuffer);
link.Attach(charArray, bytesInBuffer);
@ -1088,22 +1087,15 @@ BFont::GetEscapements(const char charArray[], int32 numChars, escapement_delta *
link.Attach<float>(fRotation);
link.Attach<uint32>(fFlags);
link.Attach<float>(delta ? delta->nonspace : 0.0);
link.Attach<float>(delta ? delta->space : 0.0);
link.Attach<bool>(offsetArray != NULL);
link.Attach<int32>(numChars);
// TODO: Support UTF8 characters
if (offsetArray) {
for (int32 i = 0; i < numChars; i++) {
link.Attach<char>(charArray[i]);
link.Attach<BPoint>(offsetArray[i]);
}
} else {
BPoint dummypt(0, 0);
for (int32 i = 0; i < numChars; i++) {
link.Attach<char>(charArray[i]);
link.Attach<BPoint>(dummypt);
}
}
// TODO: Should we not worry about the port capacity here?!?
uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
link.Attach<int32>(bytesInBuffer);
link.Attach(charArray, bytesInBuffer);
int32 code;
if (link.FlushWithReply(code) != B_OK
@ -1111,6 +1103,8 @@ BFont::GetEscapements(const char charArray[], int32 numChars, escapement_delta *
return;
link.Read(escapementArray, sizeof(BPoint) * numChars);
if (offsetArray)
link.Read(offsetArray, sizeof(BPoint) * numChars);
}

View File

@ -1558,8 +1558,8 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
link.Read<int32>(&numChars);
link.Read<int32>(&numBytes);
char charArray[numBytes];
link.Read(&charArray, numBytes);
char *charArray = new char[numBytes];
link.Read(charArray, numBytes);
ServerFont font;
status_t status = font.SetFamilyAndStyle(familyID, styleID);
@ -1569,20 +1569,22 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
font.SetRotation(rotation);
font.SetFlags(flags);
BShape **shapes = font.GetGlyphShapes(charArray, numChars);
if (shapes) {
BShape **shapes = new BShape *[numChars];
status = font.GetGlyphShapes(charArray, numChars, shapes);
if (status == B_OK) {
fLink.StartMessage(B_OK);
for (int32 i = 0; i < numChars; i++) {
fLink.AttachShape(*shapes[i]);
delete shapes[i];
}
delete shapes;
delete[] shapes;
} else
fLink.StartMessage(B_ERROR);
fLink.StartMessage(status);
} else
fLink.StartMessage(status);
delete[] charArray;
fLink.Flush();
break;
}
@ -1610,14 +1612,16 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
status_t status = font.SetFamilyAndStyle(familyID, styleID);
if (status == B_OK) {
bool hasArray[numChars];
font.GetHasGlyphs(charArray, numChars, hasArray);
fLink.StartMessage(B_OK);
fLink.Attach(hasArray, sizeof(hasArray));
status = font.GetHasGlyphs(charArray, numChars, hasArray);
if (status == B_OK) {
fLink.StartMessage(B_OK);
fLink.Attach(hasArray, sizeof(hasArray));
} else
fLink.StartMessage(status);
} else
fLink.StartMessage(status);
delete[] charArray;
fLink.Flush();
break;
}
@ -1647,14 +1651,16 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
status_t status = font.SetFamilyAndStyle(familyID, styleID);
if (status == B_OK) {
edge_info edgeArray[numChars];
font.GetEdges(charArray, numChars, edgeArray);
fLink.StartMessage(B_OK);
fLink.Attach(edgeArray, sizeof(edgeArray));
status = font.GetEdges(charArray, numChars, edgeArray);
if (status == B_OK) {
fLink.StartMessage(B_OK);
fLink.Attach(edgeArray, sizeof(edgeArray));
} else
fLink.StartMessage(status);
} else
fLink.StartMessage(status);
delete[] charArray;
fLink.Flush();
break;
}
@ -1685,15 +1691,20 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
link.Read<float>(&rotation);
link.Read<uint32>(&flags);
escapement_delta delta;
link.Read<float>(&delta.nonspace);
link.Read<float>(&delta.space);
bool wantsOffsets;
link.Read<bool>(&wantsOffsets);
int32 numChars;
link.Read<int32>(&numChars);
char charArray[numChars];
BPoint offsetArray[numChars];
for (int32 i = 0; i < numChars; i++) {
link.Read<char>(&charArray[i]);
link.Read<BPoint>(&offsetArray[i]);
}
uint32 numBytes;
link.Read<uint32>(&numBytes);
char *charArray = new char[numBytes];
link.Read(charArray, numBytes);
ServerFont font;
status_t status = font.SetFamilyAndStyle(familyID, styleID);
@ -1702,19 +1713,33 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
font.SetRotation(rotation);
font.SetFlags(flags);
BPoint *escapements = font.GetEscapements(charArray, numChars, offsetArray);
if (escapements) {
BPoint *escapements = new BPoint[numChars];
BPoint *offsets = NULL;
if (wantsOffsets)
offsets = new BPoint[numChars];
status = font.GetEscapements(charArray, numChars, delta,
escapements, offsets);
if (status == B_OK) {
fLink.StartMessage(B_OK);
for (int32 i = 0; i < numChars; i++) {
for (int32 i = 0; i < numChars; i++)
fLink.Attach<BPoint>(escapements[i]);
}
delete[] escapements;
if (wantsOffsets) {
for (int32 i = 0; i < numChars; i++)
fLink.Attach<BPoint>(offsets[i]);
delete[] offsets;
}
} else
fLink.StartMessage(B_ERROR);
fLink.StartMessage(status);
} else
fLink.StartMessage(status);
delete[] charArray;
fLink.Flush();
break;
}
@ -1771,11 +1796,13 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
font.SetRotation(rotation);
font.SetFlags(flags);
if (font.GetEscapements(charArray, numChars, numBytes, escapements, delta)) {
status = font.GetEscapements(charArray, numChars, delta,
escapements);
if (status == B_OK) {
fLink.StartMessage(B_OK);
fLink.Attach(escapements, numChars * sizeof(float));
} else
status = B_ERROR;
}
}
delete[] charArray;
@ -1837,7 +1864,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
uint32 numBytes;
link.Read<uint32>(&numBytes);
char charArray[numBytes];
char *charArray = new char[numBytes];
link.Read(charArray, numBytes);
BRect rectArray[numChars];
@ -1853,7 +1880,8 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
font.SetFlags(flags);
// TODO implement for real
if (font.GetBoundingBoxesAsString(charArray, numChars, rectArray, string_escapement, mode, delta)) {
if (font.GetBoundingBoxesAsString(charArray, numChars,
rectArray, string_escapement, mode, delta) == B_OK) {
fLink.StartMessage(B_OK);
fLink.Attach(rectArray, sizeof(rectArray));
success = true;
@ -1863,6 +1891,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
if (!success)
fLink.StartMessage(B_ERROR);
delete[] charArray;
fLink.Flush();
break;
}
@ -1927,7 +1956,8 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
font.SetFlags(flags);
// TODO implement for real
if (font.GetBoundingBoxesForStrings(stringArray, lengthArray, numStrings, rectArray, mode, deltaArray)) {
if (font.GetBoundingBoxesForStrings(stringArray, lengthArray,
numStrings, rectArray, mode, deltaArray) == B_OK) {
fLink.StartMessage(B_OK);
fLink.Attach(rectArray, sizeof(rectArray));
success = true;

View File

@ -1,10 +1,11 @@
/*
* Copyright 2001-2005, Haiku.
* Copyright 2001-2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* DarkWyrm <bpmagic@columbus.rr.com>
* Jérôme Duval, jerome.duval@free.fr
* Michael Lotz <mmlr@mlotz.ch>
*/
@ -312,18 +313,65 @@ ServerFont::SetFace(uint32 face)
\return the combination of family and style ID numbers
*/
uint32
ServerFont::GetFamilyAndStyle(void) const
ServerFont::GetFamilyAndStyle() const
{
return (FamilyID() << 16) | StyleID();
}
BShape **
ServerFont::GetGlyphShapes(const char charArray[], int32 numChars) const
FT_Face
ServerFont::GetTransformedFace(bool rotate, bool shear) const
{
if (!charArray || numChars <= 0)
FaceGetter getter(fStyle);
FT_Face face = getter.Face();
if (!face)
return NULL;
FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72);
if ((rotate && fRotation != 0) || (shear && fShear != 90)) {
FT_Matrix rmatrix, smatrix;
Angle rotationAngle(fRotation);
rmatrix.xx = (FT_Fixed)( rotationAngle.Cosine() * 0x10000);
rmatrix.xy = (FT_Fixed)(-rotationAngle.Sine() * 0x10000);
rmatrix.yx = (FT_Fixed)( rotationAngle.Sine() * 0x10000);
rmatrix.yy = (FT_Fixed)( rotationAngle.Cosine() * 0x10000);
Angle shearAngle(fShear);
smatrix.xx = (FT_Fixed)(0x10000);
smatrix.xy = (FT_Fixed)(-shearAngle.Cosine() * 0x10000);
smatrix.yx = (FT_Fixed)(0);
smatrix.yy = (FT_Fixed)(0x10000);
// Multiply togheter and apply transform
FT_Matrix_Multiply(&rmatrix, &smatrix);
FT_Set_Transform(face, &smatrix, NULL);
}
return face;
}
void
ServerFont::PutTransformedFace(FT_Face face) const
{
// Reset transformation
FT_Set_Transform(face, NULL, NULL);
}
status_t
ServerFont::GetGlyphShapes(const char charArray[], int32 numChars,
BShape *shapeArray[]) const
{
if (!charArray || numChars <= 0 || !shapeArray)
return B_BAD_DATA;
FT_Face face = GetTransformedFace(true, true);
if (!face)
return B_ERROR;
FT_Outline_Funcs funcs;
funcs.move_to = MoveToFunc;
funcs.line_to = LineToFunc;
@ -332,357 +380,208 @@ ServerFont::GetGlyphShapes(const char charArray[], int32 numChars) const
funcs.shift = 0;
funcs.delta = 0;
FaceGetter getter(fStyle);
FT_Face face = getter.Face();
if (!face)
return NULL;
FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72);
Angle rotation(fRotation);
Angle shear(fShear);
// First, rotate
FT_Matrix rmatrix;
rmatrix.xx = (FT_Fixed)( rotation.Cosine()*0x10000);
rmatrix.xy = (FT_Fixed)(-rotation.Sine()*0x10000);
rmatrix.yx = (FT_Fixed)( rotation.Sine()*0x10000);
rmatrix.yy = (FT_Fixed)( rotation.Cosine()*0x10000);
// Next, shear
FT_Matrix smatrix;
smatrix.xx = (FT_Fixed)(0x10000);
smatrix.xy = (FT_Fixed)(-shear.Cosine()*0x10000);
smatrix.yx = (FT_Fixed)(0);
smatrix.yy = (FT_Fixed)(0x10000);
// Multiply togheter
FT_Matrix_Multiply(&rmatrix, &smatrix);
FT_Set_Transform(face, &smatrix, NULL);
BShape **shapes = new BShape *[numChars];
const char *string = charArray;
for (int i = 0; i < numChars; i++) {
shapes[i] = new BShape();
shapes[i]->Clear();
// TODO : this is wrong (the nth char isn't charArray[i])
FT_Load_Char(face, charArray[i], FT_LOAD_NO_BITMAP);
shapeArray[i] = new BShape();
FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
FT_Outline outline = face->glyph->outline;
FT_Outline_Decompose(&outline, &funcs, shapes[i]);
shapes[i]->Close();
FT_Outline_Decompose(&outline, &funcs, shapeArray[i]);
shapeArray[i]->Close();
}
// Reset transformation
FT_Set_Transform(face, NULL, NULL);
return shapes;
PutTransformedFace(face);
return B_OK;
}
void
ServerFont::GetHasGlyphs(const char charArray[], int32 numChars, bool hasArray[]) const
status_t
ServerFont::GetHasGlyphs(const char charArray[], int32 numChars,
bool hasArray[]) const
{
if (!charArray || numChars <= 0 || !hasArray)
return;
return B_BAD_DATA;
FaceGetter getter(fStyle);
FT_Face face = getter.Face();
FT_Face face = GetTransformedFace(false, false);
if (!face)
return;
return B_ERROR;
FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72);
const char *string = charArray;
for (int i = 0; i < numChars; i++)
hasArray[i] = FT_Get_Char_Index(face, UTF8ToCharCode(&string)) > 0;
// 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++) {
hasArray[i] = FT_Get_Char_Index(face, glyphIndex[i]) > 0;
}
}
delete[] convertedBuffer;
PutTransformedFace(face);
return B_OK;
}
void
ServerFont::GetEdges(const char charArray[], int32 numChars, edge_info edgeArray[]) const
status_t
ServerFont::GetEdges(const char charArray[], int32 numChars,
edge_info edgeArray[]) const
{
if (!charArray || numChars <= 0 || !edgeArray)
return;
return B_BAD_DATA;
FaceGetter getter(fStyle);
FT_Face face = getter.Face();
FT_Face face = GetTransformedFace(false, false);
if (!face)
return;
return B_ERROR;
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;
}
BPoint*
ServerFont::GetEscapements(const char charArray[], int32 numChars,
BPoint offsetArray[]) const
{
if (!charArray || numChars <= 0 || !offsetArray)
return NULL;
FaceGetter getter(fStyle);
FT_Face face = getter.Face();
if (!face)
return NULL;
FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72);
Angle rotation(fRotation);
Angle shear(fShear);
// First, rotate
FT_Matrix rmatrix;
rmatrix.xx = (FT_Fixed)( rotation.Cosine()*0x10000);
rmatrix.xy = (FT_Fixed)(-rotation.Sine()*0x10000);
rmatrix.yx = (FT_Fixed)( rotation.Sine()*0x10000);
rmatrix.yy = (FT_Fixed)( rotation.Cosine()*0x10000);
// Next, shear
FT_Matrix smatrix;
smatrix.xx = (FT_Fixed)(0x10000);
smatrix.xy = (FT_Fixed)(-shear.Cosine()*0x10000);
smatrix.yx = (FT_Fixed)(0);
smatrix.yy = (FT_Fixed)(0x10000);
// Multiply togheter
FT_Matrix_Multiply(&rmatrix, &smatrix);
FT_Set_Transform(face, &smatrix, NULL);
// TODO: handle UTF8... see below!!
BPoint *escapements = new BPoint[numChars];
const char *string = charArray;
for (int i = 0; i < numChars; i++) {
// TODO : this is wrong (the nth char isn't charArray[i])
FT_Load_Char(face, charArray[i], FT_LOAD_NO_BITMAP);
escapements[i].x = float(face->glyph->advance.x) / 64 / fSize;
escapements[i].y = -float(face->glyph->advance.y) / 64 / fSize;
escapements[i] += offsetArray[i];
FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
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;
}
// Reset transformation
FT_Set_Transform(face, NULL, NULL);
return escapements;
PutTransformedFace(face);
return B_OK;
}
bool
ServerFont::GetEscapements(const char charArray[], int32 numChars, int32 numBytes,
float widthArray[], escapement_delta delta) const
status_t
ServerFont::GetEscapements(const char charArray[], int32 numChars,
escapement_delta delta, BPoint escapementArray[], BPoint offsetArray[]) const
{
if (!charArray || numChars <= 0)
return false;
if (!charArray || numChars <= 0 || !escapementArray)
return B_BAD_DATA;
FaceGetter getter(fStyle);
FT_Face face = getter.Face();
FT_Face face = GetTransformedFace(true, false);
if (!face)
return false;
return B_ERROR;
FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72);
const char *string = charArray;
for (int i = 0; i < numChars; i++) {
// Do this first as UTF8ToCharCode advances string.
escapementArray[i].x = is_white_space(*string) ? delta.space : delta.nonspace;
// 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 convertedLength = numBytes * 2;
char* convertedBuffer = new char[convertedLength];
FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
escapementArray[i].x += float(face->glyph->advance.x) / 64;
escapementArray[i].y = -float(face->glyph->advance.y) / 64;
escapementArray[i].x /= fSize;
escapementArray[i].y /= fSize;
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) {
widthArray[i] = ((float)face->glyph->metrics.horiAdvance / 64.0) / fSize;
widthArray[i] += is_white_space(glyphIndex[i]) ? delta.space : delta.nonspace;
}
if (offsetArray) {
// ToDo: According to the BeBook: "The offsetArray is applied by
// the dynamic spacing in order to improve the relative position
// of the character's width with relation to another character,
// without altering the width." So this will probably depend on
// the spacing mode.
offsetArray[i].x = 0;
offsetArray[i].y = 0;
}
}
delete[] convertedBuffer;
return ret >= B_OK;
PutTransformedFace(face);
return B_OK;
}
bool
status_t
ServerFont::GetEscapements(const char charArray[], int32 numChars,
escapement_delta delta, float widthArray[]) const
{
if (!charArray || numChars <= 0 || !widthArray)
return B_BAD_DATA;
FT_Face face = GetTransformedFace(false, false);
if (!face)
return B_ERROR;
const char *string = charArray;
for (int i = 0; i < numChars; i++) {
// Do this first as UTF8ToCharCode advances string.
widthArray[i] = is_white_space(*string) ? delta.space : delta.nonspace;
FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
widthArray[i] += float(face->glyph->metrics.horiAdvance) / 64.0;
widthArray[i] /= fSize;
}
PutTransformedFace(face);
return B_OK;
}
status_t
ServerFont::GetBoundingBoxesAsString(const char charArray[], int32 numChars,
BRect rectArray[], bool string_escapement, font_metric_mode mode,
BRect rectArray[], bool stringEscapement, font_metric_mode mode,
escapement_delta delta)
{
if (!charArray || numChars <= 0 || !rectArray)
return false;
return B_BAD_DATA;
FaceGetter getter(fStyle);
FT_Face face = getter.Face();
FT_Face face = GetTransformedFace(true, true);
if (!face)
return false;
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];
return B_ERROR;
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) {
const char *string = charArray;
for (int i = 0; i < numChars; i++) {
if (stringEscapement) {
if (i > 0)
rectArray[i].OffsetBy(is_white_space(*string) ? delta.space / 2.0 : delta.nonspace / 2.0, 0.0);
uint16* glyphIndex = (uint16*)convertedBuffer;
// just to be sure
numChars = min_c((uint32)numChars, convertedLength / sizeof(uint16));
for (int i = 0; i < numChars; i++) {
if (string_escapement) {
if (i>0)
rectArray[i].OffsetBy(is_white_space(glyphIndex[i-1]) ? delta.space/2.0 : delta.nonspace/2.0, 0.0);
rectArray[i].OffsetBy(is_white_space(glyphIndex[i]) ? delta.space/2.0 : delta.nonspace/2.0, 0.0);
}
FT_Load_Char(face, glyphIndex[i], FT_LOAD_NO_BITMAP);
if (face->glyph) {
if (i<numChars-1)
rectArray[i+1].left = rectArray[i+1].right = rectArray[i].left +
face->glyph->metrics.horiAdvance / 64.0;
rectArray[i].left += float(face->glyph->metrics.horiBearingX) /64.0;
rectArray[i].right += float(face->glyph->metrics.horiBearingX
+ face->glyph->metrics.width)/64.0;
rectArray[i].top = -float(face->glyph->metrics.horiBearingY) /64.0;
rectArray[i].bottom = float(face->glyph->metrics.height
- face->glyph->metrics.horiBearingY) /64.0;
}
rectArray[i].OffsetBy(is_white_space(*string) ? delta.space / 2.0 : delta.nonspace / 2.0, 0.0);
}
}
delete[] convertedBuffer;
return true;
FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
if (i < numChars - 1) {
rectArray[i + 1].left = rectArray[i + 1].right = rectArray[i].left
+ face->glyph->metrics.horiAdvance / 64.0;
}
rectArray[i].left += float(face->glyph->metrics.horiBearingX) /64.0;
rectArray[i].right += float(face->glyph->metrics.horiBearingX
+ face->glyph->metrics.width) / 64.0;
rectArray[i].top = -float(face->glyph->metrics.horiBearingY) / 64.0;
rectArray[i].bottom = float(face->glyph->metrics.height
- face->glyph->metrics.horiBearingY) /64.0;
}
PutTransformedFace(face);
return B_OK;
}
bool
status_t
ServerFont::GetBoundingBoxesForStrings(char *charArray[], int32 lengthArray[],
int32 numStrings, BRect rectArray[], font_metric_mode mode, escapement_delta deltaArray[])
{
if (!charArray || !lengthArray|| numStrings <= 0 || !rectArray || !deltaArray)
return false;
return B_BAD_DATA;
FaceGetter getter(fStyle);
FT_Face face = getter.Face();
FT_Face face = GetTransformedFace(true, true);
if (!face)
return false;
FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72);
return B_ERROR;
for (int32 i = 0; i < numStrings; i++) {
// TODO: ...
}
return true;
PutTransformedFace(face);
return B_OK;
}
float
ServerFont::StringWidth(const char* string, int32 numBytes) const
ServerFont::StringWidth(const char *_string, int32 numChars) const
{
if (!string || numBytes <= 0)
if (!_string || numChars <= 0)
return 0.0;
FaceGetter getter(fStyle);
FT_Face face = getter.Face();
FT_Face face = GetTransformedFace(false, false);
if (!face)
return 0.0;
FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72);
int32 convertedLength = numBytes * 2;
char* convertedBuffer = new char[convertedLength];
float width = 0.0;
int32 state = 0;
status_t ret;
if ((ret = convert_from_utf8(B_UNICODE_CONVERSION,
string, &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
int numChars = convertedLength / sizeof(uint16);
for (int i = 0; i < numChars; i++) {
FT_Load_Char(face, glyphIndex[i], FT_LOAD_NO_BITMAP);
width += face->glyph->advance.x / 64.0;
}
const char *string = _string;
for (int i = 0; i < numChars; i++) {
FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
width += face->glyph->advance.x / 64.0;
}
delete[] convertedBuffer;
PutTransformedFace(face);
return width;
}
@ -725,7 +624,7 @@ ServerFont::TruncateString(BString* inOut, uint32 mode, float width) const
// get the escapement of each glyph in font units
float* escapementArray = new float[numChars];
static escapement_delta delta = (escapement_delta){ 0.0, 0.0 };
GetEscapements(string, numChars, length, escapementArray, delta);
GetEscapements(string, numChars, delta, escapementArray);
truncate_string(string, mode, width, result,
escapementArray, fSize, ellipsisWidth, length, numChars);