DIRECTORY ImagerFontCache USING [CharAction, FontObject, FontObjectRep], Rope USING [Length, ROPE], RopeReader USING [BackupIndex, FreeRopeReader, Get, GetRopeReader, Ref, SetPosition]; ImagerFontCacheImpl: CEDAR MONITOR IMPORTS Rope, RopeReader EXPORTS ImagerFontCache = BEGIN ROPE: TYPE ~ Rope.ROPE; 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: CARDINAL, seq: SEQUENCE length: NAT OF REF ]; FontCode: TYPE ~ CARDINAL; FontObject: TYPE ~ ImagerFontCache.FontObject; FontObjectRep: TYPE ~ ImagerFontCache.FontObjectRep; fontCodeTableHeaders: NAT ~ 101; fontCodeTable: REF FontCodeTableRep _ NEW[FontCodeTableRep]; FontCodeTableRep: TYPE ~ ARRAY [0..fontCodeTableHeaders) OF CollisionList; CollisionList: TYPE ~ REF CollisionListItem; CollisionListItem: TYPE ~ RECORD [ next: CollisionList, fontCode: FontCode, fontObject: FontObject ]; fontCodeInverse: REF FontCodeInverseRep; FontCodeInverseRep: TYPE ~ RECORD [SEQUENCE length: NAT OF CollisionList]; nextFontCode: CARDINAL _ 0; Create: PUBLIC PROC RETURNS [FontCache] ~ { RETURN [NEW[FontCacheRep]]; }; GetFontCode: PUBLIC ENTRY PROC [fontObjectRep: FontObjectRep] RETURNS [fontCode: FontCode] ~ TRUSTED { ENABLE UNWIND => NULL; p: POINTER TO CARDINAL _ LOOPHOLE[@fontObjectRep]; hash: CARDINAL _ 0; IF SIZE[FontObjectRep] MOD SIZE[CARDINAL] # 0 THEN ERROR; THROUGH [0..SIZE[FontObjectRep]/SIZE[CARDINAL]) DO t: CARDINAL _ 2*hash; hash _ hash + hash*2*2 + 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.fontObject^ = fontObjectRep THEN RETURN [c.fontCode]; ENDLOOP; fontCodeTable[hash] _ NEW[CollisionListItem _ [fontCodeTable[hash], nextFontCode, NEW[FontObjectRep _ fontObjectRep]]]; IF fontCodeInverse = NIL OR fontCodeInverse.length <= nextFontCode THEN { old: REF FontCodeInverseRep _ fontCodeInverse; newLength: NAT _ IF 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 [FontObject] ~ { ENABLE UNWIND => NULL; IF fontCodeInverse = NIL OR fontCodeInverse.length <= fontCode OR fontCodeInverse[fontCode] = NIL THEN ERROR InvalidFontCode[]; RETURN [fontCodeInverse[fontCode].fontObject] }; InvalidFontCode: PUBLIC ERROR ~ CODE; EnumerateFontCodes: PUBLIC ENTRY PROC [action: PROC [fontCode: FontCode, fontObject: FontObject] RETURNS [flush: BOOLEAN]] ~ { ENABLE UNWIND => NULL; FOR i: NAT IN [0..fontCodeTableHeaders) DO c: CollisionList _ fontCodeTable[i]; prev: CollisionList _ NIL; WHILE c#NIL DO cNext: CollisionList _ c.next; IF action[c.fontCode, c.fontObject] THEN { fontCodeInverse[c.fontCode] _ NIL; IF prev = NIL THEN fontCodeTable[i] _ cNext ELSE prev.next _ cNext; } ELSE {prev _ c}; c _ cNext; ENDLOOP; ENDLOOP; }; GetCharData: PUBLIC PROC [fontCache: FontCache, fontCode: FontCode, charCode: CARDINAL] RETURNS [charData: REF] ~ { GetCachedCharData: ENTRY PROC ~ INLINE { a: REF Array; IF fontCache.seq # NIL AND fontCode >= fontCache.firstFontCode AND fontCode-fontCache.firstFontCode < fontCache.seq.length AND (a _ fontCache.seq[fontCode-fontCache.firstFontCode]) # NIL AND charCode IN [a.bc..a.bc+a.length) THEN charData _ a[charCode-a.bc]; }; GetCachedCharData[]; IF charData = NIL THEN { fontObject: FontObject _ InterpretFontCode[fontCode]; charData _ fontObject.CharDataProc[fontObject, charCode].charData; LoadCharData[fontCache, fontCode, charCode, charData]; }; }; dummyArray: REF Array _ NEW[Array[0]]; stringCharsMapped, stringPiecesMapped: INT _ 0; CharAction: TYPE ~ ImagerFontCache.CharAction; GetTextData: PUBLIC PROC [ action: CharAction, fontCache: FontCache, fontCode: FontCode, text: REF READONLY TEXT, start: NAT _ 0, length: NAT _ NAT.LAST] ~ TRUSTED { size: NAT ~ text.length; i: NAT _ MIN[start, size]; rem: NAT _ MIN[length, size-i]; GetCachedChars: ENTRY PROC ~ CHECKED INLINE { ENABLE UNWIND => NULL; a: REF Array; IF fontCache.seq # NIL AND fontCode >= fontCache.firstFontCode AND fontCode-fontCache.firstFontCode < fontCache.seq.length AND (a _ fontCache.seq[fontCode-fontCache.firstFontCode]) # NIL THEN { bc: CARDINAL _ a.bc; ecPlusOne: CARDINAL _ a.bc+a.length; WHILE rem > 0 DO charCode: CARDINAL _ text[i]-'\000; charData: REF _ NIL; IF charCode IN [bc..ecPlusOne) THEN charData _ a[charCode-bc]; IF charData = NIL THEN EXIT; IF action[charCode, charData] THEN { rem _ 0; EXIT }; i _ i+1; rem _ rem-1; ENDLOOP; }; }; WHILE rem > 0 DO GetCachedChars[]; IF rem > 0 THEN { -- must have stopped because of a hard case charCode: CARDINAL _ text[i]-'\000; charData: REF _ GetCharData[fontCache, fontCode, charCode]; IF action[charCode, charData] THEN EXIT; i _ i+1; rem _ rem - 1; }; ENDLOOP; }; GetRopeData: PUBLIC PROC [ action: CharAction, fontCache: FontCache, fontCode: FontCode, rope: ROPE, start: INT _ 0, length: INT _ LAST[INT]] ~ TRUSTED { reader: RopeReader.Ref _ RopeReader.GetRopeReader[]; GetCachedChars: ENTRY PROC ~ CHECKED INLINE { ENABLE UNWIND => NULL; a: REF Array; IF fontCache.seq # NIL AND fontCode >= fontCache.firstFontCode AND fontCode-fontCache.firstFontCode < fontCache.seq.length AND (a _ fontCache.seq[fontCode-fontCache.firstFontCode]) # NIL THEN { bc: CARDINAL _ a.bc; ecPlusOne: CARDINAL _ a.bc+a.length; WHILE length > 0 DO charCode: CARDINAL _ reader.Get-'\000; charData: REF _ NIL; IF charCode IN [bc..ecPlusOne) THEN charData _ a[charCode-bc]; IF charData = NIL THEN {reader.BackupIndex[1]; EXIT}; IF action[charCode, charData] THEN { length _ 0; EXIT }; length _ length - 1; ENDLOOP; }; }; length _ MAX[MIN[length, rope.Length-start], 0]; reader.SetPosition[rope, start]; WHILE length > 0 DO GetCachedChars[]; IF length > 0 THEN { -- must have stopped because of a hard case charCode: CARDINAL _ reader.Get-'\000; charData: REF _ GetCharData[fontCache, fontCode, charCode]; IF action[charCode, charData] THEN EXIT; length _ length - 1; }; ENDLOOP; reader.FreeRopeReader; }; LoadCharData: ENTRY PROC [fontCache: FontCache, fontCode: FontCode, charCode: CARDINAL, data: REF] ~ { ENABLE UNWIND => NULL; a: REF Array; IF fontCache.seq = NIL THEN {fontCache.seq _ NEW[Seq[6]]; fontCache.firstFontCode _ fontCode}; IF fontCode < fontCache.firstFontCode THEN { additionalLength: NAT ~ fontCache.firstFontCode - fontCode; 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 _ fontCode; }; IF fontCode-fontCache.firstFontCode >= fontCache.seq.length THEN { newLength: NAT ~ fontCode - 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[fontCode-fontCache.firstFontCode]; IF a = NIL THEN { bc: CARDINAL ~ MIN[charCode, ' -'\000]; ec: CARDINAL ~ MAX[charCode, '~-'\000]; a _ NEW[Array[ec-bc+1]]; a.bc _ bc; }; IF charCode < a.bc THEN { additionalLength: NAT ~ a.bc - charCode; 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 _ charCode; }; IF charCode >= a.bc+a.length THEN { newLength: NAT ~ charCode-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[charCode-a.bc] _ data; fontCache.seq[fontCode-fontCache.firstFontCode] _ a; }; END. PImagerFontCacheImpl.mesa Copyright c 1984 Xerox Corporation. All rights reserved. Michael Plass, September 28, 1983 10:46 am Doug Wyatt, July 19, 1984 10:17:05 pm PDT 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. Michael Plass, September 28, 1983 9:27 am: Added GetStringData, GetNSStringData; made charCode a CARDINAL; replaced cacheMiss signal with FontObject. Κ «˜™Jšœ Οmœ.™9J™*J™)—J˜šΟk ˜ Jšœžœ)˜>Jšœžœ žœ˜Jšœ žœE˜UJ˜—Iunitšœžœž˜"Jšžœ˜Jšžœ˜Jšœž˜J˜Jšžœžœžœ˜J˜Jšœ žœžœžœ˜*šœžœžœžœ˜$Jšœžœ˜Jšœžœ˜ Jšœ˜—šœžœžœ˜Jšžœ žœžœžœ˜!Jšœ˜—šœžœžœ˜Jšœžœ˜ Jšœžœ žœžœž˜ Jšœ˜—Jšœ žœžœ˜Jšœ žœ˜.Jšœžœ!˜4Kšœžœ˜ Kšœžœžœ˜Jšžœ žœžœžœ˜Jšžœžœ žœ˜5Jšœ˜Jšžœ˜—Jšœ˜—Jšœ˜—šžœ ž˜Jšœ˜šžœ žœ +˜=Jšœ žœ˜#Jšœ žœ.˜;Jšžœžœžœ˜(Jšœ˜Jšœ˜—Jšžœ˜—Jšœ˜—šŸ œžœžœ˜Jšœ=˜=Jš œžœ žœžœžœžœžœ˜@Jšœ4˜4š Ÿœžœžœžœžœ˜-Jšžœžœžœ˜Jšœžœ˜ Jšžœž˜Jšžœ$˜'Jšžœ8˜;šžœ9žœžœ˜FJšœžœ˜Jšœ žœ˜$šžœ ž˜Jšœ žœ˜&Jšœ žœžœ˜Jšžœ žœžœ˜>Jšžœ žœžœžœ˜5Jšžœžœžœ˜8Jšœ˜Jšžœ˜—Jšœ˜—Jšœ˜—Jšœ žœžœ ˜0Jšœ ˜ šžœ ž˜Jšœ˜šžœ žœ +˜@Jšœ žœ˜&Jšœ žœ.˜;Jšžœžœžœ˜(Jšœ˜Jšœ˜—Jšžœ˜—Jšœ˜Jšœ˜—š Ÿ œžœžœ6žœžœ˜fJšžœžœžœ˜Jšœžœ˜ Jšžœžœžœžœ.˜^šžœ$žœ˜,Jšœžœ&˜;Jšœ žœ+˜9Jšœžœ˜Jšœžœ˜$Jš žœžœžœžœ.žœ˜VJšœ#˜#Jšœ˜—šžœ:žœ˜BJšœ žœC˜QJšœžœ˜Jšœžœ˜$Jš žœžœžœžœžœ˜CJšœ˜—Jšœ4˜4šžœžœžœ˜Jšœžœžœ˜'Jšœžœžœ˜'Jšœžœ˜Jšœ ˜ Jšœ˜—šžœžœ˜Jšœžœ˜(Jšœ žœ˜-Jšœžœ ˜Jšœžœ˜Jš žœžœžœžœ"žœ˜JJšœ˜Jšœ˜—šžœžœ˜#Jšœ žœ˜#Jšœžœ ˜Jšœžœ˜Jš žœžœžœžœžœ˜7Jšœ˜Jšœ˜—Jšœ˜Jšœ4˜4J˜—Kšžœ˜Jšœ’™’Jšœw™wJšœažœ,™•—…—-