XFontCacheImpl.mesa
Michael Plass, May 5, 1983 2:39 pm
DIRECTORY XFontCache;
XFontCacheImpl: CEDAR MONITOR EXPORTS XFontCache = BEGIN
FontCache: PUBLIC TYPE ~ REF FontCacheRep;
FontCacheRep: PUBLIC TYPE ~ RECORD [
firstFontCode: NAT,
seq: REF Seq
];
Seq: TYPE ~ RECORD [
SEQUENCE length: NAT OF REF Array
];
Array: TYPE ~ RECORD [
bc: CHAR,
seq: SEQUENCE length: [0..256) OF REF
];
FontCode: TYPE ~ XFontCache.FontCode;
fontCodeTableHeaders: NAT ~ 101;
FontKeyRec: TYPE ~ MACHINE DEPENDENT RECORD [a, b, c, d: REAL, font: REF];
fontCodeTable: REF FontCodeTableRep ← NEW[FontCodeTableRep];
FontCodeTableRep: TYPE ~ ARRAY [0..fontCodeTableHeaders) OF CollisionList;
CollisionList: TYPE ~ REF CollisionListItem;
CollisionListItem: TYPE ~ RECORD [
next: CollisionList,
fontCode: FontCode,
fontKeyRec: FontKeyRec
];
fontCodeInverse: REF FontCodeInverseRep;
FontCodeInverseRep: TYPE ~ RECORD [SEQUENCE length: NAT OF CollisionList];
nextFontCode: CARDINAL ← 0;
GetFontCode: PUBLIC ENTRY PROC [a, b, c, d: REAL, font: REF] RETURNS [fontCode: FontCode] ~ TRUSTED {
ENABLE UNWIND => NULL;
fontKeyRec: FontKeyRec ← [a, b, c, d, font];
p: POINTER TO CARDINALLOOPHOLE[@fontKeyRec];
hash: CARDINAL ← 0;
IF SIZE[FontKeyRec] MOD SIZE[CARDINAL] # 0 THEN ERROR;
THROUGH [0..SIZE[FontKeyRec]/SIZE[CARDINAL]) DO
t: CARDINAL ← 2*hash;
hash ← 2*t+hash+p^; -- Depend on overflow not to raise a signal;
p ← p + SIZE[CARDINAL];
ENDLOOP;
hash ← hash MOD fontCodeTableHeaders;
FOR c: CollisionList ← fontCodeTable[hash], c.next UNTIL c=NIL DO
IF c.fontKeyRec = fontKeyRec THEN RETURN [c.fontCode];
ENDLOOP;
fontCodeTable[hash] ← NEW[CollisionListItem ← [fontCodeTable[hash], [nextFontCode], fontKeyRec]];
IF fontCodeInverse = NIL OR fontCodeInverse.length <= fontCode.key THEN {
old: REF FontCodeInverseRep ← fontCodeInverse;
newLength: NATIF old = NIL THEN 6 ELSE old.length + old.length/3 + 1;
fontCodeInverse ← NEW[FontCodeInverseRep[newLength]];
IF old # NIL THEN FOR i: NAT IN [0..old.length) DO
fontCodeInverse[i] ← old[i];
ENDLOOP;
old ← NIL;
};
fontCodeInverse[nextFontCode] ← fontCodeTable[hash];
fontCode ← [nextFontCode];
nextFontCode ← nextFontCode + 1;
};
InterpretFontCode: PUBLIC ENTRY PROC [fontCode: FontCode]
RETURNS [a, b, c, d: REAL, font: REF] ~ {
ENABLE UNWIND => NULL;
IF fontCodeInverse = NIL OR fontCodeInverse.length <= fontCode.key OR fontCodeInverse[fontCode.key] = NIL THEN ERROR InvalidFontCode[];
[a, b, c, d, font] ← fontCodeInverse[fontCode.key].fontKeyRec;
};
InvalidFontCode: PUBLIC ERROR ~ CODE;
Flush: PUBLIC ENTRY PROC [font: REF] ~ {
ENABLE UNWIND => NULL;
FOR i: NAT IN [0..fontCodeTableHeaders) DO
c: CollisionList ← fontCodeTable[i];
prev: CollisionList ← NIL;
WHILE c#NIL DO
IF c.fontKeyRec.font = font THEN {
fontCodeInverse[c.fontCode.key] ← NIL;
IF prev = NIL THEN fontCodeTable[i] ← c.next ELSE prev.next ← c.next;
}
ELSE prev ← c;
c ← IF prev = NIL THEN fontCodeTable[i] ELSE prev.next;
ENDLOOP;
ENDLOOP;
};
Create: PUBLIC PROC RETURNS [FontCache] ~ {
RETURN [NEW[FontCacheRep]];
};
GetCharData: PUBLIC PROC [fontCache: FontCache, fontCode: FontCode, char: CHAR]
RETURNS [data: REF] ~ {
code: NAT ~ fontCode.key;
IF fontCache.seq = NIL OR code < fontCache.firstFontCode OR code-fontCache.firstFontCode >= fontCache.seq.length THEN GOTO Miss
ELSE {
a: REF Array ← fontCache.seq[code-fontCache.firstFontCode];
IF a = NIL OR char < a.bc OR char-a.bc >= a.length THEN GOTO Miss;
data ← a[char-a.bc];
IF data = NIL THEN GOTO Miss;
};
EXITS Miss => {
data ← SIGNAL CacheMiss[fontCode, char];
LoadCharData[fontCache, fontCode, char, data];
};
};
CacheMiss: PUBLIC SIGNAL [fontCode: FontCode, char: CHAR] RETURNS [data: REF] = CODE;
LoadCharData: PUBLIC PROC [fontCache: FontCache, fontCode: FontCode, char: CHAR, data: REF] ~ {
code: NAT ~ fontCode.key;
a: REF Array;
IF fontCache.seq = NIL THEN {fontCache.seq ← NEW[Seq[6]]; fontCache.firstFontCode ← code};
IF code < fontCache.firstFontCode THEN {
additionalLength: NAT ~ fontCache.firstFontCode - code;
newLength: NAT ~ additionalLength + fontCache.seq.length;
old: REF Seq ~ fontCache.seq;
fontCache.seq ← NEW[Seq[newLength]];
FOR i: NAT IN [0..old.length) DO fontCache.seq[additionalLength + i] ← old[i] ENDLOOP;
fontCache.firstFontCode ← code;
};
IF code-fontCache.firstFontCode >= fontCache.seq.length THEN {
newLength: NAT ~ code - fontCache.firstFontCode + 1 + fontCache.seq.length/3;
old: REF Seq ~ fontCache.seq;
fontCache.seq ← NEW[Seq[newLength]];
FOR i: NAT IN [0..old.length) DO fontCache.seq[i] ← old[i] ENDLOOP;
};
a ← fontCache.seq[code-fontCache.firstFontCode];
IF fontCache.seq[code-fontCache.firstFontCode] = NIL THEN {
bc: CHAR ~ MIN[char, ' ];
ec: CHAR ~ MAX[char, '~];
a ← NEW[Array[ec-bc+1]];
a.bc ← bc;
};
IF char < a.bc THEN {
additionalLength: NAT ~ a.bc - char;
newLength: NAT ~ additionalLength + a.length;
old: REF Array ← a;
a ← NEW[Array[newLength]];
FOR i: NAT IN [0..old.length) DO a[additionalLength + i] ← old[i] ENDLOOP;
a.bc ← char;
};
IF char-a.bc >= a.length THEN {
newLength: NAT ~ char-a.bc + 1;
old: REF Array ← a;
a ← NEW[Array[newLength]];
FOR i: NAT IN [0..old.length) DO a[i] ← old[i] ENDLOOP;
};
a[char-a.bc] ← data;
fontCache.seq[code-fontCache.firstFontCode] ← a;
};
END.