Home

Fonts on RIMOS

Updated on Oct,26, 2001
The following parts is checked with BB SDK 2.1 on Rim957. Because of lacking of documents, as well as of many parts being created by experiments, I am not sure the information here is correct, though they work well for my applications. If there is anything wrong ( hopely not ;-) ), please let me know.

1. Create customed fonts from other existing fonts

Perhaps the most important programming item for customed fonts in RIMOS is the structure of FontDefinition that is defined in LCD_API.h

typedef struct {
    BYTE    bFontType;
    BYTE    bFirstChar;
    BYTE    bLastChar;
    BYTE    bCharHeight;
    BYTE    bCharUnderlineRow;
    BYTE    bCharWidth;
    BYTE   *bCharDefinitions;
    WORD   *wCharOffsets;
} FontDefinition;
bFontType: bit 0 set to 1 specifies this font is proportional; otherwise it is fixed-width. Bit 7 set to 1 specifies a blank will be added after each character.

bFirstChar: the first character that this font defines.

bLastChar: the last character that this font defines.

bCharHeight: height of font. This will help you to determine how many bytes are necessary for each vertical line.

bCharUnderlineRow: which row of the fonts will be used for underlining. bCharWidth: specifies the width of the fixed-width font.

bCharDefinitions: pointer to a memory area that contains font definitions. This area needs the help of the next field wCharOffsets to determine where each char definition begins and ends.
One or more definition bytes define a vertical line of the font. If font has font height smaller or equal to 8, then only one byte is necessary for the vertical line. If font has font height bigger then 8 and smaller than 16 then 2 bytes are used for the vertical lines, and so on.
This memory area contains two parts: the data part and the name part. The data part has all the bytes for drawing all the characters. Following the data part is the font name part, a string containing the font name, ended by zero.

wCharOffsets: pointer to an array having the members equal to number of characters defined by the font plus 1. Member[N+1] determines the offset into bCharDefinitions that begins the byte definitions for N+1 th character, and that ends the byte definitions of the N-th character, N >= 0. One of the interesting thing is if we want to omit M-th character, we just need to set Member[M] = Member[M+1]. This means M-th character has zero width.

With the above information, if we need to define a character of proportional font , height of 14, width of 8, then we need to have 16 bytes for this character. Perhaps that's enough for this font theory ( and that's all that I know about RimOS font ). Let's start some programming.

My application needs two different sets of fonts with different heights of 8 and 10, one at a time, each set requires to have normal, reversed ( black background, white foreground ) and underlined fonts. I am not sure if the Lcd API calls could help me to solve this or not, but I hate to deal with pixels, areas, lines, so I ignore these APIs.
For the normal fonts, it is easy to use the built-in fonts of the RimOS, using Font::GetDefault(int,int). For the other fonts, I clone the original ones then process them.

In the following code, there is RIMStrCpy function, that is from http://resources.rimdev.com/codesnippet.htm. Also for the sake of simplicity, codes for checking memory allocation have been got out of here.

The following function will create a set of three fonts for a given height, 8 or 10.
1. Create the normal font : line 17 - 20

2. Create the reversed font out of the normal font. This step will first create the new font definition ( line 23 - 24 ). Then the number of characters is calculated ( line 25 ). Recall the meaning of the wCharOffsets, we know that the last member of this array lets us know the offset of the last byte of the last character. This also is the size of the data part of bCharDefinitions. Knowing the size of the data part, knowing the name of the font ( line 10 ) we now can allocate memory for this memory area ( line 27 ). Line 28-30 finishes the work of creating a font definition out of the normal one.

3. Manually process the font definition as we want. We need a reversed font, so all we need to do is to XOR each byte of the data part ( line 31- 32 ).

4. Create the reversed font from the font definition ( line 33 ).

5. For the underlined font, we repeat step 2 to 4, except there is a little different for step 3.

