<> <> <> <> 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 <> 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> 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]; <> 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.