ImagerFontCacheImpl.mesa
Michael Plass, August 15, 1983 12:11 pm
DIRECTORY ImagerFontCache;
ImagerFontCacheImpl: CEDAR MONITOR EXPORTS ImagerFontCache = 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 ~ ImagerFontCache.FontCode;
FontFileCode: TYPE ~ ImagerFontCache.FontFileCode;
fontCodeTableHeaders: NAT ~ 101;
FontKeyRec: TYPE ~ MACHINE DEPENDENT RECORD [r0, r1, r2, r3, r4, r5: REAL, fontFileCode: FontFileCode, fill: BOOLEANFALSE];
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 [r0, r1, r2, r3, r4, r5: REAL, fontFileCode: FontFileCode] RETURNS [fontCode: FontCode] ~ TRUSTED {
ENABLE UNWIND => NULL;
fontKeyRec: FontKeyRec ← [r0, r1, r2, r3, r4, r5, fontFileCode];
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 <= nextFontCode 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 [r0, r1, r2, r3, r4, r5: REAL, fontFileCode: FontFileCode] ~ {
ENABLE UNWIND => NULL;
IF fontCodeInverse = NIL OR fontCodeInverse.length <= fontCode.key OR fontCodeInverse[fontCode.key] = NIL THEN ERROR InvalidFontCode[];
[r0: r0, r1: r1, r2: r2, r3: r3, r4: r4, r5: r5, fontFileCode: fontFileCode] ← fontCodeInverse[fontCode.key].fontKeyRec;
};
InvalidFontCode: PUBLIC ERROR ~ CODE;
Flush: PUBLIC ENTRY PROC [fontFileCode: FontFileCode] ~ {
ENABLE UNWIND => NULL;
FOR i: NAT IN [0..fontCodeTableHeaders) DO
c: CollisionList ← fontCodeTable[i];
prev: CollisionList ← NIL;
WHILE c#NIL DO
IF c.fontKeyRec.fontFileCode = fontFileCode 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;
LockedGetSuccess: ENTRY PROC RETURNS [BOOLEAN] ~ INLINE {
ENABLE UNWIND => NULL;
IF fontCache.seq = NIL OR code < fontCache.firstFontCode OR code-fontCache.firstFontCode >= fontCache.seq.length THEN RETURN [FALSE]
ELSE {
a: REF Array ← fontCache.seq[code-fontCache.firstFontCode];
IF a = NIL OR char < a.bc OR char-a.bc >= a.length THEN RETURN [FALSE];
data ← a[char-a.bc];
IF data = NIL THEN RETURN [FALSE];
};
RETURN [TRUE];
};
IF NOT LockedGetSuccess[] THEN {SIGNAL CacheMiss; data ← NIL};
};
CacheMiss: PUBLIC SIGNAL ~ CODE;
LoadCharData: PUBLIC ENTRY PROC [fontCache: FontCache, fontCode: FontCode, char: CHAR, data: REF] ~ {
ENABLE UNWIND => NULL;
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.bc ← old.bc;
};
a[char-a.bc] ← data;
fontCache.seq[code-fontCache.firstFontCode] ← a;
};
END.
Michael Plass, July 18, 1983 10:20 am: Fixed bug in GetFontCode; was checking fontCodeInverse.length against fontCode.key instead of nextFontCode.
Michael Plass, July 22, 1983 2:07 pm: Put monitor in GetCharData and LoadCharData so a global font cache could be used.