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:
parent
2bdbc03a1d
commit
db5734a452
@ -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
|
||||
|
@ -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(); }
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user