ImagerPixelMapsImpl.mesa
Michael Plass, October 21, 1983 5:13 pm
Last Edited by: Pier, December 12, 1983 4:00 pm
DIRECTORY Atom, BitBlt, Environment, Inline, ImagerPixelMaps, Process, RTMicrocode, RTTypesBasic, SafeStorage, Space;
ImagerPixelMapsImpl:
CEDAR
MONITOR
IMPORTS Atom, BitBlt, ImagerPixelMaps, Inline, Process, RTMicrocode, RTTypesBasic, SafeStorage, Space
EXPORTS ImagerPixelMaps
~ BEGIN
PixelMap: TYPE ~ ImagerPixelMaps.PixelMap;
Tile: TYPE ~ ImagerPixelMaps.Tile;
PixelMapRep: TYPE ~ ImagerPixelMaps.PixelMapRep;
DeviceRectangle: TYPE ~ ImagerPixelMaps.DeviceRectangle;
Function: TYPE ~ ImagerPixelMaps.Function;
bitsPerWord: NAT ~ Environment.bitsPerWord;
lgBitsPerWord: NAT ~ Environment.logBitsPerWord;
wordsPerPage: NAT ~ Environment.wordsPerPage;
-- Some inlines for basic bit-hacking operations.
BITAND:
PROC [a, b:
CARDINAL]
RETURNS[
CARDINAL]
~ INLINE {RETURN[Inline.BITAND[a, b]]};
Shift:
PROC [a:
CARDINAL, b:
INTEGER]
RETURNS [
CARDINAL]
~ INLINE {RETURN[Inline.BITSHIFT[a, b]]};
Intersect:
PUBLIC
PROC [a, b: DeviceRectangle]
RETURNS [DeviceRectangle] ~ {
sMin: INTEGER ← MAX[a.sMin, b.sMin];
fMin: INTEGER ← MAX[a.fMin, b.fMin];
sMax: INTEGER ← MIN[INT[a.sMin]+a.sSize, INT[b.sMin]+b.sSize];
fMax: INTEGER ← MIN[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 ~ Inline.LongMult[bounds.fSize, bitsPerPixel];
Will raise a bounds fault if too many bits per line.
wordsPerLine: CARDINAL ~ (bitsPerLine+(bitsPerWord-1)) / bitsPerWord;
words: LONG CARDINAL ~ Inline.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:
REF ←
NIL]
RETURNS [pixelMap: PixelMap] ~ {
bitsPerLine: NAT ~ Inline.LongMult[rast, bitsPerWord];
fSize: NAT ~ Shift[bitsPerLine, -lgBitsPerPixel];
wastedWords:
NAT ←
INT[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 CARDINAL ← pixelMap.refRep.words;
WHILE words > 32768
DO
[] ← RTMicrocode.LONGZERO[pointer, 32768];
pointer ← pointer + 32768;
words ← words - 32768;
ENDLOOP;
[] ← RTMicrocode.LONGZERO[pointer, words];
};
Reshape:
PUBLIC
PROC [refRep:
REF PixelMapRep, lgBitsPerPixel: [0..4], bounds: DeviceRectangle]
RETURNS [pixelMap: PixelMap] ~ {
bitsPerPixel: CARDINAL ~ Shift[1, lgBitsPerPixel];
bitsPerLine:
NAT ~ Inline.LongMult[bounds.fSize, bitsPerPixel];
Will raise a bounds fault if too many bits per line.
wordsPerLine: CARDINAL ~ (bitsPerLine+(bitsPerWord-1)) / bitsPerWord;
words: LONG CARDINAL ~ Inline.LongMult[wordsPerLine, bounds.sSize];
IF refRep = NIL THEN refRep ← NewRefRep[words]
ELSE
IF words > refRep.words
THEN {
refRep.pointer ← NIL;
refRep.ref ← NIL;
IF refRep.words > 1000 THEN SafeStorage.ReclaimCollectibleObjects[];
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: INTEGER ← MAX[p.sOrigin + p.sMin, p.sOrigin];
fMin: INTEGER ← MAX[p.fOrigin + p.fMin, p.fOrigin];
sMax: INTEGER ← MIN[p.sOrigin + p.sMin + p.sSize, p.sOrigin + p.refRep.lines];
fMax: INTEGER ← MIN[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;
};
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 PACKED ARRAY [0..0) OF [0..2) ← a.refRep.pointer + Inline.LongMult[(window.sMin - a.sOrigin), a.refRep.rast];
bPtr: LONG POINTER TO PACKED ARRAY [0..0) OF [0..2) ← b.refRep.pointer + Inline.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 PACKED ARRAY [0..0) OF [0..4) ← a.refRep.pointer + Inline.LongMult[(window.sMin - a.sOrigin), a.refRep.rast];
bPtr: LONG POINTER TO PACKED ARRAY [0..0) OF [0..4) ← b.refRep.pointer + Inline.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 PACKED ARRAY [0..0) OF [0..16) ← a.refRep.pointer + Inline.LongMult[(window.sMin - a.sOrigin), a.refRep.rast];
bPtr: LONG POINTER TO PACKED ARRAY [0..0) OF [0..16) ← b.refRep.pointer + Inline.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 PACKED ARRAY [0..0) OF [0..256) ← a.refRep.pointer + Inline.LongMult[(window.sMin - a.sOrigin), a.refRep.rast];
bPtr: LONG POINTER TO PACKED ARRAY [0..0) OF [0..256) ← b.refRep.pointer + Inline.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 PACKED ARRAY [0..0) OF CARDINAL ← a.refRep.pointer + Inline.LongMult[(window.sMin - a.sOrigin), a.refRep.rast];
bPtr: LONG POINTER TO PACKED ARRAY [0..0) OF CARDINAL ← b.refRep.pointer + Inline.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 PACKED ARRAY [0..0) OF [0..2) ← pixelMap.refRep.pointer + Inline.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 PACKED ARRAY [0..0) OF [0..4) ← pixelMap.refRep.pointer + Inline.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 PACKED ARRAY [0..0) OF [0..16) ← pixelMap.refRep.pointer + Inline.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 PACKED ARRAY [0..0) OF [0..256) ← pixelMap.refRep.pointer + Inline.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 PACKED ARRAY [0..0) OF CARDINAL ← pixelMap.refRep.pointer + Inline.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, backround:
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, backround] THEN {pixelMap.sSize ← pixelMap.sSize - 1}
ELSE EXIT;
ENDLOOP;
WHILE pixelMap.sSize > 0
DO
temp.sSize ← 1;
temp.sMin ← pixelMap.sMin;
IF IsAll[temp, backround] 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, backround] THEN {pixelMap.fSize ← pixelMap.fSize - 1}
ELSE EXIT;
ENDLOOP;
WHILE pixelMap.fSize > 0
DO
temp.fSize ← 1;
temp.fMin ← pixelMap.fMin;
IF IsAll[temp, backround] THEN {pixelMap.fSize ← pixelMap.fSize - 1; pixelMap.fMin ← pixelMap.fMin + 1}
ELSE EXIT;
ENDLOOP;
IF pixelMap.fSize = 0 THEN pixelMap.sSize ← 0;
RETURN [pixelMap]
};
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;
lgPixelsPerWord: INTEGER ~ lgBitsPerWord-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 ← Inline.BITAND[value, Shift[1, Shift[1, lgBitsPerPixel]]-1] * replicator[lgBitsPerPixel];
bbTableSpace: BitBlt.BBTableSpace;
bb: BitBlt.BBptr ← BitBlt.AlignedBBTable[@bbTableSpace];
IF sMin<sMax
AND fMin<fMax
THEN {
bb^ ← [
dst: [word: dest.refRep.pointer + Inline.LongMult[sMin, rast] + Shift[fMin, -lgPixelsPerWord], bit: Inline.BITAND[fMin, Shift[1, lgPixelsPerWord]-1]],
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]
];
BitBlt.BITBLT[bb];
};
};
Transfer:
PUBLIC
PROC [dest, source: PixelMap, function: Function] ~
TRUSTED {
lgBitsPerPixel: INTEGER ~ dest.refRep.lgBitsPerPixel;
lgPixelsPerWord: INTEGER ~ lgBitsPerWord-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: BitBlt.BBTableSpace;
bb: BitBlt.BBptr ~ BitBlt.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 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 ← [word: dest.refRep.pointer + Inline.LongMult[sStartDest, dest.refRep.rast] + Shift[fMinDest, -lgPixelsPerWord], bit: Inline.BITAND[fMinDest, Shift[1, lgPixelsPerWord]-1]];
bb.src ← [word: source.refRep.pointer + Inline.LongMult[sStartSource, source.refRep.rast] + Shift[fMinSource, -lgPixelsPerWord], bit: Inline.BITAND[fMinSource, Shift[1, lgPixelsPerWord]-1]];
BitBlt.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: NAT ← MAX[(((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 CARDINAL ← 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 CARDINAL ← small.refRep.pointer;
p^ ← replicator[lgBitsPerPixel] * Inline.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: NAT ← MAX[dest.sMin, 0];
endLine: INTEGER ← MIN[dest.sMin+dest.sSize, dest.refRep.lines];
startPixel: NAT ← MAX[dest.fMin, 0];
endPixel: INTEGER ← MIN[dest.fMin+dest.fSize, Shift[dest.refRep.rast, lgBitsPerWord-lgBitsPerPixel]];
IF endLine>startLine
AND endPixel>startPixel
THEN {
startBit: NAT ← Shift[startPixel, lgBitsPerPixel];
bbTableSpace: BitBlt.BBTableSpace;
bb: BitBlt.BBptr ~ BitBlt.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 + Inline.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]
];
BitBlt.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 POINTER ← @(lineBuffer[0]);
sourceFirstLine: LONG POINTER ← pixelMap.refRep.pointer + Inline.LongMult[window.sMin-pixelMap.sOrigin, pixelMap.refRep.rast];
destLine: LONG POINTER ← new.refRep.pointer;
bbTableSpace: BitBlt.BBTableSpace;
bb: BitBlt.BBptr ~ BitBlt.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];
BitBlt.BITBLT[bb];
SELECT lgBitsPerPixel
FROM
0 => {
pixelsPerWord: NAT ~ bitsPerWord/1;
w: NAT ~ 2;
p: LONG POINTER TO ARRAY [0..pixelsPerWord) OF CARDINAL ← lineBufferPtr;
q: LONG POINTER TO WORD ← 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 CARDINAL ← lineBufferPtr;
q: LONG POINTER TO WORD ← 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 CARDINAL ← lineBufferPtr;
q: LONG POINTER TO WORD ← 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 CARDINAL ← lineBufferPtr;
q: LONG POINTER TO WORD ← 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 CARDINAL ← lineBufferPtr;
q: LONG POINTER TO WORD ← 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];
SpaceRef: TYPE ~ REF SpaceRep;
SpaceRep: TYPE ~ RECORD [space: Space.Handle ← Space.nullHandle, link: SpaceRef];
spaceListKey: ATOM ← $ImagerPixelMapsSpaceKey;
NewRefRep:
ENTRY
PROC [words:
LONG
CARDINAL]
RETURNS [refRep:
REF PixelMapRep] ~ {
ENABLE UNWIND => NULL;
words ← MAX[words, 1];
refRep ← NEW[PixelMapRep];
IF words < 16000
THEN {
wordSeq: REF WordSeqRep ← NEW[WordSeqRep[words]];
refRep.ref ← wordSeq;
TRUSTED {refRep.pointer ← @wordSeq[0]};
refRep.words ← words;
}
ELSE
TRUSTED {
spaceRef: SpaceRef ← NEW[SpaceRep];
spaceListRef: REF SpaceRef ← NARROW[Atom.GetProp[spaceListKey, spaceListKey]];
spaceList: SpaceRef ← spaceListRef^;
pages: LONG CARDINAL ← (words + (wordsPerPage-1))/wordsPerPage;
words ← pages*wordsPerPage;
spaceRef.space ← Space.Create[size: pages, parent: Space.virtualMemory];
Space.Map[spaceRef.space];
Space.CreateUniformSwapUnits[16, spaceRef.space];
refRep.ref ← spaceRef;
refRep.pointer ← Space.LongPointer[spaceRef.space];
refRep.words ← words;
spaceRef.link ← spaceList;
spaceListRef^ ← spaceRef;
};
};
finalizationQueue: RTTypesBasic.FinalizationQueue ← RTTypesBasic.NewFQ[20];
InitializeFinalization:
ENTRY
PROC ~
TRUSTED {
ENABLE UNWIND => NULL;
IF Atom.GetProp[spaceListKey, spaceListKey] =
NIL
THEN {
Atom.PutProp[spaceListKey, spaceListKey, NEW[SpaceRef ← NIL]];
RTTypesBasic.EstablishFinalization[CODE[SpaceRep], 1, finalizationQueue];
Process.Detach[FORK FinalizerProcess[finalizationQueue]];
};
finalizationEstablished ← TRUE;
};
ReInitializeFinalization:
ENTRY
PROC ~
TRUSTED {
ENABLE UNWIND => NULL;
RTTypesBasic.ReEstablishFinalization[CODE[SpaceRep], 1, finalizationQueue];
Process.Detach[FORK FinalizerProcess[finalizationQueue]];
finalizationEstablished ← TRUE;
};
FinalizerProcess:
PROC [finalizationQueue: RTTypesBasic.FinalizationQueue] ~ {
DO
ENABLE
ABORTED =>
LOOP;
spaceRef: SpaceRef ← NARROW[RTTypesBasic.FQNext[finalizationQueue]];
Finalize[spaceRef];
ENDLOOP;
};
Finalize:
ENTRY
PROC [spaceRef: SpaceRef] ~
TRUSTED {
ENABLE UNWIND => NULL;
prev: SpaceRef ← NIL;
spaceListRef: REF SpaceRef ← NARROW[Atom.GetProp[spaceListKey, spaceListKey]];
spaceList: SpaceRef ← spaceListRef^;
IF spaceList = NIL THEN RETURN;
FOR p: SpaceRef ← spaceList, p.link
UNTIL p = spaceRef
DO
IF p =
NIL
THEN
RETURN;
In case this object was allocated under a different instantiation.
prev ← p
ENDLOOP;
IF prev = NIL THEN spaceList ← spaceRef.link ELSE prev.link ← spaceRef.link;
Space.Delete[spaceRef.space];
spaceRef.link ← NIL;
};
finalizationEstablished: BOOLEAN ← FALSE;
InitializeFinalization[! RTTypesBasic.CantEstablishFinalization => CONTINUE];
IF NOT finalizationEstablished THEN {ReInitializeFinalization[]};
END.