Overview
This is the interface to the global cache of character masks. This cache lives on the local disk under the name "[]<>FontCache.dontDeleteMe". Normally at most one cache is in active use at any given time. The cache may be in one of the following states:
disabled - not in use at all.
readOnly - file may be open for read, but nothing will be added to the file.
extendable - file is open for write; new masks may be added. (normal state)
transition - moving between states.
The file format consists of a fixed-length header at the beginning, a large number of variable length records, and a word of zeros as a trailer. The file format is simple enough and has enough redundancy so that it should be scavangable even if left in a somewhat inconsistent state. Since it is just a cache, it should always be correct to throw away the font cache file and start over, but in practice it may prove to be somewhat costly to rebuild it to a usable state.
There is a hash table in virtual memory that maps each font/transformation/charcode to an index to the mask in the cache. This hash table is rebuilt whenever the font cache is opened, and maintained as new masks are added to the cache. Each entry in the hash table also contains a use count, which is merged back into the font cache file when it is closed; these statistics may be helpful for utilities for offline processing of the cache, such as culling rarely-used entries, grouping frequently-used entries together, or calculating bit-tuned versions of the masks.
Each mask is identified by the triple
[ fontID, transformation, charCode ]
where
fontID is a unique identifer (i.e., hierarchical name and timestamp) for the font that was the source of the mask
transformation is the (affine) transformation (character coordinates => device coordinates), together with a code describing the type of scan conversion used.
charCode is the 32-bit character code.
The font cache file contains entries that map fontIDs and transformations onto 16-bit codes, so that the [ fontID, transformation, charCode ] identifier is 4 words long.
Font Cache File Record Definitions
Coefficients:
TYPE ~
MACHINE
DEPENDENT
RECORD [a, b, c, d, e, f:
REAL];
denominator is always positive
passwordValue: CARDINAL ~ 0FCACH;
Header:
TYPE ~
MACHINE
DEPENDENT
RECORD [
password: CARDINAL,
numberOfEntries: LONG CARDINAL,
numberOfWords: LONG CARDINAL,
totalUsage: LONG CARDINAL
];
EntryType:
TYPE ~
MACHINE
DEPENDENT
{trailer, unused, fontIDCode, transformationCode, mask};
EntryPrefix:
TYPE ~
MACHINE
DEPENDENT
RECORD [
entryType: EntryType,
entryLengthInWords: [0..8192)
not including the prefix word
];
FontIDCodeEntry:
TYPE ~
MACHINE
DEPENDENT
RECORD [
codeValue: CARDINAL,
createdTime: BasicTime.GMT,
name:
PACKED
SEQUENCE chars:
CARDINAL
OF
CHAR
The name is stored using lower-case letters, with slashes separating the components.
];
TransformationCodeEntry:
TYPE ~
MACHINE
DEPENDENT
RECORD [
codeValue: CARDINAL,
coefficients: Coefficients,
scanConversionType: ScanConversionType
];
ScanConversionType:
TYPE ~
MACHINE
DEPENDENT
RECORD [
rasterAlignment: {unaligned, aligned} ← unaligned,
tuning: {none, quick, slow, hand} ← none,
sSpread, fSpread: [0..4) ← 0,
spare: BOOLEAN ← FALSE,
algorithmCode: CHAR ← '\000
];
MaskRepresentation:
TYPE ~
MACHINE
DEPENDENT {raster, runs};
MaskEntry:
TYPE ~
MACHINE
DEPENDENT
RECORD [
fontIDCode: CARDINAL,
transformationCode: CARDINAL,
charCode: INT,
usage: CARDINAL,
sWidth, fWidth: Scaled.Value,
sMinBB, fMinBB: INTEGER,
sSizeBB, fSizeBB: CARDINAL,
flag: PACKED ARRAY [0..12) OF BOOLEAN, -- for padding and expansion
amplified: BOOLEAN,
correctSpace: BOOLEAN,
correctMask: BOOLEAN,
data:
SELECT representation: MaskRepresentation
FROM
raster => [bits: SEQUENCE COMPUTED CARDINAL -- sSize*Ceiling[fSize/16.0] -- OF WORD],
runs => [nRuns: CARDINAL, run: SEQUENCE COMPUTED CARDINAL OF Run],
ENDCASE
];
Run:
TYPE ~ PDFileFormat.Run;
[fMin: CARDINAL, lastRun: BOOLEAN, fSize: NAT]
fMin is relative to fMinBB
Font Cache Operations
Status: TYPE ~ {disabled, readOnly, extendable, transition};
Mask: TYPE ~ REF;
Transformation: TYPE ~ ImagerTransformation.Transformation;
GetStatus:
PROC [waitDuringTransition:
BOOLEAN ←
TRUE]
RETURNS [Status];
DoUnderLock:
PROC [action:
PROC];
Calls the action procedure. Until the action procedure terminates, no other processes will be allowed to alter the status of the cache.
Disable:
PROC;
Turns the font cache off, after completing any pending writes.
MakeReadOnly:
PROC;
Makes the cache read-only, after completing any pending writes.
Updates to use counts are still allowed.
Enable:
PROC;
Makes the cache extendable
FontCacheInconsistency:
ERROR [reason:
ATOM, wordOffset:
INT];
TransID:
TYPE ~
REF TransformationCodeEntry;
Canonicalized at creation.
The codeValue field may change when the cache is trimmed.
TransIDFromTransformation:
PROC [transformation: Transformation, scanConversionType: ScanConversionType, hint: TransID ←
NIL]
RETURNS [TransID];
The hint may be supplied if the client has a good idea of what the id probably is.
The ScanConversionType is chosen by the device.
TransformationFromTransID:
PROC [transID: TransID]
RETURNS [Transformation];
FontID:
TYPE ~
REF FontIDCodeEntry;
Canonicalized at creation.
The codeValue field may change when the cache is trimmed.
FontIDFromRopeAndGMT:
PROC [name:
ROPE, createdTime: BasicTime.
GMT]
RETURNS [FontID];
RopeFromFontID:
PROC [fontID: FontID]
RETURNS [name:
ROPE];
GMTFromFontID:
PROC [fontID: FontID]
RETURNS [createdTime: BasicTime.
GMT];
InsertMask:
PROC [fontID: FontID, transID: TransID, charCode:
INT, sWidth, fWidth: Scaled.Value, mask: Mask, amplified, correctSpace, correctMask:
BOOLEAN ←
FALSE]
RETURNS [ok:
BOOLEAN];
Chooses the representation. May refuse to add a mask if it is too big or if the cache is full.
MaskDesc:
TYPE ~
RECORD [ref:
REF, maskEntryPtr:
LONG
POINTER
TO MaskEntry];
For safety's sake, don't drop the ref until you are done with the long pointer.
GetMask:
UNSAFE
PROC [fontID: FontID, transID: TransID, charCode:
INT]
RETURNS [MaskDesc];
Returns a NIL maskEntryPtr if the character is not in the cache or the cache is disabled.
RopeOrRefText: TYPE ~ REF;
StringBodyDesc:
TYPE ~
RECORD [stringBody: RopeOrRefText, start:
INT ← 0, length:
INT ←
INT.
LAST, fontSet: [0..256) ← 0];
The string is encoded using the Interpress string-body encoding, i.e., a character of '\377 is treated as an escape code that precedes a byte containing the high-order 8 bits of a new character code offset.
Current:
PROC [stringBodyDesc: StringBodyDesc]
RETURNS [charCode:
INT];
Advance:
PROC [stringBodyDesc: StringBodyDesc]
RETURNS [StringBodyDesc];
GetStringBodyMasks:
PROC [
fontID: FontID,
transID: TransID,
stringBodyDesc: StringBodyDesc,
maskProc: UNSAFE PROC [MaskDesc]
] RETURNS [StringBodyDesc];
Calls the maskProc for each character code in the StringBody, until the length is exhausted or until an unavailable mask is encountered. The returned StringBodyDesc will have an updated start, length, and fontSet.
Flushing the cache
TrimCache:
PROC [maxNumberOfMasks:
INT, maxNumberOfWords:
INT];
Discards unpopular masks from the cache until the specified limits are met.
Masks with zero usage are always discarded.
SetMaskUsage:
PROC [fontID: FontID, transID: TransID, charCode:
INT, usage:
CARDINAL];
Sets the use count - useful for controlling the flushing of the cache.
Enumerate:
PROC [action:
PROC [FontID, TransID, MaskDesc]
RETURNS [continue:
BOOL]];
Enumerates the contents of the cache. It is ok to call SetMaskUsage from the action proc.