DIRECTORY Basics USING [BITSHIFT, bitsPerWord, LongMult], ImagerManhattan USING [BoundingBox, CountRuns, CreateFromBox, CreateFromRuns, Destroy, MapRuns, Polygon], ImagerMasks USING [DevicePath, DeviceRectangle, Function, ManhattanPolygon, Mask, PixelMap, Tile, Transformation], ImagerPixelArrays USING [PixelArray, PixelArrayRep], ImagerPixelMaps USING [Clear, Clip, Fill, Intersect, PixelMap, PixelMapRep, Reshape, ShiftMap, Transfer, TransferTile, Trim], ImagerScanConverter USING [BoundingBox, ConvertToPixels, ConvertToRuns, NumberOfRuns], ImagerTransform USING [IntRectangle, TransformIntRectangle], Real USING []; ImagerMasksImpl: CEDAR PROGRAM IMPORTS Basics, ImagerManhattan, ImagerPixelMaps, ImagerTransform, ImagerScanConverter EXPORTS ImagerMasks ~ BEGIN OPEN ImagerMasks; PixelArray: TYPE ~ ImagerPixelArrays.PixelArray; PixelArrayRep: TYPE ~ ImagerPixelArrays.PixelArrayRep; 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[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: ImagerTransform.IntRectangle _ pixelArray.m.TransformIntRectangle[ [0, 0, pixelArray.sPixels, pixelArray.fPixels]]; 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]]; }; }; 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; }; 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]; }; END. ,4ImagerMasksImpl.mesa Copyright c 1984 Xerox Corporation. All rights reserved. Michael Plass, January 16, 1984 2:14 pm Doug Wyatt, August 10, 1984 4:56:21 pm PDT 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]; }; 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]; }; 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; }; 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šœ Ïmœ.™9J™'J™*—J˜šÏk ˜ Jšœžœžœ˜/JšœžœT˜iJšœ žœa˜rJšœžœ˜4Jšœžœh˜}Jšœžœ=˜VJšœžœ'˜—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šœ<™