FFont Class

Primary author: Dianne Hackborn <hackbod@enteract.com>
Header file: FFont.h
Derived from: BFont


Overview


Goal

The original purpose of this code was to define a standard low-level representation for BFont objects when they are added to BMessage objects, which could be widely used in the Be developer community. By using such a common representation, applications can be sure that they will be able to communicate with each other about font information. This is important for such things as dropping fonts onto another application to control its GUI presentation, getting and setting the font used for text in scripting, and most anywhere else that font information will be moving between applications.

In the process of discussing this representation, it became apparent that what was also needed was a simple high-level interface to use it, both to explain its purpose and to make it easier for other developers to incorporate it into their code. The FFont class and its associated definitions are the end result of this discussion.


Author and Legalities

The primary author of this code is Dianne Hackborn <hackbod@enteract.com>, with contributions from Marco Nelissen, Jon Watte, Attila Mezei, Jon Ragnarsson, Rainer Riedl, David Mirchell, Ingmar Krusch, and others on the Be Developer Talk mailing list.

This code and related documentation is released to the public domain, and may be used however you see fit. However, if you make enhancements, I ask that you get in contact with me (Dianne), so that they can be rolled into the official version and made available to others. I can be contact through e-mail at either <hackbod@lucent.com>, or <hackbod@enteract.com>.


Quick Use

Most of your needs for manipulating fonts in BMessage objects can probably be handled through two simple functions. These are modelled after how hypothetical BMessage::FindFont() and BMessage::FindFont() functions would presumably work, if they were defined in BeOS.

Thus, adding the current BeOS plain font to a BMessage object is as simple as:

BMessage msg;    // Target message
if( AddMessageFont(&msg, "MyFont", be_plain_font) != B_NO_ERROR ) {
    // something bad happened...
}

This font may later be extracted with a similar function call:

BFont font(be_plain_font);    // Retrieved font
if( FindMessageFont(&msg, "MyFont", 0, &font) != B_NO_ERROR ) {
	// unable to retrieve font...
}

One thing you should be aware of when retrieving a font as shown above: while not discussed here, it is possible to store partial font representations. Thus FindMessageFont() may only change a few or even none of the attributes of the target font object. You should thus always be sure to initialize the object with values you can live with.

(The example here initializes the target font with the user's plain font; you will typically initialize it with whatever your "current" font is. This allows you you to receive partial fonts that, for example, only change the size of whatever font you are currently using.)


FFont and Extensions

The complete flattened font representation is defined by the FFont class, which is a subclass of BFont. It adds two main enhancements to BeOS's built-in font class:

  1. The FFont class implements a BFlattenable interface, so that it can be placed in a BMessage or otherwise used in the same way as any other flattenable object. The flattened representation of an FFont is defined so that it can be safely moved across different machines and platforms. See the BFlattenable class in the BeBook's support kit chapter for more information on using this interface.

  2. Each FFont object carries with it an additional "attribute mask." This is used to indicate which of the object's various BFont attributes (family and style, size, rotation, etc.) are "important." It is used to perform partial copies between font objects, and is stored in the font's flattened representation so that the receiver of a font can be directed to change only part of its current font.

The FFont attribute mask is modelled after the mask used in BView's SetFont() function; in fact, it uses the exact same bit definitions, such as B_FONT_SIZE, B_FONT_FAMILY_AND_STYLE. The current mask is set and retrieved just like other font attributes, with the new functions SetMask() and Mask().

Beyond being part of a font's flattened information, the attribute mask is used in only two places, the new FFont functions UpdateTo() and UpdateFrom(). These functions copy a font's attributes to/from (respectively) another font object, but only those attributes for which the source font's cooresponding mask bit is true.

For example, the following function will copy and font family and size name from the system plain font into an existing BFont:

void GetPlainFamilyStyle(BFont* dest)
{
    FFont pfont(be_plain_font);             // Copy the plain font
    pfont.SetMask(B_FONT_FAMILY_AND_STYLE); // Select only family & style
    pfont.UpdateTo(dest);                   // Copy into destination
}

NOTE: Clearing particular bits in the attribute mask of a font does not mean that their corresponding BFont values can be set to anything. An FFont object should always remain a valid, reasonable BFont object, regardless of how the FFont mask is set.


Constructor and Destructor


FFont()

FFont();
FFont(const BFont &font);
FFont(const BFont *font);

FFont(const FFont &font);
FFont(const FFont *font);

Like a normal BFont, a new FFont can be initialized with either the default values, or a pointer or reference to a BFont object from which it is to be copied. In addition, initializing from a pointer or reference to another FFont object will also copy the other's attribute mask. (When not copying from another FFont, the new object's attribute mask is initialize to B_FONT_ALL.)


Operators


operator=()

FFont& operator=(const BFont &font); 
FFont& operator=(const FFont &font); 

Either BFont or FFont objects can be assigned to an existing FFont object. If a BFont is assigned to an FFont, the destination object's attribute mask is reset to B_FONT_ALL; in contrast, if another FFont is assigned to it, the original's attribute mask is copied over.


Methods


SetMask(), Mask()

