IIMaskCacheImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Michael Plass, September 23, 1986 4:05:14 pm PDT
Doug Wyatt, May 20, 1985 11:40:49 am PDT
DIRECTORY
Basics USING [BITAND, BITSHIFT, bitsPerWord, BITXOR],
Checksum USING [ComputeChecksum],
IIFont USING [XChar],
IIMaskCache USING [CharMask, CharMaskRep, Run],
IISample USING [BoxesFromBitmap, Clear, Clip, FillBoxes, NewSampleMap, ObtainUnsafeDescriptor, ReleaseDescriptor, SampleMap],
RefTab USING [Create, Fetch, Pairs, Ref, Store],
SF USING [Add, Box, BoxAction, maxBox, Size, Vec, zeroVec];
IIMaskCacheImpl: CEDAR MONITOR LOCKS x USING x: MaskCache
IMPORTS Basics, IISample, Checksum, RefTab, SF
EXPORTS IIMaskCache
~ BEGIN
CharMask: TYPE ~ IIMaskCache.CharMask;
CharMaskRep: TYPE ~ IIMaskCache.CharMaskRep;
XChar: TYPE ~ IIFont.XChar;
bitsPerWord: NAT ~ Basics.bitsPerWord;
BitmapFromCharMask: PUBLIC PROC [charMask: CharMask] RETURNS [IISample.SampleMap] ~ {
size: SF.Vec ~ SF.Size[charMask.box];
WITH charMask SELECT FROM
raster: REF CharMaskRep.raster => TRUSTED {
wordsPerLine: CARDINAL ~ (size.f+(bitsPerWord-1))/bitsPerWord;
bitmap: IISample.SampleMap ~ IISample.ObtainUnsafeDescriptor[
size: size,
bitsPerSample: 1,
bitsPerLine: wordsPerLine*bitsPerWord,
base: [word: @raster[0], bit: 0],
ref: raster,
words: wordsPerLine*size.s,
delta: charMask.box.min
];
RETURN [bitmap]
};
ENDCASE => {
bitmap: IISample.SampleMap ~ IISample.NewSampleMap[box: charMask.box, bitsPerSample: 1];
boxGenerator: -- SF.BoxGenerator -- PROC [boxAction: SF.BoxAction] ~ {
BoxesFromCharMask[charMask, boxAction, SF.zeroVec, SF.maxBox];
};
IISample.Clear[bitmap];
IISample.FillBoxes[map: bitmap, boxes: boxGenerator, value: 1];
RETURN [bitmap]
};
};
BoxesFromCharMask: PUBLIC PROC [charMask: CharMask, boxAction: SF.BoxAction, delta: SF.Vec, clip: SF.Box] ~ {
WITH charMask SELECT FROM
raster: REF CharMaskRep.raster => TRUSTED {
size: SF.Vec ~ SF.Size[charMask.box];
wordsPerLine: CARDINAL ~ (size.f+(bitsPerWord-1))/bitsPerWord;
bitmap: IISample.SampleMap ~ IISample.ObtainUnsafeDescriptor[
size: size,
bitsPerSample: 1,
bitsPerLine: wordsPerLine*bitsPerWord,
base: [word: @raster[0], bit: 0],
ref: raster,
words: wordsPerLine*size.s,
delta: SF.Add[charMask.box.min, delta]
];
clipped: IISample.SampleMap ~ IISample.Clip[bitmap, clip];
IISample.BoxesFromBitmap[clipped, boxAction];
IISample.ReleaseDescriptor[bitmap];
IISample.ReleaseDescriptor[clipped];
};
runGroup: REF CharMaskRep.runs => {
s0: INTEGER ~ INT[delta.s]+charMask.box.min.s;
f0: INTEGER ~ INT[delta.f]+charMask.box.min.f;
s: INTEGER ← s0;
FOR i: NAT IN [0..runGroup.nRuns) WHILE s < clip.max.s DO
r: IIMaskCache.Run ~ runGroup[i];
IF s >= clip.min.s THEN {
fMin: INTEGER ~ MAX[NAT[r.fMin]+f0, clip.min.f];
fMax: INTEGER ~ MIN[NAT[r.fMin+r.fSize]+f0, clip.max.f];
IF fMax > fMin THEN boxAction[[min: [s, fMin], max: [s+1, fMax]]];
};
IF r.lastRun THEN s ← s + 1;
ENDLOOP;
};
ENDCASE => NULL;
};
MaskCache: TYPE ~ REF MaskCacheRep;
MaskCacheRep: PUBLIC TYPE ~ MONITORED RECORD [
size: NAT,
lgMaxSize: NAT,
stuffCount: LONG CARDINAL ← 0,
seq: SEQUENCE maxSize: CARDINAL OF CharMask
];
Create: PUBLIC PROC [size: NAT] RETURNS [new: MaskCache] ~ {
maxSize: CARDINAL ← 1;
lgMaxSize: NAT ← 0;
UNTIL maxSize > size DO
maxSize ← 2*maxSize;
lgMaxSize ← lgMaxSize + 1;
ENDLOOP;
new ← NEW[MaskCacheRep[maxSize]];
new.size ← 0;
new.lgMaxSize ← lgMaxSize;
};
Size: PUBLIC ENTRY PROC [x: MaskCache] RETURNS [NAT] ~ { RETURN [x.size] };
CharAndFont: TYPE ~ MACHINE DEPENDENT RECORD [char: XChar, font: REF];
maxProbes: NAT ← 15;
Fetch: PUBLIC ENTRY PROC [x: MaskCache, font: REF, char: XChar] RETURNS [CharMask] ~ TRUSTED {
last: CARDINAL ~ x.maxSize-1;
cf: CharAndFont ← [char, font];
cksum: CARDINAL ~ Checksum.ComputeChecksum[nWords: SIZE[CharAndFont], p: @cf];
hash: CARDINAL ← Basics.BITAND[last, Basics.BITXOR[cksum, Basics.BITSHIFT[cksum, -x.lgMaxSize]]];
probes: CARDINAL ← 0;
c: CharMask ← NIL;
UNTIL (c ← x[hash])=NIL OR (c.font=font AND c.char=char) DO
probes ← probes + 1;
IF probes < maxProbes
THEN { IF hash#0 THEN hash ← hash-1 ELSE hash ← last }
ELSE RETURN [NIL];
ENDLOOP;
RETURN [c];
};
Store: PUBLIC ENTRY PROC [x: MaskCache, charMask: CharMask] RETURNS [ok: BOOL] ~ TRUSTED {
last: CARDINAL ~ x.maxSize-1;
cf: CharAndFont ← [charMask.char, charMask.font];
cksum: CARDINAL ~ Checksum.ComputeChecksum[nWords: SIZE[CharAndFont], p: @cf];
hash: CARDINAL ← Basics.BITAND[last, Basics.BITXOR[cksum, Basics.BITSHIFT[cksum, -x.lgMaxSize]]];
probes: CARDINAL ← 0;
c: CharMask ← NIL;
UNTIL (c ← x[hash]) = NIL OR (c.font=cf.font AND c.char=cf.char) DO
probes ← probes + 1;
IF probes < maxProbes
THEN { IF hash#0 THEN hash ← hash-1 ELSE hash ← last }
ELSE {
Replace an entry - this is a cache!
x[hash] ← charMask;
x.stuffCount ← x.stuffCount + 1;
};
ENDLOOP;
IF c = NIL AND x.size < x.maxSize THEN { x.size ← x.size + 1; c ← x[hash] ← charMask };
RETURN [c # NIL];
};
Flush: PUBLIC ENTRY PROC [x: MaskCache] ~ {
FOR i: INT IN [0..x.maxSize) DO x[i] ← NIL ENDLOOP;
x.size ← 0;
};
GetList: PUBLIC ENTRY PROC [x: MaskCache] RETURNS [list: LIST OF CharMask ← NIL] ~ {
FOR i: INT IN [0..x.maxSize) DO
c: CharMask ← x[i];
IF c # NIL THEN list ← CONS[c, list];
ENDLOOP;
};
GetNamedCache: PUBLIC PROC [atom: ATOM, createSize: NAT] RETURNS [r: MaskCache] ~ {
r ← NARROW[RefTab.Fetch[cacheTab, atom].val];
IF r = NIL OR r.maxSize < createSize THEN {
IF r # NIL THEN Flush[r];
r ← Create[createSize];
[] ← RefTab.Store[cacheTab, atom, r];
};
};
cacheTab: RefTab.Ref ~ RefTab.Create[];
FlushAll: PUBLIC PROC [] ~ {
epa: PROC [key, val: REF] RETURNS [quit: BOOLFALSE] ~ {Flush[NARROW[val]]};
[] ← RefTab.Pairs[cacheTab, epa];
};
END.