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; 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: 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 ~ Basics.LongMult[bounds.fSize, bitsPerPixel]; 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: REF _ NIL] RETURNS [pixelMap: PixelMap] ~ { bitsPerLine: NAT ~ Basics.LongMult[rast, bitsPerWord]; fSize: NAT ~ Shift[bitsPerLine, -lgBitsPerPixel]; wastedWords: NAT _ INT[words]-INT[rast]*INT[lines]; 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 _ MIN[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]; 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: 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; }; PutPixel: PUBLIC PROC [source: PixelMap, s, f: INTEGER, val: CARDINAL] ~ TRUSTED { 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; 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 32 AND sMax-sMin > 8 THEN { 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 sMinfMinDest 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: 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 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 _ LOOPHOLE[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 _ LOOPHOLE[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: 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: 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 POINTER _ LOOPHOLE[@(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 CARDINAL _ LOOPHOLE[lineBufferPtr]; q: LONG POINTER TO WORD _ LOOPHOLE[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 _ LOOPHOLE[lineBufferPtr]; q: LONG POINTER TO WORD _ LOOPHOLE[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 _ LOOPHOLE[lineBufferPtr]; q: LONG POINTER TO WORD _ LOOPHOLE[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 _ LOOPHOLE[lineBufferPtr]; q: LONG POINTER TO WORD _ LOOPHOLE[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 _ LOOPHOLE[lineBufferPtr]; q: LONG POINTER TO WORD _ LOOPHOLE[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] }; 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. ~ImagerPixelMapImpl.mesa Copyright c 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 -- Some inlines for basic bit-hacking operations. Will raise a bounds fault if too many bits per line. Bounds check if `words' is too small or much too big. Will raise a bounds fault if too many bits per line. source is mis-named; sorry! The following bounding box is calculated in terms of the destination buffer. 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. Space Managment Κ7˜codešœ™Kšœ Οmœ7™BK™,K™(—K˜šΟk ˜ Kšœžœžœžœ;˜YKšœ žœ˜#Kšœžœ5˜HKšœžœk˜Kšœ žœ1˜?Kšœžœžœ ˜7Kšœžœ˜#Kšœ žœ˜.Kšžœžœ:˜B—K˜KšΠblœžœž˜!KšžœXž˜aKšžœ˜šœž˜K˜—Kšœ žœ˜)Kšœžœ˜!Kšœ žœ˜/Kšœžœ"˜7Kšœ žœ˜)Kšœ žœ˜&Kšœžœ˜+šœžœ˜*K˜—šœ1™1š Πknœžœžœžœžœ˜/Kšœžœžœžœ ˜'—š Οnœžœžœžœžœžœ˜8Kšœžœžœžœ ˜)—K˜—š‘ œžœžœžœ˜LKšœžœžœ˜$Kšœžœžœ˜$Kš œžœžœžœžœ˜>Kš œžœžœžœžœ˜>Kšžœžœžœžœ˜:Kšžœžœ%˜0Kšœ˜K˜—š‘œžœžœ3žœ˜fKšœžœ˜2šœ žœ/˜?K™4—Kšœžœ/˜EKšœžœžœ/˜CKšœ#˜#Kšœ0˜0Kšœ$˜$Kšœ%˜%Kšœ"˜"KšœO˜OKšœ˜K˜—š‘œžœžœžœ žœžœ ž œ žœ žœžœžœžœ˜½Kšœ žœ&˜6Kšœžœ'˜1š œ žœžœžœžœ˜3Kšœ5™5—KšœžœC˜XKšœH˜HKšœ˜Kšœ˜Kšœ˜K˜—š‘œžœžœžœ˜3Kšœ žœžœ˜0KšœžœžœžœV˜pšžœž˜Kšœ'˜'Kšœ˜Kšœ˜Kšžœ˜—Kšœ'˜'Kšœ˜K˜—šœžœ˜K˜—š ‘œžœžœ žœ?žœ˜€Kšœžœ˜2šœ žœ/˜?K™4—Kšœžœ/˜EKšœžœžœ/˜CKšžœ žœžœ˜.š žœžœžœžœ<žœ˜zKšœ˜Kšœ˜—Kšœ'˜'Kšœ˜Kšœ˜KšœP˜PKšœ˜K˜—š ‘œžœžœžœžœžœ˜`Kšœ@˜@Kšœ˜Kšœ#˜#Kšœ˜—š ‘œžœžœžœžœ˜IKšžœM˜SKšœ˜K˜—š ‘ œžœžœžœžœ˜LKšžœM˜SKšœ˜K˜—š‘œžœžœ(žœ˜OKšœ'˜'Kšžœm˜sKšœ˜—š‘ œžœžœ(žœ˜TKšžœm˜sKšœ˜K˜—š‘œžœžœžœ˜?Kšžœ=˜CKšœ˜K˜—š‘ œžœžœžœ˜EKšžœf˜lKšœ˜K˜—š‘ œžœžœžœ˜FKšœžœžœ ˜3Kšœžœžœ ˜3Kšœžœžœ;˜NKšœžœžœh˜{Kšžœžœžœ˜;Kšœ˜K˜—š ‘œžœžœžœžœžœ˜NKšœ0˜0Kšœžœžœ˜0Kšœžœžœ˜0šžœž˜(Kšœžœ˜"Kšœžœ˜$Kšœžœ˜$Kšœžœ˜$Kšœžœ˜%Kšžœžœ˜—Kšœ˜K˜—š ‘œžœžœžœžœžœ˜RKšœ™Kšœ0˜0Kšœžœžœ˜0Kšœžœžœ˜0KšœžœžœU˜gšžœž˜(Kš œžœžœžœžœ˜>Kš œžœžœžœžœ˜>Kš œžœžœžœžœ˜>Kš œžœžœžœžœ˜>Kš œžœžœžœžœ˜>Kšžœžœ˜—Kšœ˜K˜—Kšœžœžœžœžœžœžœžœ ˜AKšœžœžœžœžœžœžœžœ ˜AKšœžœžœžœžœžœžœžœ ˜BKšœžœžœžœžœžœžœžœ ˜CKšœžœžœžœžœžœžœžœžœ˜CK˜š ‘œžœžœžœžœ˜9Kšœ+˜+Kšžœžœžœžœ˜1Kšžœžœžœžœ˜*Kšžœ3žœžœžœ˜Išžœž˜#šœžœ˜Kš œžœžœžœžœO˜tKš œžœžœžœžœO˜tšžœžœžœ)ž˜<šžœžœžœ)ž˜˜HKšœ žœ ˜0Kšœžœžœ]˜mKšœƒ˜ƒKšœ žœ˜Kšžœ žœ žœ˜8Kšœžœ˜!Kšœ.žœ˜AKšœ˜Kšœ˜Kšœ(˜(šžœž˜Kšœ žœ˜Kšœžœ˜&Kšœ=˜=Kšžœ˜—šžœž˜Kšœ žœ˜Kšœžœ˜&KšœA˜AšœH˜HKšœ!˜!Kšœ)˜)K˜—Kšœ˜Kšžœžœ žœ˜GKšžœ˜—KšœN˜NKšœ˜—Kšœ˜K˜—š‘œžœžœ žœ žœžœžœ˜kKšœ5˜5Kšœžœžœžœžœžœžœžœ˜NKš žœžœžœžœžœ˜4šžœž˜Kšœžœžœ˜Kšœžœ˜Kšœ˜Kšžœ˜—KšœQ˜QKšœ˜K˜—š‘œžœžœžœ#žœžœžœ˜‡Kšœžœ*˜