haiku/src/servers/app/ServerFont.cpp

627 lines
13 KiB
C++
Raw Normal View History

/*
* 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>
*/
#include <Shape.h>
#include <String.h>
#include <UTF8.h>
#include "Angle.h"
#include "FontManager.h"
#include "moreUTF8.h"
#include "truncate_string.h"
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_OUTLINE_H
#include "ServerFont.h"
// functions needed to convert a freetype vector graphics to a BShape
inline BPoint
VectorToPoint(FT_Vector *vector)
{
BPoint result;
result.x = float(vector->x) / 64;
result.y = -float(vector->y) / 64;
return result;
}
int
MoveToFunc(FT_Vector *to, void *user)
{
((BShape *)user)->MoveTo(VectorToPoint(to));
return 0;
}
int
LineToFunc(FT_Vector *to, void *user)
{
((BShape *)user)->LineTo(VectorToPoint(to));
return 0;
}
int
ConicToFunc(FT_Vector *control, FT_Vector *to, void *user)
{
BPoint controls[3];
controls[0] = VectorToPoint(control);
controls[1] = VectorToPoint(to);
controls[2] = controls[1];
((BShape *)user)->BezierTo(controls);
return 0;
}
int
CubicToFunc(FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *user)
{
BPoint controls[3];
controls[0] = VectorToPoint(control1);
controls[1] = VectorToPoint(control2);
controls[2] = VectorToPoint(to);
((BShape *)user)->BezierTo(controls);
return 0;
}
inline bool
is_white_space(uint32 charCode)
{
switch (charCode) {
case 0x0009: /* tab */
case 0x000b: /* vertical tab */
case 0x000c: /* form feed */
case 0x0020: /* space */
case 0x00a0: /* non breaking space */
case 0x000a: /* line feed */
case 0x000d: /* carriage return */
case 0x2028: /* line separator */
case 0x2029: /* paragraph separator */
return true;
}
return false;
}
// #pragma mark -
/*!
\brief Constructor
\param style Style object to which the ServerFont belongs
\param size Character size in points
\param rotation Rotation in degrees
\param shear Shear (slant) in degrees. 45 <= shear <= 135
\param flags Style flags as defined in <Font.h>
\param spacing String spacing flag as defined in <Font.h>
*/
ServerFont::ServerFont(FontStyle& style, float size,
float rotation, float shear,
uint16 flags, uint8 spacing)
: fStyle(&style),
fSize(size),
fRotation(rotation),
fShear(shear),
fBounds(0, 0, 0, 0),
fFlags(flags),
fSpacing(spacing),
fDirection(style.Direction()),
fFace(style.Face()),
fEncoding(B_UNICODE_UTF8)
{
fStyle->Acquire();
}
ServerFont::ServerFont()
:
fStyle(NULL)
{
*this = *gFontManager->DefaultPlainFont();
}
/*!
\brief Copy Constructor
\param font ServerFont to copy
*/
ServerFont::ServerFont(const ServerFont &font)
:
fStyle(NULL)
{
*this = font;
}
/*!
\brief Removes itself as a dependency of its owning style.
*/
ServerFont::~ServerFont()
{
fStyle->Release();
}
/*!
\brief Returns a copy of the specified font
\param The font to copy from.
\return A copy of the specified font
*/
ServerFont&
ServerFont::operator=(const ServerFont& font)
{
ServerFont: * fixed weird pointer conversion in SetStyle() * fixed a potential mix up in operator=() in case the other ServerFont has fStyle == NULL ServerWindow: * the WindowLayer fTopLayer cannot be deleted by client request, just for safety reasons * the link is flushed if there is no drawing engine, but this case is theoretical only * deleting the ServerWindow object syncs with the client, so that when BBitmaps are deleted, they can be sure there are no pending messages (which would be executed in a nother thread) * there is no timeout anymore when sending messages to the client, which made absolutely no sense AGGTextRenderer: * renamed fFontManager to fFontCache, because that's what it really is * fLastFamilyAndStyle defaulted to the system plain font and therefor that font was never loaded when the font never changed meanwhile DrawingMode: * I'm not quite sure but I think there was the potential of a division by zero, at least I had crashes with "divide error" HWInterface: * fix update when the cursor shape changed in double buffered mode ViewLayer: * since the top layer is never really deleted before its time has come, it is not necessary to set it to NULL in the ViewLayer destructor ViewLayer/WindowLayer: * added a function to collect the view tokens that are affected by an update session EventDispatcher: * use the importance of the message for the timeout in _SendMessage() * drop mouse moved events in the server if we're lagging behind more than 5 ms (Axel, maybe review) View: * there were some problems with the locking of the BWindow looper in RemoveSelf(), since this is called from the window destructor, also of BWindows from BBitmaps, which have never been run (this might need review), at least I seem to have solved the crashing problems introduced by actually deleting the view hirarchy in the BWindow destructor * fixed _Draw() for being used non-recursively, temporarily disabled DrawAfterChildren, which didn't work yet anyways (because views cannot draw over children in the server yet) Window: * small cleanup when deleting shortcuts * sync with the server when having send AS_DELETE_WINDOW (see ServerWindow above) * fixed locking in Begin/EndViewTransaction() * removed folding of _UPDATE_ messages, since there is only one ever in the queue * set the fInTransaction flag during an update, I plan to use this in BView later to flush the link when drawing outside of an update * BView::_Draw() is now called by view token, this gives the next leap forward in speed, the overhead because of drawing clean views was considerable git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15878 a95241bf-73f2-0310-859d-f6bbb57e9c96
2006-01-09 01:04:52 +03:00
if (font.fStyle) {
fSize = font.fSize;
fRotation = font.fRotation;
fShear = font.fShear;
fFlags = font.fFlags;
fSpacing = font.fSpacing;
fEncoding = font.fEncoding;
fBounds = font.fBounds;
SetStyle(font.fStyle);
}
return *this;
}
/*!
\brief Returns the number of strikes in the font
\return The number of strikes in the font
*/
int32
ServerFont::CountTuned()
{
return fStyle->TunedCount();
}
/*!
\brief Returns the file format of the font.
\return Mostly B_TRUETYPE_WINDOWS :)
*/
font_file_format
ServerFont::FileFormat()
{
return fStyle->FileFormat();
}
const char*
ServerFont::Style() const
{
return fStyle->Name();
}
const char*
ServerFont::Family() const
{
return fStyle->Family()->Name();
}
void
ServerFont: * fixed weird pointer conversion in SetStyle() * fixed a potential mix up in operator=() in case the other ServerFont has fStyle == NULL ServerWindow: * the WindowLayer fTopLayer cannot be deleted by client request, just for safety reasons * the link is flushed if there is no drawing engine, but this case is theoretical only * deleting the ServerWindow object syncs with the client, so that when BBitmaps are deleted, they can be sure there are no pending messages (which would be executed in a nother thread) * there is no timeout anymore when sending messages to the client, which made absolutely no sense AGGTextRenderer: * renamed fFontManager to fFontCache, because that's what it really is * fLastFamilyAndStyle defaulted to the system plain font and therefor that font was never loaded when the font never changed meanwhile DrawingMode: * I'm not quite sure but I think there was the potential of a division by zero, at least I had crashes with "divide error" HWInterface: * fix update when the cursor shape changed in double buffered mode ViewLayer: * since the top layer is never really deleted before its time has come, it is not necessary to set it to NULL in the ViewLayer destructor ViewLayer/WindowLayer: * added a function to collect the view tokens that are affected by an update session EventDispatcher: * use the importance of the message for the timeout in _SendMessage() * drop mouse moved events in the server if we're lagging behind more than 5 ms (Axel, maybe review) View: * there were some problems with the locking of the BWindow looper in RemoveSelf(), since this is called from the window destructor, also of BWindows from BBitmaps, which have never been run (this might need review), at least I seem to have solved the crashing problems introduced by actually deleting the view hirarchy in the BWindow destructor * fixed _Draw() for being used non-recursively, temporarily disabled DrawAfterChildren, which didn't work yet anyways (because views cannot draw over children in the server yet) Window: * small cleanup when deleting shortcuts * sync with the server when having send AS_DELETE_WINDOW (see ServerWindow above) * fixed locking in Begin/EndViewTransaction() * removed folding of _UPDATE_ messages, since there is only one ever in the queue * set the fInTransaction flag during an update, I plan to use this in BView later to flush the link when drawing outside of an update * BView::_Draw() is now called by view token, this gives the next leap forward in speed, the overhead because of drawing clean views was considerable git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15878 a95241bf-73f2-0310-859d-f6bbb57e9c96
2006-01-09 01:04:52 +03:00
ServerFont::SetStyle(FontStyle* style)
{
ServerFont: * fixed weird pointer conversion in SetStyle() * fixed a potential mix up in operator=() in case the other ServerFont has fStyle == NULL ServerWindow: * the WindowLayer fTopLayer cannot be deleted by client request, just for safety reasons * the link is flushed if there is no drawing engine, but this case is theoretical only * deleting the ServerWindow object syncs with the client, so that when BBitmaps are deleted, they can be sure there are no pending messages (which would be executed in a nother thread) * there is no timeout anymore when sending messages to the client, which made absolutely no sense AGGTextRenderer: * renamed fFontManager to fFontCache, because that's what it really is * fLastFamilyAndStyle defaulted to the system plain font and therefor that font was never loaded when the font never changed meanwhile DrawingMode: * I'm not quite sure but I think there was the potential of a division by zero, at least I had crashes with "divide error" HWInterface: * fix update when the cursor shape changed in double buffered mode ViewLayer: * since the top layer is never really deleted before its time has come, it is not necessary to set it to NULL in the ViewLayer destructor ViewLayer/WindowLayer: * added a function to collect the view tokens that are affected by an update session EventDispatcher: * use the importance of the message for the timeout in _SendMessage() * drop mouse moved events in the server if we're lagging behind more than 5 ms (Axel, maybe review) View: * there were some problems with the locking of the BWindow looper in RemoveSelf(), since this is called from the window destructor, also of BWindows from BBitmaps, which have never been run (this might need review), at least I seem to have solved the crashing problems introduced by actually deleting the view hirarchy in the BWindow destructor * fixed _Draw() for being used non-recursively, temporarily disabled DrawAfterChildren, which didn't work yet anyways (because views cannot draw over children in the server yet) Window: * small cleanup when deleting shortcuts * sync with the server when having send AS_DELETE_WINDOW (see ServerWindow above) * fixed locking in Begin/EndViewTransaction() * removed folding of _UPDATE_ messages, since there is only one ever in the queue * set the fInTransaction flag during an update, I plan to use this in BView later to flush the link when drawing outside of an update * BView::_Draw() is now called by view token, this gives the next leap forward in speed, the overhead because of drawing clean views was considerable git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15878 a95241bf-73f2-0310-859d-f6bbb57e9c96
2006-01-09 01:04:52 +03:00
if (style && style != fStyle) {
// detach from old style
if (fStyle)
fStyle->Release();
// attach to new style
ServerFont: * fixed weird pointer conversion in SetStyle() * fixed a potential mix up in operator=() in case the other ServerFont has fStyle == NULL ServerWindow: * the WindowLayer fTopLayer cannot be deleted by client request, just for safety reasons * the link is flushed if there is no drawing engine, but this case is theoretical only * deleting the ServerWindow object syncs with the client, so that when BBitmaps are deleted, they can be sure there are no pending messages (which would be executed in a nother thread) * there is no timeout anymore when sending messages to the client, which made absolutely no sense AGGTextRenderer: * renamed fFontManager to fFontCache, because that's what it really is * fLastFamilyAndStyle defaulted to the system plain font and therefor that font was never loaded when the font never changed meanwhile DrawingMode: * I'm not quite sure but I think there was the potential of a division by zero, at least I had crashes with "divide error" HWInterface: * fix update when the cursor shape changed in double buffered mode ViewLayer: * since the top layer is never really deleted before its time has come, it is not necessary to set it to NULL in the ViewLayer destructor ViewLayer/WindowLayer: * added a function to collect the view tokens that are affected by an update session EventDispatcher: * use the importance of the message for the timeout in _SendMessage() * drop mouse moved events in the server if we're lagging behind more than 5 ms (Axel, maybe review) View: * there were some problems with the locking of the BWindow looper in RemoveSelf(), since this is called from the window destructor, also of BWindows from BBitmaps, which have never been run (this might need review), at least I seem to have solved the crashing problems introduced by actually deleting the view hirarchy in the BWindow destructor * fixed _Draw() for being used non-recursively, temporarily disabled DrawAfterChildren, which didn't work yet anyways (because views cannot draw over children in the server yet) Window: * small cleanup when deleting shortcuts * sync with the server when having send AS_DELETE_WINDOW (see ServerWindow above) * fixed locking in Begin/EndViewTransaction() * removed folding of _UPDATE_ messages, since there is only one ever in the queue * set the fInTransaction flag during an update, I plan to use this in BView later to flush the link when drawing outside of an update * BView::_Draw() is now called by view token, this gives the next leap forward in speed, the overhead because of drawing clean views was considerable git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15878 a95241bf-73f2-0310-859d-f6bbb57e9c96
2006-01-09 01:04:52 +03:00
fStyle = style;
fStyle->Acquire();
ServerFont: * fixed weird pointer conversion in SetStyle() * fixed a potential mix up in operator=() in case the other ServerFont has fStyle == NULL ServerWindow: * the WindowLayer fTopLayer cannot be deleted by client request, just for safety reasons * the link is flushed if there is no drawing engine, but this case is theoretical only * deleting the ServerWindow object syncs with the client, so that when BBitmaps are deleted, they can be sure there are no pending messages (which would be executed in a nother thread) * there is no timeout anymore when sending messages to the client, which made absolutely no sense AGGTextRenderer: * renamed fFontManager to fFontCache, because that's what it really is * fLastFamilyAndStyle defaulted to the system plain font and therefor that font was never loaded when the font never changed meanwhile DrawingMode: * I'm not quite sure but I think there was the potential of a division by zero, at least I had crashes with "divide error" HWInterface: * fix update when the cursor shape changed in double buffered mode ViewLayer: * since the top layer is never really deleted before its time has come, it is not necessary to set it to NULL in the ViewLayer destructor ViewLayer/WindowLayer: * added a function to collect the view tokens that are affected by an update session EventDispatcher: * use the importance of the message for the timeout in _SendMessage() * drop mouse moved events in the server if we're lagging behind more than 5 ms (Axel, maybe review) View: * there were some problems with the locking of the BWindow looper in RemoveSelf(), since this is called from the window destructor, also of BWindows from BBitmaps, which have never been run (this might need review), at least I seem to have solved the crashing problems introduced by actually deleting the view hirarchy in the BWindow destructor * fixed _Draw() for being used non-recursively, temporarily disabled DrawAfterChildren, which didn't work yet anyways (because views cannot draw over children in the server yet) Window: * small cleanup when deleting shortcuts * sync with the server when having send AS_DELETE_WINDOW (see ServerWindow above) * fixed locking in Begin/EndViewTransaction() * removed folding of _UPDATE_ messages, since there is only one ever in the queue * set the fInTransaction flag during an update, I plan to use this in BView later to flush the link when drawing outside of an update * BView::_Draw() is now called by view token, this gives the next leap forward in speed, the overhead because of drawing clean views was considerable git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15878 a95241bf-73f2-0310-859d-f6bbb57e9c96
2006-01-09 01:04:52 +03:00
fFace = fStyle->Face();
fDirection = fStyle->Direction();
}
}
/*!
\brief Sets the ServerFont instance to whatever font is specified
\param familyID ID number of the family to set
\param styleID ID number of the style to set
\return B_OK if successful, B_ERROR if not
*/
status_t
ServerFont::SetFamilyAndStyle(uint16 familyID, uint16 styleID)
{
FontStyle* style = NULL;
if (gFontManager->Lock()) {
style = gFontManager->GetStyle(familyID, styleID);
if (style != NULL)
style->Acquire();
gFontManager->Unlock();
}
if (!style)
return B_ERROR;
ServerFont: * fixed weird pointer conversion in SetStyle() * fixed a potential mix up in operator=() in case the other ServerFont has fStyle == NULL ServerWindow: * the WindowLayer fTopLayer cannot be deleted by client request, just for safety reasons * the link is flushed if there is no drawing engine, but this case is theoretical only * deleting the ServerWindow object syncs with the client, so that when BBitmaps are deleted, they can be sure there are no pending messages (which would be executed in a nother thread) * there is no timeout anymore when sending messages to the client, which made absolutely no sense AGGTextRenderer: * renamed fFontManager to fFontCache, because that's what it really is * fLastFamilyAndStyle defaulted to the system plain font and therefor that font was never loaded when the font never changed meanwhile DrawingMode: * I'm not quite sure but I think there was the potential of a division by zero, at least I had crashes with "divide error" HWInterface: * fix update when the cursor shape changed in double buffered mode ViewLayer: * since the top layer is never really deleted before its time has come, it is not necessary to set it to NULL in the ViewLayer destructor ViewLayer/WindowLayer: * added a function to collect the view tokens that are affected by an update session EventDispatcher: * use the importance of the message for the timeout in _SendMessage() * drop mouse moved events in the server if we're lagging behind more than 5 ms (Axel, maybe review) View: * there were some problems with the locking of the BWindow looper in RemoveSelf(), since this is called from the window destructor, also of BWindows from BBitmaps, which have never been run (this might need review), at least I seem to have solved the crashing problems introduced by actually deleting the view hirarchy in the BWindow destructor * fixed _Draw() for being used non-recursively, temporarily disabled DrawAfterChildren, which didn't work yet anyways (because views cannot draw over children in the server yet) Window: * small cleanup when deleting shortcuts * sync with the server when having send AS_DELETE_WINDOW (see ServerWindow above) * fixed locking in Begin/EndViewTransaction() * removed folding of _UPDATE_ messages, since there is only one ever in the queue * set the fInTransaction flag during an update, I plan to use this in BView later to flush the link when drawing outside of an update * BView::_Draw() is now called by view token, this gives the next leap forward in speed, the overhead because of drawing clean views was considerable git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15878 a95241bf-73f2-0310-859d-f6bbb57e9c96
2006-01-09 01:04:52 +03:00
SetStyle(style);
style->Release();
return B_OK;
}
/*!
\brief Sets the ServerFont instance to whatever font is specified
\param fontID the combination of family and style ID numbers
\return B_OK if successful, B_ERROR if not
*/
status_t
ServerFont::SetFamilyAndStyle(uint32 fontID)
{
uint16 style = fontID & 0xFFFF;
uint16 family = (fontID & 0xFFFF0000) >> 16;
return SetFamilyAndStyle(family, style);
}
void
ServerFont::SetFace(uint32 face)
{
// TODO: change font style as requested!
fFace = face;
}
/*!
\brief Gets the ID values for the ServerFont instance in one shot
\return the combination of family and style ID numbers
*/
uint32
ServerFont::GetFamilyAndStyle() const
{
return (FamilyID() << 16) | StyleID();
}
FT_Face
ServerFont::GetTransformedFace(bool rotate, bool shear) const
{
fStyle->Lock();
FT_Face face = fStyle->FreeTypeFace();
if (!face) {
fStyle->Unlock();
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);
fStyle->Unlock();
}
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;
funcs.conic_to = ConicToFunc;
funcs.cubic_to = CubicToFunc;
funcs.shift = 0;
funcs.delta = 0;
const char *string = charArray;
for (int i = 0; i < numChars; i++) {
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, shapeArray[i]);
shapeArray[i]->Close();
}
PutTransformedFace(face);
return B_OK;
}
status_t
ServerFont::GetHasGlyphs(const char charArray[], int32 numChars,
bool hasArray[]) const
{
if (!charArray || numChars <= 0 || !hasArray)
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++)
hasArray[i] = FT_Get_Char_Index(face, UTF8ToCharCode(&string)) > 0;
PutTransformedFace(face);
return B_OK;
}
status_t
ServerFont::GetEdges(const char charArray[], int32 numChars,
edge_info edgeArray[]) const
{
if (!charArray || numChars <= 0 || !edgeArray)
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++) {
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;
}
PutTransformedFace(face);
return B_OK;
}
status_t
ServerFont::GetEscapements(const char charArray[], int32 numChars,
escapement_delta delta, BPoint escapementArray[], BPoint offsetArray[]) const
{
if (!charArray || numChars <= 0 || !escapementArray)
return B_BAD_DATA;
FT_Face face = GetTransformedFace(true, false);
if (!face)
return B_ERROR;
const char *string = charArray;
for (int i = 0; i < numChars; i++) {
uint32 charCode = UTF8ToCharCode(&string);
FT_Load_Char(face, charCode, FT_LOAD_NO_BITMAP);
escapementArray[i].x = is_white_space(charCode) ? delta.space : delta.nonspace;
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;
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;
}
}
PutTransformedFace(face);
return B_OK;
}
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++) {
uint32 charCode = UTF8ToCharCode(&string);
FT_Load_Char(face, charCode, FT_LOAD_NO_BITMAP);
widthArray[i] = is_white_space(charCode) ? delta.space : delta.nonspace;
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 stringEscapement, font_metric_mode mode,
escapement_delta delta)
{
if (!charArray || numChars <= 0 || !rectArray)
return B_BAD_DATA;
FT_Face face = GetTransformedFace(true, true);
if (!face)
return B_ERROR;
const char *string = charArray;
for (int i = 0; i < numChars; i++) {
uint32 charCode = UTF8ToCharCode(&string);
if (stringEscapement) {
if (i > 0)
rectArray[i].OffsetBy(is_white_space(charCode) ? delta.space / 2.0 : delta.nonspace / 2.0, 0.0);
rectArray[i].OffsetBy(is_white_space(charCode) ? delta.space / 2.0 : delta.nonspace / 2.0, 0.0);
}
FT_Load_Char(face, charCode, 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;
}
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 B_BAD_DATA;
FT_Face face = GetTransformedFace(true, true);
if (!face)
return B_ERROR;
for (int32 i = 0; i < numStrings; i++) {
// TODO: ...
}
PutTransformedFace(face);
return B_OK;
}
float
ServerFont::StringWidth(const char *_string, int32 numChars) const
{
if (!_string || numChars <= 0)
return 0.0;
FT_Face face = GetTransformedFace(false, false);
if (!face)
return 0.0;
float width = 0.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;
}
PutTransformedFace(face);
return width;
}
/*!
\brief Returns a BRect which encloses the entire font
\return A BRect which encloses the entire font
*/
BRect
ServerFont::BoundingBox()
{
// TODO: fBounds is nowhere calculated!
return fBounds;
}
/*!
\brief Obtains the height values for characters in the font in its current state
\param fh pointer to a font_height object to receive the values for the font
*/
void
ServerFont::GetHeight(font_height& height) const
{
fStyle->GetHeight(fSize, height);
}
void
ServerFont::TruncateString(BString* inOut, uint32 mode, float width) const
{
if (!inOut)
return;
// the width of the "…" glyph
float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS, 1);
const char *string = inOut->String();
int32 length = inOut->Length();
// temporary array to hold result
char *result = new char[length + 3];
// count the individual glyphs
int32 numChars = UTF8ToLength(string);
// get the escapement of each glyph in font units
float *escapementArray = new float[numChars];
static escapement_delta delta = (escapement_delta){ 0.0, 0.0 };
if (GetEscapements(string, numChars, delta, escapementArray) == B_OK) {
truncate_string(string, mode, width, result, escapementArray, fSize,
ellipsisWidth, length, numChars);
inOut->SetTo(result);
}
delete[] escapementArray;
delete[] result;
}