<> <> <> <> DIRECTORY Basics USING [BITSHIFT, bitsPerWord, LongMult], FunctionCache USING [Cache, CompareProc, GlobalCache, Insert, Lookup], ImagerBitmapDevicePrivate USING [grayHeight, GrayArray, Case, Data, DataRep], ImagerBrick USING [Brick, BrickRep, ThresholdsFromBrick], ImagerColorDefs USING [Color, ColorOperator, ConstantColor, ConstantColorImplRep, PixelArray, SampledColor], ImagerColorOperator USING [GetColorOperatorClass, Mapper, MapPixels, NewMapper], ImagerColorPrivate USING [ConstantColorImpl, ConstantColorImplRep, StippleFunction], ImagerDevice USING [BoxProc, Class, ClassRep, Device, DeviceBox, DeviceRep, HalftoneParameters, RunProc], ImagerMask USING [RunsFromBits, RunsFromBox], ImagerPixelArray USING [GetPixels, MaxSampleValue, PixelArray, UnsafeGetBits], ImagerPixelMap USING [BoundedWindow, Clip, Create, CreateTile, Function, PixelMap, PixelMapRep, ShiftMap, Tile, TransferTile], ImagerRaster USING [], ImagerSample USING [GetPointer, GetPointSamples, NewBuffer, Sample, SampleBuffer, Sampler, SamplerRep, SetSamplerIncrements, SetSamplerPosition, SubSamples, UnsafePutF, UnsafePutFSign, UnsafeSamples], ImagerTransformation USING [ApplyCat, ApplyPreRotate, Scale, Transformation, Translate], PrincOps USING [BBTableSpace, BitBltFlags, BitBltTable, BitBltTablePtr, GrayParm, op, zBNDCK, zINC], PrincOpsUtils USING [AlignedBBTable, BITBLT, LongCopy], Real USING [RoundC], Vector2 USING [VEC]; ImagerBitmapDeviceImpl: CEDAR PROGRAM IMPORTS Basics, FunctionCache, ImagerBrick, ImagerColorOperator, ImagerMask, ImagerPixelArray, ImagerPixelMap, ImagerSample, ImagerTransformation, PrincOpsUtils, Real EXPORTS ImagerColorDefs, ImagerRaster ~ BEGIN OPEN ImagerDevice; VEC: TYPE ~ Vector2.VEC; Transformation: TYPE ~ ImagerTransformation.Transformation; Color: TYPE ~ ImagerColorDefs.Color; ConstantColor: TYPE ~ ImagerColorDefs.ConstantColor; SampledColor: TYPE ~ ImagerColorDefs.SampledColor; ColorOperator: TYPE ~ ImagerColorDefs.ColorOperator; PixelArray: TYPE ~ ImagerPixelArray.PixelArray; Sample: TYPE ~ ImagerSample.Sample; SampleBuffer: TYPE ~ ImagerSample.SampleBuffer; UnsafeSamples: TYPE ~ ImagerSample.UnsafeSamples; grayHeight: NAT ~ ImagerBitmapDevicePrivate.grayHeight; GrayArray: TYPE ~ ImagerBitmapDevicePrivate.GrayArray; Case: TYPE ~ ImagerBitmapDevicePrivate.Case; Data: TYPE ~ ImagerBitmapDevicePrivate.Data; DataRep: TYPE ~ ImagerBitmapDevicePrivate.DataRep; grayParm: PrincOps.GrayParm ~ [yOffset: 0, widthMinusOne: 0, heightMinusOne: grayHeight-1]; class: ImagerDevice.Class ~ NEW[ImagerDevice.ClassRep _ [ type: $Bitmap, SetColor: BitmapSetColor, SetPriority: BitmapSetPriority, SetHalftone: BitmapSetHalftone, MaskRuns: BitmapMaskRuns, MaskBoxes: BitmapMaskBoxes, MaskBits: BitmapMaskBits, DrawBits: BitmapDrawBits, MoveBoxes: BitmapMoveBoxes ]]; NewBitmapDevice: PUBLIC PROC[frame: ImagerPixelMap.PixelMap, pixelsPerInch: REAL] RETURNS[Device] ~ { clipped: ImagerPixelMap.PixelMap ~ frame.Clip[frame.BoundedWindow]; data: Data ~ NEW[DataRep _ [sSizeFrame: clipped.sMin+clipped.sSize, fSizeFrame: clipped.fMin+clipped.fSize, frame: clipped.refRep, pixelsPerInch: pixelsPerInch, paToDevice: ImagerTransformation.Scale[0]]]; surfaceToDevice: Transformation ~ ImagerTransformation.Translate[[clipped.sSize-clipped.sOrigin, -clipped.fOrigin]]; surfaceToDevice.ApplyPreRotate[90]; RETURN[NEW[ImagerDevice.DeviceRep _ [class: class, box: [smin: clipped.sMin, fmin: clipped.fMin, smax: clipped.sMin+clipped.sSize, fmax: clipped.sMin+clipped.fSize], surfaceToDevice: surfaceToDevice, surfaceUnitsPerInch: [pixelsPerInch, pixelsPerInch], surfaceUnitsPerPixel: 1, data: data ]]]; }; nullBitBltTable: PrincOps.BitBltTable ~ [ dst: [word: NIL, bit: 0], dstBpl: 0, src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]], width: 0, height: 0, flags: [] ]; bitsPerWord: NAT ~ Basics.bitsPerWord; StippleFunction: TYPE ~ ImagerColorPrivate.StippleFunction; ConstantColorImpl: TYPE ~ ImagerColorPrivate.ConstantColorImpl; ConstantColorImplRep: PUBLIC TYPE ~ ImagerColorPrivate.ConstantColorImplRep; desktopStipple: WORD ~ 01144H; <> <<>> defaultBrick: ImagerBrick.Brick _ InitDefaultBrick[]; InitDefaultBrick: PROC RETURNS [ImagerBrick.Brick] ~ { brick: ImagerBrick.Brick ~ NEW[ImagerBrick.BrickRep[16] _ [ sSize: 4, fSize: 4, phase: 0, u: 1, v: 1, samples: ]]; Val: PROC[n: [1..16]] RETURNS [REAL] ~ { RETURN[(n-0.5)/16.0] }; brick[00] _ Val[01]; brick[01] _ Val[09]; brick[02] _ Val[03]; brick[03] _ Val[11]; brick[04] _ Val[15]; brick[05] _ Val[05]; brick[06] _ Val[13]; brick[07] _ Val[07]; brick[08] _ Val[04]; brick[09] _ Val[12]; brick[10] _ Val[02]; brick[11] _ Val[10]; brick[12] _ Val[14]; brick[13] _ Val[08]; brick[14] _ Val[16]; brick[15] _ Val[06]; RETURN[brick]; }; stippleTableMax: NAT ~ 16; stippleTable: ARRAY [0..stippleTableMax] OF WORD _ [ 0FFFFH, 07FFFH, 07FDFH, 05FDFH, 05F5FH, 05B5FH, 05B5EH, 05A5EH, 05A5AH, 01A5AH, 01A4AH, 00A4AH, 00A0AH, 0080AH, 00802H, 00002H, 00000H ]; StippleFromIntensity: PROC [Y: REAL] RETURNS [WORD] ~ { IF Y<=0 THEN RETURN[WORD.LAST]; -- black IF Y>=1 THEN RETURN[0]; -- white RETURN[stippleTable[Real.RoundC[Y*stippleTableMax]]]; }; grayTable: ARRAY[0..16) OF WORD _ [ 00000H, 01111H, 02222H, 03333H, 04444H, 05555H, 06666H, 07777H, 08888H, 09999H, 0AAAAH, 0BBBBH, 0CCCCH, 0DDDDH, 0EEEEH, 0FFFFH ]; GrayArrayFromStipple: PROC [stipple: WORD] RETURNS [GrayArray] ~ { SELECT stipple FROM WORD.LAST => RETURN[ALL[WORD.LAST]]; 0 => RETURN[ALL[0]]; ENDCASE => { nibbles: PACKED ARRAY [0..4) OF [0..16) ~ LOOPHOLE[stipple]; grayArray: GrayArray; FOR i: NAT IN[0..4) DO grayArray[i] _ grayTable[nibbles[i]] ENDLOOP; RETURN[grayArray]; }; }; sourceLgBitsPerSample: NAT ~ 3; -- for sampled color source oneFlags: PrincOps.BitBltFlags ~ [srcFunc: null, dstFunc: or]; zeroFlags: PrincOps.BitBltFlags ~ [srcFunc: complement, dstFunc: and]; xorFlags: PrincOps.BitBltFlags ~ [srcFunc: null, dstFunc: xor]; BitmapSetColor: PROC[device: Device, color: Color, viewToDevice: Transformation] ~ { data: Data ~ NARROW[device.data]; data.source.refRep _ NIL; WITH color SELECT FROM color: ConstantColor => { impl: ConstantColorImpl ~ color.impl; stipple: WORD _ 0; function: StippleFunction _ replace; data.case _ constant; data.source.refRep _ NIL; data.flags _ [disjoint: TRUE, gray: TRUE]; WITH impl: impl SELECT FROM stipple => { stipple _ impl.word; function _ impl.function }; ENDCASE => stipple _ StippleFromIntensity[impl.Y]; SELECT function FROM replace => NULL; paint => { data.flags.dstFunc _ or }; invert => { data.flags.dstFunc _ xor }; erase => { data.flags.srcFunc _ complement; data.flags.dstFunc _ and }; ENDCASE => ERROR; data.grayArray _ GrayArrayFromStipple[stipple]; IF stipple=WORD.LAST THEN SELECT function FROM replace, paint => data.maskBitsFlags _ oneFlags; invert => data.maskBitsFlags _ xorFlags; erase => data.maskBitsFlags _ zeroFlags; ENDCASE => ERROR ELSE IF stipple=0 THEN SELECT function FROM replace => data.maskBitsFlags _ zeroFlags; paint, invert, erase => data.case _ noop; ENDCASE => ERROR ELSE data.case _ stipple; data.sampledBlack _ data.sampledBlackClear _ FALSE; }; color: SampledColor => { maxSample: CARDINAL _ SetUpSampledColorData[data, color, viewToDevice]; IF data.sampledBlack AND data.paToDevice.form = 3 AND data.paToDevice.integerTrans THEN { IF data.source.fSize >= 32 AND data.source.sMin=0 AND data.source.fMin = 0 THEN { data.tile _ [sOrigin: data.source.sOrigin+data.paToDevice.tx, fOrigin: data.source.fOrigin+data.paToDevice.ty, sSize: data.source.sSize, fSize: data.source.fSize, phase: 0, refRep: data.source.refRep] } ELSE { data.tile _ ImagerPixelMap.CreateTile[pixelMap: ImagerPixelMap.ShiftMap[data.source, data.paToDevice.tx, data.paToDevice.ty], phase: 0, fSizeHint: 32, scratch: data.tile.refRep]; }; data.case _ tile; }; IF data.buffer=NIL OR data.buffer.jSize < data.fSizeFrame THEN data.buffer _ ImagerSample.NewBuffer[1, data.fSizeFrame]; IF NOT data.sampledBlack THEN { br: SampleBuffer ~ ImagerBrick.ThresholdsFromBrick[defaultBrick, maxSample]; brick: SampleBuffer ~ ImagerSample.NewBuffer[br.iSize, data.fSizeFrame]; FOR i: NAT IN[0..br.iSize) DO from: UnsafeSamples ~ br.GetPointer[i, 0, br.jSize]; to: UnsafeSamples ~ brick.GetPointer[i, 0, brick.jSize]; TRUSTED { PrincOpsUtils.LongCopy[from: from, nwords: br.jSize, to: to]; PrincOpsUtils.LongCopy[from: to, nwords: brick.jSize-br.jSize, to: to+br.jSize]; }; ENDLOOP; data.brick _ brick; }; }; ENDCASE => ERROR; -- unknown color variant }; me: REF TEXT ~ "BitDev"; -- a globally unique REF for use as a clientID in the global cache. SetUpSampledColorData: PROC [data: Data, color: SampledColor, viewToDevice: Transformation] RETURNS [max: Sample] ~ { pa: PixelArray ~ color.pa; um: Transformation ~ color.um; colorOperator: ColorOperator ~ color.colorOperator; samplesPerPixel: NAT ~ pa.samplesPerPixel; sSize: NAT ~ pa.sSize; fSize: NAT ~ pa.fSize; maxIn: Sample ~ ImagerPixelArray.MaxSampleValue[pa, 0]; lgBitsPerSample: NAT ~ IF maxIn = 1 AND samplesPerPixel = 1 THEN 0 ELSE sourceLgBitsPerSample; bitsPerSample: NAT ~ Basics.BITSHIFT[1, lgBitsPerSample]; maxSample: Sample ~ Basics.BITSHIFT[1, bitsPerSample]-1; cache: FunctionCache.Cache _ FunctionCache.GlobalCache[]; compare: FunctionCache.CompareProc ~ {RETURN [argument=pa]}; source: REF ImagerPixelMap.PixelMap _ NARROW[FunctionCache.Lookup[cache, compare, me].value]; data.sampledColor _ color; ImagerTransformation.ApplyCat[data.paToDevice, pa.m, um, viewToDevice]; data.case _ sampled; SELECT ImagerColorOperator.GetColorOperatorClass[colorOperator] FROM $SampledBlack => {data.sampledBlack _ TRUE; data.sampledBlackClear _ FALSE}; $SampledBlackClear => {data.sampledBlack _ data.sampledBlackClear _ TRUE}; ENDCASE => data.sampledBlack _ data.sampledBlackClear _ FALSE; IF source = NIL THEN { source _ NEW[ImagerPixelMap.PixelMap _ ImagerPixelMap.Create[lgBitsPerSample, [sMin: 0, fMin: 0, sSize: sSize, fSize: fSize]]]; IF data.sampledBlack THEN TRUSTED { ImagerPixelArray.UnsafeGetBits[pa: pa, i: 0, s: 0, f: 0, dst: [word: source.refRep.pointer, bit: 0], dstBpl: source.refRep.rast*bitsPerWord, width: source.fSize, height: source.sSize]; } ELSE { pixels: SampleBuffer ~ ImagerSample.NewBuffer[samplesPerPixel, fSize]; buffer: SampleBuffer ~ ImagerSample.NewBuffer[1, fSize]; mapper: ImagerColorOperator.Mapper ~ ImagerColorOperator.NewMapper[ op: colorOperator, component: $Intensity, maxIn: maxIn, maxOut: maxSample]; samples: UnsafeSamples ~ buffer.GetPointer[0, 0, fSize]; FOR s: NAT IN[0..sSize) DO ImagerPixelArray.GetPixels[pa: pa, s: s, f: 0, buffer: pixels, count: fSize]; ImagerColorOperator.MapPixels[mapper: mapper, pixels: pixels, buffer: buffer, count: fSize]; TRUSTED { ImagerSample.UnsafePutF[samples: samples, count: fSize, base: source.refRep.pointer, wordsPerLine: source.refRep.rast, bitsPerSample: bitsPerSample, s: s, f: 0] }; ENDLOOP; }; FunctionCache.Insert[cache, pa, source, source.refRep.words, me]; }; data.source _ source^; IF data.sampler=NIL THEN data.sampler _ NEW[ImagerSample.SamplerRep _ []]; data.sampler.base _ source^.refRep.pointer; data.sampler.wordsPerLine _ source.refRep.rast; data.sampler.bitsPerSample _ bitsPerSample; data.sampler.sMin _ source.sMin; data.sampler.fMin _ source.fMin; data.sampler.sSize _ source.sSize; data.sampler.fSize _ source.fSize; ImagerSample.SetSamplerIncrements[data.sampler, data.paToDevice]; RETURN [maxSample] }; BitmapSetPriority: PROC[device: Device, priorityImportant: BOOL] ~ { }; BitmapSetHalftone: PROC[device: Device, halftone: HalftoneParameters] ~ { data: Data ~ NARROW[device.data]; <> }; Check: PROC[x: CARDINAL, max: NAT] RETURNS[NAT] ~ TRUSTED MACHINE CODE { PrincOps.zINC; PrincOps.zBNDCK }; <> BitmapMaskRunsInternal: PROC[data: Data, bounds: DeviceBox, runs: PROC[RunProc]] ~ { sSizeFrame: NAT ~ data.sSizeFrame; fSizeFrame: NAT ~ data.fSizeFrame; frame: REF ImagerPixelMap.PixelMapRep ~ data.frame; base: LONG POINTER ~ frame.pointer; wordsPerLine: NAT ~ frame.rast; SELECT data.case FROM nil => ERROR; -- color not initialized noop => NULL; constant, stipple => TRUSTED { grayBase: LONG POINTER ~ LOOPHOLE[@data.grayArray]; bbspace: PrincOps.BBTableSpace; bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace]; constantRun: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ TRUSTED { f: NAT ~ Check[fMin, fSizeFrame]; s: NAT ~ Check[sMin, sSizeFrame]; bb.dst.word _ base+Basics.LongMult[s, wordsPerLine]+f/bitsPerWord; bb.src.word _ grayBase+(bb.srcDesc.gray.yOffset _ s MOD grayHeight); bb.dst.bit _ bb.src.bit _ f MOD bitsPerWord; bb.width _ Check[fSize, fSizeFrame-f]; bb.height _ Check[1, sSizeFrame-s]; PrincOpsUtils.BITBLT[bb]; }; bb^ _ nullBitBltTable; bb.dstBpl _ wordsPerLine*bitsPerWord; bb.srcDesc.gray _ grayParm; bb.flags _ data.flags; runs[constantRun]; }; tile => { tile: ImagerPixelMap.Tile ~ data.tile; function: ImagerPixelMap.Function ~ IF data.sampledBlackClear THEN [or, null] ELSE [null, null]; tileRun: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ TRUSTED { ImagerPixelMap.TransferTile[ [sOrigin: 0, fOrigin: 0, sMin: sMin, fMin: fMin, sSize: 1, fSize: fSize, refRep: frame], tile, function ]; }; runs[tileRun]; }; sampled => { sampler: ImagerSample.Sampler ~ data.sampler; buffer: SampleBuffer ~ data.buffer; brick: SampleBuffer ~ data.brick; bitmapSampledRun: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ CHECKED { s: NAT ~ Check[sMin, sSizeFrame]; f: NAT ~ Check[fMin, fSizeFrame]; count: NAT ~ Check[fSize, fSizeFrame-f]; ImagerSample.GetPointSamples[sampler: sampler, s: s, f: f, buffer: buffer, bi: 0, bj: f, count: count]; IF data.sampledBlack THEN TRUSTED { ImagerSample.UnsafePutF[samples: buffer.GetPointer[0, f, count], count: count, s: s, f: f, base: base, wordsPerLine: wordsPerLine, bitsPerSample: 1, srcFunc: null, dstFunc: IF data.sampledBlackClear THEN or ELSE null]; } ELSE { ImagerSample.SubSamples[samples: brick, si: s MOD brick.iSize, sj: f, buffer: buffer, bi: 0, bj: f, count: count]; TRUSTED { samples: UnsafeSamples ~ buffer.GetPointer[0, f, count]; ImagerSample.UnsafePutFSign[samples: samples, count: count, s: s, f: f, base: base, wordsPerLine: wordsPerLine]; }; }; }; ImagerSample.SetSamplerPosition[sampler: sampler, m: data.paToDevice, s: bounds.smin, f: bounds.fmin]; runs[bitmapSampledRun]; }; ENDCASE => ERROR; -- illegal case }; BitmapMaskRuns: PROC[device: Device, bounds: DeviceBox, runs: PROC[RunProc]] ~ { data: Data ~ NARROW[device.data]; BitmapMaskRunsInternal[data, bounds, runs]; }; BitmapMaskBoxes: PROC[device: Device, bounds: DeviceBox, boxes: PROC[BoxProc]] ~ { data: Data ~ NARROW[device.data]; sSizeFrame: NAT ~ data.sSizeFrame; fSizeFrame: NAT ~ data.fSizeFrame; frame: REF ImagerPixelMap.PixelMapRep ~ data.frame; SELECT data.case FROM constant, stipple => TRUSTED { base: LONG POINTER ~ frame.pointer; wordsPerLine: NAT ~ frame.rast; grayBase: LONG POINTER ~ LOOPHOLE[@data.grayArray]; bbspace: PrincOps.BBTableSpace; bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace]; bitmapConstantBox: SAFE PROC[box: DeviceBox] ~ TRUSTED { f: NAT ~ Check[box.fmin, fSizeFrame]; s: NAT ~ Check[box.smin, sSizeFrame]; bb.dst.word _ base+Basics.LongMult[s, wordsPerLine]+f/bitsPerWord; bb.src.word _ grayBase+(bb.srcDesc.gray.yOffset _ s MOD grayHeight); bb.dst.bit _ bb.src.bit _ f MOD bitsPerWord; bb.width _ Check[box.fmax, fSizeFrame]-f; bb.height _ Check[box.smax, sSizeFrame]-s; PrincOpsUtils.BITBLT[bb]; }; bb^ _ nullBitBltTable; bb.dstBpl _ wordsPerLine*bitsPerWord; bb.srcDesc.gray _ grayParm; bb.flags _ data.flags; boxes[bitmapConstantBox]; }; tile => { tile: ImagerPixelMap.Tile ~ data.tile; function: ImagerPixelMap.Function ~ IF data.sampledBlackClear THEN [or, null] ELSE [null, null]; tileBox: PROC[box: DeviceBox] ~ TRUSTED { ImagerPixelMap.TransferTile[ dest: [ sOrigin: 0, fOrigin: 0, sMin: box.smin, fMin: box.fmin, sSize: box.smax-box.smin, fSize: box.fmax-box.fmin, refRep: frame ], tile: tile, function: function ]; }; boxes[tileBox]; }; ENDCASE => { bitmapNonConstantBox: PROC[box: DeviceBox] ~ { runs: PROC[run: RunProc] ~ { ImagerMask.RunsFromBox[box: box, run: run] }; BitmapMaskRunsInternal[data: data, bounds: box, runs: runs]; }; boxes[bitmapNonConstantBox]; }; }; BitmapMaskBits: PROC [device: Device, srcBase: LONG POINTER, srcWordsPerLine: NAT, ts, tf: INTEGER, boxes: PROC[BoxProc]] ~ { data: Data ~ NARROW[device.data]; IF data.case=constant THEN TRUSTED { sSizeFrame: NAT ~ data.sSizeFrame; fSizeFrame: NAT ~ data.fSizeFrame; frame: REF ImagerPixelMap.PixelMapRep ~ data.frame; dstBase: LONG POINTER ~ frame.pointer; dstWordsPerLine: NAT ~ frame.rast; bbspace: PrincOps.BBTableSpace; bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace]; fastBox: PROC[box: DeviceBox] ~ TRUSTED { df: NAT ~ Check[box.fmin, fSizeFrame]; ds: NAT ~ Check[box.smin, sSizeFrame]; sf: NAT ~ df-tf; ss: NAT ~ ds-ts; bb.dst.word _ dstBase+Basics.LongMult[ds, dstWordsPerLine]+df/bitsPerWord; bb.dst.bit _ df MOD bitsPerWord; bb.src.word _ srcBase+Basics.LongMult[ss, srcWordsPerLine]+sf/bitsPerWord; bb.src.bit _ sf MOD bitsPerWord; bb.width _ Check[box.fmax, fSizeFrame]-df; bb.height _ Check[box.smax, sSizeFrame]-ds; PrincOpsUtils.BITBLT[bb]; }; bb^ _ nullBitBltTable; bb.dstBpl _ dstWordsPerLine*bitsPerWord; bb.srcDesc.srcBpl _ srcWordsPerLine*bitsPerWord; bb.flags _ data.maskBitsFlags; bb.flags.gray _ FALSE; bb.flags.disjoint _ TRUE; boxes[fastBox]; } ELSE { bitmapMaskBitsBox: PROC[box: DeviceBox] ~ { runs: PROC[run: RunProc] ~ { ImagerMask.RunsFromBits[ base: srcBase, wordsPerLine: srcWordsPerLine, sBits: box.smin-ts, fBits: box.fmin-tf, sRuns: box.smin, fRuns: box.fmin, sSize: box.smax-box.smin, fSize: box.fmax-box.fmin, run: run]; }; BitmapMaskRunsInternal[data: data, bounds: box, runs: runs]; }; boxes[bitmapMaskBitsBox]; }; }; BitmapDrawBits: PROC [device: Device, srcBase: LONG POINTER, srcWordsPerLine: NAT, ts, tf: INTEGER, boxes: PROC[BoxProc]] ~ TRUSTED { data: Data ~ NARROW[device.data]; sSizeFrame: NAT ~ data.sSizeFrame; fSizeFrame: NAT ~ data.fSizeFrame; frame: REF ImagerPixelMap.PixelMapRep ~ data.frame; dstBase: LONG POINTER ~ frame.pointer; dstWordsPerLine: NAT ~ frame.rast; bbspace: PrincOps.BBTableSpace; bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace]; fastBox: PROC[box: DeviceBox] ~ TRUSTED { df: NAT ~ Check[box.fmin, fSizeFrame]; ds: NAT ~ Check[box.smin, sSizeFrame]; sf: NAT ~ df-tf; ss: NAT ~ ds-ts; bb.dst.word _ dstBase+Basics.LongMult[ds, dstWordsPerLine]+df/bitsPerWord; bb.dst.bit _ df MOD bitsPerWord; bb.src.word _ srcBase+Basics.LongMult[ss, srcWordsPerLine]+sf/bitsPerWord; bb.src.bit _ sf MOD bitsPerWord; bb.width _ Check[box.fmax, fSizeFrame]-df; bb.height _ Check[box.smax, sSizeFrame]-ds; PrincOpsUtils.BITBLT[bb]; }; bb^ _ nullBitBltTable; bb.dstBpl _ dstWordsPerLine*bitsPerWord; bb.srcDesc.srcBpl _ srcWordsPerLine*bitsPerWord; bb.flags _ [direction: forward, disjoint: TRUE, disjointItems: FALSE, gray: FALSE, srcFunc: null, dstFunc: null]; boxes[fastBox]; }; BitmapMoveBoxes: PROC [device: Device, ts, tf: INTEGER, boxes: PROC[BoxProc]] ~ TRUSTED { data: Data ~ NARROW[device.data]; sSizeFrame: NAT ~ data.sSizeFrame; fSizeFrame: NAT ~ data.fSizeFrame; frame: REF ImagerPixelMap.PixelMapRep ~ data.frame; base: LONG POINTER ~ frame.pointer; wordsPerLine: NAT ~ frame.rast; bbspace: PrincOps.BBTableSpace; bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace]; moveBox: PROC[box: DeviceBox] ~ TRUSTED { dfmin: NAT ~ Check[box.fmin, fSizeFrame]; dsmin: NAT ~ Check[box.smin, sSizeFrame]; dfmax: NAT ~ Check[box.fmax, fSizeFrame]; dsmax: NAT ~ Check[box.smax, sSizeFrame]; sfmin: NAT ~ dfmin-tf; ssmin: NAT ~ dsmin-ts; sfmax: NAT ~ dfmax-tf; ssmax: NAT ~ dsmax-ts; bpl: INTEGER _ wordsPerLine*bitsPerWord; ss: NAT _ ssmin; ds: NAT _ dsmin; bb.flags _ [disjoint: TRUE, disjointItems: TRUE, direction: forward, gray: FALSE]; IF dsminssmin THEN { bb.flags.disjoint _ FALSE; IF dsmin=ssmin AND dfminsfmin THEN bb.flags.disjointItems _ FALSE; IF dsmin>ssmin OR (dsmin=ssmin AND dfmin>sfmin) THEN { bb.flags.direction _ backward; bpl _ -bpl; ss _ ssmax-1; ds _ dsmax-1; }; }; bb.dst.word _ base+Basics.LongMult[ds, wordsPerLine]+dfmin/bitsPerWord; bb.dst.bit _ dfmin MOD bitsPerWord; bb.dstBpl _ bpl; bb.src.word _ base+Basics.LongMult[ss, wordsPerLine]+sfmin/bitsPerWord; bb.src.bit _ sfmin MOD bitsPerWord; bb.srcDesc.srcBpl _ bpl; bb.width _ dfmax-dfmin; bb.height _ dsmax-dsmin; PrincOpsUtils.BITBLT[bb]; }; bb^ _ nullBitBltTable; boxes[moveBox]; }; <<>> END.