ImagerPixelMapImpl.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Michael Plass, August 5, 1985 2:08:32 pm PDT
Doug Wyatt, March 9, 1985 5:29:40 pm PST
DIRECTORY
Basics USING [BITAND, BITSHIFT, bitsPerWord, DoubleShiftRight, logBitsPerWord, LongMult],
CountedVM USING [Allocate, Handle],
FunctionCache USING [Cache, CacheInfo, GetInfo, GlobalCache, SetLimits],
ImagerPixelMap USING [DeviceRectangle, Function, Get16Bits, Get2Bits, Get4Bits, Get8Bits, GetBit, PixelMap, PixelMapRep, Tile],
PrincOps USING [BBTableSpace, BBptr, BitAddress, wordsPerPage],
PrincOpsUtils USING [AlignedBBTable, BITBLT, LongZero],
Process USING [Pause, MsecToTicks],
SafeStorage USING [ReclaimCollectibleObjects],
VM USING [CantAllocate, PageNumberForAddress, PageNumber, SwapIn];
ImagerPixelMapImpl: CEDAR PROGRAM
IMPORTS Basics, CountedVM, ImagerPixelMap, FunctionCache, PrincOpsUtils, Process, SafeStorage, VM
EXPORTS ImagerPixelMap
~ BEGIN
PixelMap: TYPE ~ ImagerPixelMap.PixelMap;
Tile: TYPE ~ ImagerPixelMap.Tile;
PixelMapRep: TYPE ~ ImagerPixelMap.PixelMapRep;
DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle;
Function: TYPE ~ ImagerPixelMap.Function;
bitsPerWord: NAT ~ Basics.bitsPerWord;
lgBitsPerWord: NAT ~ Basics.logBitsPerWord;
wordsPerPage: NAT ~ PrincOps.wordsPerPage;
-- Some inlines for basic bit-hacking operations.
BITAND: PROC [a, b: CARDINAL] RETURNS[CARDINAL]
~ INLINE {RETURN[Basics.BITAND[a, b]]};
Shift: PROC [a: CARDINAL, b: INTEGER] RETURNS [CARDINAL]
~ INLINE {RETURN[Basics.BITSHIFT[a, b]]};
Intersect: PUBLIC PROC [a, b: DeviceRectangle] RETURNS [DeviceRectangle] ~ {
sMin: INTEGERMAX[a.sMin, b.sMin];
fMin: INTEGERMAX[a.fMin, b.fMin];
sMax: INTEGERMIN[INT[a.sMin]+a.sSize, INT[b.sMin]+b.sSize];
fMax: INTEGERMIN[INT[a.fMin]+a.fSize, INT[b.fMin]+b.fSize];
IF sMax <= sMin OR fMax <= fMin THEN RETURN [[0, 0, 0, 0]]
ELSE RETURN [[sMin, fMin, sMax-sMin, fMax-fMin]]
};
Create: PUBLIC PROC [lgBitsPerPixel: [0..4], bounds: DeviceRectangle] RETURNS [pixelMap: PixelMap] ~ {
bitsPerPixel: CARDINAL ~ Shift[1, lgBitsPerPixel];
bitsPerLine: NAT ~ Basics.LongMult[bounds.fSize, bitsPerPixel];
Will raise a bounds fault if too many bits per line.
wordsPerLine: CARDINAL ~ (bitsPerLine+(bitsPerWord-1)) / bitsPerWord;
words: LONG CARDINAL ~ Basics.LongMult[wordsPerLine, bounds.sSize];
pixelMap.refRep ← NewRefRep[words];
pixelMap.refRep.lgBitsPerPixel ← lgBitsPerPixel;
pixelMap.refRep.rast ← wordsPerLine;
pixelMap.refRep.lines ← bounds.sSize;
pixelMap.sMin ← pixelMap.fMin ← 0;
[pixelMap.sOrigin, pixelMap.fOrigin, pixelMap.sSize, pixelMap.fSize] ← bounds;
};
CreateFrameBuffer: PUBLIC UNSAFE PROC [pointer: LONG POINTER, words: LONG CARDINAL, lgBitsPerPixel: [0..4], rast: CARDINAL, lines: CARDINAL, ref: REFNIL] RETURNS [pixelMap: PixelMap] ~ {
bitsPerLine: NAT ~ Basics.LongMult[rast, bitsPerWord];
fSize: NAT ~ Shift[bitsPerLine, -lgBitsPerPixel];
wastedWords: NATINT[words]-INT[rast]*INT[lines];
Bounds check if `words' is too small or much too big.
pixelMap.refRep ← NEW[PixelMapRep ← [ref, pointer, words, lgBitsPerPixel, rast, lines]];
pixelMap.sOrigin ← pixelMap.fOrigin ← pixelMap.sMin ← pixelMap.fMin ← 0;
pixelMap.sSize ← lines;
pixelMap.fSize ← fSize;
};
Clear: PUBLIC PROC [pixelMap: PixelMap] ~ TRUSTED {
pointer: LONG POINTER ← pixelMap.refRep.pointer;
words: LONG CARDINALMIN[pixelMap.refRep.words, Basics.LongMult[pixelMap.refRep.lines, pixelMap.refRep.rast]];
WHILE words > 32768 DO
PrincOpsUtils.LongZero[pointer, 32768];
pointer ← pointer + 32768;
words ← words - 32768;
ENDLOOP;
PrincOpsUtils.LongZero[pointer, words];
};
aFew: NAT ← 1280;
Reshape: PUBLIC PROC [refRep: REF PixelMapRep, lgBitsPerPixel: [0..4], bounds: DeviceRectangle] RETURNS [pixelMap: PixelMap] ~ {
bitsPerPixel: CARDINAL ~ Shift[1, lgBitsPerPixel];
bitsPerLine: NAT ~ Basics.LongMult[bounds.fSize, bitsPerPixel];
Will raise a bounds fault if too many bits per line.
wordsPerLine: CARDINAL ~ (bitsPerLine+(bitsPerWord-1)) / bitsPerWord;
words: LONG CARDINAL ~ Basics.LongMult[wordsPerLine, bounds.sSize];
IF refRep = NIL THEN refRep ← NewRefRep[words]
ELSE IF words > refRep.words OR (refRep.words > aFew AND words < Basics.DoubleShiftRight[[lc[refRep.words]], 3].lc) THEN {
refRep ← NewRefRep[words];
};
refRep.lgBitsPerPixel ← lgBitsPerPixel;
refRep.rast ← wordsPerLine;
refRep.lines ← bounds.sSize;
pixelMap ← [bounds.sMin, bounds.fMin, 0, 0, bounds.sSize, bounds.fSize, refRep];
};
Copy: PUBLIC PROC [p: PixelMap, scratch: REF PixelMapRep ← NIL] RETURNS [pixelMap: PixelMap] ~ {
pixelMap ← Reshape[scratch, p.refRep.lgBitsPerPixel, Window[p]];
Clear[pixelMap];
Transfer[pixelMap, p, [null,null]];
};
ShiftMap: PUBLIC PROC [p: PixelMap, s, f: INTEGER] RETURNS [PixelMap] ~ {
RETURN [[p.sOrigin + s, p.fOrigin + f, p.sMin, p.fMin, p.sSize, p.fSize, p.refRep]]
};
ShiftWindow: PUBLIC PROC [p: PixelMap, s, f: INTEGER] RETURNS [PixelMap] ~ {
RETURN [[p.sOrigin, p.fOrigin, p.sMin + s, p.fMin + f, p.sSize, p.fSize, p.refRep]]
};
Clip: PUBLIC PROC [p: PixelMap, bounds: DeviceRectangle] RETURNS [PixelMap] ~ {
bounds ← Intersect[Window[p], bounds];
RETURN [[p.sOrigin, p.fOrigin, bounds.sMin-p.sOrigin, bounds.fMin-p.fOrigin, bounds.sSize, bounds.fSize, p.refRep]]
};
SetWindow: PUBLIC PROC [p: PixelMap, bounds: DeviceRectangle] RETURNS [PixelMap] ~ {
RETURN [[p.sOrigin, p.fOrigin, bounds.sMin-p.sOrigin, bounds.fMin-p.fOrigin, bounds.sSize, bounds.fSize, p.refRep]]
};
Window: PUBLIC PROC [p: PixelMap] RETURNS [DeviceRectangle] ~ {
RETURN [[p.sOrigin + p.sMin, p.fOrigin + p.fMin, p.sSize, p.fSize]]
};
BufferBounds: PUBLIC PROC [p: PixelMap] RETURNS [DeviceRectangle] ~ {
RETURN [[p.sOrigin, p.fOrigin, p.refRep.lines, Shift[p.refRep.rast, lgBitsPerWord-p.refRep.lgBitsPerPixel]]]
};
BoundedWindow: PUBLIC PROC [p: PixelMap] RETURNS [DeviceRectangle] ~ {
sMin: INTEGERMAX[p.sOrigin + p.sMin, p.sOrigin];
fMin: INTEGERMAX[p.fOrigin + p.fMin, p.fOrigin];
sMax: INTEGERMIN[p.sOrigin + p.sMin + p.sSize, p.sOrigin + p.refRep.lines];
fMax: INTEGERMIN[p.fOrigin + p.fMin + p.fSize, p.fOrigin + Shift[p.refRep.rast, lgBitsPerWord-p.refRep.lgBitsPerPixel]];
RETURN [[sMin, fMin, MAX[sMax-sMin, 0], MAX[fMax-fMin, 0]]]
};
GetPixel: PUBLIC PROC [source: PixelMap, s, f: INTEGER] RETURNS [CARDINAL] ~ {
bounds: DeviceRectangle ← BoundedWindow[source];
sCheck: NAT ← bounds.sSize-1-NAT[s-bounds.sMin];
fCheck: NAT ← bounds.fSize-1-NAT[f-bounds.fMin];
SELECT source.refRep.lgBitsPerPixel FROM
0 => RETURN [source.GetBit[s, f]];
1 => RETURN [source.Get2Bits[s, f]];
2 => RETURN [source.Get4Bits[s, f]];
3 => RETURN [source.Get8Bits[s, f]];
4 => RETURN [source.Get16Bits[s, f]];
ENDCASE => ERROR;
};
PutPixel: PUBLIC PROC [source: PixelMap, s, f: INTEGER, val: CARDINAL] ~ TRUSTED {
source is mis-named; sorry!
bounds: DeviceRectangle ← BoundedWindow[source];
sCheck: NAT ← bounds.sSize-1-NAT[s-bounds.sMin];
fCheck: NAT ← bounds.fSize-1-NAT[f-bounds.fMin];
line: LONG POINTER ~ source.refRep.pointer + Basics.LongMult[(s - source.sOrigin), source.refRep.rast];
SELECT source.refRep.lgBitsPerPixel FROM
0=>LOOPHOLE[line, LONG POINTER TO Seq0][f-source.fOrigin]←val;
1=>LOOPHOLE[line, LONG POINTER TO Seq1][f-source.fOrigin]←val;
2=>LOOPHOLE[line, LONG POINTER TO Seq2][f-source.fOrigin]←val;
3=>LOOPHOLE[line, LONG POINTER TO Seq3][f-source.fOrigin]←val;
4=>LOOPHOLE[line, LONG POINTER TO Seq4][f-source.fOrigin]←val;
ENDCASE => ERROR;
};
Seq0: TYPE ~ RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..2)];
Seq1: TYPE ~ RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..4)];
Seq2: TYPE ~ RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..16)];
Seq3: TYPE ~ RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..256)];
Seq4: TYPE ~ RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF CARDINAL];
Equal: PUBLIC PROC [a, b: PixelMap] RETURNS [BOOLEAN] ~ {
window: DeviceRectangle ← BoundedWindow[a];
IF window # BoundedWindow[b] THEN RETURN [FALSE];
IF a.refRep = b.refRep THEN RETURN [TRUE];
IF a.refRep.lgBitsPerPixel # b.refRep.lgBitsPerPixel THEN RETURN [FALSE];
SELECT a.refRep.lgBitsPerPixel FROM
0 => TRUSTED {
aPtr: LONG POINTER TO Seq0 ← LOOPHOLE[a.refRep.pointer + Basics.LongMult[(window.sMin - a.sOrigin), a.refRep.rast]];
bPtr: LONG POINTER TO Seq0 ← LOOPHOLE[b.refRep.pointer + Basics.LongMult[(window.sMin - b.sOrigin), b.refRep.rast]];
FOR s: INTEGER IN [window.sMin..window.sMin+window.sSize) DO
FOR f: INTEGER IN [window.fMin..window.fMin+window.fSize) DO
IF aPtr^[f-a.fOrigin] # bPtr^[f-b.fOrigin] THEN RETURN [FALSE];
ENDLOOP;
aPtr ← aPtr+a.refRep.rast;
bPtr ← bPtr+b.refRep.rast;
ENDLOOP;
};
1 => TRUSTED {
aPtr: LONG POINTER TO Seq1 ← LOOPHOLE[a.refRep.pointer + Basics.LongMult[(window.sMin - a.sOrigin), a.refRep.rast]];
bPtr: LONG POINTER TO Seq1 ← LOOPHOLE[b.refRep.pointer + Basics.LongMult[(window.sMin - b.sOrigin), b.refRep.rast]];
FOR s: INTEGER IN [window.sMin..window.sMin+window.sSize) DO
FOR f: INTEGER IN [window.fMin..window.fMin+window.fSize) DO
IF aPtr^[f-a.fOrigin] # bPtr^[f-b.fOrigin] THEN RETURN [FALSE];
ENDLOOP;
aPtr ← aPtr+a.refRep.rast;
bPtr ← bPtr+b.refRep.rast;
ENDLOOP;
};
2 => TRUSTED {
aPtr: LONG POINTER TO Seq2 ← LOOPHOLE[a.refRep.pointer + Basics.LongMult[(window.sMin - a.sOrigin), a.refRep.rast]];
bPtr: LONG POINTER TO Seq2 ← LOOPHOLE[b.refRep.pointer + Basics.LongMult[(window.sMin - b.sOrigin), b.refRep.rast]];
FOR s: INTEGER IN [window.sMin..window.sMin+window.sSize) DO
FOR f: INTEGER IN [window.fMin..window.fMin+window.fSize) DO
IF aPtr^[f-a.fOrigin] # bPtr^[f-b.fOrigin] THEN RETURN [FALSE];
ENDLOOP;
aPtr ← aPtr+a.refRep.rast;
bPtr ← bPtr+b.refRep.rast;
ENDLOOP;
};
3 => TRUSTED {
aPtr: LONG POINTER TO Seq3 ← LOOPHOLE[a.refRep.pointer + Basics.LongMult[(window.sMin - a.sOrigin), a.refRep.rast]];
bPtr: LONG POINTER TO Seq3 ← LOOPHOLE[b.refRep.pointer + Basics.LongMult[(window.sMin - b.sOrigin), b.refRep.rast]];
FOR s: INTEGER IN [window.sMin..window.sMin+window.sSize) DO
FOR f: INTEGER IN [window.fMin..window.fMin+window.fSize) DO
IF aPtr^[f-a.fOrigin] # bPtr^[f-b.fOrigin] THEN RETURN [FALSE];
ENDLOOP;
aPtr ← aPtr+a.refRep.rast;
bPtr ← bPtr+b.refRep.rast;
ENDLOOP;
};
4 => TRUSTED {
aPtr: LONG POINTER TO Seq4 ← LOOPHOLE[a.refRep.pointer + Basics.LongMult[(window.sMin - a.sOrigin), a.refRep.rast]];
bPtr: LONG POINTER TO Seq4 ← LOOPHOLE[b.refRep.pointer + Basics.LongMult[(window.sMin - b.sOrigin), b.refRep.rast]];
FOR s: INTEGER IN [window.sMin..window.sMin+window.sSize) DO
FOR f: INTEGER IN [window.fMin..window.fMin+window.fSize) DO
IF aPtr^[f-a.fOrigin] # bPtr^[f-b.fOrigin] THEN RETURN [FALSE];
ENDLOOP;
aPtr ← aPtr+a.refRep.rast;
bPtr ← bPtr+b.refRep.rast;
ENDLOOP;
};
ENDCASE => ERROR;
RETURN [TRUE];
};
IsAll: PUBLIC PROC [pixelMap: PixelMap, value: CARDINAL ← 0] RETURNS [BOOLEAN] ~ {
window: DeviceRectangle ← BoundedWindow[pixelMap];
SELECT pixelMap.refRep.lgBitsPerPixel FROM
0 => TRUSTED {
p: LONG POINTER TO Seq0 ← LOOPHOLE[pixelMap.refRep.pointer + Basics.LongMult[(window.sMin - pixelMap.sOrigin), pixelMap.refRep.rast]];
FOR s: INTEGER IN [window.sMin..window.sMin+window.sSize) DO
FOR f: INTEGER IN [window.fMin..window.fMin+window.fSize) DO
IF p^[f-pixelMap.fOrigin] # value THEN RETURN [FALSE];
ENDLOOP;
p ← p+pixelMap.refRep.rast;
ENDLOOP;
};
1 => TRUSTED {
p: LONG POINTER TO Seq1 ← LOOPHOLE[pixelMap.refRep.pointer + Basics.LongMult[(window.sMin - pixelMap.sOrigin), pixelMap.refRep.rast]];
FOR s: INTEGER IN [window.sMin..window.sMin+window.sSize) DO
FOR f: INTEGER IN [window.fMin..window.fMin+window.fSize) DO
IF p^[f-pixelMap.fOrigin] # value THEN RETURN [FALSE];
ENDLOOP;
p ← p+pixelMap.refRep.rast;
ENDLOOP;
};
2 => TRUSTED {
p: LONG POINTER TO Seq2 ← LOOPHOLE[pixelMap.refRep.pointer + Basics.LongMult[(window.sMin - pixelMap.sOrigin), pixelMap.refRep.rast]];
FOR s: INTEGER IN [window.sMin..window.sMin+window.sSize) DO
FOR f: INTEGER IN [window.fMin..window.fMin+window.fSize) DO
IF p^[f-pixelMap.fOrigin] # value THEN RETURN [FALSE];
ENDLOOP;
p ← p+pixelMap.refRep.rast;
ENDLOOP;
};
3 => TRUSTED {
p: LONG POINTER TO Seq3 ← LOOPHOLE[pixelMap.refRep.pointer + Basics.LongMult[(window.sMin - pixelMap.sOrigin), pixelMap.refRep.rast]];
FOR s: INTEGER IN [window.sMin..window.sMin+window.sSize) DO
FOR f: INTEGER IN [window.fMin..window.fMin+window.fSize) DO
IF p^[f-pixelMap.fOrigin] # value THEN RETURN [FALSE];
ENDLOOP;
p ← p+pixelMap.refRep.rast;
ENDLOOP;
};
4 => TRUSTED {
p: LONG POINTER TO Seq4 ← LOOPHOLE[pixelMap.refRep.pointer + Basics.LongMult[(window.sMin - pixelMap.sOrigin), pixelMap.refRep.rast]];
FOR s: INTEGER IN [window.sMin..window.sMin+window.sSize) DO
FOR f: INTEGER IN [window.fMin..window.fMin+window.fSize) DO
IF p^[f-pixelMap.fOrigin] # value THEN RETURN [FALSE];
ENDLOOP;
p ← p+pixelMap.refRep.rast;
ENDLOOP;
};
ENDCASE => ERROR;
RETURN [TRUE];
};
Trim: PUBLIC PROC [pixelMap: PixelMap, background: CARDINAL ← 0] RETURNS [PixelMap] ~ {
temp: PixelMap ← pixelMap;
WHILE pixelMap.sSize > 0 DO
temp.sSize ← 1;
temp.sMin ← pixelMap.sMin+pixelMap.sSize-1;
IF IsAll[temp, background] THEN {pixelMap.sSize ← pixelMap.sSize - 1}
ELSE EXIT;
ENDLOOP;
WHILE pixelMap.sSize > 0 DO
temp.sSize ← 1;
temp.sMin ← pixelMap.sMin;
IF IsAll[temp, background] THEN {pixelMap.sSize ← pixelMap.sSize - 1; pixelMap.sMin ← pixelMap.sMin + 1}
ELSE EXIT;
ENDLOOP;
IF pixelMap.sSize = 0 THEN pixelMap.fSize ← 0;
temp ← pixelMap;
WHILE pixelMap.fSize > 0 DO
temp.fSize ← 1;
temp.fMin ← pixelMap.fMin+pixelMap.fSize-1;
IF IsAll[temp, background] THEN {pixelMap.fSize ← pixelMap.fSize - 1}
ELSE EXIT;
ENDLOOP;
WHILE pixelMap.fSize > 0 DO
temp.fSize ← 1;
temp.fMin ← pixelMap.fMin;
IF IsAll[temp, background] THEN {pixelMap.fSize ← pixelMap.fSize - 1; pixelMap.fMin ← pixelMap.fMin + 1}
ELSE EXIT;
ENDLOOP;
IF pixelMap.fSize = 0 THEN pixelMap.sSize ← 0;
RETURN [pixelMap]
};
BitAddr: UNSAFE PROC [lineStart: LONG POINTER, pixel: CARDINAL, lgBitsPerPixel: INTEGER] RETURNS [PrincOps.BitAddress] ~ UNCHECKED {
RETURN [[
word: lineStart + Shift[pixel, lgBitsPerPixel-lgBitsPerWord],
bit: Basics.BITAND[Shift[pixel, lgBitsPerPixel], bitsPerWord-1]
]]
};
replicator: ARRAY [0..4] OF CARDINAL ~ [0FFFFH, 05555H, 01111H, 00101H, 00001H];
Fill: PUBLIC PROC [dest: PixelMap, area: DeviceRectangle, value: CARDINAL, function: Function] ~ TRUSTED {
lgBitsPerPixel: INTEGER ~ dest.refRep.lgBitsPerPixel;
rast: CARDINAL ~ dest.refRep.rast;
The following bounding box is calculated in terms of the destination buffer.
sMin: INTEGER ~ MAX[dest.sMin, 0, area.sMin-dest.sOrigin];
sMax: INTEGER ~ MIN[dest.sMin+dest.sSize, dest.refRep.lines, area.sMin+area.sSize-dest.sOrigin];
fMin: INTEGER ~ MAX[dest.fMin, 0, area.fMin-dest.fOrigin];
fMax: INTEGER ~ MIN[dest.fMin+dest.fSize, Shift[rast, lgBitsPerWord-lgBitsPerPixel], area.fMin+area.fSize-dest.fOrigin];
replicatedPixel: CARDINAL ← Basics.BITAND[value, Shift[1, Shift[1, lgBitsPerPixel]]-1] * replicator[lgBitsPerPixel];
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ← PrincOpsUtils.AlignedBBTable[@bbTableSpace];
IF sMin<sMax AND fMin<fMax THEN {
bb^ ← [
dst: BitAddr[dest.refRep.pointer + Basics.LongMult[sMin, rast], fMin, lgBitsPerPixel],
dstBpl: rast*bitsPerWord,
src: [word: @replicatedPixel, bit: 0],
srcDesc: [gray[[yOffset: 0, widthMinusOne: 0, heightMinusOne: 0]]],
height: sMax-sMin,
width: Shift[fMax-fMin, lgBitsPerPixel],
flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: TRUE, srcFunc: function.srcFunc, dstFunc: function.dstFunc]
];
PrincOpsUtils.BITBLT[bb];
};
};
Transfer: PUBLIC PROC [dest, source: PixelMap, function: Function] ~ TRUSTED {
lgBitsPerPixel: INTEGER ~ dest.refRep.lgBitsPerPixel;
sMin: INTEGER ~ MAX[dest.sOrigin+MAX[dest.sMin, 0], source.sOrigin+MAX[source.sMin, 0]];
sMax: INTEGER ~ MIN[dest.sOrigin+MIN[dest.sMin+dest.sSize, dest.refRep.lines], source.sOrigin+MIN[source.sMin+source.sSize, source.refRep.lines]];
fMin: INTEGER ~ MAX[dest.fOrigin+MAX[dest.fMin, 0], source.fOrigin+MAX[source.fMin, 0]];
fMax: INTEGER ~ MIN[dest.fOrigin+MIN[dest.fMin+dest.fSize, Shift[dest.refRep.rast, lgBitsPerWord-lgBitsPerPixel]], source.fOrigin+MIN[source.fMin+source.fSize, Shift[source.refRep.rast, lgBitsPerWord-lgBitsPerPixel]]];
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
fMinDest: NAT ~ fMin - dest.fOrigin;
fMinSource: NAT ~ fMin - source.fOrigin;
sStartDest: NAT ← sMin-dest.sOrigin;
sStartSource: NAT ← sMin-source.sOrigin;
IF source.refRep.lgBitsPerPixel # lgBitsPerPixel THEN ERROR;
IF source.refRep.rast > 32 AND sMax-sMin > 8 THEN {
more than a page, so a SwapIn is worthwhile
dest is most likely to be a frame buffer, so don't worry about swapping it in.
firstPage: VM.PageNumber ~ VM.PageNumberForAddress[source.refRep.pointer + Basics.LongMult[sStartSource, source.refRep.rast]];
lastPage: VM.PageNumber ~ VM.PageNumberForAddress[source.refRep.pointer + Basics.LongMult[sStartSource+sMax-sMin, source.refRep.rast] - 1];
VM.SwapIn[[page: firstPage, count: lastPage-firstPage+1]];
};
IF sMin<sMax AND fMin<fMax THEN {
bb^ ← [
dstBpl: dest.refRep.rast*bitsPerWord,
srcDesc: [srcBpl[source.refRep.rast*bitsPerWord]],
height: sMax-sMin,
width: Shift[fMax-fMin, lgBitsPerPixel],
flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: FALSE, srcFunc: function.srcFunc, dstFunc: function.dstFunc]
];
IF source.refRep = dest.refRep THEN {
sSize: NAT ~ sMax-sMin;
fSize: NAT ~ fMax-fMin;
IF (fMinSource+fSize)>fMinDest AND (fMinDest+fSize)>fMinSource AND (sStartSource+sSize)>sStartDest AND (sStartDest+sSize)>sStartSource THEN {
bb.flags.disjoint ← FALSE; -- the rectangles overlap
IF sStartDest=sStartSource THEN bb.flags.disjointItems ← FALSE; -- so do the items
IF sStartDest>sStartSource OR (sStartDest=sStartSource AND fMinDest>fMinSource) THEN { -- reverse direction
bb.flags.direction ← backward; bb.srcDesc.srcBpl ← bb.dstBpl ← -bb.dstBpl;
sStartSource ← sStartSource + (sSize-1); sStartDest ← sStartDest + (sSize-1);
};
};
};
bb.dst ← BitAddr[dest.refRep.pointer + Basics.LongMult[sStartDest, dest.refRep.rast], fMinDest, lgBitsPerPixel];
bb.src ← BitAddr[source.refRep.pointer + Basics.LongMult[sStartSource, source.refRep.rast], fMinSource, lgBitsPerPixel];
PrincOpsUtils.BITBLT[bb];
};
};
IsPowerOfTwo: PROC [c: CARDINAL] RETURNS [BOOLEAN] ~ INLINE {
RETURN [BITAND[c, c-1] = 0]
};
largeBitSize: INT ← 5000;
CreateTile: PUBLIC PROC [pixelMap: PixelMap, phase: INTEGER ← 0, fSizeHint: NAT ← 100, scratch: REF PixelMapRep ← NIL] RETURNS [tile: Tile] ~ {
lgBitsPerPixel: NAT ← pixelMap.refRep.lgBitsPerPixel;
bitWidth: CARDINAL ← Shift[pixelMap.fSize, lgBitsPerPixel];
IF bitWidth <= 16 AND IsPowerOfTwo[bitWidth] AND pixelMap.sSize <= 16 AND phase = 0 THEN {
small: PixelMap ← Reshape[scratch, lgBitsPerPixel, [pixelMap.sOrigin+pixelMap.sMin, pixelMap.fOrigin+pixelMap.fMin, pixelMap.sSize, Shift[16, -lgBitsPerPixel]]];
FOR fShift: NAT ← 0, fShift+pixelMap.fSize UNTIL fShift>=small.fSize DO
Transfer[small, ShiftMap[pixelMap, 0, fShift], [null, null]];
ENDLOOP;
tile ← [small.sOrigin, small.fOrigin, small.sSize, small.fSize, 0, small.refRep];
}
ELSE {
fSize: NAT ← (fSizeHint+pixelMap.fSize-1)/pixelMap.fSize*pixelMap.fSize;
bitsPerLine: NAT ← Shift[fSize, lgBitsPerPixel];
sSize: NATMAX[(((largeBitSize+bitsPerLine-1)/bitsPerLine)/pixelMap.sSize)*pixelMap.sSize, pixelMap.sSize];
large: PixelMap ← Reshape[scratch, lgBitsPerPixel, [pixelMap.sOrigin+pixelMap.sMin, pixelMap.fOrigin+pixelMap.fMin, sSize, fSize]];
finalPhase: CARDINAL;
WHILE phase<0 DO phase ← phase + pixelMap.fSize ENDLOOP;
phase ← phase MOD pixelMap.fSize;
finalPhase ← (phase * (sSize/pixelMap.sSize)) MOD pixelMap.fSize;
large.sSize ← pixelMap.sSize;
large.fSize ← pixelMap.fSize;
Transfer[large, pixelMap, [null, null]];
WHILE large.fSize<fSize DO
fSizePrev: NAT ~ large.fSize;
large.fSize ← MIN[fSize, 2*fSizePrev];
Transfer[large, ShiftMap[large, 0, fSizePrev], [null, null]];
ENDLOOP;
WHILE large.sSize<sSize DO
sSizePrev: NAT ~ large.sSize;
large.sSize ← MIN[sSize, 2*sSizePrev];
Transfer[large, ShiftMap[large, sSizePrev, phase], [null, null]];
{firstPart: PixelMap ← ShiftMap[large, sSizePrev, phase-pixelMap.fSize];
firstPart.fSize ← pixelMap.fSize;
Transfer[large, firstPart, [null, null]];
};
phase ← 2*phase;
WHILE phase > pixelMap.fSize DO phase ← phase - pixelMap.fSize ENDLOOP;
ENDLOOP;
tile ← [large.sOrigin, large.fOrigin, sSize, fSize, finalPhase, large.refRep];
};
};
TileFromStipple: PUBLIC PROC [stipple: CARDINAL, scratch: REF PixelMapRep] RETURNS [tile: Tile] ~ TRUSTED {
small: PixelMap ← Reshape[scratch, 0, [0, 0, 4, 16]];
p: LONG POINTER TO CARDINALLOOPHOLE[small.refRep.pointer+4*SIZE[CARDINAL]];
IF small.refRep.words < 4*SIZE[CARDINAL] THEN ERROR;
THROUGH [0..4) DO
p ← p - SIZE[CARDINAL];
p^ ← 1111H * (stipple MOD 16);
stipple ← stipple/16;
ENDLOOP;
tile ← [small.sOrigin, small.fOrigin, small.sSize, small.fSize, 0, small.refRep];
};
TileFromConstant: PUBLIC PROC [pixelValue: CARDINAL, lgBitsPerPixel: [0..4], scratch: REF PixelMapRep] RETURNS [tile: Tile] ~ TRUSTED {
pixelsPerWord: NAT ← Shift[1, lgBitsPerWord-lgBitsPerPixel];
small: PixelMap ← Reshape[scratch, lgBitsPerPixel, [0, 0, 1, pixelsPerWord]];
p: LONG POINTER TO CARDINALLOOPHOLE[small.refRep.pointer];
p^ ← replicator[lgBitsPerPixel] * Basics.BITAND[pixelValue, Shift[1, Shift[1, lgBitsPerPixel]]-1];
tile ← [small.sOrigin, small.fOrigin, small.sSize, small.fSize, 0, small.refRep];
};
TransferTile: PUBLIC PROC [dest: PixelMap, tile: Tile, function: Function ← [null, null]] ~ TRUSTED {
lgBitsPerPixel: NAT ~ tile.refRep.lgBitsPerPixel;
bitWidth: CARDINAL ~ Shift[tile.fSize, lgBitsPerPixel];
IF dest.refRep.lgBitsPerPixel # lgBitsPerPixel THEN ERROR;
IF bitWidth = bitsPerWord AND tile.refRep.rast = 1 AND tile.sSize <= 16 AND tile.phase = 0 THEN {
startLine: NATMAX[dest.sMin, 0];
endLine: INTEGERMIN[dest.sMin+dest.sSize, dest.refRep.lines];
startPixel: NATMAX[dest.fMin, 0];
endPixel: INTEGERMIN[dest.fMin+dest.fSize, Shift[dest.refRep.rast, lgBitsPerWord-lgBitsPerPixel]];
IF endLine>startLine AND endPixel>startPixel THEN {
startBit: NAT ← Shift[startPixel, lgBitsPerPixel];
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
sOffset: INTEGER ← (dest.sOrigin+dest.sMin-tile.sOrigin) MOD tile.sSize;
fOffset: INTEGER ← (dest.fOrigin+dest.fMin-tile.fOrigin) MOD tile.fSize;
WHILE sOffset < 0 DO sOffset ← sOffset + tile.sSize ENDLOOP;
WHILE fOffset < 0 DO fOffset ← fOffset + tile.fSize ENDLOOP;
bb^ ← [
dst: [word: dest.refRep.pointer + Basics.LongMult[startLine, dest.refRep.rast] + startBit/bitsPerWord, bit: startBit MOD bitsPerWord],
dstBpl: dest.refRep.rast*bitsPerWord,
src: [word: tile.refRep.pointer+sOffset, bit: Shift[fOffset, lgBitsPerPixel]],
srcDesc: [gray[[yOffset: sOffset, widthMinusOne: 0, heightMinusOne: tile.sSize-1]]],
height: endLine-startLine,
width: Shift[endPixel-startPixel, lgBitsPerPixel],
flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: TRUE, srcFunc: function.srcFunc, dstFunc: function.dstFunc]
];
PrincOpsUtils.BITBLT[bb];
};
}
ELSE {
sMin: INT ← dest.sOrigin+dest.sMin;
fMin: INT ← dest.fOrigin+dest.fMin;
source: PixelMap;
sOrigin: INT ← tile.sOrigin;
fOrigin: INT ← tile.fOrigin;
WHILE sOrigin < sMin DO
sOrigin ← sOrigin + tile.sSize;
fOrigin ← fOrigin + tile.phase;
ENDLOOP;
WHILE sOrigin > sMin DO
sOrigin ← sOrigin - tile.sSize;
fOrigin ← fOrigin - tile.phase;
ENDLOOP;
WHILE fOrigin < fMin DO fOrigin ← fOrigin + tile.fSize ENDLOOP;
WHILE fOrigin > fMin DO fOrigin ← fOrigin - tile.fSize ENDLOOP;
source ← [sOrigin, fOrigin, 0, 0, tile.sSize, tile.fSize, tile.refRep];
WHILE source.sOrigin < sMin+dest.sSize DO
source.fOrigin ← fOrigin;
WHILE source.fOrigin < fMin+dest.fSize DO
Transfer[dest, source, function];
source.fOrigin ← source.fOrigin + source.fSize;
ENDLOOP;
source.sOrigin ← source.sOrigin + source.sSize;
fOrigin ← fOrigin + tile.phase;
WHILE fOrigin > fMin DO fOrigin ← fOrigin - source.fSize ENDLOOP;
ENDLOOP;
};
};
Rotate: PUBLIC PROC [pixelMap: PixelMap, scratch: REF PixelMapRep ← NIL] RETURNS [PixelMap] ~ TRUSTED {
lgBitsPerPixel: INTEGER ← pixelMap.refRep.lgBitsPerPixel;
bitsPerPixel: INTEGER ← Shift[1, lgBitsPerPixel];
window: DeviceRectangle ← BoundedWindow[pixelMap];
newWindow: DeviceRectangle ← [window.fMin, -(window.sMin+window.sSize), window.fSize, window.sSize];
new: PixelMap ← Reshape[scratch, lgBitsPerPixel, newWindow];
extraPixels: NAT ← new.refRep.rast*bitsPerWord/bitsPerPixel - window.sSize;
lineBuffer: REF WordSeqRep ← NEW[WordSeqRep[MAX[window.sSize+extraPixels, 1]]];
lineBufferPtr: LONG POINTERLOOPHOLE[@(lineBuffer[0])];
sourceFirstLine: LONG POINTER ← pixelMap.refRep.pointer + Basics.LongMult[window.sMin-pixelMap.sOrigin, pixelMap.refRep.rast];
destLine: LONG POINTER ← new.refRep.pointer;
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
IF bitsPerWord # 16 THEN ERROR;
bb^ ← [
dst: [word: lineBufferPtr + extraPixels, bit: bitsPerWord-bitsPerPixel],
dstBpl: bitsPerWord,
srcDesc: [srcBpl[pixelMap.refRep.rast*bitsPerWord]],
height: window.sSize,
width: bitsPerPixel,
flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: FALSE, srcFunc: null, dstFunc: null]
];
FOR fSource: INTEGER IN [window.fMin-pixelMap.fOrigin .. window.fMin-pixelMap.fOrigin+pixelMap.fSize) DO
fSourceBit: NAT ← Shift[fSource, lgBitsPerPixel];
bb.src ← [word: sourceFirstLine + fSourceBit/bitsPerWord, bit: fSourceBit MOD bitsPerWord];
PrincOpsUtils.BITBLT[bb];
SELECT lgBitsPerPixel FROM
0 => {
pixelsPerWord: NAT ~ bitsPerWord/1;
w: NAT ~ 2;
p: LONG POINTER TO ARRAY [0..pixelsPerWord) OF CARDINALLOOPHOLE[lineBufferPtr];
q: LONG POINTER TO WORDLOOPHOLE[destLine + new.refRep.rast];
THROUGH [0..new.refRep.rast) DO
q ← q - 1;
q^ ← ((((((((((((((p[15]*w+p[14])*w+p[13])*w+p[12])*w+p[11])*w+p[10])*w+p[9])*w+p[8])*w+p[7])*w+p[6])*w+p[5])*w+p[4])*w+p[3])*w+p[2])*w+p[1])*w+p[0];
p ← p + pixelsPerWord;
ENDLOOP;
};
1 => {
pixelsPerWord: NAT ~ bitsPerWord/2;
w: NAT ~ 4;
p: LONG POINTER TO ARRAY [0..pixelsPerWord) OF CARDINALLOOPHOLE[lineBufferPtr];
q: LONG POINTER TO WORDLOOPHOLE[destLine + new.refRep.rast];
THROUGH [0..new.refRep.rast) DO
q ← q - 1;
q^ ← ((((((p[7]*w+p[6])*w+p[5])*w+p[4])*w+p[3])*w+p[2])*w+p[1])*w+p[0];
p ← p + pixelsPerWord;
ENDLOOP;
};
2 => {
pixelsPerWord: NAT ~ bitsPerWord/4;
w: NAT ~ 16;
p: LONG POINTER TO ARRAY [0..pixelsPerWord) OF CARDINALLOOPHOLE[lineBufferPtr];
q: LONG POINTER TO WORDLOOPHOLE[destLine + new.refRep.rast];
THROUGH [0..new.refRep.rast) DO
q ← q - 1;
q^ ← ((p[3]*w+p[2])*w+p[1])*w+p[0];
p ← p + pixelsPerWord;
ENDLOOP;
};
3 => {
pixelsPerWord: NAT ~ bitsPerWord/8;
w: NAT ~ 256;
p: LONG POINTER TO ARRAY [0..pixelsPerWord) OF CARDINALLOOPHOLE[lineBufferPtr];
q: LONG POINTER TO WORDLOOPHOLE[destLine + new.refRep.rast];
THROUGH [0..new.refRep.rast) DO
q ← q - 1;
q^ ← p[1]*w+p[0];
p ← p + pixelsPerWord;
ENDLOOP;
};
4 => {
pixelsPerWord: NAT ~ bitsPerWord/16;
p: LONG POINTER TO ARRAY [0..pixelsPerWord) OF CARDINALLOOPHOLE[lineBufferPtr];
q: LONG POINTER TO WORDLOOPHOLE[destLine + new.refRep.rast];
THROUGH [0..new.refRep.rast) DO
q ← q - 1;
q^ ← p[0];
p ← p + pixelsPerWord;
ENDLOOP;
};
ENDCASE => ERROR;
destLine ← destLine + new.refRep.rast;
ENDLOOP;
RETURN [new]
};
Reflect: PUBLIC PROC [pixelMap: PixelMap, scratch: REF PixelMapRep ← NIL] RETURNS [PixelMap] ~ {
window: DeviceRectangle ← BoundedWindow[pixelMap];
newWindow: DeviceRectangle ← [-window.sMin-window.sSize, window.fMin, window.sSize, window.fSize];
new: PixelMap ← Reshape[scratch, pixelMap.refRep.lgBitsPerPixel, newWindow];
FOR s: INTEGER IN [0..window.sSize) DO
line: PixelMap ← Clip[ShiftMap[pixelMap, -window.sMin-s, 0], [0, window.fMin, 1, window.fSize]];
Transfer[new, ShiftMap[line, newWindow.sMin+newWindow.sSize-1-s, 0], [null, null]];
ENDLOOP;
RETURN [new]
};
Space Managment
WordSeqRep: TYPE ~ RECORD [SEQUENCE length: NAT OF WORD];
NewRefRep: PROC [words: LONG CARDINAL] RETURNS [refRep: REF PixelMapRep] ~ {
ENABLE UNWIND => NULL;
words ← MAX[words, 1];
refRep ← NEW[PixelMapRep];
IF words < 2000 THEN {
wordSeq: REF WordSeqRep ← NEW[WordSeqRep[words]];
refRep.ref ← wordSeq;
TRUSTED {refRep.pointer ← LOOPHOLE[@wordSeq[0]]};
refRep.words ← words;
}
ELSE TRUSTED {
countedVM: CountedVM.Handle ← NIL;
FOR i: INT ← 0, i+1 WHILE countedVM=NIL DO
countedVM ← CountedVM.Allocate[words ! VM.CantAllocate => {IF i < 5 THEN CONTINUE}];
IF countedVM = NIL THEN {
cache: FunctionCache.Cache ~ FunctionCache.GlobalCache[];
info: FunctionCache.CacheInfo ~ FunctionCache.GetInfo[cache];
FunctionCache.SetLimits[cache, 0, 0];
FunctionCache.SetLimits[x: cache, maxEntries: info.maxEntries, maxTotalSize: info.maxTotalSize];
SafeStorage.ReclaimCollectibleObjects[suspendMe: TRUE];
Process.Pause[Process.MsecToTicks[500]];
};
ENDLOOP;
refRep.ref ← countedVM;
refRep.pointer ← countedVM.pointer;
refRep.words ← countedVM.words;
};
};
END.