Files
haiku-beta6/src/kits/interface/Font.cpp
T

1409 lines
29 KiB
C++
Raw Normal View History

2005-08-24 15:08:32 +00:00
/*
2006-04-26 10:16:19 +00:00
* Copyright 2001-2006, Haiku, Inc.
2005-08-24 15:08:32 +00:00
* Distributed under the terms of the MIT License.
*
* Authors:
* DarkWyrm <[email protected]>
* Jérôme Duval, [email protected]
* Axel Dörfler, [email protected]
2005-08-24 15:08:32 +00:00
*/
2006-04-26 10:16:19 +00:00
#include <AppServerLink.h>
#include <FontPrivate.h>
#include <ObjectList.h>
#include <ServerProtocol.h>
#include <truncate_string.h>
#include <utf8_functions.h>
#include <Autolock.h>
2005-11-07 11:02:39 +00:00
#include <Font.h>
#include <Locker.h>
2005-01-21 12:11:31 +00:00
#include <Message.h>
2003-09-01 17:08:34 +00:00
#include <PortLink.h>
#include <Rect.h>
#include <Shape.h>
#include <String.h>
2006-04-26 10:16:19 +00:00
#include <new>
#include <stdio.h>
#include <stdlib.h>
2003-09-01 17:08:34 +00:00
using namespace std;
2003-09-01 17:08:34 +00:00
const float kUninitializedAscent = INFINITY;
2005-11-07 11:02:39 +00:00
const uint32 kUninitializedExtraFlags = 0xffffffff;
2003-09-01 17:08:34 +00:00
// The actual objects which the globals point to
2004-12-20 13:56:14 +00:00
static BFont sPlainFont;
static BFont sBoldFont;
static BFont sFixedFont;
2003-09-01 17:08:34 +00:00
2004-12-20 13:56:14 +00:00
const BFont *be_plain_font = &sPlainFont;
const BFont *be_bold_font = &sBoldFont;
const BFont *be_fixed_font = &sFixedFont;
2003-09-01 17:08:34 +00:00
struct style {
BString name;
uint16 face;
uint32 flags;
};
struct family {
BString name;
uint32 flags;
BObjectList<style> styles;
};
namespace BPrivate {
class FontList : public BLocker {
public:
FontList();
~FontList();
bool UpdatedOnServer();
status_t FamilyAt(int32 index, font_family *_family, uint32 *_flags);
status_t StyleAt(font_family family, int32 index, font_style *_style,
uint16 *_face, uint32 *_flags);
int32 CountFamilies();
int32 CountStyles(font_family family);
private:
status_t _UpdateIfNecessary();
status_t _Update();
int32 _RevisionOnServer();
family* _FindFamily(font_family name);
BObjectList<family> fFamilies;
family* fLastFamily;
bigtime_t fLastUpdate;
int32 fRevision;
};
} // namespace BPrivate
static BPrivate::FontList sFontList;
// #pragma mark -
static int
compare_families(const family* a, const family* b)
{
// TODO: compare font names according to the user's locale settings
return strcmp(a->name.String(), b->name.String());
}
namespace BPrivate {
FontList::FontList()
: BLocker("font list"),
fLastFamily(NULL),
fLastUpdate(0),
fRevision(0)
{
}
FontList::~FontList()
{
}
bool
FontList::UpdatedOnServer()
{
return _RevisionOnServer() != fRevision;
}
int32
FontList::_RevisionOnServer()
{
BPrivate::AppServerLink link;
link.StartMessage(AS_GET_FONT_LIST_REVISION);
int32 code;
if (link.FlushWithReply(code) != B_OK || code != B_OK)
return B_ERROR;
int32 revision;
link.Read<int32>(&revision);
return revision;
}
status_t
FontList::_Update()
{
// check version
int32 revision = _RevisionOnServer();
fLastUpdate = system_time();
// are we up-to-date already?
if (revision == fRevision)
return B_OK;
fFamilies.MakeEmpty();
fLastFamily = NULL;
BPrivate::AppServerLink link;
for (int32 index = 0;; index++) {
link.StartMessage(AS_GET_FAMILY_AND_STYLES);
link.Attach<int32>(index);
int32 status;
if (link.FlushWithReply(status) != B_OK
|| status != B_OK)
break;
::family* family = new (nothrow) ::family;
if (family == NULL)
return B_NO_MEMORY;
link.ReadString(family->name);
link.Read<uint32>(&family->flags);
int32 styleCount;
link.Read<int32>(&styleCount);
for (int32 i = 0; i < styleCount; i++) {
::style* style = new (nothrow) ::style;
if (style == NULL) {
delete family;
return B_NO_MEMORY;
}
link.ReadString(style->name);
link.Read<uint16>(&style->face);
link.Read<uint32>(&style->flags);
family->styles.AddItem(style);
}
fFamilies.BinaryInsert(family, compare_families);
}
fRevision = revision;
// if the font list has been changed in the mean time, just update again
if (UpdatedOnServer())
_Update();
return B_OK;
}
status_t
FontList::_UpdateIfNecessary()
{
// an updated font list is at least valid for 1 second
if (fLastUpdate > system_time() - 1000000)
return B_OK;
return _Update();
}
family*
FontList::_FindFamily(font_family name)
{
if (fLastFamily != NULL && fLastFamily->name == name)
return fLastFamily;
::family family;
family.name = name;
fLastFamily = const_cast< ::family*>(fFamilies.BinarySearch(family, compare_families));
return fLastFamily;
}
status_t
FontList::FamilyAt(int32 index, font_family *_family, uint32 *_flags)
{
BAutolock locker(this);
status_t status = _UpdateIfNecessary();
if (status < B_OK)
return status;
::family* family = fFamilies.ItemAt(index);
if (family == NULL)
return B_BAD_VALUE;
memcpy(*_family, family->name.String(), family->name.Length() + 1);
if (_flags)
*_flags = family->flags;
return B_OK;
}
status_t
FontList::StyleAt(font_family familyName, int32 index, font_style *_style,
uint16 *_face, uint32 *_flags)
{
BAutolock locker(this);
status_t status = _UpdateIfNecessary();
if (status < B_OK)
return status;
::family* family = _FindFamily(familyName);
if (family == NULL)
return B_BAD_VALUE;
::style* style = family->styles.ItemAt(index);
if (style == NULL)
return B_BAD_VALUE;
memcpy(*_style, style->name.String(), style->name.Length() + 1);
if (_face)
*_face = style->face;
if (_flags)
*_flags = style->flags;
return B_OK;
}
int32
FontList::CountFamilies()
{
BAutolock locker(this);
_UpdateIfNecessary();
return fFamilies.CountItems();
}
int32
FontList::CountStyles(font_family familyName)
{
BAutolock locker(this);
_UpdateIfNecessary();
::family* family = _FindFamily(familyName);
if (family == NULL)
return 0;
return family->styles.CountItems();
}
} // namespace BPrivate
// #pragma mark -
2004-12-20 13:56:14 +00:00
void
2005-11-07 11:02:39 +00:00
_init_global_fonts_()
2003-09-01 17:08:34 +00:00
{
BPrivate::AppServerLink link;
2005-11-07 11:02:39 +00:00
link.StartMessage(AS_GET_SYSTEM_FONTS);
int32 code;
if (link.FlushWithReply(code) != B_OK
2005-11-01 16:28:01 +00:00
|| code != B_OK) {
2005-11-07 11:02:39 +00:00
printf("DEBUG: Couldn't initialize global fonts!\n");
2005-01-15 22:12:05 +00:00
return;
}
2005-11-07 11:02:39 +00:00
char type[B_OS_NAME_LENGTH];
while (link.ReadString(type, sizeof(type)) >= B_OK && type[0]) {
BFont dummy;
BFont *font = &dummy;
if (!strcmp(type, "plain"))
font = &sPlainFont;
else if (!strcmp(type, "bold"))
font = &sBoldFont;
else if (!strcmp(type, "fixed"))
font = &sFixedFont;
link.Read<uint16>(&font->fFamilyID);
link.Read<uint16>(&font->fStyleID);
link.Read<float>(&font->fSize);
link.Read<uint16>(&font->fFace);
link.Read<uint32>(&font->fFlags);
font->fHeight.ascent = kUninitializedAscent;
font->fExtraFlags = kUninitializedExtraFlags;
}
2003-09-01 17:08:34 +00:00
}
void _font_control_(BFont *font, int32 cmd, void *data)
{
}
status_t get_font_cache_info(uint32 id, void *set)
{
return B_ERROR;
}
status_t set_font_cache_info(uint32 id, void *set)
{
return B_ERROR;
}
2005-11-07 11:02:39 +00:00
/*!
\brief Private function used to replace the R5 hack which sets a system font
\param which string denoting which font to set
\param family the new family for the system font
\param style the new style for the system font
\param size the size for the system font to have
R5 used a global area offset table to set the system fonts in the Font
preferences panel. Bleah.
*/
void
_set_system_font_(const char *which, font_family family, font_style style,
float size)
{
2005-11-07 11:02:39 +00:00
BPrivate::AppServerLink link;
link.StartMessage(AS_SET_SYSTEM_FONT);
link.AttachString(which, B_OS_NAME_LENGTH);
link.AttachString(family, sizeof(font_family));
link.AttachString(style, sizeof(font_style));
2005-11-07 11:02:39 +00:00
link.Attach<float>(size);
link.Flush();
}
2004-12-20 13:56:14 +00:00
status_t
_get_system_default_font_(const char* which, font_family family,
font_style style, float* _size)
{
BPrivate::AppServerLink link;
link.StartMessage(AS_GET_SYSTEM_DEFAULT_FONT);
link.AttachString(which, B_OS_NAME_LENGTH);
int32 status = B_ERROR;
if (link.FlushWithReply(status) != B_OK
|| status < B_OK)
return status;
link.ReadString(family, sizeof(font_family));
link.ReadString(style, sizeof(font_style));
link.Read<float>(_size);
return B_OK;
}
2003-09-01 17:08:34 +00:00
/*!
\brief Returns the number of installed font families
\return The number of installed font families
*/
2004-12-20 13:56:14 +00:00
int32
count_font_families()
2003-09-01 17:08:34 +00:00
{
return sFontList.CountFamilies();
2003-09-01 17:08:34 +00:00
}
2004-12-20 13:56:14 +00:00
2003-09-01 17:08:34 +00:00
/*!
\brief Returns the number of styles available for a font family
\return The number of styles available for a font family
*/
2004-12-20 13:56:14 +00:00
int32
count_font_styles(font_family family)
2003-09-01 17:08:34 +00:00
{
return sFontList.CountStyles(family);
2003-09-01 17:08:34 +00:00
}
2004-12-20 13:56:14 +00:00
2003-09-01 17:08:34 +00:00
/*!
\brief Retrieves the family name at the specified index
\param index Unique font identifier code.
\param name font_family string to receive the name of the family
\param flags if non-NULL, the values of the flags IS_FIXED and B_HAS_TUNED_FONT are returned
2003-09-01 17:08:34 +00:00
\return B_ERROR if the index does not correspond to a font family
*/
2004-12-20 13:56:14 +00:00
status_t
get_font_family(int32 index, font_family *_name, uint32 *_flags)
2003-09-01 17:08:34 +00:00
{
if (_name == NULL)
return B_BAD_VALUE;
2004-12-20 13:56:14 +00:00
return sFontList.FamilyAt(index, _name, _flags);
2003-09-01 17:08:34 +00:00
}
2004-12-20 13:56:14 +00:00
2003-09-01 17:08:34 +00:00
/*!
\brief Retrieves the family name at the specified index
\param index Unique font identifier code.
\param name font_family string to receive the name of the family
\param flags if non-NULL, the values of the flags IS_FIXED and B_HAS_TUNED_FONT are returned
2003-09-01 17:08:34 +00:00
\return B_ERROR if the index does not correspond to a font style
*/
2004-12-20 13:56:14 +00:00
status_t
2005-11-01 16:28:01 +00:00
get_font_style(font_family family, int32 index, font_style *_name,
uint32 *_flags)
2003-09-01 17:08:34 +00:00
{
2005-11-01 16:28:01 +00:00
return get_font_style(family, index, _name, NULL, _flags);
2003-09-01 17:08:34 +00:00
}
2004-12-20 13:56:14 +00:00
2003-09-01 17:08:34 +00:00
/*!
\brief Retrieves the family name at the specified index
\param index Unique font identifier code.
\param name font_family string to receive the name of the family
\param face recipient of font face value, such as B_REGULAR_FACE
2005-11-01 16:28:01 +00:00
\param flags if non-NULL, the values of the flags IS_FIXED and B_HAS_TUNED_FONT are returned
2003-09-01 17:08:34 +00:00
\return B_ERROR if the index does not correspond to a font style
The face value returned by this function is not very reliable. At the same time, the value
returned should be fairly reliable, returning the proper flag for 90%-99% of font names.
*/
2004-12-20 13:56:14 +00:00
status_t
2005-11-01 16:28:01 +00:00
get_font_style(font_family family, int32 index, font_style *_name,
uint16 *_face, uint32 *_flags)
2003-09-01 17:08:34 +00:00
{
2005-11-01 16:28:01 +00:00
if (_name == NULL)
return B_BAD_VALUE;
2003-09-01 17:08:34 +00:00
return sFontList.StyleAt(family, index, _name, _face, _flags);
2003-09-01 17:08:34 +00:00
}
2004-12-20 13:56:14 +00:00
2003-09-01 17:08:34 +00:00
/*!
\brief Updates the font family list
\param checkOnly is ignored
2003-09-01 17:08:34 +00:00
\return true if the font list has changed, false if not.
*/
2004-12-20 13:56:14 +00:00
bool
update_font_families(bool /*checkOnly*/)
2003-09-01 17:08:34 +00:00
{
return sFontList.UpdatedOnServer();
2003-09-01 17:08:34 +00:00
}
2004-12-20 13:56:14 +00:00
// #pragma mark -
2003-09-01 17:08:34 +00:00
2004-12-20 13:56:14 +00:00
BFont::BFont()
2004-12-20 13:56:14 +00:00
:
// initialise for be_plain_font (avoid circular definition)
fFamilyID(0),
fStyleID(0),
fSize(10.0),
2005-03-27 03:15:34 +00:00
fShear(90.0),
2004-12-20 13:56:14 +00:00
fRotation(0.0),
fSpacing(0),
fEncoding(0),
fFace(0),
2005-11-07 11:02:39 +00:00
fFlags(0),
fExtraFlags(kUninitializedExtraFlags)
{
if (be_plain_font != NULL && this != &sPlainFont)
*this = *be_plain_font;
else {
fHeight.ascent = 7.0;
fHeight.descent = 2.0;
fHeight.leading = 13.0;
}
}
2004-12-20 13:56:14 +00:00
BFont::BFont(const BFont &font)
{
*this = font;
}
2004-12-20 13:56:14 +00:00
BFont::BFont(const BFont *font)
{
if (font)
*this = *font;
else
*this = *be_plain_font;
}
2004-12-20 13:56:14 +00:00
2003-09-01 17:08:34 +00:00
/*!
\brief Sets the font's family and style all at once
\param family Font family to set
\param style Font style to set
\return B_NAME_NOT_FOUND if family or style do not exist.
2002-10-23 20:08:17 +00:00
*/
2004-12-20 13:56:14 +00:00
status_t
BFont::SetFamilyAndStyle(const font_family family, const font_style style)
{
if (family == NULL && style == NULL)
return B_BAD_VALUE;
BPrivate::AppServerLink link;
2005-11-07 11:02:39 +00:00
link.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS);
link.AttachString(family, sizeof(font_family));
link.AttachString(style, sizeof(font_style));
2005-11-01 16:28:01 +00:00
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(0xffff);
link.Attach<uint16>(fFace);
int32 status = B_ERROR;
if (link.FlushWithReply(status) != B_OK
|| status != B_OK)
return status;
link.Read<uint16>(&fFamilyID);
link.Read<uint16>(&fStyleID);
link.Read<uint16>(&fFace);
fHeight.ascent = kUninitializedAscent;
return B_OK;
}
2004-12-20 13:56:14 +00:00
2003-09-01 17:08:34 +00:00
/*!
\brief Sets the font's family and style all at once
\param code Unique font identifier obtained from the server.
*/
2004-12-20 13:56:14 +00:00
void
2005-01-21 12:11:31 +00:00
BFont::SetFamilyAndStyle(uint32 fontcode)
{
// R5 has a bug here: the face is not updated even though the IDs are set. This
// is a problem because the face flag includes Regular/Bold/Italic information in
// addition to stuff like underlining and strikethrough. As a result, this will
// need a trip to the server and, thus, be slower than R5's in order to be correct
2005-11-01 16:28:01 +00:00
uint16 family, style;
2005-01-21 12:11:31 +00:00
style = fontcode & 0xFFFF;
family = (fontcode & 0xFFFF0000) >> 16;
2005-11-01 16:28:01 +00:00
BPrivate::AppServerLink link;
2005-11-07 11:02:39 +00:00
link.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS);
2005-11-01 16:28:01 +00:00
link.AttachString(NULL); // no family and style name
link.AttachString(NULL);
2005-01-21 12:11:31 +00:00
link.Attach<uint16>(family);
link.Attach<uint16>(style);
2005-11-01 16:28:01 +00:00
link.Attach<uint16>(fFace);
2005-11-01 16:28:01 +00:00
int32 code;
if (link.FlushWithReply(code) != B_OK
2005-11-01 16:28:01 +00:00
|| code != B_OK)
2005-01-21 12:11:31 +00:00
return;
2005-11-01 16:28:01 +00:00
link.Read<uint16>(&fFamilyID);
link.Read<uint16>(&fStyleID);
link.Read<uint16>(&fFace);
fHeight.ascent = kUninitializedAscent;
}
2004-12-20 13:56:14 +00:00
2003-09-01 17:08:34 +00:00
/*!
\brief Sets the font's family and face all at once
\param family Font family to set
\param face Font face to set.
\return B_ERROR if family does not exists or face is an invalid value.
To comply with the BeBook, this function will only set valid values - i.e. passing a
nonexistent family will cause only the face to be set. Additionally, if a particular
face does not exist in a family, the closest match will be chosen.
*/
2004-12-20 13:56:14 +00:00
status_t
BFont::SetFamilyAndFace(const font_family family, uint16 face)
{
2005-11-01 16:28:01 +00:00
BPrivate::AppServerLink link;
2005-11-07 11:02:39 +00:00
link.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS);
link.AttachString(family, sizeof(font_family));
2005-11-01 16:28:01 +00:00
link.AttachString(NULL); // no style given
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(0xffff);
link.Attach<uint16>(face);
int32 status = B_ERROR;
2005-11-01 16:28:01 +00:00
if (link.FlushWithReply(status) != B_OK
|| status != B_OK)
return status;
2005-11-01 16:28:01 +00:00
link.Read<uint16>(&fFamilyID);
link.Read<uint16>(&fStyleID);
link.Read<uint16>(&fFace);
fHeight.ascent = kUninitializedAscent;
2005-11-01 16:28:01 +00:00
return B_OK;
}
2004-12-20 13:56:14 +00:00
void
BFont::SetSize(float size)
{
2004-12-20 13:56:14 +00:00
fSize = size;
fHeight.ascent = kUninitializedAscent;
}
2004-12-20 13:56:14 +00:00
void
BFont::SetShear(float shear)
{
2004-12-20 13:56:14 +00:00
fShear = shear;
fHeight.ascent = kUninitializedAscent;
}
2004-12-20 13:56:14 +00:00
void
BFont::SetRotation(float rotation)
{
2004-12-20 13:56:14 +00:00
fRotation = rotation;
fHeight.ascent = kUninitializedAscent;
}
2004-12-20 13:56:14 +00:00
void
BFont::SetSpacing(uint8 spacing)
{
2004-12-20 13:56:14 +00:00
fSpacing = spacing;
}
2004-12-20 13:56:14 +00:00
void
BFont::SetEncoding(uint8 encoding)
{
2004-12-20 13:56:14 +00:00
fEncoding = encoding;
}
2004-12-20 13:56:14 +00:00
void
BFont::SetFace(uint16 face)
{
2005-11-01 16:28:01 +00:00
if (face == fFace)
return;
SetFamilyAndFace(NULL, face);
}
2004-12-20 13:56:14 +00:00
void
BFont::SetFlags(uint32 flags)
{
2004-12-20 13:56:14 +00:00
fFlags = flags;
}
2004-12-20 13:56:14 +00:00
void
BFont::GetFamilyAndStyle(font_family *family, font_style *style) const
{
if (family == NULL && style == NULL)
return;
// it's okay to call this function with either family or style set to NULL
font_family familyBuffer;
font_style styleBuffer;
if (family == NULL)
family = &familyBuffer;
if (style == NULL)
style = &styleBuffer;
BPrivate::AppServerLink link;
link.StartMessage(AS_GET_FAMILY_AND_STYLE);
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(fStyleID);
2005-11-01 16:28:01 +00:00
int32 code;
if (link.FlushWithReply(code) != B_OK
2005-11-01 16:28:01 +00:00
|| code != B_OK) {
// the least we can do is to clear the buffers
memset(*family, 0, sizeof(font_family));
memset(*style, 0, sizeof(font_style));
return;
}
link.ReadString(*family, sizeof(font_family));
link.ReadString(*style, sizeof(font_style));
}
2004-12-20 13:56:14 +00:00
uint32
2005-11-07 11:02:39 +00:00
BFont::FamilyAndStyle() const
{
return (fFamilyID << 16UL) | fStyleID;
}
2004-12-20 13:56:14 +00:00
float
2005-11-07 11:02:39 +00:00
BFont::Size() const
{
return fSize;
}
2004-12-20 13:56:14 +00:00
float
2005-11-07 11:02:39 +00:00
BFont::Shear() const
{
return fShear;
}
2004-12-20 13:56:14 +00:00
float
2005-11-07 11:02:39 +00:00
BFont::Rotation() const
{
return fRotation;
}
2004-12-20 13:56:14 +00:00
uint8
2005-11-07 11:02:39 +00:00
BFont::Spacing() const
{
return fSpacing;
}
2004-12-20 13:56:14 +00:00
uint8
2005-11-07 11:02:39 +00:00
BFont::Encoding() const
{
return fEncoding;
}
2004-12-20 13:56:14 +00:00
uint16
2005-11-07 11:02:39 +00:00
BFont::Face() const
{
return fFace;
}
2004-12-20 13:56:14 +00:00
uint32
2005-11-07 11:02:39 +00:00
BFont::Flags() const
{
return fFlags;
}
2004-12-20 13:56:14 +00:00
font_direction
2005-11-07 11:02:39 +00:00
BFont::Direction() const
{
_GetExtraFlags();
2005-11-07 11:02:39 +00:00
return (font_direction)(fExtraFlags >> B_PRIVATE_FONT_DIRECTION_SHIFT);
}
2004-12-20 13:56:14 +00:00
bool
2005-11-07 11:02:39 +00:00
BFont::IsFixed() const
{
2005-11-07 11:02:39 +00:00
_GetExtraFlags();
return (fExtraFlags & B_IS_FIXED) != 0;
}
2004-12-20 13:56:14 +00:00
2003-09-01 17:08:34 +00:00
/*!
\brief Returns true if the font is fixed-width and contains both full and half-width characters
This was left unimplemented as of R5. It was a way to work with both Kanji and Roman
characters in the same fixed-width font.
*/
2004-12-20 13:56:14 +00:00
bool
2005-11-07 11:02:39 +00:00
BFont::IsFullAndHalfFixed() const
{
2005-11-07 11:02:39 +00:00
_GetExtraFlags();
return (fExtraFlags & B_PRIVATE_FONT_IS_FULL_AND_HALF_FIXED) != 0;
}
2004-12-20 13:56:14 +00:00
BRect
2005-11-07 11:02:39 +00:00
BFont::BoundingBox() const
{
BPrivate::AppServerLink link;
link.StartMessage(AS_GET_FONT_BOUNDING_BOX);
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(fStyleID);
2005-11-01 16:28:01 +00:00
int32 code;
if (link.FlushWithReply(code) != B_OK
2005-11-01 16:28:01 +00:00
|| code != B_OK)
return BRect(0, 0, 0 ,0);
BRect box;
link.Read<BRect>(&box);
return box;
}
2004-12-20 13:56:14 +00:00
unicode_block
2005-11-07 11:02:39 +00:00
BFont::Blocks() const
{
// TODO: Add Block support
return unicode_block();
}
2004-12-20 13:56:14 +00:00
font_file_format
2005-11-07 11:02:39 +00:00
BFont::FileFormat() const
{
BPrivate::AppServerLink link;
link.StartMessage(AS_GET_FONT_FILE_FORMAT);
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(fStyleID);
int32 status;
if (link.FlushWithReply(status) != B_OK
|| status != B_OK) {
// just take a safe bet...
return B_TRUETYPE_WINDOWS;
}
uint16 format;
link.Read<uint16>(&format);
return (font_file_format)format;
}
2004-12-20 13:56:14 +00:00
int32
2005-11-07 11:02:39 +00:00
BFont::CountTuned() const
{
BPrivate::AppServerLink link;
link.StartMessage(AS_GET_TUNED_COUNT);
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(fStyleID);
2005-11-01 16:28:01 +00:00
int32 code;
if (link.FlushWithReply(code) != B_OK
2005-11-01 16:28:01 +00:00
|| code != B_OK)
return -1;
int32 count;
link.Read<int32>(&count);
return count;
}
2004-12-20 13:56:14 +00:00
void
BFont::GetTunedInfo(int32 index, tuned_font_info *info) const
{
if (!info)
return;
BPrivate::AppServerLink link;
link.StartMessage(AS_GET_TUNED_INFO);
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(fStyleID);
link.Attach<uint32>(index);
2005-11-01 16:28:01 +00:00
int32 code;
if (link.FlushWithReply(code) != B_OK
2005-11-01 16:28:01 +00:00
|| code != B_OK)
return;
link.Read<tuned_font_info>(info);
}
2004-12-20 13:56:14 +00:00
void
BFont::TruncateString(BString *inOut, uint32 mode, float width) const
{
// NOTE: Careful, we cannot directly use "inOut->String()" as result
// array, because the string length increases by 3 bytes in the worst case scenario.
2005-11-01 16:28:01 +00:00
const char *string = inOut->String();
GetTruncatedStrings(&string, 1, mode, width, inOut);
}
2004-12-20 13:56:14 +00:00
void
BFont::GetTruncatedStrings(const char *stringArray[], int32 numStrings,
uint32 mode, float width, BString resultArray[]) const
{
if (stringArray && resultArray && numStrings > 0) {
// allocate storage, see BeBook for "+ 3" (make space for ellipsis)
char** truncatedStrings = new char*[numStrings];
for (int32 i = 0; i < numStrings; i++) {
truncatedStrings[i] = new char[strlen(stringArray[i]) + 3];
}
GetTruncatedStrings(stringArray, numStrings, mode, width, truncatedStrings);
// copy the strings into the BString array and free each one
for (int32 i = 0; i < numStrings; i++) {
resultArray[i].SetTo(truncatedStrings[i]);
delete[] truncatedStrings[i];
}
delete[] truncatedStrings;
2005-01-21 12:11:31 +00:00
}
}
2004-12-20 13:56:14 +00:00
void
BFont::GetTruncatedStrings(const char *stringArray[], int32 numStrings,
uint32 mode, float width, char *resultArray[]) const
{
if (stringArray && numStrings > 0) {
// the width of the "…" glyph
float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS);
for (int32 i = 0; i < numStrings; i++) {
int32 length = strlen(stringArray[i]);
// count the individual glyphs
int32 numChars = UTF8CountChars(stringArray[i], length);
// get the escapement of each glyph in font units
float* escapementArray = new float[numChars];
GetEscapements(stringArray[i], numChars, NULL, escapementArray);
truncate_string(stringArray[i], mode, width, resultArray[i],
escapementArray, fSize, ellipsisWidth, length, numChars);
delete[] escapementArray;
}
2005-01-21 12:11:31 +00:00
}
}
2004-12-20 13:56:14 +00:00
float
BFont::StringWidth(const char *string) const
{
if (!string)
return 0.0;
int32 length = strlen(string);
float width;
GetStringWidths(&string, &length, 1, &width);
return width;
}
2004-12-20 13:56:14 +00:00
float
BFont::StringWidth(const char *string, int32 length) const
{
if (!string || length < 1)
return 0.0f;
float width = 0.0f;
GetStringWidths(&string, &length, 1, &width);
2005-01-21 12:11:31 +00:00
return width;
}
2004-12-20 13:56:14 +00:00
void
BFont::GetStringWidths(const char *stringArray[], const int32 lengthArray[],
int32 numStrings, float widthArray[]) const
{
if (!stringArray || !lengthArray || numStrings < 1 || !widthArray)
2005-01-21 12:11:31 +00:00
return;
BPrivate::AppServerLink link;
2005-01-21 12:11:31 +00:00
link.StartMessage(AS_GET_STRING_WIDTHS);
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(fStyleID);
link.Attach<float>(fSize);
link.Attach<uint8>(fSpacing);
2005-01-21 12:11:31 +00:00
link.Attach<int32>(numStrings);
// TODO: all strings into a single array???
// we do have a maximum message length, and it could be easily touched here...
for (int32 i = 0; i < numStrings; i++) {
link.AttachString(stringArray[i], lengthArray[i]);
2005-01-21 12:11:31 +00:00
}
status_t status;
if (link.FlushWithReply(status) != B_OK
|| status != B_OK)
return;
link.Read(widthArray, sizeof(float) * numStrings);
}
2004-12-20 13:56:14 +00:00
void
BFont::GetEscapements(const char charArray[], int32 numChars, float escapementArray[]) const
{
GetEscapements(charArray, numChars, NULL, escapementArray);
}
2004-12-20 13:56:14 +00:00
void
BFont::GetEscapements(const char charArray[], int32 numChars, escapement_delta *delta,
float escapementArray[]) const
{
if (!charArray || numChars < 1 || !escapementArray)
return;
BPrivate::AppServerLink link;
link.StartMessage(AS_GET_ESCAPEMENTS_AS_FLOATS);
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(fStyleID);
link.Attach<float>(fSize);
link.Attach<uint8>(fSpacing);
link.Attach<float>(fRotation);
link.Attach<uint32>(fFlags);
link.Attach<float>(delta ? delta->nonspace : 0.0f);
link.Attach<float>(delta ? delta->space : 0.0f);
link.Attach<int32>(numChars);
2006-02-05 23:36:59 +00:00
// 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
2005-11-01 16:28:01 +00:00
|| code != B_OK)
return;
link.Read(escapementArray, numChars * sizeof(float));
}
2004-12-20 13:56:14 +00:00
void
BFont::GetEscapements(const char charArray[], int32 numChars, escapement_delta *delta,
BPoint escapementArray[]) const
{
GetEscapements(charArray, numChars, delta, escapementArray, NULL);
}
2004-12-20 13:56:14 +00:00
void
BFont::GetEscapements(const char charArray[], int32 numChars, escapement_delta *delta,
BPoint escapementArray[], BPoint offsetArray[]) const
{
if (!charArray || numChars < 1 || !escapementArray)
2005-01-21 12:11:31 +00:00
return;
BPrivate::AppServerLink link;
2005-01-21 12:11:31 +00:00
link.StartMessage(AS_GET_ESCAPEMENTS);
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(fStyleID);
link.Attach<float>(fSize);
link.Attach<uint8>(fSpacing);
link.Attach<float>(fRotation);
link.Attach<uint32>(fFlags);
2006-02-05 23:36:59 +00:00
link.Attach<float>(delta ? delta->nonspace : 0.0);
link.Attach<float>(delta ? delta->space : 0.0);
link.Attach<bool>(offsetArray != NULL);
2005-01-21 12:11:31 +00:00
link.Attach<int32>(numChars);
2006-02-05 23:36:59 +00:00
// TODO: Should we not worry about the port capacity here?!?
uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
link.Attach<int32>(bytesInBuffer);
link.Attach(charArray, bytesInBuffer);
2005-01-21 12:11:31 +00:00
int32 code;
if (link.FlushWithReply(code) != B_OK
2005-11-01 16:28:01 +00:00
|| code != B_OK)
return;
link.Read(escapementArray, sizeof(BPoint) * numChars);
2006-02-05 23:36:59 +00:00
if (offsetArray)
link.Read(offsetArray, sizeof(BPoint) * numChars);
}
2004-12-20 13:56:14 +00:00
void
BFont::GetEdges(const char charArray[], int32 numChars, edge_info edgeArray[]) const
{
if (!charArray || numChars < 1 || !edgeArray)
2005-01-21 12:11:31 +00:00
return;
2005-01-21 12:11:31 +00:00
int32 code;
BPrivate::AppServerLink link;
2005-01-21 12:11:31 +00:00
link.StartMessage(AS_GET_EDGES);
link.Attach<int32>(numChars);
uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
link.Attach<int32>(bytesInBuffer);
link.Attach(charArray, bytesInBuffer);
2005-01-21 12:11:31 +00:00
if (link.FlushWithReply(code) != B_OK
2005-11-01 16:28:01 +00:00
|| code != B_OK)
return;
link.Read(edgeArray, sizeof(edge_info) * numChars);
}
2004-12-20 13:56:14 +00:00
void
BFont::GetHeight(font_height *_height) const
{
if (_height == NULL)
return;
if (fHeight.ascent == kUninitializedAscent) {
// we don't have the font height cached yet
BPrivate::AppServerLink link;
2005-01-17 19:57:51 +00:00
link.StartMessage(AS_GET_FONT_HEIGHT);
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(fStyleID);
link.Attach<float>(fSize);
int32 code;
if (link.FlushWithReply(code) != B_OK
2005-11-01 16:28:01 +00:00
|| code != B_OK)
2005-01-17 19:57:51 +00:00
return;
// Who put that "const" to this method? :-)
// We made fHeight mutable for this, but we should drop the "const" when we can
link.Read<font_height>(&fHeight);
2005-01-17 19:57:51 +00:00
}
*_height = fHeight;
}
2004-12-20 13:56:14 +00:00
void
BFont::GetBoundingBoxesAsGlyphs(const char charArray[], int32 numChars, font_metric_mode mode,
BRect boundingBoxArray[]) const
{
2005-11-07 11:02:39 +00:00
_GetBoundingBoxes(charArray, numChars, mode, false, NULL, boundingBoxArray);
}
2004-12-20 13:56:14 +00:00
void
BFont::GetBoundingBoxesAsString(const char charArray[], int32 numChars, font_metric_mode mode,
escapement_delta *delta, BRect boundingBoxArray[]) const
2005-08-26 08:40:24 +00:00
{
2005-11-07 11:02:39 +00:00
_GetBoundingBoxes(charArray, numChars, mode, true, delta, boundingBoxArray);
2005-08-26 08:40:24 +00:00
}
void
2005-11-07 11:02:39 +00:00
BFont::_GetBoundingBoxes(const char charArray[], int32 numChars, font_metric_mode mode,
2005-08-26 08:40:24 +00:00
bool string_escapement, escapement_delta *delta, BRect boundingBoxArray[]) const
{
if (!charArray || numChars < 1 || !boundingBoxArray)
2005-01-21 12:11:31 +00:00
return;
2005-01-21 12:11:31 +00:00
int32 code;
BPrivate::AppServerLink link;
2005-01-21 12:11:31 +00:00
link.StartMessage(AS_GET_BOUNDINGBOXES_CHARS);
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(fStyleID);
link.Attach<float>(fSize);
link.Attach<float>(fRotation);
2005-08-26 08:40:24 +00:00
link.Attach<float>(fShear);
link.Attach<uint8>(fSpacing);
link.Attach<uint32>(fFlags);
2005-01-21 12:11:31 +00:00
link.Attach<font_metric_mode>(mode);
2005-08-26 08:40:24 +00:00
link.Attach<bool>(string_escapement);
if (delta) {
2005-01-21 12:11:31 +00:00
link.Attach<escapement_delta>(*delta);
} else {
escapement_delta emptyDelta = {0, 0};
link.Attach<escapement_delta>(emptyDelta);
2005-01-21 12:11:31 +00:00
}
2005-01-21 12:11:31 +00:00
link.Attach<int32>(numChars);
uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
link.Attach<int32>(bytesInBuffer);
link.Attach(charArray, bytesInBuffer);
2005-01-21 12:11:31 +00:00
if (link.FlushWithReply(code) != B_OK
2005-11-01 16:28:01 +00:00
|| code != B_OK)
return;
link.Read(boundingBoxArray, sizeof(BRect) * numChars);
}
2004-12-20 13:56:14 +00:00
void
BFont::GetBoundingBoxesForStrings(const char *stringArray[], int32 numStrings,
font_metric_mode mode, escapement_delta deltas[], BRect boundingBoxArray[]) const
{
if (!stringArray || numStrings < 1 || !boundingBoxArray)
2005-01-21 12:11:31 +00:00
return;
2005-01-21 12:11:31 +00:00
int32 code;
BPrivate::AppServerLink link;
2005-01-21 12:11:31 +00:00
link.StartMessage(AS_GET_BOUNDINGBOXES_STRINGS);
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(fStyleID);
link.Attach<float>(fSize);
link.Attach<float>(fRotation);
2005-08-26 08:40:24 +00:00
link.Attach<float>(fShear);
link.Attach<uint8>(fSpacing);
link.Attach<uint32>(fFlags);
2005-01-21 12:11:31 +00:00
link.Attach<font_metric_mode>(mode);
link.Attach<int32>(numStrings);
if (deltas) {
for (int32 i = 0; i < numStrings; i++) {
2005-01-21 12:11:31 +00:00
link.AttachString(stringArray[i]);
link.Attach<escapement_delta>(deltas[i]);
}
} else {
escapement_delta emptyDelta = {0, 0};
for (int32 i = 0; i < numStrings; i++) {
2005-01-21 12:11:31 +00:00
link.AttachString(stringArray[i]);
link.Attach<escapement_delta>(emptyDelta);
2005-01-21 12:11:31 +00:00
}
}
if (link.FlushWithReply(code) != B_OK
2005-11-01 16:28:01 +00:00
|| code != B_OK)
return;
link.Read(boundingBoxArray, sizeof(BRect) * numStrings);
}
2004-12-20 13:56:14 +00:00
void
BFont::GetGlyphShapes(const char charArray[], int32 numChars, BShape *glyphShapeArray[]) const
{
2005-01-21 12:11:31 +00:00
// TODO: implement code specifically for passing BShapes to and from the server
if (!charArray || numChars < 1 || !glyphShapeArray)
2005-01-21 12:11:31 +00:00
return;
2005-01-21 12:11:31 +00:00
int32 code;
BPrivate::AppServerLink link;
2005-01-21 12:11:31 +00:00
link.StartMessage(AS_GET_GLYPH_SHAPES);
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(fStyleID);
link.Attach<float>(fSize);
link.Attach<float>(fShear);
link.Attach<float>(fRotation);
link.Attach<uint32>(fFlags);
link.Attach<int32>(numChars);
uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
link.Attach<int32>(bytesInBuffer);
link.Attach(charArray, bytesInBuffer);
if (link.FlushWithReply(code) != B_OK
2005-11-01 16:28:01 +00:00
|| code != B_OK)
return;
for (int32 i = 0; i < numChars; i++)
link.ReadShape(glyphShapeArray[i]);
}
2004-12-20 13:56:14 +00:00
void
BFont::GetHasGlyphs(const char charArray[], int32 numChars, bool hasArray[]) const
{
if (!charArray || numChars < 1 || !hasArray)
2005-01-21 12:11:31 +00:00
return;
2005-01-21 12:11:31 +00:00
int32 code;
BPrivate::AppServerLink link;
2005-01-21 12:11:31 +00:00
link.StartMessage(AS_GET_HAS_GLYPHS);
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(fStyleID);
2005-01-21 12:11:31 +00:00
link.Attach<int32>(numChars);
2005-08-23 21:47:41 +00:00
uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
link.Attach<int32>(bytesInBuffer);
link.Attach(charArray, bytesInBuffer);
2005-01-21 12:11:31 +00:00
if (link.FlushWithReply(code) != B_OK
2005-11-01 16:28:01 +00:00
|| code != B_OK)
return;
link.Read(hasArray, sizeof(bool) * numChars);
}
2004-12-20 13:56:14 +00:00
2006-03-01 17:38:40 +00:00
BFont &
BFont::operator=(const BFont &font)
{
2004-12-20 13:56:14 +00:00
fFamilyID = font.fFamilyID;
fStyleID = font.fStyleID;
fSize = font.fSize;
fShear = font.fShear;
fRotation = font.fRotation;
fSpacing = font.fSpacing;
fEncoding = font.fEncoding;
fFace = font.fFace;
fHeight = font.fHeight;
fFlags = font.fFlags;
return *this;
}
2004-12-20 13:56:14 +00:00
bool
BFont::operator==(const BFont &font) const
{
return fFamilyID == font.fFamilyID
&& fStyleID == font.fStyleID
&& fSize == font.fSize
&& fShear == font.fShear
&& fRotation == font.fRotation
&& fSpacing == font.fSpacing
&& fEncoding == font.fEncoding
&& fFace == font.fFace;
}
2004-12-20 13:56:14 +00:00
bool
BFont::operator!=(const BFont &font) const
{
return fFamilyID != font.fFamilyID
|| fStyleID != font.fStyleID
|| fSize != font.fSize
|| fShear != font.fShear
|| fRotation != font.fRotation
|| fSpacing != font.fSpacing
|| fEncoding != font.fEncoding
|| fFace != font.fFace;
}
void
2005-11-07 11:02:39 +00:00
BFont::PrintToStream() const
{
font_family family;
font_style style;
GetFamilyAndStyle(&family, &style);
printf("BFont { %s (%d), %s (%d) 0x%x %f/%f %fpt (%f %f %f), %d }\n", family,
fFamilyID, style, fStyleID, fFace, fShear, fRotation, fSize,
fHeight.ascent, fHeight.descent, fHeight.leading, fEncoding);
}
2005-11-07 11:02:39 +00:00
void
2005-11-07 11:02:39 +00:00
BFont::_GetExtraFlags() const
{
// TODO: this has to be const in order to allow other font getters to stay const as well
if (fExtraFlags != kUninitializedExtraFlags)
return;
2005-11-07 11:02:39 +00:00
BPrivate::AppServerLink link;
link.StartMessage(AS_GET_EXTRA_FONT_FLAGS);
link.Attach<uint16>(fFamilyID);
link.Attach<uint16>(fStyleID);
status_t status = B_ERROR;
if (link.FlushWithReply(status) != B_OK
|| status != B_OK) {
// use defaut values for the flags
fExtraFlags = (uint32)B_FONT_LEFT_TO_RIGHT << B_PRIVATE_FONT_DIRECTION_SHIFT;
return;
}
2005-11-07 11:02:39 +00:00
link.Read<uint32>(&fExtraFlags);
}