DIRECTORY ImagerMasks, ImagerMasksPrivate, ImagerPixelMaps, UnsafeStorage, ImagerScanConverter, Environment ; ImagerMasksImpl: CEDAR PROGRAM IMPORTS UnsafeStorage, ImagerPixelMaps, ImagerScanConverter EXPORTS ImagerMasks, ImagerMasksPrivate = BEGIN OPEN ImagerMasks; maxBlockLength: NAT ~ 150; indexSize: NAT ~ 200; bitsPerWord: NAT ~ Environment.bitsPerWord; TempRunRep: TYPE ~ RECORD [ newLineRepeatCount: NAT, -- zero if the run does not start a new scanline fMin: INTEGER, fSize: INTEGER ]; TempRunGroupRep: TYPE ~ ARRAY [0..maxBlockLength) OF TempRunRep; IndexArrayRep: TYPE ~ ARRAY [0..indexSize) OF LONG POINTER TO TempRunGroupRep; uz: UNCOUNTED ZONE _ SysZone[]; SysZone: PROC RETURNS[UNCOUNTED ZONE] ~ TRUSTED {RETURN[UnsafeStorage.GetSystemUZone[]]}; RunsOutOfOrder: PUBLIC ERROR ~ CODE; Create: PUBLIC PROC [ runs: PROC[ -- Create calls this back run: PROC[sMin, fMin: INTEGER, fSize: NAT], -- client calls this from inside runs. repeat: PROC[timesToRepeatScanline: NAT] -- client calls this to repeat a scanline ] ] RETURNS [mask: Mask] ~ TRUSTED { indexArrayLength: CARDINAL _ 0; indexArrayEnd: CARDINAL _ 0; indexArray: LONG POINTER TO IndexArrayRep; tempLength: CARDINAL _ maxBlockLength; totalLength: INT; Release: UNSAFE PROC = { IF indexArray # NIL THEN { FOR i: CARDINAL IN [0..indexArrayLength) DO IF indexArray[i] # NIL THEN uz.FREE[@(indexArray[i])]; ENDLOOP; uz.FREE[@indexArray]; }; }; minf: INTEGER _ LAST[INTEGER]; maxf: INTEGER _ FIRST[INTEGER]; mins: INTEGER _ LAST[INTEGER]; lasts: INTEGER _ LAST[INTEGER]; lastf: INTEGER _ FIRST[INTEGER]; TRUSTED {ENABLE UNWIND => Release[]; temp: LONG POINTER TO TempRunGroupRep _ NIL; -- = indexArray[indexArrayEnd - 1] curLineStartIndex: CARDINAL _ 0; curLineStartBlockNumber: CARDINAL _ 0; Extend: UNSAFE PROC = { indexArrayEnd _ indexArrayEnd + 1; IF indexArrayEnd > indexArrayLength THEN { indexArray[indexArrayLength] _ NIL; indexArrayLength _ indexArrayLength + 1; indexArray[indexArrayLength - 1] _ uz.NEW[TempRunGroupRep]; }; temp _ indexArray[indexArrayEnd - 1]; tempLength _ 0; }; StartNewLine: UNSAFE PROC = { pi: CARDINAL _ curLineStartIndex; pb: CARDINAL _ curLineStartBlockNumber; ci: CARDINAL _ tempLength; cb: CARDINAL _ indexArrayEnd - 1; cBlock: LONG POINTER TO TempRunGroupRep _ temp; pBlock: LONG POINTER TO TempRunGroupRep _ indexArray[pb]; lastf _ FIRST[INTEGER]; DO -- Terminate by RETURN if duplicate scanline, by EXIT if not. cr: TempRunRep; IF pi = 0 THEN { IF pb = 0 THEN EXIT; pb _ pb - 1; pBlock _ indexArray[pb]; pi _ maxBlockLength; }; pi _ pi - 1; IF ci = 0 THEN { IF cb = 0 THEN ERROR; cb _ cb - 1; cBlock _ indexArray[cb]; ci _ maxBlockLength; }; ci _ ci - 1; IF (cr _ cBlock[ci]).newLineRepeatCount # 0 THEN { pr: TempRunRep _ pBlock[pi]; IF cr.fMin = pr.fMin AND cr.fSize = pr.fSize AND pr.newLineRepeatCount # 0 THEN { IF ci # curLineStartIndex THEN ERROR; pBlock[pi].newLineRepeatCount _ pr.newLineRepeatCount + cr.newLineRepeatCount; tempLength _ curLineStartIndex; indexArrayEnd _ curLineStartBlockNumber + 1; temp _ indexArray[curLineStartBlockNumber]; RETURN; } ELSE EXIT }; IF cr # pBlock[pi] THEN EXIT; ENDLOOP; curLineStartIndex _ tempLength; curLineStartBlockNumber _ indexArrayEnd - 1; }; Run: SAFE PROC[sMin, fMin: INTEGER, fSize: NAT] ~ TRUSTED { newLine: BOOLEAN _ FALSE; IF sMin < lasts THEN {IF lasts = LAST[INTEGER] THEN {mins _ lasts _ sMin; newLine _ TRUE} ELSE ERROR RunsOutOfOrder}; WHILE sMin # lasts DO IF newLine THEN { IF tempLength = maxBlockLength THEN Extend[]; StartNewLine[]; temp[tempLength] _ [sMin-lasts, 0, 0]; tempLength _ tempLength + 1; lasts _ sMin; } ELSE {newLine _ TRUE; lasts _ lasts + 1}; ENDLOOP; IF tempLength = maxBlockLength THEN Extend[]; IF newLine THEN { StartNewLine[]; temp[tempLength] _ [1, fMin, fSize]; } ELSE temp[tempLength] _ [0, fMin, fSize]; IF lastf > fMin THEN ERROR RunsOutOfOrder; lastf _ INT[fMin] + fSize; tempLength _ tempLength + 1; minf _ MIN[minf, fMin]; maxf _ MAX[maxf, fMin + fSize]; }; Repeat: SAFE PROC[timesToRepeatScanline: NAT] ~ TRUSTED { pBlock: LONG POINTER TO TempRunGroupRep _ indexArray[curLineStartBlockNumber]; oldRepeat: NAT _ pBlock[curLineStartIndex].newLineRepeatCount; IF oldRepeat = 0 THEN ERROR; IF pBlock = temp AND curLineStartIndex = tempLength THEN ERROR; pBlock[curLineStartIndex].newLineRepeatCount _ oldRepeat + timesToRepeatScanline; lasts _ lasts + timesToRepeatScanline; }; indexArray _ uz.NEW[IndexArrayRep]; runs[Run, Repeat]; StartNewLine[]; -- merges duplicates in case last call was to Repeat totalLength _ INT[indexArrayEnd]*maxBlockLength + tempLength - maxBlockLength; IF lasts = LAST[INTEGER] THEN {mask _ [0, 0, 0, 0, NIL]} ELSE IF indexArrayEnd = 1 AND tempLength = 1 THEN { mask.sMin _ mins; mask.fMin _ minf; mask.sSize _ lasts + 1 - mins; mask.fSize _ maxf - minf; mask.refRep _ NIL; } ELSE { runsMaskRef: REF RunsRep _ NEW[RunsRep[indexArrayEnd]]; mask.sMin _ mins; mask.fMin _ minf; mask.sSize _ lasts + 1 - mins; mask.fSize _ maxf - minf; mask.refRep _ runsMaskRef; FOR i: CARDINAL DECREASING IN [0..indexArrayEnd) DO new: RunBlock _ NEW[RunBlockRep[tempLength]]; runsMaskRef[i] _ new; temp _ indexArray[i]; FOR j: [0..maxBlockLength) DECREASING IN [0..tempLength) DO tempj: TempRunRep _ temp[j]; new[j] _ [ newLineRepeatCount: tempj.newLineRepeatCount, fMin: IF tempj.fSize = 0 THEN 0 ELSE tempj.fMin - minf, fSize: tempj.fSize ]; ENDLOOP; tempLength _ maxBlockLength; ENDLOOP; }; }; TRUSTED {Release[]}; }; MaskFromPixelMap: PUBLIC PROC [pixelMap: PixelMap, minValue, maxValue: CARDINAL] RETURNS [Mask] ~ { IF minValue > maxValue THEN RETURN [[0, 0, 0, 0, NIL]]; IF pixelMap.refRep.lgBitsPerPixel = 0 THEN { function: ImagerPixelMaps.Function; copy: PixelMap; SELECT TRUE FROM maxValue = 0 => function _ [null, complement]; minValue = 1 => function _ [null, null]; minValue > 1 => RETURN [[0, 0, 0, 0, NIL]]; minValue = 0 AND maxValue > 0 => RETURN [Box[pixelMap.Window]]; ENDCASE => ERROR; copy _ ImagerPixelMaps.Create[0, pixelMap.Window]; copy.Transfer[pixelMap, function]; RETURN [[pixelMap.sOrigin+pixelMap.sMin, pixelMap.fOrigin+pixelMap.fMin, pixelMap.sSize, pixelMap.fSize, pixelMap.refRep]]; } ELSE { window: DeviceRectangle _ pixelMap.Window; Runs: PROC [run: PROC[sMin, fMin: INTEGER, fSize: NAT], repeat: PROC[timesToRepeatScanline: NAT]] ~ { fMax: INTEGER _ window.fMin + window.fSize; FOR s: INTEGER IN [window.sMin..window.sMin+window.sSize) DO f, fMin: INTEGER _ window.fMin; WHILE f < fMax DO WHILE f < fMax AND NOT (pixelMap.GetPixel[s, f] IN [minValue..maxValue]) DO f _ f + 1; ENDLOOP; IF f = fMax THEN EXIT; fMin _ f; WHILE f < fMax AND pixelMap.GetPixel[s, f] IN [minValue..maxValue] DO f _ f + 1; ENDLOOP; IF f > fMin THEN run[s, fMin, f-fMin]; ENDLOOP; ENDLOOP; }; RETURN [Create[Runs]]; }; }; MaskFromDevicePath: PUBLIC PROC [devicePath: DevicePath, parityFill: BOOLEAN] RETURNS [Mask] ~ { window: DeviceRectangle _ ImagerScanConverter.BoundingBox[devicePath]; runCount: INT _ devicePath.NumberOfRuns; IF runCount * 16 > INT[window.sSize]*window.fSize THEN { pixelMap: PixelMap _ ImagerPixelMaps.Create[0, window]; ImagerPixelMaps.Clear[pixelMap]; devicePath.ConvertToPixels[pixelMap, 1, parityFill]; pixelMap _ pixelMap.Trim[0]; IF pixelMap.fOrigin # 0 OR pixelMap.sOrigin # 0 THEN RETURN [MaskFromPixelMap[pixelMap, 1, 1]] ELSE IF pixelMap.IsAll[1] THEN RETURN[Box[pixelMap.Window]] ELSE RETURN [[pixelMap.sMin, pixelMap.fMin, pixelMap.sSize, pixelMap.fSize, pixelMap.refRep]]; } ELSE { Runs: PROC [run: PROC[sMin, fMin: INTEGER, fSize: NAT], repeat: PROC[timesToRepeatScanline: NAT]] ~ {devicePath.ConvertToRuns[run, window, parityFill]}; RETURN [Create[Runs]]; }; }; Box: PUBLIC PROC [r: DeviceRectangle] RETURNS [Mask] ~ { RETURN[[r.sMin, r.fMin, r.sSize, r.fSize, NIL]] }; Representation: TYPE ~ ImagerMasksPrivate.Representation; Reader: TYPE ~ ImagerMasksPrivate.Reader; SetReader: PUBLIC UNSAFE PROC [reader: POINTER TO Reader, mask: Mask] ~ UNCHECKED { reader.s _ mask.sMin; reader.index _ 0; reader.fTranslate _ mask.fMin; reader.done _ FALSE; reader.repeatCount _ 1; reader.firstRunOnLine _ TRUE; reader.refRep _ mask.refRep; IF mask.sSize = 0 THEN { reader.done _ TRUE; reader.fMin _ reader.fMax _ 0; reader.s _ LAST[INTEGER]; RETURN }; WITH reader.refRep SELECT FROM b: REF ImagerPixelMaps.PixelMapRep => { IF b.lgBitsPerPixel # 0 THEN ERROR; reader.representation _ bitmap; reader.currentWord _ 0; reader.validBitCount _ 0; reader.nextWordPtr _ reader.currentLinePtr _ b.pointer; reader.fCurrent _ 0; reader.fSize _ MIN[mask.fSize, b.rast*bitsPerWord]; reader.sMax _ MIN[mask.sSize, b.lines] + mask.sMin; reader.wordsPerLine _ b.rast; Advance[reader]; reader.firstRunOnLine _ TRUE; }; r: REF RunsRep => { fMin, fSize: NAT; reader.representation _ runs; reader.blockDirectory _ r; reader.blockDirectoryIndex _ 0; reader.runBlock _ r[0]; [newLineRepeatCount: reader.repeatCount, fMin: fMin, fSize: fSize] _ reader.runBlock[0]; reader.lineStartBlockDirectoryIndex _ 0; reader.lineStartIndex _ 0; reader.fMax _ (reader.fMin _ fMin + reader.fTranslate) + fSize; }; ENDCASE => { reader.representation _ box; reader.repeatCount _ mask.sSize; reader.fMin _ mask.fMin; reader.fMax _ reader.fMin + mask.fSize; }; }; Advance: PUBLIC UNSAFE PROC [r: POINTER TO Reader] ~ UNCHECKED { IF r.done THEN RETURN; SELECT r.representation FROM bitmap => { olds: INTEGER _ r.s; WHILE r.currentWord = 0 DO WHILE r.currentWord = 0 AND r.fCurrent < r.fSize DO r.fCurrent _ r.fCurrent + r.validBitCount; r.currentWord _ r.nextWordPtr^; r.nextWordPtr _ r.nextWordPtr + 1; r.validBitCount _ bitsPerWord; ENDLOOP; IF r.fCurrent >= r.fSize THEN { IF (r.s _ r.s + 1) >= r.sMax THEN { r.s _ LAST[INTEGER]; r.fMin _ r.fMax _ 0; r.firstRunOnLine _ r.done _ TRUE; RETURN; }; r.fCurrent _ 0; r.nextWordPtr _ r.currentLinePtr _ r.currentLinePtr + r.wordsPerLine; r.currentWord _ r.nextWordPtr^; r.nextWordPtr _ r.nextWordPtr + 1; r.validBitCount _ bitsPerWord; }; ENDLOOP; IF r.currentWord = -1 THEN { IF r.validBitCount # bitsPerWord THEN ERROR; r.fMin _ r.fTranslate + r.fCurrent; r.fCurrent _ r.fCurrent + bitsPerWord; r.validBitCount _ 0; } ELSE { r.fCurrent _ r.fCurrent+r.validBitCount; WHILE r.currentWord > 0 DO r.currentWord _ 2*r.currentWord; r.validBitCount _ r.validBitCount-1; ENDLOOP; r.fMin _ r.fTranslate + r.fCurrent - r.validBitCount; WHILE r.currentWord < 0 DO r.currentWord _ 2*r.currentWord; r.validBitCount _ r.validBitCount-1; ENDLOOP; r.fCurrent _ r.fCurrent-r.validBitCount; }; WHILE r.fCurrent < r.fSize AND r.validBitCount = 0 DO r.currentWord _ r.nextWordPtr^; r.nextWordPtr _ r.nextWordPtr + 1; IF r.currentWord = -1 THEN r.fCurrent _ r.fCurrent + bitsPerWord ELSE r.validBitCount _ bitsPerWord; ENDLOOP; IF r.fCurrent < r.fSize THEN { WHILE r.currentWord < 0 DO r.currentWord _ 2*r.currentWord; r.validBitCount _ r.validBitCount-1; r.fCurrent _ r.fCurrent + 1; ENDLOOP; }; IF (r.fMax _ r.fTranslate + MIN[r.fSize, r.fCurrent]) < r.fMin THEN r.fMin _ r.fMax; r.firstRunOnLine _ r.s # olds; IF r.fCurrent >= r.fSize THEN { r.currentWord _ 0; }; }; runs => { newline: BOOLEAN _ FALSE; runRep: RunRep; IF r.runBlock.length = (r.index _ r.index + 1) THEN { r.index _ 0; IF (r.blockDirectoryIndex _ r.blockDirectoryIndex+1) = r.blockDirectory.length THEN { IF r.repeatCount = 1 THEN { r.done _ TRUE; r.firstRunOnLine _ TRUE; r.fMin _ r.fMax _ 0; r.s _ LAST[INTEGER]; RETURN } ELSE { r.index _ r.lineStartIndex; r.runBlock _ r.blockDirectory[r.blockDirectoryIndex _ r.lineStartBlockDirectoryIndex]; }; } ELSE r.runBlock _ r.blockDirectory[r.blockDirectoryIndex]; }; runRep _ r.runBlock[r.index]; IF r.firstRunOnLine _ (runRep.newLineRepeatCount # 0) THEN { r.s _ r.s + 1; IF (r.repeatCount _ r.repeatCount - 1) = 0 THEN { r.repeatCount _ runRep.newLineRepeatCount; r.lineStartIndex _ r.index; r.lineStartBlockDirectoryIndex _ r.blockDirectoryIndex; } ELSE { r.index _ r.lineStartIndex; r.runBlock _ r.blockDirectory[r.blockDirectoryIndex _ r.lineStartBlockDirectoryIndex]; runRep _ r.runBlock[r.index]; }; }; r.fMax _ (r.fMin _ runRep.fMin + r.fTranslate) + runRep.fSize; }; box => { IF (r.repeatCount _ r.repeatCount - 1) = 0 THEN { r.done _ TRUE; r.fMin _ r.fMax _ 0; r.s _ LAST[INTEGER]; } ELSE r.s _ r.s + 1; }; ENDCASE => ERROR; }; SkipTo: PUBLIC UNSAFE PROC [r: POINTER TO Reader, s: INTEGER] ~ UNCHECKED { IF r.s >= s THEN RETURN; SELECT r.representation FROM runs => { WHILE r.s < s DO IF r.firstRunOnLine AND r.repeatCount > 1 THEN { delta: NAT _ MIN[s-r.s, r.repeatCount-1]; r.repeatCount _ r.repeatCount - delta; r.s _ r.s + delta; } ELSE Advance[r]; ENDLOOP; }; box => { IF s >= INT[r.s] + r.repeatCount THEN { r.done _ TRUE; r.fMin _ r.fMax _ 0; r.s _ LAST[INTEGER]; } ELSE { r.repeatCount _ r.repeatCount - (s-r.s); r.s _ s; }; }; ENDCASE => {WHILE r.s < s DO Advance[r] ENDLOOP}; }; And: PUBLIC PROC [a, b: Mask] RETURNS [Mask] ~ { Runs: PROC[run: PROC[sMin, fMin: INTEGER, fSize: NAT], repeat: PROC[timesToRepeatScanline: NAT]] ~ TRUSTED { aReader, bReader: Reader; SetReader[@aReader, a]; SetReader[@bReader, b]; DO duplicates: NAT; s: INTEGER; somethingInScanline: BOOLEAN _ FALSE; IF aReader.s < bReader.s THEN SkipTo[@aReader, bReader.s]; IF aReader.done THEN EXIT; IF aReader.s > bReader.s THEN SkipTo[@bReader, aReader.s]; IF bReader.done THEN EXIT; s _ aReader.s; duplicates _ MIN[aReader.repeatCount, bReader.repeatCount] - 1; WHILE s = aReader.s AND s = bReader.s DO fMin: INTEGER _ MAX[aReader.fMin, bReader.fMin]; fMax: INTEGER _ MIN[aReader.fMax, bReader.fMax]; IF fMin < fMax THEN {run[s, fMin, fMax - fMin]; somethingInScanline _ TRUE}; SELECT fMax FROM aReader.fMax => {Advance[@aReader]}; bReader.fMax => {Advance[@bReader]}; ENDCASE => ERROR; ENDLOOP; IF duplicates > 0 THEN { IF somethingInScanline THEN repeat[duplicates]; SkipTo[@aReader, s+1+duplicates]; SkipTo[@bReader, s+1+duplicates]; }; ENDLOOP; }; IF b.refRep = NIL AND a.sMin >= b.sMin AND a.fMin >= b.fMin AND a.sMin + a.sSize <= b.sMin + b.sSize AND a.fMin + a.fSize <= b.fMin + b.fSize THEN RETURN [a]; IF a.refRep = NIL AND b.sMin >= a.sMin AND b.fMin >= a.fMin AND b.sMin + b.sSize <= a.sMin + a.sSize AND b.fMin + b.fSize <= a.fMin + a.fSize THEN RETURN [b]; IF a.sSize = 0 OR b.sSize = 0 OR a.sMin >= b.sMin + b.sSize OR b.sMin >= a.sMin + a.sSize OR a.fMin >= b.fMin + b.fSize OR b.fMin >= a.fMin + a.fSize THEN RETURN [[0, 0, 0, 0, NIL]]; RETURN[Create[Runs]]; }; Or: PUBLIC PROC [a, b: Mask] RETURNS [Mask] ~ { Runs: PROC[run: PROC[sMin, fMin: INTEGER, fSize: NAT], repeat: PROC[timesToRepeatScanline: NAT]] ~ TRUSTED { aReader, bReader: Reader; SetReader[@aReader, a]; SetReader[@bReader, b]; UNTIL aReader.done AND bReader.done DO as: INTEGER _ aReader.s; bs: INTEGER _ bReader.s; s: INTEGER _ MIN[as, bs]; duplicates: NAT _ MIN[aReader.repeatCount, bReader.repeatCount]; somethingInScanline: BOOLEAN _ FALSE; WHILE s = aReader.s OR s = bReader.s DO fStart: INTEGER _ LAST[INTEGER]; fEnd: INTEGER; IF s = aReader.s THEN {fStart _ aReader.fMin}; IF s = bReader.s THEN {fStart _ MIN[fStart, bReader.fMin]}; fEnd _ fStart; DO SELECT TRUE FROM s = aReader.s AND aReader.fMin <= fEnd => { fEnd _ MAX[fEnd, aReader.fMax]; Advance[@aReader]; }; s = bReader.s AND bReader.fMin <= fEnd => { fEnd _ MAX[fEnd, bReader.fMax]; Advance[@bReader]; }; ENDCASE => EXIT; ENDLOOP; IF fEnd > fStart THEN {run[s, fStart, fEnd - fStart]; somethingInScanline _ TRUE}; ENDLOOP; IF as = s AND bs = s AND duplicates > 1 THEN { IF somethingInScanline THEN repeat[duplicates-1]; SkipTo[@aReader, s+duplicates]; SkipTo[@bReader, s+duplicates]; }; ENDLOOP; }; RETURN[Create[Runs]]; }; Difference: PUBLIC PROC [a, b: Mask] RETURNS [Mask] ~ { Runs: PROC[run: PROC[sMin, fMin: INTEGER, fSize: NAT], repeat: PROC[timesToRepeatScanline: NAT]] ~ TRUSTED { aReader, bReader: Reader; SetReader[@aReader, a]; SetReader[@bReader, b]; DO duplicates: NAT; s: INTEGER; somethingInScanline: BOOLEAN _ FALSE; bInversefMin, bInversefMax: INTEGER; s _ aReader.s; duplicates _ MIN[s + aReader.repeatCount, bReader.s] - s; WHILE aReader.s < bReader.s DO run[aReader.s, aReader.fMin, aReader.fMax - aReader.fMin]; Advance[@aReader]; IF s # aReader.s THEN { IF duplicates > 1 THEN {repeat[duplicates-1]; SkipTo[@aReader, s+duplicates]}; s _ aReader.s; duplicates _ MIN[s + aReader.repeatCount, bReader.s] - s; }; ENDLOOP; IF aReader.done THEN EXIT; IF aReader.s > bReader.s THEN SkipTo[@bReader, aReader.s]; s _ aReader.s; duplicates _ MIN[aReader.repeatCount, bReader.repeatCount] - 1; bInversefMin _ FIRST[INTEGER]; bInversefMax _ bReader.fMin; WHILE s = aReader.s DO fMin: INTEGER _ MAX[aReader.fMin, bInversefMin]; fMax: INTEGER _ MIN[aReader.fMax, bInversefMax]; IF fMin < fMax THEN {run[s, fMin, fMax - fMin]; somethingInScanline _ TRUE}; SELECT fMax FROM aReader.fMax => {Advance[@aReader]}; bInversefMax => { IF bInversefMax = LAST[INTEGER] THEN EXIT; bInversefMin _ bReader.fMax; Advance[@bReader]; bInversefMax _ IF bReader.s = s THEN bReader.fMin ELSE LAST[INTEGER]; }; ENDCASE => ERROR; ENDLOOP; IF duplicates > 0 THEN { IF somethingInScanline THEN repeat[duplicates]; SkipTo[@aReader, s+1+duplicates]; SkipTo[@bReader, s+1+duplicates]; }; ENDLOOP; }; RETURN[Create[Runs]]; }; InShift: PROC [mask: Mask, s, f: INTEGER] RETURNS [Mask] ~ INLINE { RETURN[[mask.sMin+s, mask.fMin+f, mask.sSize, mask.fSize, mask.refRep]] }; Shift: PUBLIC PROC [mask: Mask, s, f: INTEGER] RETURNS [Mask] ~ { RETURN[[mask.sMin+s, mask.fMin+f, mask.sSize, mask.fSize, mask.refRep]] }; Bitmap: PUBLIC PROC [mask: Mask] RETURNS [Mask] ~ { WITH mask.refRep SELECT FROM b: REF ImagerPixelMaps.PixelMapRep => RETURN[mask]; ENDCASE => { pixelMap: PixelMap _ ImagerPixelMaps.Create[0, [mask.sMin, mask.fMin, mask.sSize, mask.fSize]]; BoxProc: PROC [r: DeviceRectangle] ~ {pixelMap.Fill[r, 1]}; ImagerPixelMaps.Clear[pixelMap]; MapBoxes[mask, BoxProc]; RETURN[[mask.sMin, mask.fMin, mask.sSize, mask.fSize, pixelMap.refRep]]; }; }; CountRuns: PUBLIC PROC [mask: Mask] RETURNS [runs: INT _ 0] ~ TRUSTED { aReader: Reader; SetReader[@aReader, mask]; UNTIL aReader.done DO sSize: NAT _ aReader.repeatCount; s: INTEGER _ aReader.s; WHILE s = aReader.s DO runs _ runs + sSize; Advance[@aReader]; ENDLOOP; SkipTo[@aReader, s+sSize]; ENDLOOP; }; MapRuns: PUBLIC PROC [mask: Mask, run: PROC [sMin, fMin: INTEGER, fSize: NAT]] ~ TRUSTED { aReader: Reader; SetReader[@aReader, mask]; UNTIL aReader.done DO run[aReader.s, aReader.fMin, aReader.fMax - aReader.fMin]; Advance[@aReader]; ENDLOOP; }; MapBoxes: PUBLIC PROC [mask: Mask, box: PROC [DeviceRectangle]] ~ TRUSTED { aReader: Reader; SetReader[@aReader, mask]; UNTIL aReader.done DO sSize: NAT _ aReader.repeatCount; s: INTEGER _ aReader.s; WHILE s = aReader.s DO box[[s, aReader.fMin, sSize, aReader.fMax - aReader.fMin]]; Advance[@aReader]; ENDLOOP; SkipTo[@aReader, s+sSize]; ENDLOOP; }; MapClippedRuns: PUBLIC PROC [mask, clipper: Mask, run: PROC [sMin, fMin: INTEGER, fSize: NAT]] ~ TRUSTED { aReader, bReader: Reader; SetReader[@aReader, mask]; SetReader[@bReader, clipper]; DO s: INTEGER; IF aReader.s < bReader.s THEN SkipTo[@aReader, bReader.s]; IF aReader.done THEN EXIT; IF aReader.s > bReader.s THEN SkipTo[@bReader, aReader.s]; IF bReader.done THEN EXIT; s _ aReader.s; WHILE s = aReader.s AND s = bReader.s DO fMin: INTEGER _ MAX[aReader.fMin, bReader.fMin]; fMax: INTEGER _ MIN[aReader.fMax, bReader.fMax]; IF fMin < fMax THEN run[aReader.s, fMin, fMax - fMin]; SELECT fMax FROM aReader.fMax => {Advance[@aReader]}; bReader.fMax => {Advance[@bReader]}; ENDCASE => ERROR; ENDLOOP; ENDLOOP; }; MapClippedBoxes: PUBLIC PROC [mask, clipper: Mask, box: PROC [DeviceRectangle]] ~ TRUSTED { aReader, bReader: Reader; SetReader[@aReader, mask]; SetReader[@bReader, clipper]; DO duplicates: NAT; s: INTEGER; IF aReader.s < bReader.s THEN SkipTo[@aReader, bReader.s]; IF aReader.done THEN EXIT; IF aReader.s > bReader.s THEN SkipTo[@bReader, aReader.s]; IF bReader.done THEN EXIT; s _ aReader.s; duplicates _ MIN[aReader.repeatCount, bReader.repeatCount] - 1; WHILE s = aReader.s AND s = bReader.s DO fMin: INTEGER _ MAX[aReader.fMin, bReader.fMin]; fMax: INTEGER _ MIN[aReader.fMax, bReader.fMax]; IF fMin < fMax THEN box[[aReader.s, fMin, duplicates+1, fMax - fMin]]; SELECT fMax FROM aReader.fMax => {Advance[@aReader]}; bReader.fMax => {Advance[@bReader]}; ENDCASE => ERROR; ENDLOOP; IF duplicates > 0 THEN { SkipTo[@aReader, s+1+duplicates]; SkipTo[@bReader, s+1+duplicates]; }; ENDLOOP; }; IsVisible: PUBLIC PROC [mask, clipper: Mask] RETURNS [Visibility] ~ TRUSTED { reader: Reader; empty: BOOLEAN _ TRUE; CheckRun: SAFE PROC [sMin, fMin: INTEGER, fSize: CARDINAL] ~ TRUSTED { fMax: INTEGER _ fMin+fSize; empty _ FALSE; IF sMin = reader.s AND fMin = reader.fMin AND fMax = reader.fMax THEN Advance[@reader]; }; IF clipper.refRep = NIL THEN { IF mask.sMin >= clipper.sMin AND mask.sMin + mask.sSize <= clipper.sMin + clipper.sSize AND mask.fMin >= clipper.fMin AND mask.fMin + mask.fSize <= clipper.fMin + clipper.fSize THEN RETURN[visible]; }; IF mask.sMin >= clipper.sMin + clipper.sSize OR mask.sMin + mask.sSize <= clipper.sMin OR mask.fMin >= clipper.fMin + clipper.fSize OR mask.fMin + mask.fSize <= clipper.fMin THEN RETURN[invisible]; SetReader[@reader, mask]; MapClippedRuns[mask, clipper, CheckRun]; RETURN[IF empty THEN invisible ELSE IF reader.done THEN visible ELSE partlyVisible]; }; TileType: PROC [tile: ImagerPixelMaps.Tile] RETURNS [ImagerPixelMaps.Function] ~ TRUSTED { w: LONG POINTER TO INTEGER _ tile.refRep.pointer; IF tile.sSize = 1 AND tile.fSize = 16 THEN { IF w^ = -1 THEN RETURN [[or, null]]; IF w^ = 0 THEN RETURN [[and, complement]]; }; RETURN [[xor, null]]; }; MaskTile: PUBLIC PROC [dest: PixelMap, mask: Mask, tile: ImagerPixelMaps.Tile, function: ImagerPixelMaps.Function] ~ { IF function = [null, null] AND dest.refRep.lgBitsPerPixel = 0 THEN WITH mask.refRep SELECT FROM refRep: REF ImagerPixelMaps.PixelMapRep => { tileType: ImagerPixelMaps.Function _ TileType[tile]; IF tileType = [xor, null] THEN { dest _ dest.Clip[[mask.sMin, mask.fMin, mask.sSize, mask.fSize]]; dest.TransferTile[tile, [xor, null]]; dest.Transfer[[mask.sMin, mask.fMin, 0, 0, mask.sSize, mask.fSize, refRep], [and, complement]]; dest.TransferTile[tile, [xor, null]]; } ELSE dest.Transfer[[mask.sMin, mask.fMin, 0, 0, mask.sSize, mask.fSize, refRep], tileType]; RETURN; }; ENDCASE => NULL; TRUSTED { aReader: Reader; SetReader[@aReader, mask]; UNTIL aReader.done DO sSize: NAT _ aReader.repeatCount; s: INTEGER _ aReader.s; WHILE s = aReader.s DO dest.Clip[[s, aReader.fMin, sSize, aReader.fMax - aReader.fMin]].TransferTile[tile, function]; Advance[@aReader]; ENDLOOP; SkipTo[@aReader, s+sSize]; ENDLOOP; }; }; END. ImagerMasksImpl.mesa Michael Plass, October 17, 1983 3:44 pm Count clear words in this scanline. Advance to next scanline Count clear bits. Count one bits. Count all-ones words. Count some more one bits. Fix up so a new line will start next time around. Ê(˜J™J™'šÏk ˜ Jšœ ˜ Jšœ˜J˜Jšœ˜Jšœ˜J˜ J˜—J˜šœœ˜Jšœ4˜;Jšœ ˜'Jšœœœ ˜—Jšœœ˜Jšœ œ˜Jšœ œ˜+šœ œœ˜JšœœÏc0˜IJšœœ˜Jšœ˜Jšœ˜—Jšœœœœ ˜@Jš œœœœœœœ˜NJšœ œœ ˜JšÏnœœœ œœœœ"˜YJšœœœœ˜$šŸœœœ˜šœœž˜%Jšœœ œ œž&˜SJšœœœž)˜SJšœ˜—Jšœœœ˜"Jšœœ˜Jšœœ˜Jšœ œœœ˜*Jšœ œ˜&Jšœ œ˜šŸœœœ˜šœœœ˜šœœœ˜+Jšœœœœ˜6Jšœ˜—Jšœœ˜Jšœ˜—Jšœ˜—Jšœœœœ˜Jšœœœœ˜Jšœœœœ˜Jšœœœœ˜Jšœœœœ˜ šœœœ˜$Jš œœœœœž"˜OJšœœ˜ Jšœœ˜&šŸœœœ˜Jšœ"˜"šœ"œ˜*Jšœœ˜#Jšœ(˜(Jšœ&œ˜;J˜—Jšœ%˜%Jšœ˜Jšœ˜—šŸ œœœ˜Jšœœ˜!Jšœœ˜'Jšœœ˜Jšœœ˜!Jšœœœœ˜/Jšœœœœ"˜9Jšœœœ˜šœž=˜@Jšœ˜šœœ˜Jšœœœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜—Jšœ ˜ šœœ˜Jšœœœ˜J˜ Jšœ˜Jšœ˜Jšœ˜—Jšœ ˜ šœ*œ˜2Jšœ˜šœœœœ˜QJšœœœ˜%JšœN˜NJšœ˜Jšœ,˜,Jšœ+˜+Jšœ˜Jšœ˜—Jšœ˜ Jšœ˜—Jšœœœ˜Jšœ˜—Jšœ˜Jšœ,˜,Jšœ˜—š Ÿœœœ œ œœ˜;Jšœ œœ˜Jšœœœ œœœ!œœœ˜ušœ˜šœ œ˜Jšœœ ˜-Jšœ˜Jšœ&˜&Jšœ˜Jšœ ˜ Jšœ˜—Jšœ œ˜)Jšœ˜—Jšœœ ˜-šœ œ˜Jšœ˜Jšœ$˜$Jšœ˜—Jšœ%˜)Jšœœœ˜*Jšœœ˜Jšœ˜Jšœœ ˜Jšœœ˜Jšœ˜—š Ÿœœœœœ˜9Jšœœœœ7˜NJšœ œ0˜>Jšœœœ˜Jšœœ œœ˜?JšœQ˜QJšœ&˜&Jšœ˜—Jšœœ˜#Jšœ˜Jšœž4˜DJšœœ=˜NJš œ œœœœ˜8šœœœœ˜3Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœœ˜Jšœ˜—šœ˜Jšœ œ œ˜7Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜š œœ œœ˜3Jšœœ˜-Jšœ˜Jšœ˜šœ œœ˜;Jšœ˜šœ ˜ Jšœ-˜-Jšœœœœ˜7Jšœ˜J˜—Jšœ˜—Jšœ˜Jšœ˜—J˜—Jšœ˜—Jšœ ˜Jšœ˜—š Ÿœœœ*œœ ˜cJšœœœœ˜7šœ$œ˜,Jšœ#˜#Jšœ˜šœœ˜Jšœ.˜.Jšœ(˜(Jšœœœ˜+Jšœ œœ˜?Jšœœ˜—Jšœ2˜2Jšœ"˜"Jšœu˜{Jšœ˜—šœ˜Jšœ*˜*šŸœœœ œ œ œœ˜eJšœœ˜+šœœœ)˜˜>Jšœ˜—šœ˜šœ)œ˜1Jšœ œ˜Jšœ˜Jšœœœ˜Jšœ˜—Jšœ˜Jšœ˜—Jšœœ˜—Jšœ˜—šŸœœœœœœ œ œ˜KJšœ œœ˜šœ˜šœ ˜ šœ ˜šœœœ˜0Jšœœœ˜)Jšœ&˜&Jšœ˜Jšœ˜—Jšœ ˜Jšœ˜—Jšœ˜—šœ˜šœœœ˜'Jšœ œ˜Jšœ˜Jšœœœ˜Jšœ˜—šœ˜Jšœ(˜(J˜Jšœ˜—Jšœ˜—Jšœœ œ œ˜1—Jšœ˜—šŸœœœœ ˜0šŸœœœ œ œ œœœ˜lJšœ˜Jšœ˜Jšœ˜š˜Jšœ œ˜Jšœœ˜ Jšœœœ˜%Jš œœœœœ˜UJš œœœœœ˜UJšœ˜Jšœ œ/˜?šœœ˜(Jšœœœ˜0Jšœœœ˜0Jšœ œ3œ˜Lšœ˜Jšœ$˜$Jšœ$˜$Jšœœ˜—Jšœ˜—šœœ˜Jšœœ˜/Jšœ!˜!Jšœ!˜!J˜—Jšœ˜—Jšœ˜—šœ ˜Jšœœ˜)Jšœ&œ%˜QJšœœ˜—šœ ˜Jšœœ˜)Jšœ&œ%˜QJšœœ˜—šœ œ ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœœœ˜ —Jšœ˜Jšœ˜—šŸœœœœ ˜/šŸœœœ œ œ œœœ˜lJšœ˜Jšœ˜Jšœ˜šœœ˜&Jšœœ ˜Jšœœ ˜Jšœœœ ˜Jšœ œœ+˜@Jšœœœ˜%šœœ˜'Jšœœœœ˜ Jšœœ˜Jšœœ˜.Jšœœ œ˜;Jšœ˜š˜šœœ˜šœœ˜+Jšœœ˜Jšœ˜Jšœ˜—šœœ˜+Jšœœ˜Jšœ˜Jšœ˜—Jšœœ˜—Jšœ˜—Jšœœ7œ˜RJšœ˜—šœœœœ˜.Jšœœ˜1Jšœ˜Jšœ˜Jšœ˜—Jšœ˜—Jšœ˜—Jšœ˜Jšœ˜—šŸ œœœœ ˜7šŸœœœ œ œ œœœ˜lJšœ˜Jšœ˜Jšœ˜š˜Jšœ œ˜Jšœœ˜ Jšœœœ˜%Jšœœ˜$Jšœ˜Jšœ œ)˜9šœ˜Jšœ:˜:Jšœ˜šœœ˜Jšœœ8˜NJšœ˜Jšœ œ)˜9Jšœ˜—Jšœ˜—Jšœœœ˜Jšœœ˜:Jšœ˜Jšœ œ/˜?Jšœœœ˜Jšœ˜šœ˜Jšœœœ˜0Jšœœœ˜0Jšœ œ3œ˜Lšœ˜Jšœ$˜$šœ˜Jš œœœœœ˜*Jšœ˜Jšœ˜Jš œœœœœœ˜EJšœ˜—Jšœœ˜—Jšœ˜—šœœ˜Jšœœ˜/Jšœ!˜!Jšœ!˜!J˜—Jšœ˜—Jšœ˜—Jšœ˜Jšœ˜—š Ÿœœœœ œ˜CJšœA˜GJšœ˜—š Ÿœœœœœ ˜AJšœA˜GJšœ˜—šŸœœœœ ˜3šœ œ˜Jšœœ œ˜3šœ˜ Jšœ_˜_JšŸœœ.˜;Jšœ ˜ Jšœ˜JšœB˜HJšœ˜——Jšœ˜—š Ÿ œœœœœœ˜GJšœ˜Jšœ˜šœ˜Jšœœ˜!Jšœœ ˜šœ˜Jšœ˜Jšœ˜Jšœ˜—Jšœ˜Jšœ˜—Jšœ˜—šŸœœœœœ œœ˜ZJšœ˜Jšœ˜šœ˜Jšœ:˜:Jšœ˜Jšœ˜—Jšœ˜—š Ÿœœœœœ˜KJšœ˜Jšœ˜šœ˜Jšœœ˜!Jšœœ ˜šœ˜Jšœ;˜;Jšœ˜Jšœ˜—Jšœ˜Jšœ˜—Jšœ˜—šŸœœœœœ œœ˜jJšœ˜Jšœ˜Jšœ˜š˜Jšœœ˜ Jš œœœœœ˜UJš œœœœœ˜UJšœ˜šœœ˜(Jšœœœ˜0Jšœœœ˜0Jšœ œ#˜6šœ˜Jšœ$˜$Jšœ$˜$Jšœœ˜—Jšœ˜—Jšœ˜—Jšœ˜—š Ÿœœœœœ˜[Jšœ˜Jšœ˜Jšœ˜š˜Jšœ œ˜Jšœœ˜ Jš œœœœœ˜UJš œœœœœ˜UJšœ˜Jšœ œ/˜?šœœ˜(Jšœœœ˜0Jšœœœ˜0Jšœ œ3˜Fšœ˜Jšœ$˜$Jšœ$˜$Jšœœ˜—Jšœ˜—šœœ˜Jšœ!˜!Jšœ!˜!J˜—Jšœ˜—Jšœ˜—š Ÿ œœœœœ˜MJšœ˜Jšœœœ˜š Ÿœœœœ œœ˜FJšœœ˜Jšœœ˜Jšœœœœ˜WJšœ˜—šœœœ˜Jšœ˜Jšœ7˜:Jšœ˜Jšœ7˜:Jšœœ ˜Jšœ˜—Jšœ*˜,Jšœ'˜)Jšœ*˜,Jšœ'˜)Jšœœ ˜Jšœ˜Jšœ(˜(Jšœœœ œœ œ œ˜TJšœ˜—šŸœœœœ˜ZJš œœœœœ˜1šœœœ˜,Jšœ œœ˜$Jšœœœ˜*Jšœ˜—Jšœ˜Jšœ˜—šŸœœœa˜vš œœ œœ œ˜_šœœ!˜,Jšœ4˜4šœœ˜ JšœA˜AJšœ%˜%Jšœ_˜_Jšœ%˜%Jšœ˜—JšœW˜[Jšœ˜Jšœ˜—Jšœœ˜—šœ˜ Jšœ˜Jšœ˜šœ˜Jšœœ˜!Jšœœ ˜šœ˜Jšœ^˜^Jšœ˜Jšœ˜—Jšœ˜Jšœ˜—J˜—Jšœ˜—Jšœ˜—…—X,xX