void SetMask(uint32 mask);
uint32 Mask(void) const;

In addition to all the normal BFont attributes, and FFont also has an "attribute mask." This is an integer mask that indicates which of the basic BFont attributes (family and style name, size, rotation, encoding, etc.) are "important." The mask takes on the same values as BView's SetFont() function: B_FONT_FAMILY_AND_STYLE, B_FONT_SIZE, B_FONT_ROTATION, B_FONT_ENCODING, etc., which can be logically or'ed together to select the various attributes. The value B_FONT_ALL stands for all attributes, and is the default.

Note that clearing a certain attribute mask bit does not mean that the corresponding BFont attribute can be anything. These bits are only a guide, and the FFont should always be valid and reasonable even if they are ignored.


UpdateTo(), UpdateFrom()

void UpdateTo(BFont* font, uint32 mask = B_FONT_ALL) const;
void UpdateTo(FFont* font, uint32 mask = B_FONT_ALL) const;
void UpdateFrom(const FFont* font, uint32 mask = B_FONT_ALL);

These methods copy one FFont to or from another font object, respecting the source font's attribute bits. This can be thought of as similar to BView's SetFont() method, but where the object being set is another font.

The actual attributes that are copied is determined by taking the logical and of the source font object and the mask parameter that is passed in as the second argument. Thus the default is to copy only those attributes for which the source font's attribute mask bits are set.

UpdateTo() copies the attributes from the member's object into another selected BFont or FFont. If the destination is an FFont, the attribute mask of the source is logically or'ed into the destination's mask, indicating that all its existing values plus the newly changed ones are "important."

font1->UpdateTo(font2,mask) is equivalent to font2->UpdateFrom(font1,mask) if both font1 and font2 are FFont objects.

As an example, this code will copy the family and style of the system plain font into in existing BFont object named myFont:

FFont(be_plain_font).UpdateTo(myFont,B_FONT_FAMILY_AND_STYLE);

IsFixedSize(), TypeCode(), FlattenedSize(), AllowsTypeCode(), Flatten(), Unflatten()

virtual bool      IsFixedSize() const;
virtual	type_code TypeCode() const;
virtual	ssize_t   FlattenedSize() const;
virtual	bool      AllowsTypeCode(type_code code) const;
virtual	status_t  Flatten(void *buffer, ssize_t size) const;
virtual	status_t  Unflatten(type_code c, const void *buf, ssize_t size);

These methods implement the complete BFlattenable interface. See support/BFlattenable for more information on how to use them.

A flattened font is stored with the type code FFont::FONT_TYPE, which is defined as 'FONt'. The flattened representation includes all BFont attributes (family name, style name, size, shear, rotation, spacing encoding, face, flags), plus the FFont's attribute mask. This last is used so that the source of a message can indicate which of the font attributes are important. For example, if you are interested in only changing the font size used by another application, you could flatten an FFont that is set to the desired size and only has the B_FONT_SIZE attribute bit set.

NOTE: If you are sending a partially defined font as described above, you must be sure to still set the other attributes to reasonable values. The receiver of the font is free to ignore the attribute mask you send, and directly use the entire font description it is given.


Test()

static void Test(void);

This static inline function can be used to perform a brief sanity check of the FFont implementation. When called, it creates various FFont objects and performs operations on them, printing the results of these to stdout.

Note that this test does not pretend to be either comprehensive or particularily understandable.


Convenience Functions

These are functions that are not a formal part of the FFont class itself, but provide a simple interface to how FFont objects are most commonly used.


AddMessageFont()

status_t
AddMessageFont(BMessage* msg, const char *name, const FFont *font);
status_t
AddMessageFont(BMessage* msg, const char *name, const BFont *font);

This function is the moral equivalent to having an "AddFont()" method as part of the BMessage interface; since we don't, a global function is provided instead.

Calling AddMessageFont() adds the given BFont or FFont object font to the BMessage object msg, under the name name. The BMessage method AddFlat() is used internally to accomplish this.

If font is an actual FFont, the given object is added to the message exactly as is. If font is instead a basic BFont, an equivalent FFont object is added with its attribute mask set to B_FONT_ALL.

Any errors encountered by this function are reported as per the standard BMessage add methods.


FindMessageFont()

status_t
FindMessageFont(const BMessage* msg, const char *name,
                int32 index, FFont *font);
status_t
FindMessageFont(const BMessage* msg, const char *name,
                int32 index, BFont *font);

This function is the moral equivalent to having a "FindFont()" method as part of the BMessage interface; since we don't, a global function is provided instead.

Calling FindMessageFont() looks for an FFont object in the given BMessage msg, under the name name and at index number index. If one is found, it is placed in the destination font object font. The BMessage method FindFlat() is used internally to accomplish this.

If font points to an actual FFont, it is filled with the exact font information found in the message. Otherwise, if font points to a basic BFont object, the font mask attributes in the BMessage are used to determine which of the attributes of the destination object are changed. This latter case is the equivalent of retrieving a complete FFont object and using its UpdateTo() method to copy it into the final destination BFont.

Any errors encountered by this function are reported as per the standard BMessage find methods. If an error occurs, the destination object font is left unchanged.