To have the underline, we need to put a dot at the lower part of each vertical line of the font. This requires us know how many byte a vertical line requires. That's why in the codes ( line 42 and 53 ) we check if this font requires one or two bytes for one vertical line : font 8 requires 1 byte, font 10 requires 2 bytes. For font 8, we just simply OR each byte with 0x80, the lowest dot of the vertical line. For font 10, there are two bytes for each vertical line, so we need to add a dot to the 2nd byte only ( line 50 ).


 1. Font *gpfont1 = NULL;
 2. Font *gpfont2 = NULL;
 3. Font *gpfont3 = NULL;
 4. Font *gpselectedfont = NULL;
 5. FontDefinition gfontdef2, gfontdef3;
 6.
 7.void InitializeFonts( int fontsize)
 8.{
 9. const FontDefinition *pfontdef;
10. const char *customedfontname="Custom Font";
11. Font *font;
12. int i;
13. 
14.	// support size 10 and size 8 only at this time
15.	if( fontsize != 10 && fontsize != 8 ) fontsize = 10;
16.
17.	font = (Font*)Font::GetDefault(fontsize);
18.
19.	// font 1 is the default font
20.	gpfont1 = new Font(font->GetDefinition());
21.
22.	// font 2 is the reversed font of font 1 
23.	pfontdef = gpfont1->GetDefinition();
24.	memcpy( &gfontdef2, pfontdef, sizeof(gfontdef2));
25.	int charnum = pfontdef->bLastChar - pfontdef->bFirstChar ;
26.	int size = pfontdef->wCharOffsets[charnum+1];
27.	unsigned char *pnewdata2 = new unsigned char[size + RIMStrLen(customedfontname)+1];
28.	memcpy( pnewdata2, pfontdef->bCharDefinitions, size );	
29.	RIMStrCpy( (char*)pnewdata2+size, customedfontname );
30.	gfontdef2.bCharDefinitions = pnewdata2;
31.	for( i = 0; i < size; i++ )
32.		*(pnewdata2+i) = (*(pnewdata2+i))^0xFF;
33.	gpfont2 =  new Font(&gfontdef2);
34.
35.	// font 3 is the underlined font 1 
36.	memcpy( &gfontdef3, pfontdef, sizeof(gfontdef3));
37.	unsigned char *pnewdata3 = new unsigned char[size + RIMStrLen(customedfontname)+1];
38.	memcpy( pnewdata3, pfontdef->bCharDefinitions, size );	
39.	RIMStrCpy( (char*)pnewdata3+size, customedfontname );
40.	gfontdef3.bCharDefinitions = pnewdata3;
41.	int height = gfontdef3.bCharHeight;
42.	if( fontsize == 10 )
43.	{
44.		for( i = 1; i < charnum; i++ )
45.		{
46.			int index1 = gfontdef3.wCharOffsets[i-1];
47.			int index2 = gfontdef3.wCharOffsets[i];
48.			int j;
49.			for(  j = index1; j < index2; j++ )
50.					*(pnewdata3 + ++j) |= 0x2;
51.		}
52.	}
53.	else	// fontsize = 8; 
54.	{
55.		for( i = 1; i < charnum; i++ )
56.		{
57.			int index1 = gfontdef3.wCharOffsets[i-1];
58.			int index2 = gfontdef3.wCharOffsets[i];
59.			int j;
60.			for(  j = index1; j < index2; j++ )
61.					*(pnewdata3 + j) |= 0x80;
62.		}
63.	}
64.	gpfont3 = new Font(&gfontdef3);
65.}
Note: Even if we just need the reversed ( or any customed ) font, not the normal one, we still need to allocate memory for bCharDefinitions. The memory pointed to by original font definition 's bCharDefinitions is "constant". For RimOS, it means the flash memory. Writing to this will cause a memory fault.

2. Using stock fonts

The SDK includes some fonts such as Font8High_b.h, Font10High_b.h. To use these fonts, you need to look for the name of the font definition in these files by searching the declaration of FontDefinition, this will let you know the name of that font. For example, for Font8High_b.h, it is EightFontB , for Font12High_bu.h, it is TwelveFontBU. Knowing the font definition name, we can easily create the font as:
...
#include        // include the font definition file
...
    Font * font = new Font( &EightFontB );
There are a lot of useful fonts that we can find at http://resources.rimdev.com/codesnippet.htm

3. Specify fonts for UI objects

Do a quick search at Field.h in the SDK ( I am using SDK 2.1 Balckbarry) , there is a public function SetFont(Font const * font ). This means that all classes that are subclasses from class Field ( such as Edit, StringList ... ) can use this function. If we already have created a font called font1, then we can apply this font to objects of the above classes. For example:

Edit m_edit_name;
    m_edit_name.SetBuffer(11,11);
    m_edit_name.Append("Hello world");
    m_edit_name.SetFont( &font1 );

In this case, all the characrers in the field will be applied the same font format.

If you need to have an edit field that can have multiple fonts, then use class RichText. In order to specify which fonts that it will need, use void SetFonts(Font const * const * fonts, int nFonts). This function will let ReciText knows of the font definitions and their corresponding data. To know which part of RichText will apply which font, use void SetAttributes(TextRangeAttribute const * AttributeArray, int NumberOfAttributes). TextRangeAttribute is declared privately in class RichText as follows ( copied from RichText.h):

        struct TextRangeAttribute
        {
            int Offset;
            int Length;
            unsigned char Attribute;  //current implementation supports only font index (0..4)
        };
where offset is the starting position in the text that will apply the font specified by Attribute as an index into the array of Fonts that specified in SetFonts, and length is the number of characters starting from Offset will apply this font. Note: although there is a comment of index from 0 to 4, but I 've tried to use SetFonts with 7 fonts, and SetAttributes with index of 5 and 6, it still works.

An example for using RichText with Font:

RichText m_richtext;
RichText::TextRangeAttribute  arAttb[3];
Font const * arFonts[3];
const char *  pSentence = "This is font 0.This is font 1.This is font 3.";

    arFont[0] = new Font( &font0definition );
    arFont[1] = new Font( &font1definition );
    arFont[2] = new Font( &font2definition );

    m_richtext.SetFonts( arFonts, 3 );
    arAttb[0].Offset = 0;       // beginning of pSentence : "This is font 0"
    arAttb[0].Length = 15;
    arAttb[0].Attribute = 0;    // index into arFonts
    arAttb[0].Offset = 15;      // "this is font 1"
    arAttb[0].Length = 15;
    arAttb[0].Attribute = 1;    // index into arFonts
    arAttb[0].Offset = 30;      // "this is font 2"
    arAttb[0].Length = 15;
    arAttb[0].Attribute = 2;    // index into arFonts
    m_richtext.SetAttributes( arAttb, 3 ); 
    
All the above are much more than what I need for my apps, and that's all I know about fonts on RIMOS.

Home

Counter