-- PDInterpPageImpl.mesa -- Copyright (C) 1984, 1986 Xerox Corporation. All rights reserved. -- Michael Plass, October 31, 1984 10:35:36 am PST -- Last Edited by: Pier, November 30, 1983 6:37 pm -- Tim Diebert, 5-Sep-86 13:52:52 DIRECTORY Environment, Inline, PDFileFormat, PDInterpReader, PDInterpOutput, PDInterpPage, PDInterpBitmap, PDInterpSysCalls, Heap, PDQueue, Process; PDInterpPageImpl: PROGRAM IMPORTS Inline, PDInterpReader, PDInterpOutput, PDInterpBitmap, PDInterpSysCalls, Heap, Process, PDQueue EXPORTS PDInterpPage = BEGIN CommandBuffer: TYPE = PDInterpReader.CommandBuffer; bitsPerWord: NAT = Environment.bitsPerWord; heapZone: UNCOUNTED ZONE=Heap.systemZone; totalAllocates, totalFrees: INT ← 0; availCount: NAT; --count of the number of leftover records on the free list -- Leftover list types LeftoverRef: TYPE = LONG POINTER TO Leftover; Leftover: TYPE = RECORD [ link: LeftoverRef ← NIL, commandBuffer: CommandBuffer, colorType: PDInterpReader.ColorType, colorTileLoadAddress: INT ← -1, priority: INT ]; InterpretPage: PUBLIC PROC [handle: PDInterpReader.Handle, request: PDQueue.Request, abort: LONG POINTER TO BOOLEAN] RETURNS [ok: BOOLEAN] = { readHead, writeHead, availHead, writeTail: LeftoverRef ← NIL; --heads and tail of leftover lists currentColorType: PDInterpReader.ColorType; currentColorTileLoadAddress: INT ← -1; currentPriority: INT ← -1; leftovers: BOOLEAN; --can't be filled in until StartImage has happened commandBuffer: CommandBuffer; band: PDInterpBitmap.BitmapDesc; bandMaxS: INT; cachedColorTile: PDInterpBitmap.Tile; cachedColorReference: INT ← -1; GetColorTile: PROC = { IF currentColorTileLoadAddress # cachedColorReference THEN { cachedColorTile ← PDInterpReader.ColorTileFromLoad[handle, cachedColorReference ← currentColorTileLoadAddress, scratchPointer, scratchWords]; }; }; TransferRectangle: PROC [rectangle: PDInterpBitmap.Rectangle] = { SELECT currentColorType FROM none => ERROR; clear => PDInterpBitmap.Fill[band, rectangle, 0]; ink => PDInterpBitmap.Fill[band, rectangle, 1]; opaqueTile => { GetColorTile[]; PDInterpBitmap.TransferTile[band.Clip[rectangle], cachedColorTile]; }; transparentTile => { GetColorTile[]; PDInterpBitmap.TransferTile[band.Clip[rectangle], cachedColorTile, [or, null]]; }; ENDCASE => ERROR; }; DoLine: PROCEDURE [sMin,fMin,fSize: CARDINAL] = { SELECT currentColorType FROM none => ERROR; clear => PDInterpBitmap.Fill[band, [sMin: sMin, fMin: fMin, sSize: 1, fSize: fSize], 0]; opaqueTile, ink => PDInterpBitmap.Fill[band, [sMin: sMin, fMin: fMin, sSize: 1, fSize: fSize], 1]; transparentTile => PDInterpBitmap.TransferTile[band.Clip[[sMin: sMin, fMin: fMin, sSize: 1, fSize: fSize]], cachedColorTile, [or, null]]; ENDCASE => ERROR; }; TempColor: PROC [rectangle: PDInterpBitmap.Rectangle] = { SELECT currentColorType FROM none => ERROR; clear => NULL; ink => NULL; opaqueTile => { GetColorTile[]; PDInterpBitmap.TransferTile[band.Clip[rectangle], cachedColorTile, [xor, complement]]; }; transparentTile => GetColorTile[]; ENDCASE => ERROR; }; AddLeftover: PROC = { IF availCount=0 THEN { totalAllocates←totalAllocates+1; IF writeHead=NIL THEN writeHead←writeTail←heapZone.NEW[Leftover ←[link: NIL, commandBuffer: commandBuffer, colorType: currentColorType, colorTileLoadAddress: currentColorTileLoadAddress, priority: currentPriority]] ELSE { writeTail.link←heapZone.NEW[Leftover ←[link: NIL, commandBuffer: commandBuffer, colorType: currentColorType, colorTileLoadAddress: currentColorTileLoadAddress, priority: currentPriority]]; writeTail←writeTail.link; }; } ELSE { availCount←availCount-1; --move a node from availList to writeList IF writeHead=NIL THEN {writeHead←writeTail←availHead; availHead←availHead.link;} ELSE { writeTail.link←availHead; writeTail←availHead; availHead←availHead.link; }; writeTail↑←[link: NIL, commandBuffer: commandBuffer, colorType: currentColorType, colorTileLoadAddress: currentColorTileLoadAddress, priority: currentPriority]; }; }; FreeList: PROC[head: LeftoverRef] = { --this proc out here so the UNWIND can call it tempHead: LeftoverRef; UNTIL head=NIL DO tempHead←head↑.link; heapZone.FREE[@head]; totalFrees←totalFrees+1; head←tempHead; ENDLOOP; }; CheckAbort: PROC = {IF abort↑ THEN ERROR ABORTED}; availCount←0; Process.SetPriority[Process.priorityBackground]; DO ENABLE UNWIND => { FreeList[readHead]; FreeList[writeHead]; FreeList[availHead]; availCount←0; Process.SetPriority[Process.priorityNormal]; }; IF readHead#NIL AND readHead.priority<handle.priority THEN { tempHead: LeftoverRef ← readHead; commandBuffer ← readHead.commandBuffer; currentColorTileLoadAddress←readHead.colorTileLoadAddress; currentColorType←readHead.colorType; currentPriority←readHead.priority; -- now move this record from readList to availList readHead←readHead.link; tempHead.link←availHead; availHead←tempHead; availCount←availCount+1; } ELSE { commandBuffer ← PDInterpReader.Get[handle]; currentColorTileLoadAddress←handle.colorTileLoadAddress; currentColorType←handle.colorType; currentPriority←handle.priority; }; WITH commandBuffer SELECT FROM stateChange: CommandBuffer.stateChange => { SELECT stateChange.whatChanged FROM imageStart => { band ← PDInterpOutput.StartImage[handle.herald, handle.image, request]; bandMaxS ← band.sOrigin+band.sMin+band.sSize; leftovers ← handle.image.leftOverMode; IF handle.image.nBands = 0 THEN {PDInterpOutput.EndImage[request]}; }; imageEnd => { [] ← PDInterpOutput.EndBand[]; IF readHead#NIL THEN ERROR; --DEBUGGING CHECK !! readHead←writeHead; writeHead←NIL; FreeList[readHead]; --from this image FreeList[writeHead]; --from this image FreeList[availHead]; availCount←0; Process.SetPriority[Process.priorityForeground]; PDQueue.DeferSaving[]; PDInterpOutput.EndImage[request]; Process.SetPriority[Process.priorityNormal]; PDQueue.DoDeferredSave[]; RETURN [TRUE]; }; priorityChange => NULL; colorChange => NULL; bandChange => { CheckAbort[]; band ← PDInterpOutput.EndBand[]; bandMaxS←band.sOrigin+band.sMin+band.sSize; IF readHead#NIL THEN ERROR; --DEBUGGING CHECK !! readHead←writeHead; writeHead←NIL; }; loadChange => NULL; documentEnd => {Process.SetPriority[Process.priorityNormal]; RETURN [FALSE]}; ENDCASE => ERROR; }; maskRectangle: CommandBuffer.maskRectangle => { TransferRectangle[[maskRectangle.sMin, maskRectangle.fMin, maskRectangle.sSize, maskRectangle.fSize]]; IF leftovers AND maskRectangle.sMin+maskRectangle.sSize>bandMaxS THEN AddLeftover[]; }; maskTrapezoid: CommandBuffer.maskTrapezoid => { EdgeBlock: TYPE = RECORD [fPos, fIncr: Environment.LongNumber]; MakeEdge: PROC[fMinLast, fMin, sSize: CARDINAL] RETURNS [edge: EdgeBlock] = { edge.fPos.highbits ← fMin; edge.fPos.lowbits ← 0; edge.fIncr.highbits ← fMinLast - fMin; edge.fIncr.lowbits ← 0; IF sSize > 1 THEN edge.fIncr.li ← edge.fIncr.li/sSize; }; fMinBox: CARDINAL←MIN[maskTrapezoid.fMin, maskTrapezoid.fMinLast]; fMaxBox: CARDINAL←MAX[maskTrapezoid.fMin+maskTrapezoid.fSize, maskTrapezoid.fMinLast+maskTrapezoid.fSizeLast]; fSizeBox: CARDINAL←fMaxBox-fMinBox; trapMaxS: CARDINAL ← maskTrapezoid.sMin+maskTrapezoid.sSize; s: CARDINAL ← maskTrapezoid.sMin; sMinBand: CARDINAL ← MIN[band.sOrigin+band.sMin, maskTrapezoid.sMin+maskTrapezoid.sSize]; sMaxBand: CARDINAL ← MIN[bandMaxS, trapMaxS]; -- calculate initial edges: minEdge: EdgeBlock ← MakeEdge[fMinLast: maskTrapezoid.fMinLast, fMin: maskTrapezoid.fMin, sSize: maskTrapezoid.sSize]; maxEdge: EdgeBlock ← MakeEdge[fMinLast: maskTrapezoid.fMinLast+maskTrapezoid.fSizeLast, fMin: maskTrapezoid.fMin+maskTrapezoid.fSize, sSize: maskTrapezoid.sSize]; TempColor[[sMin: maskTrapezoid.sMin, fMin: fMinBox, sSize: maskTrapezoid.sSize, fSize: fSizeBox]]; WHILE s < sMinBand DO minEdge.fPos.lc ← minEdge.fPos.lc + minEdge.fIncr.li; maxEdge.fPos.lc ← maxEdge.fPos.lc + maxEdge.fIncr.li; s ← s + 1; ENDLOOP; WHILE s < sMaxBand DO DoLine[sMin: s, fMin: minEdge.fPos.highbits, fSize: maxEdge.fPos.highbits-minEdge.fPos.highbits]; minEdge.fPos.lc ← minEdge.fPos.lc + minEdge.fIncr.li; maxEdge.fPos.lc ← maxEdge.fPos.lc + maxEdge.fIncr.li; s ← s + 1; ENDLOOP; TempColor[[sMin: maskTrapezoid.sMin, fMin: fMinBox, sSize: maskTrapezoid.sSize, fSize: fSizeBox]]; IF leftovers AND trapMaxS>bandMaxS THEN AddLeftover[]; }; maskRunGroup: CommandBuffer.maskRunGroup => { s: CARDINAL ← maskRunGroup.sMin; sMinBand: CARDINAL ← MIN[band.sOrigin+band.sMin, maskRunGroup.sMin+maskRunGroup.sSize]; sMaxBand: CARDINAL ← MIN[band.sOrigin+band.sMin+band.sSize, maskRunGroup.sMin+maskRunGroup.sSize]; run: LONG POINTER TO PDFileFormat.Run ← maskRunGroup.pointer; TempColor[[maskRunGroup.sMin, maskRunGroup.fMin, maskRunGroup.sSize, maskRunGroup.fSize]]; WHILE s < sMinBand DO IF run.lastRun THEN s ← s + 1; run ← run + SIZE[PDFileFormat.Run]; ENDLOOP; WHILE s < sMaxBand DO IF run.fMin+run.fSize > maskRunGroup.fSize THEN ERROR; DoLine[sMin: s, fMin: run.fMin+maskRunGroup.fOffset, fSize: run.fSize]; IF run.lastRun THEN s ← s + 1; run ← run + SIZE[PDFileFormat.Run]; ENDLOOP; TempColor[[maskRunGroup.sMin, maskRunGroup.fMin, maskRunGroup.sSize, maskRunGroup.fSize]]; IF leftovers AND maskRunGroup.loadAddress>=0 AND maskRunGroup.sMin+maskRunGroup.sSize>bandMaxS THEN { maskRunGroup.sSize←maskRunGroup.sSize-(s-maskRunGroup.sMin); maskRunGroup.sMin←s; maskRunGroup.runCount ← -1; --unused, eventually eliminate from DEF maskRunGroup.pointer←run; AddLeftover[]; }; }; maskSamples: CommandBuffer.maskSamples => { rectangle: PDInterpBitmap.Rectangle ← PDInterpBitmap.Window[maskSamples.samples]; TempColor[rectangle]; SELECT currentColorType FROM none => ERROR; clear => PDInterpBitmap.Transfer[band, maskSamples.samples, [and, complement]]; opaqueTile, ink => PDInterpBitmap.Transfer[band, maskSamples.samples, [or, null]]; transparentTile => { bounds: PDInterpBitmap.Rectangle ← PDInterpBitmap.Intersect[rectangle, PDInterpBitmap.Window[band]]; scratchWords: INT ← Inline.LongMult[bounds.sSize, (bounds.fSize+bitsPerWord-1)/bitsPerWord]; buffer: LONG POINTER ←PDInterpSysCalls.AllocateSpace[scratchWords]; destDesc:PDInterpBitmap.BitmapDesc←PDInterpBitmap.Reshape[pointer: buffer, words: scratchWords, bounds: bounds]; GetColorTile[]; PDInterpBitmap.TransferTile[dest: destDesc, tile: cachedColorTile]; PDInterpBitmap.Transfer[destDesc, maskSamples.samples, [and, null]]; PDInterpBitmap.Transfer[band, destDesc, [or, null]]; PDInterpSysCalls.FreeSpace[buffer]; }; ENDCASE => ERROR; TempColor[rectangle]; IF leftovers AND maskSamples.loadAddress>=0 AND maskSamples.samples.sOrigin+maskSamples.samples.sMin+maskSamples.samples.sSize > bandMaxS THEN AddLeftover[]; }; colorSamples: CommandBuffer.colorSamples => { PDInterpBitmap.Transfer[band, colorSamples.samples]; }; deviceCommand: CommandBuffer.deviceCommand => { }; ENDCASE => NULL; ENDLOOP; }; scratchPages: INT = 4; scratchWords: INT ← scratchPages*Environment.wordsPerPage; scratchPointer: LONG POINTER ← PDInterpSysCalls.AllocateSpace[scratchWords]; END.