In all the formats described below, 2-byte quantities are little-endian: that is, the least significant byte comes first, followed by the most-significant. The values are unsigned unless otherwise stated.
IntMetrics / IntMet<n>:
40 Name of font, padded with <cr> 4 16 4 16 1 nlo = low-byte of number of defined characters 1 version number of file format: 0 flags and nhi must be 0 1 **** not supported **** 2 you can set the flags as described and nchars can be > 255 1 flags: bit 0 set => there is no bbox data (use Outlines) bit 1 set => there is no x-offset data bit 2 set => there is no y-offset data bit 3 set => there is more data after the metrics bit 4 reserved (must be 0) bit 5 set => character map size precedes map bit 6 set => kern characters are 16-bit, else 8-bit bit 7 reserved (must be 0) 1 nhi = high byte of number of defined characters
n = nlo + 256*nhi
If flags bit 5 set: 2 m = character map size (lo,hi) (0 => no map) m = 256 if flags bit 5 clear
m character mapping (ie. indices into following arrays) if not present, index = character code
Note that since the mapping table is 8-bit, there cannot be one if n > 256.
Tables giving bounding boxes (1/1000th em) of characters: If flags bit 0 clear: 2n signed x0 2-byte values 2n signed y0 2-byte values 2n signed x1 2-byte values 2n signed y1 2-byte values
Tables of character widths: If flags bit 1 clear: 2n signed 2-byte x-offsets after printing each character If flags bit 2 clear: 2n signed 2-byte y-offsets after printing each character
To calculate offset to here:
nlo = byte at offset 48 in file nhi = byte at offset 51 in file flags = byte at offset 50 in file n = nlo + 256*nhi
offset = 52 if (flags bit 5 clear) then offset += 256 else offset += 2 + byte(52) + 256*byte(53) if (flags bit 0 clear) then offset += 8n if (flags bit 1 clear) then offset += 2n if (flags bit 2 clear) then offset += 2n
If flags bit 3 set:
8 table of 4 2-byte unsigned offsets from start of table: entry 0 = offset to 'miscellaneous' data entry 1 = offset to kern pair data entry 2 = offset to reserved area #1 entry 3 = offset to reserved area #2
The entries must be consecutive in the file, so the end of one area coincides with the beginning of the next. The areas are not necessarily word-aligned, and the space at the end of each area is reserved (ie. there must not be any 'dead' space at the end of an area).
Area 0: Miscellaneous data:
8 font bounding box in 1/1000th em (signed x0,y0,x1,y1) 2 default x-offset per char (if flags bit 1 set) 2 default y-offset per char (if flags bit 2 set) 2 italic h-offset per em (-1000 * TAN(italic angle)) 1 underline position (signed, in 1/256th of an em) 1 underline thickness (unsigned, in 1/256th of an em) 2 CapHeight (1/1000th em, 2-byte signed) 2 XHeight (1/1000th em, 2-byte signed) 2 Descender (1/1000th em, 2-byte signed) 2 Ascender (1/1000th em, 2-byte signed) 4 reserved field (must be 0)
Area 1: Kern pair data:
flags bit 6 clr => character codes are 8-bit flags bit 6 set => character codes are 16-bit (lo,hi)
1 or 2 left-hand letter code ] 1 or 2 right-hand letter code ] ] 2 x-kern amount (if flags bit 1 clear) ] repeat ] repeat 2 y-kern amount (if flags bit 2 clear) ] ] 1 or 2 0 => end of list for this letter ] 1 or 2 0 => end of kerns
Or, in pseudo-Backus-Naur notation:
<kerns> ::= <kernsforaletter>* <letter 0> <kernsforaletter> ::= <letter> <kernpair>* <letter 0> <kernpair> ::= <letter> <x-offset> <y-offset> <letter> ::= <8-bit character code> if flags bit 6 clear or <16-bit character code> if flags bit 6 set <x-offset> ::= <signed 16-bit offset in 1/1000 em> or <null> if flags bit 1 set <y-offset> ::= <signed 16-bit offset in 1/1000 em> or <null> if flags bit 2 set <letter 0> ::= <<letter> with code 0>
Area 2: Reserved (must be null)
Area 3: Reserved (must be null)
x90y45:
Index: 1 point size (not multiplied by 16) 1 bits per pixel (4) 1 pixels per inch (x-direction) 1 pixels per inch (y-direction) 4 reserved (was checksum) - must be 0 4 offset of pixel data in file 4 size of pixel data ... more of the same 1 0
Pixel data: 4 x-size in 1/16ths point * pixels per inch (x) 4 y-size in 1/16ths point * pixels per inch (y) 4 pixels per inch (x-direction) 4 pixels per inch (y-direction) 1 x0 - maximum bounding box for any character 1 y0 - bottom-left is inclusive 1 x1 - top-right is exclusive 1 y1 - all coordinates are in pixels 512 2-byte offsets from table start of character data 0 => character is not defined (pixel data is limited to 64K per block)
Character data:
1 x0 - bounding box 1 y0 1 x1-x0 1 y1-y0 4*n 4-bpp, consecutive rows bottom->top not aligned until the end
Outlines / Outlines<n> / f9999x9999 / b9999x9999:
b9999x9999 1-bpp definition a9999x9999 4-bpp (anti-aliased) definition Outlines the outline file
'9999' = pixel size (ie. point size * 16 * dpi / 72) zero-suppressed decimal number
File header: 4 "FONT" - identification word 1 Bits per pixel: 0 = outlines 1 = 1 bpp 4 = 4 bpp 1 Version number of file format 4: no "don't draw skeleton lines unless smaller than this" byte present 5: byte at [table+512] = max pixel size for skeleton lines (0 => always do it) 6: byte at [chunk+indexsize] = dependency mask (see below) 7: flag word precedes index in chunk (offsets are rel. to index, not chunk) 8: file offset array is in a different place 2 if bpp = 0: design size of font if bpp > 0: flags: bit 0 set => horizontal subpixel placement bit 1 set => vertical subpixel placement bit 6 set => flag word precedes index in chunk (version 7 onwards) bits 2..5, 7 must be 0 NB: for outline files, bit 6 is derived from the version number but if present, its value must suit the version number 2 x0 - font bounding box (16-bit signed) 2 y0 - units are pixels or design units 2 x1-x0 - x0,y0 inclusive, x1,y1 exclusive 2 y1-y0
If Version < 8: nchunks = 8
4 file offset of 0..31 chunk (word-aligned) 4 file offset of 32..63 chunk ... 4 file offset of 224..255 chunk 4 file offset of end (ie. size of file) if offset(n+1)=offset(n), then chunk n is null.
Else (Version >= 8): nchunks = as defined below
4 file offset of area containing file offsets of chunks 4 number of defined chunks 4 ns = number of scaffold index entries (including entry[0] = size) 4 scaffold flags: bit 0 set => ALL scaffold base chars are 16-bit bit 1 set => these outlines should not be anti-aliased (eg. System.Fixed) bit 2 set => fill using non-zero winding rule, else odd-even. bits 3..31 reserved (must be 0) 4*5 all reserved (must be 0)
Table start: 2 n = size of table/scaffold data
Bitmaps: (n=10 normally - other values are reserved) 2 x-size (1/16th point) 2 x-res (dpi) 2 y-size (1/16th point) 2 y-res (dpi)
Outlines: ns*2-2 2-byte offsets to scaffold data:
If scaffold flags bit 0 clear: bits 0..14 = offset of scaffold data from table start bit 15 set => base char code is 2 bytes, else 1
If scaffold flags bit 0 set: bits 0..15 = offset of scaffold data from table start base char code is always 2 bytes
0 => no scaffold data for char
1 Skeleton threshold pixel size (if file format version >= 5) When rastering the outlines, skeleton lines will only be drawn if either the x-or y- pixel size is less than this value (except if value=0, which means 'always draw skeleton lines'). ? ... sets of scaffold data (see below)
Table end: ? description of contents of file: <Font name>, 0, "Outlines", 0 "999x999 point at 999x999 dpi", 0 padded with zeros until word-aligned
If Version >= 8:
4 file offset of chunk 0 4 file offset of chunk 1 ... 4 file offset of chunk (nchunks-1) 4 file offset of end of file
All versions:
... word-aligned chunks follow
Scaffold data: 1 or 2 char code of 'base' scaffold entry (0 ==> none) 1 bit n set ==> x-scaffold line n defined in base char 1 bit n set ==> y-scaffold line n defined in base char 1 bit n set ==> x-scaffold line n defined locally 1 bit n set ==> y-scaffold line n defined locally ... local scaffold lines follow Scaffold lines: 2 bits 0..11 = coordinate (signed) bits 12..14 = scaffold link index (0 => none) bit 15 set => 'linear' scaffold link 1 width (254 ==> L-tangent, 255 ==> R-tangent)
Chunk data: 4 flag word (not present before file format version 7): bit 0 set => horizontal subpixel placement bit 1 set => vertical subpixel placement bit 7 set => dependency byte(s) present (see below) bits 2..6 and 8..30 must be 0 bit 31 must be 1
4 * 32 offset from index start to character 0 => character is not defined * 4 for vertical placement * 4 for horizontal placement Character index is more tightly bound than vertical placement which is more tightly bound than horizontal placement.
n Dependency byte(s) (if outline file, version >= 6). One bit required for each chunk in file. Bit n set => chunk n must be loaded in order to rasterise this chunk. This is required for composite characters which include characters from other chunks (see below).
... character data follows (word-aligned at end of chunk)
Note: All character definitions must follow the index in the order in which they are specified in the index. This is to allow the font editor to easily determine the size of each character.
Char data: 1 flags: bit 0 set => coords are 12-bit, else 8-bit bit 1 set => data is 1-bpp, else 4-bpp bit 2 set => initial pixel is black, else white bit 3 set => data is outline, else bitmap if bit 3 clr: bits 4..7 = 'f' value for char (0 ==> not encoded) if bit 3 set: bit 4 set => composite character bit 5 set => with an accent as well bit 6 set => ascii codes within this char are 16-bit, else 8-bit bit 7 reserved (must be 0)
if flag bits 3 and 4 set: 1 or 2 character code of base character if flag bit 5 set: 1 or 2 character code of accent 2 or 3 x,y offset of accent character
if flag bits 3 or 4 clear: 2 or 3 x0, y0 sign-extended 8- or 12- bit coordinates 2 or 3 xs, ys width, height (bbox = x0,y0,x0+xs,y0+ys) n data: (depends on type of file) 1-bpp uncrunched: rows from bottom->top 4-bpp uncrunched: rows from bottom->top 1-bpp crunched: list of (packed) run-lengths outlines: list of move/line/curve segments word-aligned at the end of the character data
Here the 'pixel bounding box' is actually the bounding box of the outline in terms of the design size of the font (in the file header). The data following the bounding box consists of a series of move/line/curve segments followed by a terminator and an optional extra set of line segments followed by another terminator. When constructing the bitmap from the outlines, the font manager will fill the first set of line segments to half-way through the boundary using an even-odd fill, and will thin-stroke the second set of line segments (if present). See the documentation on the Draw module for further details.
If the font is version 8 or greater then it can specifiy that the winding rule be either non-zero or odd-even, this is to provide compatibility with other type face formats (see above in scaffold flags).
Each line segment consists of:
1 bits 0..1 = segment type: 0 => terminator (see below) 1 => move to x,y 2 => line to x,y 3 => curve to x1,y1,x2,y2,x3,y3 bits 2..4 = x-scaffold link bits 5..7 = y-scaffold link ... coordinates (design units) followTerminator:
bit 3 set => composite character inclusions follow:
Composite character inclusions:
1 or 2 character code of character to include (0 => finished) 2 or 3 x,y offset of this inclusion (design units)
The coordinates are either 8- or 12-bit sign-extended, depending on bit 0 of the character flags (see above), including the composite character inclusions.
The character codes in the composite character sections are either 8- or 16-bit (low-byte first), depending on bit 6 of the character flags.
The scaffold links associated with each line segment relate to the last point specified in the definition of that move/line/curve, and the control points of a bezier curve have the same links as their nearest endpoint.
Note that if a character includes another, the appropriate bit in the parent character's chunk dependency flags must be set. This byte tells the Font Manager which extra chunk(s) must be loaded in order to rasterise the parent character's chunk.
1 bit per pixel, bit set => paint in foreground colour, in rows from bottom-left to top-right, not aligned until word-aligned at the end of the character.
The whole character is initially treated as a stream of bits, as for the uncompacted form. The bit stream is then scanned row by row, with consecutive duplicate rows being replaced by a 'repeat count', and alternate runs of black and white pixels are noted. The repeat counts and run counts are then themselves encoded in a set of 4-bit entries.
Bit 2 of the character flags determine whether the initial pixel is black or white (black = foreground), and bits 4..7 are the value of 'f' (see below). The character is then represented as a series of packed numbers, which represent the length of the next run of pixels. These runs can span more than one row, and after each run the pixel colour is changed over. Special values are used to denote row repeats.
<packed number> ==
0 followed by n-1 zeroes, followed by n+1 nibbles = resulting number + (13-f)*16 + f+1 - 16i = 1 .. f i
14 followed by n=<packed number> = repeat count of n 15 repeat count of 1 (ie. 1 extra copy of this row)
The optimal value of f lies between 1 and 12, and must be computed individually for each character, by scanning the data and calculating the length of the output for each possible value. The value yielding the shortest result is then used, unless that is larger than the bitmap itself, in which case the bitmap is used.
Repeat counts operate on the current row, as understood by the unpacking algorithm, ie. at the end of the row the repeat count is used to duplicate the row as many times as necessary. This effectively means that the repeat count applies to the row containing the first pixel of the next run to start up.
Note that rows consisting of entirely white or entirely black pixels cannot always be represented by using repeat counts, since the run may span more than one row, so a long run count is used instead.
An encoding file is a text file which contains a set of identifiers which indicate which characters appear in which positions in a font.
Each identifier is preceded by a "/", and the characters are numbered from 0, increasing by 1 with each identifier found.
Comments are introduced by "%", and continue until the next control character.
The following special comment lines are understood by the font manager:
%%RISCOS_BasedOn <baseencoding> %%RISCOS_Alphabet <alphabet>
where <baseencoding> and <alphabet> denote positive decimal integers.
Both lines are optional, and they indicate respectively the number of the base encoding and the alphabet number of this encoding.
If the %%RISCOS_BasedOn line is not present, then the Font Manager assumes that the target encoding describes the actual positions of the glyphs in an existing file, the data for which is in:
<font directory>.IntMetrics<alphabet> <font directory>.Outlines<alphabet>
where <alphabet> is null if the %%RISCOS_Alphabet line is omitted.
(In fact the leafnames are shortened to fit in 10 characters, by removing characters from just before the <alphabet> suffix).
In this case the IntMetrics and Outlines files are used directly, since there is a one-to-one correspondence between the positions of the characters in the datafiles and the positions required in the font.
If the %%RISCOS_BasedOn line IS present, then the Font Manager accesses the following datafiles:
<font directory>.IntMetrics<baseencoding> <font directory>.Outlines<baseencoding>
and assumes that the positions of the glyphs in the datafiles are as given by the contents of the base encoding file.
The base encoding is called "/Base<n>", and lives in the Encodings directory under Font$Path, along with all the other encodings. Because it is preceded by a "/", the Font Manager does not return it in the list of encodings returned by Font_ListFonts.
Note that only one encoding file with a given name can apply to all the fonts known to the system. Because of this, a given encoding can only be either a direct encoding, where the alphabet number is used to reference the datafiles, or an indirect encoding, where the base encoding number specifies the datafile names.
Here is the start of a sample base encoding ("/Base0"):
% /Base0 encoding
%%RISCOS_Alphabet 0
/.notdef /.NotDef /.NotDef /.NotDef /zero /one /two /three /four /five /six /seven /eight
Here is the start of a sample encoding file ("Latin1"):
% Latin 1 encoding
%%RISCOS_BasedOn 0 %%RISCOS_Alphabet 101
/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle
(Note that the sample /Base0 file is not the same as the released one).
These illustrate several points: