<> <> <> <<>> DIRECTORY II, IIOps, IIPixelMap, IIPixelArray, IITransformation, Terminal, IIBitmapDevicePrivate, IIDitheredDevicePrivate, IIColor24DevicePrivate, IIRasterPrivate, IIDevice, IIState, Vector2, IIManhattan, IIManhattanExtras, IIBackdoor, IIPixelArrayDefs, IISample, UnsafeStorage, IIPixelArrayPrivate, PrincOps, Basics, PrincOpsUtils; IIOpsImpl: CEDAR MONITOR IMPORTS II, IIPixelMap, IITransformation, IIRasterPrivate, IIManhattan, IIManhattanExtras, IIBackdoor, IISample, UnsafeStorage, Basics, PrincOpsUtils, IIPixelArray, Terminal EXPORTS IIOps, II, IIPixelArrayDefs ~ BEGIN Context: TYPE ~ II.Context; VEC: TYPE ~ Vector2.VEC; Color: TYPE ~ II.Color; PixelArray: TYPE ~ IIPixelArray.PixelArray; PixelMap: TYPE ~ IIPixelMap.PixelMap; DeviceRectangle: TYPE ~ IIPixelMap.DeviceRectangle; Transformation: TYPE ~ IITransformation.Transformation; Rectangle: TYPE ~ IITransformation.Rectangle; FrameBuffer: TYPE ~ Terminal.FrameBuffer; Virtual: TYPE ~ Terminal.Virtual; Kind: TYPE ~ ATOM; State: TYPE ~ IIState.State; StateRep: PUBLIC TYPE ~ IIState.StateRep; -- export to II.StateRep PixelArrayFromPixelMaps: PUBLIC PROC [pms: LIST OF PixelMap, um: Transformation] RETURNS [PixelArray] ~ { w: DeviceRectangle ~ IIPixelMap.BoundedWindow[pms.first]; samplesPerPixel: INT _ 0; FOR p: LIST OF PixelMap _ pms.rest, p.rest UNTIL p=NIL DO IF w # IIPixelMap.BoundedWindow[p.first] THEN ERROR II.Error[[$specification, "Pixel map windows do not match."]]; ENDLOOP; FOR p: LIST OF PixelMap _ pms, p.rest UNTIL p=NIL DO samplesPerPixel _ samplesPerPixel + 1; p.first _ IIPixelMap.ShiftMap[p.first, -w.sMin, -w.fMin]; ENDLOOP; RETURN [NEW[IIPixelArrayDefs.PixelArrayRep _ [ samplesPerPixel: samplesPerPixel, sSize: w.sSize, fSize: w.fSize, m: IITransformation.PostTranslate[um, [w.sMin, w.fMin]], impl: NIL, class: pixelArrayClass, data: pms ]]]; }; PixelArrayClass: TYPE ~ IIPixelArrayPrivate.PixelArrayClass; PixelArrayClassRep: PUBLIC TYPE ~ IIPixelArrayPrivate.PixelArrayClassRep; pixelArrayClass: PixelArrayClass ~ NEW[PixelArrayClassRep _ [ type: $PixelMaps, MaxSampleValue: PmsMaxSampleValue, UnsafeGetSamples: PmsUnsafeGetSamples, UnsafeGetBits: PmsUnsafeGetBits ]]; GetPM: PROC [pa: PixelArray, i: NAT] RETURNS [PixelMap] ~ { pms: LIST OF PixelMap _ NARROW[pa.data]; THROUGH [0..Basics.BoundsCheck[i, pa.samplesPerPixel]) DO pms _ pms.rest ENDLOOP; RETURN [pms.first]; }; PmsMaxSampleValue: PROC [pa: PixelArray, i: NAT] RETURNS [IIPixelArray.Sample] ~ { pm: PixelMap ~ GetPM[pa, i]; RETURN [Basics.BITSHIFT[1, Basics.BITSHIFT[1, pm.refRep.lgBitsPerPixel]]-1]; }; PmsUnsafeGetSamples: UNSAFE PROC [pa: PixelArray, i: NAT, s, f: INT, samples: IISample.UnsafeSamples, count: NAT] ~ UNCHECKED { pm: PixelMap ~ GetPM[pa, i]; IISample.UnsafeGetF[samples: samples, count: count, base: pm.refRep.pointer, wordsPerLine: pm.refRep.rast, bitsPerSample: Basics.BITSHIFT[1, pm.refRep.lgBitsPerPixel], s: s-pm.sOrigin, f: f-pm.fOrigin]; }; bitsPerWord: NAT ~ Basics.bitsPerWord; PmsUnsafeGetBits: UNSAFE PROC [pa: PixelArray, i: NAT _ 0, s, f: INT, dst: PrincOps.BitAddress, dstBpl: INTEGER, width, height: CARDINAL, srcFunc: PrincOps.SrcFunc _ null, dstFunc: PrincOps.DstFunc _ null] ~ UNCHECKED { source: PixelMap ~ GetPM[pa, i]; sStartSource: NAT ~ s-source.sOrigin; fMinSource: NAT ~ f-source.fOrigin; bbTableSpace: PrincOps.BBTableSpace; bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace]; [] _ Basics.BoundsCheck[width, source.fSize+1]; [] _ Basics.BoundsCheck[height, source.sSize+1]; [] _ Basics.BoundsCheck[source.refRep.lgBitsPerPixel, 1]; bb^ _ [ dstBpl: dstBpl, srcDesc: [srcBpl[source.refRep.rast*bitsPerWord]], height: height, width: width, flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: FALSE, srcFunc: srcFunc, dstFunc: dstFunc], dst: dst, src: [word: (source.refRep.pointer + Basics.LongMult[sStartSource, source.refRep.rast] + (fMinSource/bitsPerWord)), bit: fMinSource MOD bitsPerWord] ]; PrincOpsUtils.BITBLT[bb]; }; PixelMapFromPixelArray: PUBLIC PROC [pa: PixelArray, i: NAT] RETURNS [PixelMap] ~ { IF pa.class = pixelArrayClass THEN RETURN [GetPM[pa, i]] ELSE { max: INT ~ IIPixelArray.MaxSampleValue[pa, i]; bitsPerSample: NAT ~ Lg[max+1]; pm: PixelMap ~ IIPixelMap.Create[Lg[bitsPerSample], [0, 0, pa.sSize, pa.fSize]]; IIPixelMap.Clear[pm]; IF bitsPerSample = 1 THEN TRUSTED { IIPixelArray.UnsafeGetBits[pa: pa, i: i, s: 0, f: 0, dst: [word: pm.refRep.pointer, bit: 0], dstBpl: pm.refRep.rast*bitsPerWord, width: pm.fSize, height: pm.sSize, srcFunc: null, dstFunc: null] } ELSE TRUSTED { tZone: UNCOUNTED ZONE ~ UnsafeStorage.GetTransientPageUZone[]; buf: IISample.UnsafeSamples _ tZone.NEW[IISample.RawSamples[pm.fSize]]; base: LONG POINTER ~ pm.refRep.pointer; wpl: NAT ~ pm.refRep.rast; FOR line: NAT IN [0..pm.sSize) DO IIPixelArray.UnsafeGetSamples[pa: pa, i: i, s: line, f: 0, samples: buf, count: pm.fSize]; IISample.UnsafePutF[samples: buf, count: pm.fSize, s: line, f: 0, base: base, wordsPerLine: wpl, bitsPerSample: bitsPerSample, srcFunc: null, dstFunc: null]; ENDLOOP; tZone.FREE[@buf]; }; RETURN [pm]; }; }; KindOf: PUBLIC PROC [context: Context] RETURNS [Kind] ~ { WITH context.data SELECT FROM rasterData: IIRasterPrivate.Data => { device: IIDevice.Device ~ rasterData.device; WITH device.data SELECT FROM bitmap: IIBitmapDevicePrivate.Data => RETURN [$Bitmap]; dithered: IIDitheredDevicePrivate.Data => RETURN [$Dithered]; fullColor: IIColor24DevicePrivate.Data => RETURN [$Color24]; ENDCASE => NULL; }; ENDCASE => NULL; RETURN [NIL] }; SurfaceToDevice: PUBLIC PROC [context: Context] RETURNS [Transformation] ~ { WITH context.data SELECT FROM rasterData: IIRasterPrivate.Data => { device: IIDevice.Device ~ rasterData.device; RETURN [device.surfaceToDevice]; }; ENDCASE => NULL; RETURN [NIL]; }; knownKinds: LIST OF Kind _ LIST [$Bitmap, $Dithered, $Color24]; KnownKinds: PUBLIC PROC RETURNS [LIST OF Kind] ~ {RETURN [knownKinds]}; TerminalFromContext: PUBLIC PROC [context: Context] RETURNS [vt: Virtual, color: BOOL] ~ { WITH context.data SELECT FROM rasterData: IIRasterPrivate.Data => { device: IIDevice.Device ~ rasterData.device; WITH device.data SELECT FROM bitmap: IIBitmapDevicePrivate.Data => { vt: Virtual ~ Terminal.Current[]; fb: Terminal.FrameBuffer ~ Terminal.GetBWFrameBuffer[vt]; IF fb = NIL OR fb.base # bitmap.frame.pointer THEN RETURN [NIL, FALSE] ELSE RETURN [vt, FALSE] }; dithered: IIDitheredDevicePrivate.Data => RETURN [dithered.terminal, TRUE]; fullColor: IIColor24DevicePrivate.Data => RETURN [fullColor.terminal, TRUE]; ENDCASE => NULL; }; ENDCASE => NULL; RETURN [NIL, FALSE]; }; Lg: PROC [n: INT] RETURNS [lg: NAT _ 0] ~ { nn: LONG CARDINAL ~ n; k: LONG CARDINAL _ 1; UNTIL k=0 OR k>= nn DO lg _ lg + 1; k _ k + k; ENDLOOP; }; PixelMapFromFrameBuffer: PUBLIC PROC [frameBuffer: FrameBuffer] RETURNS [PixelMap] ~ { refRep: REF IIPixelMap.PixelMapRep ~ NEW[IIPixelMap.PixelMapRep _ [ ref: frameBuffer, pointer: frameBuffer.base, words: INT[frameBuffer.wordsPerLine]*INT[frameBuffer.height], lgBitsPerPixel: Lg[frameBuffer.bitsPerPixel], rast: frameBuffer.wordsPerLine, lines: frameBuffer.height ]]; pixelMap: IIPixelMap.PixelMap ~ [ sOrigin: 0, fOrigin: 0, sMin: 0, fMin: 0, sSize: frameBuffer.height, fSize: frameBuffer.width, refRep: refRep ]; RETURN[pixelMap]; }; PixelMapsFromContext: PUBLIC PROC [context: Context] RETURNS [LIST OF PixelMap] ~ { WITH context.data SELECT FROM rasterData: IIRasterPrivate.Data => { device: IIDevice.Device ~ rasterData.device; WITH device.data SELECT FROM bitmap: IIBitmapDevicePrivate.Data => RETURN [LIST[[sOrigin: 0, fOrigin: 0, sMin: 0, fMin: 0, sSize: bitmap.sSizeFrame, fSize: bitmap.fSizeFrame, refRep: bitmap.frame]]]; dithered: IIDitheredDevicePrivate.Data => RETURN [LIST[dithered.frame]]; fullColor: IIColor24DevicePrivate.Data => RETURN [LIST[PixelMapFromFrameBuffer[fullColor.frame[A]], PixelMapFromFrameBuffer[fullColor.frame[B]]]]; ENDCASE => NULL; }; ENDCASE => NULL; RETURN [NIL]; }; Validate: PROC [context: Context, data: IIRasterPrivate.Data, needs: IIRasterPrivate.Flags] ~ INLINE { state: IIState.State ~ context.state; IF state.changed#IIState.notChanged THEN IIRasterPrivate.NoteStateChanges[data, state]; IF IIRasterPrivate.AndFlags[data.valid, needs]#needs THEN IIRasterPrivate.ValidateIfNeeded[data, state, needs]; }; DoSaveClipRectangleI: PROC [context: Context, action: PROC, x, y, w, h: INTEGER] ~ { clippedAction: PROC ~ { II.ClipRectangleI[context, x, y, w, h]; action[]; }; WITH context.data SELECT FROM rasterData: IIRasterPrivate.Data => { clientToDevice: Transformation; Validate[context, rasterData, [clientToDevice: TRUE]]; clientToDevice _ rasterData.clientToDevice; IF clientToDevice.form=9 AND clientToDevice.integerTrans AND NOT rasterData.specialClipPresent THEN { smin: INT _ INT[clientToDevice.tx]-y; smax: INT _ smin-h; fmin: INT _ INT[clientToDevice.ty]+x; fmax: INT _ fmin+w; IF smax rasterData.specialClipPresent _ rasterData.valid.clientClipper _ FALSE]; rasterData.specialClipPresent _ rasterData.valid.clientClipper _ FALSE; RETURN; }; }; ENDCASE => NULL; II.DoSave[context, clippedAction]; }; DoWithBuffer: PUBLIC PROC [context: Context, action: PROC, x, y, w, h: INTEGER, backgroundColor: Color _ NIL] ~ { paintBack: PROC ~ { II.SetColor[context, backgroundColor]; II.MaskRectangleI[context, x, y, w, h]; }; clippedAction: PROC ~ { IF bufferingOn THEN WITH context.data SELECT FROM rasterData: IIRasterPrivate.Data => { Validate[context, rasterData, [clientClipper: TRUE]]; IF rasterData.clientClipBoxOnly THEN { device: IIDevice.Device ~ rasterData.device; WITH device.data SELECT FROM bitmapData: IIBitmapDevicePrivate.Data => { IF DoWithBitmapBuffer[context, action, backgroundColor, rasterData, bitmapData] THEN RETURN; }; ditheredData: IIDitheredDevicePrivate.Data => { IF DoWithDitheredBuffer[context, action, backgroundColor, rasterData, ditheredData] THEN RETURN; }; fullColorData: IIColor24DevicePrivate.Data => { }; ENDCASE => NULL; }; }; ENDCASE => NULL; IF backgroundColor # NIL THEN II.DoSave[context, paintBack]; action[]; }; DoSaveClipRectangleI[context, clippedAction, x, y, w, h]; }; DeviceBoxFromDeviceRectangle: PROC [r: IIPixelMap.DeviceRectangle] RETURNS [IIDevice.DeviceBox] ~ { RETURN[[smin: r.sMin, smax: r.sMin+r.sSize, fmin: r.fMin, fmax: r.fMin+r.fSize]]; }; DoWithShift: PROC [rasterData: IIRasterPrivate.Data, action: PROC, sDelta, fDelta: INTEGER] ~ { <> delta: VEC ~ [sDelta, fDelta]; minusDelta: VEC ~ [-delta.x, -delta.y]; true: BOOL[TRUE..TRUE] ~ rasterData.valid.clientClipper; savedClipMask: IIManhattan.Polygon ~ rasterData.viewClipMask; savedDeviceBox: IIDevice.DeviceBox ~ rasterData.device.box; Restore: PROC ~ { minusDelta: VEC ~ [-delta.x, -delta.y]; IITransformation.ApplyPostTranslate[rasterData.viewToDevice, minusDelta]; IITransformation.ApplyPostTranslate[rasterData.device.surfaceToDevice, minusDelta]; rasterData.device.box _ savedDeviceBox; IIManhattan.Destroy[rasterData.viewClipMask]; rasterData.viewClipMask _ savedClipMask; rasterData.viewClipBox _ IIManhattan.BoundingBox[rasterData.viewClipMask]; rasterData.specialClipRect.sMin _ rasterData.specialClipRect.sMin-sDelta; rasterData.specialClipRect.fMin _ rasterData.specialClipRect.fMin-fDelta; rasterData.valid.clientClipper _ FALSE; rasterData.valid.clientToDevice _ FALSE; }; IITransformation.ApplyPostTranslate[rasterData.viewToDevice, delta]; IITransformation.ApplyPostTranslate[rasterData.device.surfaceToDevice, delta]; rasterData.viewClipMask _ IIManhattanExtras.DestructiveClip[ IIManhattan.Copy[rasterData.viewClipMask], rasterData.specialClipRect ]; IIManhattan.Shift[rasterData.viewClipMask, sDelta, fDelta]; rasterData.viewClipBox _ IIManhattan.BoundingBox[rasterData.viewClipMask]; rasterData.device.box _ DeviceBoxFromDeviceRectangle[rasterData.viewClipBox]; rasterData.specialClipRect.sMin _ rasterData.specialClipRect.sMin+sDelta; rasterData.specialClipRect.fMin _ rasterData.specialClipRect.fMin+fDelta; rasterData.valid.clientClipper _ FALSE; rasterData.valid.clientToDevice _ FALSE; action[ ! UNWIND => Restore[]]; Restore[]; }; nScratch: NAT ~ 2; scratch: ARRAY [0..nScratch) OF REF IIPixelMap.PixelMapRep _ ALL[NIL]; ObtainScratch: ENTRY PROC RETURNS [r: REF IIPixelMap.PixelMapRep] ~ { FOR i: NAT IN [0..nScratch) DO IF (r _ scratch[i]) # NIL THEN {scratch[i] _ NIL; RETURN}; ENDLOOP; RETURN [NIL]; }; ReleaseScratch: ENTRY PROC [r: REF IIPixelMap.PixelMapRep] ~ { FOR i: NAT IN [0..nScratch) DO IF scratch[i] = NIL THEN {scratch[i] _ r; RETURN} ENDLOOP; }; DoWithBitmapBuffer: PROC [context: Context, action: PROC, backgroundColor: Color, rasterData: IIRasterPrivate.Data, bitmapData: IIBitmapDevicePrivate.Data] RETURNS [ok: BOOL _ TRUE] ~ { tightBox: IIDevice.DeviceBox ~ rasterData.clientClipBox; box: IIDevice.DeviceBox ~ [ smin: tightBox.smin/4*4, fmin: tightBox.fmin/4*4, smax: tightBox.smax, fmax: tightBox.fmax]; display: PixelMap ~ [sOrigin: 0, fOrigin: 0, sMin: 0, fMin: 0, sSize: bitmapData.sSizeFrame, fSize: bitmapData.fSizeFrame, refRep: bitmapData.frame]; buffer: PixelMap ~ IIPixelMap.Reshape[ObtainScratch[], 0, [box.smin, box.fmin, box.smax-box.smin, box.fmax-box.fmin]].Clip[[tightBox.smin, tightBox.fmin, tightBox.smax-tightBox.smin, tightBox.fmax-tightBox.fmin]]; frameAction: PROC ~ { bitmapData.sSizeFrame _ buffer.sMin+buffer.sSize; bitmapData.fSizeFrame _ buffer.fMin+buffer.fSize; bitmapData.frame _ buffer.refRep; IF backgroundColor # NIL THEN { state: IIState.State ~ context.state; oldColor: Color ~ state.color; II.SetColor[context, backgroundColor]; II.MaskRectangle[context, IIBackdoor.GetBounds[context]]; II.SetColor[context, oldColor]; }; II.DoSave[context, action ! UNWIND => { bitmapData.sSizeFrame _ display.sSize; bitmapData.fSizeFrame _ display.fSize; bitmapData.frame _ display.refRep; }]; display.Transfer[buffer]; bitmapData.sSizeFrame _ display.sSize; bitmapData.fSizeFrame _ display.fSize; bitmapData.frame _ display.refRep; }; IF backgroundColor = NIL THEN { buffer.Transfer[display]; } ELSE IF backgroundColor = II.white THEN { IIPixelMap.Clear[buffer]; backgroundColor _ NIL; }; DoWithShift[rasterData, frameAction, -buffer.sOrigin, -buffer.fOrigin]; ReleaseScratch[buffer.refRep]; }; DoWithDitheredBuffer: PROC [context: Context, action: PROC, backgroundColor: Color, rasterData: IIRasterPrivate.Data, ditheredData: IIDitheredDevicePrivate.Data] RETURNS [ok: BOOL _ TRUE] ~ { tightBox: IIDevice.DeviceBox ~ rasterData.clientClipBox; box: IIDevice.DeviceBox ~ [ smin: tightBox.smin/12*12, fmin: tightBox.fmin/12*12, smax: tightBox.smax, fmax: tightBox.fmax]; terminal: Terminal.Virtual ~ ditheredData.terminal; display: PixelMap ~ ditheredData.frame; buffer: PixelMap ~ IIPixelMap.Reshape[ObtainScratch[], display.refRep.lgBitsPerPixel, [box.smin, box.fmin, box.smax-box.smin, box.fmax-box.fmin]].Clip[[tightBox.smin, tightBox.fmin, tightBox.smax-tightBox.smin, tightBox.fmax-tightBox.fmin]]; frameAction: PROC ~ { ditheredData.frame _ buffer; ditheredData.frame.sOrigin _ ditheredData.frame.fOrigin _ 0; IF backgroundColor # NIL THEN { state: IIState.State ~ context.state; oldColor: Color ~ state.color; II.SetColor[context, backgroundColor]; II.MaskRectangle[context, IIBackdoor.GetBounds[context]]; II.SetColor[context, oldColor]; }; II.DoSave[context, action ! UNWIND => { ditheredData.frame _ display; }]; IF terminal = NIL THEN display.Transfer[buffer] ELSE { action: PROC ~ {display.Transfer[buffer]}; Terminal.ModifyColorFrame[vt: terminal, action: action, xmin: box.fmin, ymin: box.smin, xmax: box.fmax, ymax: box.smax]; }; display.Transfer[buffer]; ditheredData.frame _ display; }; IF backgroundColor = NIL THEN { IF terminal = NIL THEN buffer.Transfer[display] ELSE { action: PROC ~ {buffer.Transfer[display]}; Terminal.ModifyColorFrame[vt: terminal, action: action, xmin: box.fmin, ymin: box.smin, xmax: box.fmax, ymax: box.smax]; }; buffer.Transfer[display]; }; ditheredData.terminal _ NIL; DoWithShift[rasterData, frameAction, -buffer.sOrigin, -buffer.fOrigin ! UNWIND => {ditheredData.terminal _ terminal}]; ditheredData.terminal _ terminal; ReleaseScratch[buffer.refRep]; }; bufferingOn: BOOL _ TRUE; END.