DIRECTORY Basics, ImagerBasic, ImagerManhattan, ImagerPixelMaps, ImagerScanConverter, ImagerTransform, Scaled, ImagerMasks ; ImagerMasksImpl: CEDAR PROGRAM IMPORTS Basics, ImagerManhattan, ImagerPixelMaps, ImagerTransform, ImagerScanConverter, Scaled EXPORTS ImagerMasks ~ BEGIN OPEN ImagerMasks; bitsPerWord: NAT ~ Basics.bitsPerWord; FromRectangle: PUBLIC PROC [box: DeviceRectangle] RETURNS [Mask] ~ { IF box.sSize = 0 OR box.fSize = 0 THEN RETURN [NIL] ELSE RETURN [ImagerManhattan.CreateFromBox[box]] }; FromManhattanPolygon: PUBLIC PROC [polygon: ImagerManhattan.Polygon] RETURNS [Mask] ~ { RETURN [polygon] }; FromBitmap: PUBLIC PROC [pixelMap: PixelMap] RETURNS [Mask] ~ { IF pixelMap.refRep.lgBitsPerPixel # 0 THEN ERROR; IF pixelMap.sSize = 0 OR pixelMap.fSize = 0 THEN RETURN [NIL] ELSE RETURN [NEW[PixelMap _ ImagerPixelMaps.Trim[pixelMap]]]; }; FromDevicePath: PUBLIC PROC [devicePath: DevicePath] RETURNS [Mask] ~ { RETURN [devicePath]; }; FromPixelArray: PUBLIC PROC [pixelArray: PixelArray, compositeTransformation: Transformation] RETURNS [Mask] ~ { IF compositeTransformation = pixelArray.m THEN RETURN [pixelArray] ELSE { copy: PixelArray _ NEW[ImagerBasic.PixelArrayRep _ pixelArray^]; copy.m _ compositeTransformation; RETURN [copy] }; }; BBList: PUBLIC PROC [mask: Mask] RETURNS [LIST OF DeviceRectangle] ~ { RETURN [LIST[BoundingBox[mask]]] }; BoundingBox: PUBLIC PROC [mask: Mask] RETURNS [DeviceRectangle] ~ { WITH mask SELECT FROM polygon: ManhattanPolygon => RETURN [ImagerManhattan.BoundingBox[polygon]]; bitmap: REF PixelMap => RETURN [[bitmap.sOrigin+bitmap.sMin, bitmap.fOrigin+bitmap.fMin, bitmap.sSize, bitmap.fSize]]; devicePath: DevicePath => RETURN [ImagerScanConverter.BoundingBox[devicePath]]; pixelArray: PixelArray => { bb: ImagerBasic.IntRectangle _ ImagerTransform.TransformIntRectangle[ [0, 0, pixelArray.xPixels, pixelArray.yPixels], pixelArray.m ]; RETURN [[bb.x, bb.y, bb.w, bb.h]]; }; ENDCASE => RETURN [[0, 0, 0, 0]]; }; CountRuns: PUBLIC PROC [mask: Mask] RETURNS [numberOfRuns: INT] ~ { WITH mask SELECT FROM polygon: ManhattanPolygon => RETURN [ImagerManhattan.CountRuns[polygon]]; devicePath: DevicePath => RETURN [ImagerScanConverter.NumberOfRuns[devicePath]]; ENDCASE => { RunProc: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ {numberOfRuns _ numberOfRuns+1}; t1: ManhattanPolygon _ ImagerManhattan.CreateFromBox[BoundingBox[mask]]; numberOfRuns _ 0; GenerateRuns[mask, t1, RunProc, 0, 0]; ImagerManhattan.Destroy[t1]; }; }; GenerateRuns: PUBLIC PROC [mask, clipper: Mask, runProc: PROC [sMin, fMin: INTEGER, fSize: NAT], sTranslate, fTranslate: INTEGER] ~ { clipPoly: ManhattanPolygon _ WITH clipper SELECT FROM polygon: ManhattanPolygon => polygon, ENDCASE => ToManhattanPolygon[clipper, BBList[clipper], 0, 0]; remainder: ManhattanPolygon _ clipPoly; TranslateAndClipRunProc: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ { sMin _ sMin + sTranslate; fMin _ fMin + fTranslate; WHILE remainder # NIL AND remainder.first.sMin + remainder.first.sSize <= sMin DO remainder _ remainder.rest; ENDLOOP; FOR l: LIST OF DeviceRectangle _ remainder, l.rest UNTIL l = NIL OR l.first.sMin > sMin DO fMinRun: INTEGER ~ MAX[l.first.fMin, fMin]; fMaxRun: INTEGER ~ MIN[l.first.fMin+l.first.fSize, fMin+fSize]; IF fMaxRun > fMinRun THEN runProc [sMin, fMinRun, fMaxRun-fMinRun]; ENDLOOP; }; WITH mask SELECT FROM polygon: ManhattanPolygon => ImagerManhattan.MapRuns[polygon, TranslateAndClipRunProc]; bitmap: REF PixelMap => { IF clipPoly # NIL AND clipPoly.rest = NIL THEN { BitmapGenerateRuns[bitmap^.ShiftMap[sTranslate, fTranslate].Clip[clipPoly.first], runProc]; } ELSE BitmapGenerateRuns[bitmap^, TranslateAndClipRunProc]; }; devicePath: DevicePath => { IF clipPoly # NIL AND clipPoly.rest = NIL AND sTranslate = 0 AND fTranslate = 0 THEN { devicePath.ConvertToRuns[runProc, clipPoly.first]; } ELSE { devicePath.ConvertToRuns[TranslateAndClipRunProc, ImagerManhattan.BoundingBox[clipPoly]]; }; }; pixelArray: PixelArray => { m: ImagerTransform.TransformationRec _ ImagerTransform.Contents[pixelArray.m]; X: PROC [x, y: REAL] RETURNS [REAL] ~ { RETURN [m.a * x + m.b * y + m.c + sTranslate] }; Y: PROC [x, y: REAL] RETURNS [REAL] ~ { RETURN [m.d * x + m.e * y + m.f + fTranslate] }; PathMap: ImagerScanConverter.PathProc ~ { move[X[0, 0], Y[0, 0]]; line[X[0, pixelArray.yPixels], Y[0, pixelArray.yPixels]]; line[X[pixelArray.xPixels, pixelArray.yPixels], Y[pixelArray.xPixels, pixelArray.yPixels]]; line[X[pixelArray.xPixels, 0], Y[pixelArray.xPixels, 0]]; }; devicePath: DevicePath _ ImagerScanConverter.CreatePath[PathMap, BoundingBox[clipPoly]]; clipPoly _ ToManhattanPolygon[devicePath, clipPoly, 0, 0]; PixelArrayGenerateRuns[pixelArray, runProc, clipPoly]; }; ENDCASE => {IF mask # NIL THEN ERROR}; IF clipPoly # clipper THEN ImagerManhattan.Destroy[clipPoly]; }; BitmapGenerateRuns: PROC [bitmap: PixelMap, runProc: PROC [sMin, fMin: INTEGER, fSize: NAT]] ~ TRUSTED { refRep: REF ImagerPixelMaps.PixelMapRep _ bitmap.refRep; rast: NAT _ refRep.rast; s: INTEGER _ bitmap.sOrigin + MAX[bitmap.sMin, 0]; sMax: INTEGER _ MIN[bitmap.sOrigin + bitmap.sMin + bitmap.sSize, bitmap.sOrigin + refRep.lines]; linePtr: LONG POINTER TO CARDINAL _ refRep.pointer + Basics.LongMult[s-bitmap.sOrigin, rast]; fFirst: NAT _ MAX[bitmap.fMin, 0]; fEnd: NAT _ MAX[MIN[bitmap.fMin+bitmap.fSize, rast*bitsPerWord], 0]; fFirstWord: CARDINAL _ fFirst / bitsPerWord; fFirstBit: CARDINAL _ fFirst MOD bitsPerWord; IF refRep.lgBitsPerPixel # 0 THEN ERROR; WHILE s < sMax DO wordPtr: LONG POINTER TO CARDINAL _ linePtr+fFirstWord; wordsWorth: CARDINAL _ Basics.BITSHIFT[wordPtr^, fFirstBit]; goodBitCount: INTEGER _ bitsPerWord-fFirstBit; f: CARDINAL _ fFirst; someRuns: BOOLEAN _ FALSE; WHILE f < fEnd DO fStart: CARDINAL; WHILE f < fEnd DO IF goodBitCount = bitsPerWord AND wordsWorth = 0 THEN f _ f + bitsPerWord ELSE { f _ f + goodBitCount; WHILE goodBitCount > 0 AND wordsWorth <= LAST[NAT] DO goodBitCount _ goodBitCount-1; wordsWorth _ wordsWorth*2; ENDLOOP; f _ f - goodBitCount; IF goodBitCount > 0 THEN EXIT; goodBitCount _ bitsPerWord; }; wordPtr _ wordPtr + 1; wordsWorth _ wordPtr^; ENDLOOP; fStart _ f; WHILE f < fEnd DO IF goodBitCount = bitsPerWord AND wordsWorth = LAST[CARDINAL] THEN f _ f + bitsPerWord ELSE { f _ f + goodBitCount; WHILE goodBitCount > 0 AND wordsWorth > LAST[NAT] DO goodBitCount _ goodBitCount-1; wordsWorth _ wordsWorth*2; ENDLOOP; f _ f - goodBitCount; IF goodBitCount > 0 THEN EXIT; goodBitCount _ bitsPerWord; }; wordPtr _ wordPtr + 1; wordsWorth _ wordPtr^; ENDLOOP; f _ MIN[f, fEnd]; IF f > fStart THEN runProc[s, fStart+bitmap.fOrigin, f-fStart]; ENDLOOP; s _ s + 1; linePtr _ linePtr + rast; ENDLOOP; }; PixelArrayGenerateRuns: PROC [pixelArray: PixelArray, runProc: PROC [sMin, fMin: INTEGER, fSize: NAT], area: Mask] ~ { buffer: ImagerBasic.PixelBuffer _ NEW[ImagerBasic.PixelBufferRep[BoundingBox[area].fSize+1]]; inverseM: Transformation ~ ImagerTransform.Invert[pixelArray.m]; nextPixel: ImagerBasic.Pair _ ImagerTransform.TransformVec[[0, 1], inverseM]; xDeltaPixel: Scaled.Value _ Scaled.FromReal[nextPixel.x]; yDeltaPixel: Scaled.Value _ Scaled.FromReal[nextPixel.y]; DoRun: PROC [sMin, fMin: INTEGER, fSize: CARDINAL] ~ { start: ImagerBasic.Pair _ ImagerTransform.Transform[[0.5+sMin, 0.5+fMin], inverseM]; xStart: Scaled.Value _ Scaled.FromReal[start.x]; yStart: Scaled.Value _ Scaled.FromReal[start.y]; runStart: NAT _ 0; fRel: NAT _ 0; pixelArray.get[pixelArray, buffer, fSize, 0, xStart, yStart, xDeltaPixel, yDeltaPixel]; WHILE fRel < fSize DO buffer[fSize] _ 0; WHILE buffer[fRel] # 0 DO fRel _ fRel + 1 ENDLOOP; IF fRel > runStart THEN {runProc[sMin, fMin + runStart, fRel - runStart]}; buffer[fSize] _ 1; WHILE buffer[fRel] = 0 DO fRel _ fRel + 1 ENDLOOP; runStart _ fRel; ENDLOOP; }; GenerateRuns[area, area, DoRun, 0, 0]; }; ApplyTile: PUBLIC PROC [mask, clipper: Mask, dest: PixelMap, tile: Tile, function: Function _ [null, null], sTranslate, fTranslate: INTEGER] ~ { RunProc: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ { dest.Clip[[sMin, fMin, 1, fSize]].TransferTile[tile, function]; }; GenerateRuns[mask, clipper, RunProc, sTranslate, fTranslate]; }; ApplyConstant: PUBLIC PROC [mask, clipper: Mask, dest: PixelMap, value: CARDINAL, function: Function _ [null, null], sTranslate, fTranslate: INTEGER] ~ { RunProc: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ { dest.Fill[[sMin, fMin, 1, fSize], value, function]; }; clipPoly: ManhattanPolygon _ WITH clipper SELECT FROM polygon: ManhattanPolygon => polygon, ENDCASE => ToManhattanPolygon[clipper, BBList[clipper], 0, 0]; WITH mask SELECT FROM polygon: ManhattanPolygon => { IF clipPoly # NIL AND clipPoly.rest = NIL THEN { clippedDest: PixelMap _ dest.Clip[clipPoly.first]; FOR l: LIST OF DeviceRectangle _ polygon, l.rest UNTIL l=NIL DO ImagerPixelMaps.Fill[clippedDest, [l.first.sMin+sTranslate, l.first.fMin+fTranslate, l.first.sSize, l.first.fSize], value, function]; ENDLOOP; } ELSE GenerateRuns[mask, clipPoly, RunProc, sTranslate, fTranslate]; }; devicePath: DevicePath => { IF clipPoly # NIL AND clipPoly.rest = NIL AND sTranslate = 0 AND fTranslate = 0 THEN { devicePath.ConvertToPixels[pixelMap: dest.Clip[clipPoly.first], value: value, function: function]; } ELSE GenerateRuns[mask, clipPoly, RunProc, sTranslate, fTranslate]; }; bitmap: REF PixelMap => { IF clipPoly # NIL AND clipPoly.rest = NIL THEN { SELECT TRUE FROM dest.refRep.lgBitsPerPixel = 0 AND function = [null, null] => { pixelMap: PixelMap _ bitmap^; pixelMap.sOrigin _ pixelMap.sOrigin + sTranslate; pixelMap.fOrigin _ pixelMap.fOrigin + fTranslate; IF value MOD 2 = 1 THEN function _ [or, null] ELSE function _ [and, complement]; dest.Clip[clipPoly.first].Transfer[pixelMap, function]; }; bitmap.refRep.lgBitsPerPixel = 0 AND function = [xor, null] => { pixelMap: PixelMap _ bitmap^; IF value MOD 2 = 0 THEN RETURN; pixelMap.sOrigin _ pixelMap.sOrigin + sTranslate; pixelMap.fOrigin _ pixelMap.fOrigin + fTranslate; dest.Clip[clipPoly.first].Transfer[pixelMap, function]; }; ENDCASE => GenerateRuns[mask, clipPoly, RunProc, sTranslate, fTranslate]; } ELSE GenerateRuns[mask, clipPoly, RunProc, sTranslate, fTranslate]; }; ENDCASE => { GenerateRuns[mask, clipPoly, RunProc, sTranslate, fTranslate]; }; IF clipPoly # clipper THEN ImagerManhattan.Destroy[clipPoly]; }; ToPixelMap: PUBLIC PROC [mask, clipper: Mask, sTranslate, fTranslate: INTEGER, scratch: REF ImagerPixelMaps.PixelMapRep] RETURNS [pixelMap: PixelMap] ~ { bb: DeviceRectangle _ BoundingBox[mask]; bb.sMin _ bb.sMin + sTranslate; bb.fMin _ bb.fMin + fTranslate; bb _ ImagerPixelMaps.Intersect[bb, BoundingBox[clipper]]; pixelMap _ ImagerPixelMaps.Reshape[scratch, 0, bb]; ImagerPixelMaps.Clear[pixelMap]; ApplyConstant[mask, clipper, pixelMap, 1, [null, null], sTranslate, sTranslate]; }; ToManhattanPolygon: PUBLIC PROC [mask, clipper: Mask, sTranslate, fTranslate: INTEGER] RETURNS [manhattanPolygon: ManhattanPolygon] ~ { Runs: PROC [ run: PROC [sMin, fMin: INTEGER, fSize: NAT], repeat: PROC [timesToRepeatScanline: NAT] ] ~ { GenerateRuns[mask, clipper, run, sTranslate, fTranslate]; }; manhattanPolygon _ ImagerManhattan.CreateFromRuns[Runs]; }; PixelArrayFromPixelMap: PUBLIC PROC [pixelMap: PixelMap] RETURNS [pixelArray: PixelArray] ~ { pixelArray _ NEW[ImagerBasic.PixelArrayRep]; pixelArray.xPixels _ pixelMap.sSize; pixelArray.yPixels _ pixelMap.fSize; pixelArray.samplesPerPixel _ 1; pixelArray.m _ ImagerTransform.Rotate[0]; pixelArray.data _ NEW[ImagerPixelMaps.PixelMap _ pixelMap]; SELECT pixelMap.refRep.lgBitsPerPixel FROM 0 => { pixelArray.maxSampleValue _ 1; pixelArray.get _ GetOne; }; 1 => { pixelArray.maxSampleValue _ 3; pixelArray.get _ GetTwo; }; 2 => { pixelArray.maxSampleValue _ 15; pixelArray.get _ GetFour; }; 3 => { pixelArray.maxSampleValue _ 255; pixelArray.get _ GetEight; }; 4 => { pixelArray.maxSampleValue _ LAST[CARDINAL]; pixelArray.get _ GetSixteen; }; ENDCASE => ERROR; }; GetOne: PROC [self: ImagerBasic.PixelArray, buffer: ImagerBasic.PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ { pixelArrayRef: REF ImagerPixelMaps.PixelMap ~ NARROW[self.data]; pixelArray: ImagerPixelMaps.PixelMap ~ pixelArrayRef^; IF layer#0 THEN ERROR; FOR i: NAT IN [0..nSamples) DO WHILE yStart.Floor < 0 DO yStart _ yStart.PLUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE yStart.Floor >= pixelArray.fSize DO yStart _ yStart.MINUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE xStart.Floor < 0 DO xStart _ xStart.PLUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; WHILE xStart.Floor >= pixelArray.sSize DO xStart _ xStart.MINUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; buffer[i] _ pixelArray.GetBit[xStart.Floor, yStart.Floor]; xStart _ xStart.PLUS[xDelta]; yStart _ yStart.PLUS[yDelta]; ENDLOOP; }; GetTwo: PROC [self: ImagerBasic.PixelArray, buffer: ImagerBasic.PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ { pixelArrayRef: REF ImagerPixelMaps.PixelMap ~ NARROW[self.data]; pixelArray: ImagerPixelMaps.PixelMap ~ pixelArrayRef^; IF layer#0 THEN ERROR; FOR i: NAT IN [0..nSamples) DO WHILE yStart.Floor < 0 DO yStart _ yStart.PLUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE yStart.Floor >= pixelArray.fSize DO yStart _ yStart.MINUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE xStart.Floor < 0 DO xStart _ xStart.PLUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; WHILE xStart.Floor >= pixelArray.sSize DO xStart _ xStart.MINUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; buffer[i] _ pixelArray.Get2Bits[xStart.Floor, yStart.Floor]; xStart _ xStart.PLUS[xDelta]; yStart _ yStart.PLUS[yDelta]; ENDLOOP; }; GetFour: PROC [self: ImagerBasic.PixelArray, buffer: ImagerBasic.PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ { pixelArrayRef: REF ImagerPixelMaps.PixelMap ~ NARROW[self.data]; pixelArray: ImagerPixelMaps.PixelMap ~ pixelArrayRef^; IF layer#0 THEN ERROR; FOR i: NAT IN [0..nSamples) DO WHILE yStart.Floor < 0 DO yStart _ yStart.PLUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE yStart.Floor >= pixelArray.fSize DO yStart _ yStart.MINUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE xStart.Floor < 0 DO xStart _ xStart.PLUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; WHILE xStart.Floor >= pixelArray.sSize DO xStart _ xStart.MINUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; buffer[i] _ pixelArray.Get4Bits[xStart.Floor, yStart.Floor]; xStart _ xStart.PLUS[xDelta]; yStart _ yStart.PLUS[yDelta]; ENDLOOP; }; GetEight: PROC [self: ImagerBasic.PixelArray, buffer: ImagerBasic.PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ { pixelArrayRef: REF ImagerPixelMaps.PixelMap ~ NARROW[self.data]; pixelArray: ImagerPixelMaps.PixelMap ~ pixelArrayRef^; IF layer#0 THEN ERROR; FOR i: NAT IN [0..nSamples) DO WHILE yStart.Floor < 0 DO yStart _ yStart.PLUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE yStart.Floor >= pixelArray.fSize DO yStart _ yStart.MINUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE xStart.Floor < 0 DO xStart _ xStart.PLUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; WHILE xStart.Floor >= pixelArray.sSize DO xStart _ xStart.MINUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; buffer[i] _ pixelArray.Get8Bits[xStart.Floor, yStart.Floor]; xStart _ xStart.PLUS[xDelta]; yStart _ yStart.PLUS[yDelta]; ENDLOOP; }; GetSixteen: PROC [self: ImagerBasic.PixelArray, buffer: ImagerBasic.PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ { pixelArrayRef: REF ImagerPixelMaps.PixelMap ~ NARROW[self.data]; pixelArray: ImagerPixelMaps.PixelMap ~ pixelArrayRef^; IF layer#0 THEN ERROR; FOR i: NAT IN [0..nSamples) DO WHILE yStart.Floor < 0 DO yStart _ yStart.PLUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE yStart.Floor >= pixelArray.fSize DO yStart _ yStart.MINUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE xStart.Floor < 0 DO xStart _ xStart.PLUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; WHILE xStart.Floor >= pixelArray.sSize DO xStart _ xStart.MINUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; buffer[i] _ pixelArray.Get16Bits[xStart.Floor, yStart.Floor]; xStart _ xStart.PLUS[xDelta]; yStart _ yStart.PLUS[yDelta]; ENDLOOP; }; END. FImagerMasksImpl.mesa Michael Plass, January 16, 1984 2:14 pm ApplyConstantUsingRuns: PROC [mask: Mask, dest: PixelMap, value: CARDINAL, function: Function] ~ TRUSTED { lgBitsPerPixel: INTEGER ~ dest.refRep.lgBitsPerPixel; lgPixelsPerWord: INTEGER ~ lgBitsPerWord-lgBitsPerPixel; rast: CARDINAL ~ dest.refRep.rast; sMinClip: INTEGER ~ MAX[ INT[mask.sOrigin]+mask.sMin, INT[dest.sOrigin]+dest.sMin, dest.sOrigin ]; sMaxClip: INTEGER ~ MIN[ INT[mask.sOrigin]+mask.sMin+mask.sSize, INT[dest.sOrigin]+dest.sMin+dest.sSize, dest.sOrigin+dest.refRep.lines ]; fMinClip: INTEGER ~ MAX[ INT[mask.fOrigin]+mask.fMin, INT[dest.fOrigin]+dest.fMin, dest.fOrigin ]; fMaxClip: INTEGER ~ MIN[ INT[mask.fOrigin]+mask.fMin+mask.fSize, INT[dest.fOrigin]+dest.fMin+dest.fSize, INT[dest.fOrigin]+Shift[rast, lgBitsPerWord-lgBitsPerPixel] ]; IF sMaxClip>sMinClip AND fMaxClip>fMinClip THEN { fMinBufferLimit: INTEGER ~ MAX[dest.fMin, 0]; fMaxBufferLimit: INTEGER ~ MIN[dest.fMin+dest.fSize, Shift[rast, lgBitsPerWord-lgBitsPerPixel]]; replicatedPixel: CARDINAL _ Basics.BITAND[value, Shift[1, Shift[1, lgBitsPerPixel]]-1] * replicator[lgBitsPerPixel]; bbTableSpace: BitBlt.BBTableSpace; bb: BitBlt.BBptr _ BitBlt.AlignedBBTable[@bbTableSpace]; bitMask: CARDINAL _ Shift[1, lgPixelsPerWord]-1; s: INTEGER _ sMinClip; linePtr: LONG POINTER _ dest.refRep.pointer+Basics.LongMult[rast, sMinClip-dest.sOrigin]; RunProc: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ TRUSTED { fMinBuffer: NAT _ fMin-dest.fOrigin; IF fMin + fSize > fMaxClip THEN ERROR; IF NOT (sMin IN [s..sMaxClip)) THEN ERROR; WHILE s { IF dest.refRep.lgBitsPerPixel = 0 THEN { sMin: INTEGER ~ MAX[dest.sOrigin+MAX[dest.sMin, 0], mask.sOrigin+MAX[mask.sMin, 0]]; sMax: INTEGER ~ MIN[dest.sOrigin+MIN[dest.sMin+dest.sSize, dest.refRep.lines], mask.sOrigin+MIN[mask.sMin+mask.sSize, refRep.lines]]; fMin: INTEGER ~ MAX[dest.fOrigin+MAX[dest.fMin, 0], mask.fOrigin+MAX[mask.fMin, 0]]; fMax: INTEGER ~ MIN[dest.fOrigin+MIN[dest.fMin+dest.fSize, dest.refRep.rast * bitsPerWord], mask.fOrigin+MIN[mask.fMin+mask.fSize, refRep.rast * bitsPerWord]]; bbTableSpace: BitBlt.BBTableSpace; bb: BitBlt.BBptr ~ BitBlt.AlignedBBTable[@bbTableSpace]; fMinDest: NAT ~ fMin - dest.fOrigin; fMinSource: NAT ~ fMin - mask.fOrigin; sStartDest: NAT ~ sMin-dest.sOrigin; sStartSource: NAT ~ sMin-mask.sOrigin; srcFunc: BitBlt.SrcFunc _ null; dstFunc: BitBlt.DstFunc _ or; IF function.srcFunc = complement THEN value _ 1-value; IF value MOD 2 = 0 THEN { IF function.dstFunc = xor THEN RETURN; srcFunc _ complement; dstFunc _ and; }; IF function.dstFunc = xor THEN dstFunc _ xor; IF sMin ERROR; }; Ê´˜J™J™'J˜šÏk ˜ J˜Jšœ ˜ J˜Jšœ˜Jšœ˜J˜J˜J˜ J˜J˜—šœ ˜JšœW˜^Jšœœœ ˜-—J˜šœ œ˜&J˜—šÏn œœœœ ˜DJš œœœœœ˜3Jšœœ%˜0Jšœ˜J˜—šžœœœ$œ ˜WJšœ ˜Jšœ˜J˜—šž œœœœ ˜?Jšœ$œœ˜1Jš œœœœœ˜=Jšœœœ-˜=Jšœ˜J˜—šžœœœœ ˜GJšœ˜Jšœ˜J˜—šžœœœCœ ˜pJšœ(œœ ˜Bšœ˜Jšœœ*˜@Jšœ!˜!Jšœ˜ Jšœ˜—Jšœ˜J˜—š žœœœœœœ˜FJšœœ˜ Jšœ˜J˜—šž œœœœ˜Cšœœ˜Jšœœ(˜KJšœœ œX˜vJšœœ/˜Ošœ˜šœE˜EJšœ/˜/Jšœ ˜ Jšœ˜—Jšœ˜"Jšœ˜—Jšœœ˜!—Jšœ˜J˜—š ž œœœœœ˜Cšœœ˜Jšœœ&˜IJšœœ0˜Pšœ˜ šžœœœ œ˜1Jšœ ˜ —JšœH˜HJšœ˜Jšœ&˜&Jšœ˜Jšœ˜——Jšœ˜J˜—šž œœœ œœ œœ˜…šœœ œ˜5J˜%Jšœ7˜>—Jšœ'˜'šžœœœ œ˜CJšœ˜Jšœ˜šœ œœ6˜QJšœ˜Jš˜—š œœœ%œœœ˜ZJšœ œœ˜+Jšœ œœ)˜?Jšœœ*˜CJš˜—Jšœ˜—šœœ˜JšœW˜Wšœœ˜š œ œœœœ˜0Jšœ[˜[Jšœ˜—Jšœ6˜:Jšœ˜—šœ˜šœ œœœœœœ˜VJšœ2˜2Jšœ˜—šœ˜JšœY˜YJšœ˜—Jšœ˜—šœ˜JšœN˜Nš žœœœœœ˜'Jšœ'˜-Jšœ˜—š žœœœœœ˜'Jšœ'˜-Jšœ˜—šžœ"˜)Jšœ˜Jšœ9˜9Jšœ[˜[Jšœ9˜9Jšœ˜—JšœX˜XJšœ:˜:Jšœ6˜6Jšœ˜—Jš œœœœœ˜&—Jšœœ#˜=Jšœ˜J˜—š žœœœœ œœ˜hJšœœ-˜8Jšœœ˜Jšœœœ˜2JšœœœM˜`Jš œ œœœœ<˜]Jšœœœ˜"Jšœœœœ1˜DJšœ œ˜,Jšœ œ œ ˜-Jšœœœ˜(šœ ˜Jš œ œœœœ˜7Jšœ œ œ˜—šœœ˜šœ˜š œ œœœœ˜0Jšœ2˜2š œœœ#œœ˜?Jšœ…˜…Jš˜—Jšœ˜—Jšœ?˜CJšœ˜—šœ˜šœ œœœœœœ˜VJšœb˜bJ˜—Jšœ>˜CJšœ˜—šœœ˜š œ œœœœ˜0šœœ˜šœœ˜?Jšœ˜Jšœ1˜1Jšœ1˜1Jšœœœ˜-Jšœ˜"Jšœ7˜7Jšœ˜—šœ!œ˜@Jšœ˜Jšœœœœ˜Jšœ1˜1Jšœ1˜1Jšœ7˜7Jšœ˜—JšœB˜I—Jšœ˜—Jšœ?˜CJšœ˜—šœ˜ Jšœ>˜>Jšœ˜——Jšœœ#˜=Jšœ˜J˜—š ž œœœ/œ œ˜xJšœ˜ Jšœ(˜(Jšœ˜Jšœ˜Jšœ9˜9Jšœ3˜3Jšœ ˜ JšœP˜PJšœ˜J˜—š žœœœ/œœ)˜‡šžœœ˜ Jšœœœ œ˜,Jšœœœ˜)Jšœ˜Jšœ9˜9Jšœ˜—Jšœ8˜8Jšœ˜J˜—šžœœœœ˜]Jšœ œ˜,Jšœ$˜$Jšœ$˜$Jšœ˜Jšœ)˜)Jšœœ&˜;šœ ˜*˜Jšœ˜Jšœ˜J˜—˜Jšœ˜Jšœ˜J˜—˜Jšœ˜Jšœ˜J˜—˜Jšœ ˜ Jšœ˜J˜—˜Jšœœœ˜+Jšœ˜J˜—Jšœœ˜—Jšœ˜J˜—šžœœKœ œA˜§Jšœœœ ˜@Jšœ6˜6Jšœ œœ˜šœœœ˜šœ˜Jšœœ#˜7Jšœ˜—šœ"˜)Jšœœ#˜8Jšœ˜—šœ˜Jšœœ#˜7Jšœ˜—šœ"˜)Jšœœ#˜8Jšœ˜—Jšœ:˜:Jšœœ ˜Jšœœ ˜Jšœ˜—J˜J˜—šžœœKœ œA˜§Jšœœœ ˜@Jšœ6˜6Jšœ œœ˜šœœœ˜šœ˜Jšœœ#˜7Jšœ˜—šœ"˜)Jšœœ#˜8Jšœ˜—šœ˜Jšœœ#˜7Jšœ˜—šœ"˜)Jšœœ#˜8Jšœ˜—Jšœ<˜