-- Copyright (C) 1982, 1983 by Xerox Corporation. All rights reserved. -- WindowImplC.mesa - last edited by -- Rick 4-Aug-82 10:36:58 -- Bruce 18-Dec-82 13:14:16 -- Daniels 29-Nov-83 16:25:25 DIRECTORY BitBlt: TYPE USING [ AlignedBBTable, BBptr, BBTableSpace, BitAddress, BITBLT, BitBltFlags, DstFunc, GrayParm], Display: TYPE USING [ boxFlags, BreakReason, Brick, fiftyPercent, infinity, TrajectoryProc, xorBoxFlags], Environment: TYPE USING [Block], Inline: TYPE USING [BITAND, DBITSHIFT, LongMult, LongNumber, LowHalf], RecOps: TYPE USING [Coalesce, Convert, ConvertBox, FreeRecList, Intersect], SpecialDisplay: TYPE USING [defaultContext, Special], Window: TYPE USING [Box, BoxHandle, nullBox, Place], WindowFont: TYPE USING [defaultFont, Handle], WindowOps: TYPE USING [ AbsoluteBox, AbsoluteBoxHandle, Bounds, DisplayList, DIVMOD16, GetContext, lock, Object, Offset, RecList, ScreenBox, SpecialTimesWpl]; WindowImplC: MONITOR LOCKS WindowOps.lock IMPORTS BitBlt, Inline, RecOps, SpecialDisplay, WindowOps, WindowFont EXPORTS Display, SpecialDisplay, Window, WindowOps = BEGIN Handle: TYPE = LONG POINTER TO Object; Object: PUBLIC TYPE = WindowOps.Object; Place: TYPE = Window.Place; bbTable: BitBlt.BBTableSpace; bbPtr: PUBLIC BitBlt.BBptr ¬ BitBlt.AlignedBBTable[@bbTable]; -- box things White: PUBLIC PROC [window: Handle, box: Window.Box] = { white: ARRAY [0..1) OF CARDINAL ¬ ALL[0]; IF window.inTree THEN SpGray[ window, box, DESCRIPTOR[white], Display.boxFlags]}; SpWhite: PUBLIC PROC [ window: Handle, box: Window.Box, context: SpecialDisplay.Special] = { white: ARRAY [0..1) OF CARDINAL ¬ ALL[0]; SpGray[window, box, DESCRIPTOR[white], Display.boxFlags, context]}; Black: PUBLIC PROC [window: Handle, box: Window.Box] = { black: ARRAY [0..1) OF CARDINAL ¬ ALL[CARDINAL.LAST]; IF window.inTree THEN SpGray[ window, box, DESCRIPTOR[black], Display.boxFlags]}; SpBlack: PUBLIC PROC [ window: Handle, box: Window.Box, context: SpecialDisplay.Special] = { black: ARRAY [0..1) OF CARDINAL ¬ ALL[CARDINAL.LAST]; SpGray[window, box, DESCRIPTOR[black], Display.boxFlags, context]}; Invert: PUBLIC PROC [window: Handle, box: Window.Box] = { black: ARRAY [0..1) OF CARDINAL ¬ ALL[CARDINAL.LAST]; IF window.inTree THEN SpGray[ window, box, DESCRIPTOR[black], Display.xorBoxFlags]}; SpInvert: PUBLIC PROC [ window: Handle, box: Window.Box, context: SpecialDisplay.Special] = { black: ARRAY [0..1) OF CARDINAL ¬ ALL[CARDINAL.LAST]; SpGray[window, box, DESCRIPTOR[black], Display.xorBoxFlags, context]}; Gray: PUBLIC PROC [ window: Handle, box: Window.Box, gray: Display.Brick, dstFunc: BitBlt.DstFunc] = { flags: BitBlt.BitBltFlags = [ direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: TRUE, srcFunc: null, dstFunc: dstFunc, reserved: 0]; IF window.inTree THEN SpGray[window, box, gray, flags]}; fifty: ARRAY [0..2) OF CARDINAL ¬ [125252B, 52525B]; SpGray: PUBLIC ENTRY PROC [ window: Handle, box: Window.Box, gray: Display.Brick, flags: BitBlt.BitBltFlags, context: SpecialDisplay.Special ¬ SpecialDisplay.defaultContext] = { ENABLE UNWIND => NULL; abs: WindowOps.ScreenBox = WindowOps.AbsoluteBox[window, box]; IF gray = Display.fiftyPercent THEN gray ¬ DESCRIPTOR[fifty]; flags.gray ¬ TRUE; FOR r: WindowOps.RecList ¬ WindowOps.DisplayList[window], r.link UNTIL r = NIL DO left: INTEGER = MAX[r.box.left, abs.left]; top: INTEGER = MAX[r.box.top, abs.top]; right: INTEGER = MIN[r.box.right, abs.right]; bottom: INTEGER = MIN[r.box.bottom, abs.bottom]; width: INTEGER = right - left; height: INTEGER = bottom - top; ctx: SpecialDisplay.Special = WindowOps.GetContext[r, context]; offset, bit, yOffset: INTEGER; IF width <= 0 OR height <= 0 THEN LOOP; yOffset ¬ CARDINAL[top - window.place.y] MOD gray.LENGTH; [offset, bit] ¬ WindowOps.DIVMOD16[CARDINAL[left]]; bbPtr­ ¬ [ dst: [ word: ctx.bmAddress + WindowOps.SpecialTimesWpl[top, ctx] + offset, bit: bit], src: [ word: gray.BASE + yOffset, bit: CARDINAL[left - window.place.x] MOD 16], srcDesc: [gray[BitBlt.GrayParm[ yOffset: yOffset, widthMinusOne: 0, heightMinusOne: gray.LENGTH - 1]]], dstBpl: ctx.bpl, width: width, height: height, flags: flags]; BitBlt.BITBLT[bbPtr]; ENDLOOP}; Trajectory: PUBLIC ENTRY PROC [ window: Handle, box: Window.Box, proc: Display.TrajectoryProc, source: LONG POINTER, bpl: CARDINAL, height: CARDINAL, flags: BitBlt.BitBltFlags, missesChildren: BOOLEAN, brick: Display.Brick] = { ENABLE UNWIND => NULL; dl, temp: WindowOps.RecList; IF ~window.inTree THEN RETURN; dl ¬ RecOps.Coalesce[RecOps.Intersect[ (temp ¬ IF box = Window.nullBox THEN RecOps.Convert[window] ELSE RecOps.ConvertBox[window, box]), WindowOps.DisplayList[window]]]; RecOps.FreeRecList[temp]; IF dl = NIL THEN RETURN; IF flags.gray AND brick = Display.fiftyPercent THEN brick ¬ DESCRIPTOR[fifty]; DO ENABLE UNWIND => RecOps.FreeRecList[dl]; brushOffset, absOffset, absBit: CARDINAL; abs: WindowOps.ScreenBox; brushBox: Window.Box; [brushBox, brushOffset] ¬ proc[window]; IF brushBox.dims.w = 0 THEN EXIT; -- really should be Window.nullBox... abs ¬ WindowOps.AbsoluteBox[window, brushBox]; [absOffset, absBit] ¬ WindowOps.Offset[abs.left]; -- do gray in a separate loop... IF flags.gray THEN FOR r: WindowOps.RecList ¬ dl, r.link UNTIL r = NIL DO left: INTEGER = MAX[r.box.left, abs.left]; top: INTEGER = MAX[r.box.top, abs.top]; right: INTEGER = MIN[r.box.right, abs.right]; bottom: INTEGER = MIN[r.box.bottom, abs.bottom]; width: INTEGER = right - left; height: INTEGER = bottom - top; ctx: SpecialDisplay.Special = WindowOps.GetContext[ r, SpecialDisplay.defaultContext]; offset, bit, yOffset: INTEGER; IF width <= 0 OR height <= 0 THEN LOOP; yOffset ¬ CARDINAL[top - window.place.y] MOD brick.LENGTH; [offset, bit] ¬ WindowOps.DIVMOD16[CARDINAL[left]]; bbPtr­ ¬ [ dst: [ word: ctx.bmAddress + WindowOps.SpecialTimesWpl[top, ctx] + offset, bit: bit], src: [ word: brick.BASE + yOffset, bit: CARDINAL[left - window.place.x] MOD 16], srcDesc: [gray[BitBlt.GrayParm[ yOffset: yOffset, widthMinusOne: 0, heightMinusOne: brick.LENGTH - 1]]], dstBpl: ctx.bpl, width: width, height: height, flags: flags]; BitBlt.BITBLT[bbPtr]; ENDLOOP ELSE FOR r: WindowOps.RecList ¬ dl, r.link UNTIL r = NIL DO clipLeft: INTEGER = r.box.left - abs.left; clipTop: INTEGER = r.box.top - abs.top; clipRight: INTEGER = abs.right - r.box.right; clipBottom: INTEGER = abs.bottom - r.box.bottom; ctx: SpecialDisplay.Special = WindowOps.GetContext[ r, SpecialDisplay.defaultContext]; offset, bit: CARDINAL; [offset, bit] ¬ WindowOps.DIVMOD16[brushOffset]; bbPtr­ ¬ [ dst: [word: ctx.bmAddress + absOffset + WindowOps.SpecialTimesWpl[abs.top, ctx], bit: absBit], dstBpl: ctx.bpl, flags: flags, height: brushBox.dims.h, width: brushBox.dims.w, src: [word: source + offset, bit: bit], srcDesc: [srcBpl[bpl]]]; IF clipTop > 0 THEN { bbPtr.src.word ¬ bbPtr.src.word + Inline.DBITSHIFT[Inline.LongMult[clipTop, bpl], -4]; bbPtr.height ¬ bbPtr.height - clipTop; bbPtr.dst.word ¬ bbPtr.dst.word + WindowOps.SpecialTimesWpl[clipTop, ctx]}; IF clipBottom > 0 THEN bbPtr.height ¬ bbPtr.height - clipBottom; IF clipRight > 0 THEN bbPtr.width ¬ bbPtr.width - clipRight; IF clipLeft > 0 THEN { wordOffset, bitOffset, bit: INTEGER; [wordOffset, bitOffset] ¬ WindowOps.DIVMOD16[CARDINAL[clipLeft]]; bbPtr.src.word ¬ bbPtr.src.word + wordOffset; bbPtr.dst.word ¬ bbPtr.dst.word + wordOffset; [wordOffset, bit] ¬ WindowOps.DIVMOD16[ CARDINAL[bbPtr.src.bit + bitOffset]]; bbPtr.src ¬ [word: bbPtr.src.word + wordOffset, bit: bit]; [wordOffset, bit] ¬ WindowOps.DIVMOD16[ CARDINAL[bbPtr.dst.bit + bitOffset]]; bbPtr.dst ¬ [word: bbPtr.dst.word + wordOffset, bit: bit]; bbPtr.width ¬ bbPtr.width - clipLeft}; IF INTEGER[bbPtr.width] <= 0 OR INTEGER[bbPtr.height] <= 0 THEN LOOP; BitBlt.BITBLT[bbPtr]; ENDLOOP; ENDLOOP; RecOps.FreeRecList[dl]}; -- text Character: PUBLIC PROC [ window: Handle, char: CHARACTER, place: Window.Place, font: WindowFont.Handle, flags: BitBlt.BitBltFlags, bounds: Window.BoxHandle] RETURNS [Window.Place] = { IF window.inTree THEN RETURN SpCharacter[window, char, place, font, flags, bounds] ELSE { IF font = NIL THEN font ¬ WindowFont.defaultFont; RETURN[[place.x + font.width[char], place.y]]}}; SpCharacter: PUBLIC ENTRY PROC [ window: Handle, char: CHARACTER, place: Window.Place, font: WindowFont.Handle, flags: BitBlt.BitBltFlags, bounds: Window.BoxHandle, context: SpecialDisplay.Special ¬ SpecialDisplay.defaultContext] RETURNS [Window.Place] = { ENABLE UNWIND => NULL; absBound: WindowOps.ScreenBox = IF bounds = NIL THEN WindowOps.Bounds[window] ELSE WindowOps.AbsoluteBoxHandle[window, bounds]; flags.gray ¬ FALSE; IF font = NIL THEN font ¬ WindowFont.defaultFont; FOR r: WindowOps.RecList ¬ WindowOps.DisplayList[window], r.link UNTIL r = NIL DO top: INTEGER = place.y + window.place.y; left: INTEGER = place.x + window.place.x; height: INTEGER ¬ font.height; clipBottom: INTEGER = top + height - MIN[r.box.bottom, absBound.bottom]; clipTop: INTEGER = MAX[r.box.top, absBound.top] - top; clipLeft: INTEGER = MAX[r.box.left, absBound.left]; clipRight: INTEGER = MIN[r.box.right, absBound.right]; bits: LONG POINTER ¬ font.bitmap; width: INTEGER ¬ font.width[char]; ctx: SpecialDisplay.Special = WindowOps.GetContext[r, context]; bitmapBase: LONG POINTER ¬ ctx.bmAddress + WindowOps.SpecialTimesWpl[top, ctx]; clippedPart, charOffset, charBit, bitmapOffset, bitmapBit: INTEGER; IF width = 0 THEN { char ¬ font.max.SUCC; width ¬ font.width[char]}; IF clipTop > 0 THEN { bits ¬ bits + Inline.LongMult[clipTop, font.raster]; height ¬ height - clipTop; bitmapBase ¬ bitmapBase + WindowOps.SpecialTimesWpl[clipTop, ctx]}; IF clipBottom > 0 THEN height ¬ height - clipBottom; IF height <= 0 THEN LOOP; IF (clippedPart ¬ left + width - clipRight) > 0 THEN { width ¬ width - clippedPart; IF width <= 0 THEN LOOP}; IF (clippedPart ¬ clipLeft - left) > 0 THEN { width ¬ width - clippedPart; IF width <= 0 THEN LOOP; [bitmapOffset, bitmapBit] ¬ WindowOps.DIVMOD16[CARDINAL[clipLeft]]; [charOffset, charBit] ¬ WindowOps.DIVMOD16[ font.xInSegment[char] + clippedPart]} ELSE { [bitmapOffset, bitmapBit] ¬ WindowOps.Offset[left]; [charOffset, charBit] ¬ WindowOps.DIVMOD16[font.xInSegment[char]]}; bbPtr­ ¬ [ dst: [word: bitmapBase + bitmapOffset, bit: bitmapBit], src: [word: bits + charOffset, bit: charBit], dstBpl: ctx.bpl, height: height, width: width, srcDesc: [srcBpl[font.raster*16]], flags: flags]; BitBlt.BITBLT[bbPtr]; ENDLOOP; RETURN[[place.x + font.width[char], place.y]]}; Block: PUBLIC PROC [ window: Handle, block: Environment.Block, lineLength: INTEGER, place: Window.Place, font: WindowFont.Handle, flags: BitBlt.BitBltFlags, bounds: Window.BoxHandle] RETURNS [ newPlace: Window.Place, positions: CARDINAL, why: Display.BreakReason] = { RETURN ( IF window.inTree THEN SpBlock[window, block, lineLength, place, font, flags, bounds] ELSE MeasureBlock[window, block, lineLength, place, font])}; Text: PUBLIC PROC [ window: Handle, string: LONG STRING, place: Window.Place, font: WindowFont.Handle, lineLength: INTEGER, flags: BitBlt.BitBltFlags, bounds: Window.BoxHandle] RETURNS [newPlace: Window.Place] = { RETURN[( IF window.inTree THEN SpBlock[ window, [LOOPHOLE[@string.text], 0, string.length], lineLength, place, font, flags, bounds] ELSE MeasureBlock[ window, [LOOPHOLE[@string.text], 0, string.length], lineLength, place, font]).newPlace]}; SpBlock: PUBLIC ENTRY PROC [ window: Handle, block: Environment.Block, lineLength: INTEGER, place: Window.Place, font: WindowFont.Handle, flags: BitBlt.BitBltFlags, bounds: Window.BoxHandle, context: SpecialDisplay.Special ¬ SpecialDisplay.defaultContext] RETURNS [ newPlace: Window.Place, positions: CARDINAL, why: Display.BreakReason] = { ENABLE UNWIND => NULL; absBound: WindowOps.ScreenBox = IF bounds = NIL THEN WindowOps.Bounds[window] ELSE WindowOps.AbsoluteBoxHandle[window, bounds]; displayList: WindowOps.RecList; IF font = NIL THEN font ¬ WindowFont.defaultFont; IF lineLength = Display.infinity THEN lineLength ¬ window.box.dims.w - place.x; flags.gray ¬ FALSE; positions ¬ 0; why ¬ normal; newPlace ¬ place; displayList ¬ WindowOps.DisplayList[window]; IF displayList = NIL THEN RETURN MeasureBlock[window, block, lineLength, place, font]; FOR r: WindowOps.RecList ¬ displayList, r.link UNTIL r = NIL DO top: INTEGER = place.y + window.place.y; left: INTEGER ¬ place.x + window.place.x; -- start of character x: INTEGER ¬ left; -- stop of character stop: INTEGER = left + lineLength; bits: LONG POINTER ¬ font.bitmap; height: INTEGER ¬ font.height; clipBottom: INTEGER = top + height - MIN[r.box.bottom, absBound.bottom]; clipTop: INTEGER = MAX[r.box.top, absBound.top] - top; clipLeft: INTEGER = MAX[r.box.left, absBound.left]; clipRight: INTEGER = MIN[r.box.right, absBound.right]; ctx: SpecialDisplay.Special = WindowOps.GetContext[r, context]; bitmapBase: LONG POINTER ¬ ctx.bmAddress + WindowOps.SpecialTimesWpl[top, ctx]; charCount: CARDINAL ¬ 0; IF clipTop > 0 THEN { bits ¬ bits + Inline.LongMult[clipTop, font.raster]; height ¬ height - clipTop; bitmapBase ¬ bitmapBase + WindowOps.SpecialTimesWpl[clipTop, ctx]}; IF clipBottom > 0 THEN height ¬ height - clipBottom; FOR i: CARDINAL IN [block.startIndex..block.stopIndexPlusOne) DO char: CHARACTER = LOOPHOLE[block.blockPointer[i]]; width: INTEGER ¬ font.width[char]; clippedPart, charOffset, charBit, bitmapOffset, bitmapBit: INTEGER; IF width = 0 THEN {why ¬ stop; EXIT}; IF (x ¬ x + width) > stop THEN {why ¬ margin; EXIT}; charCount ¬ charCount + 1; IF height <= 0 THEN {left ¬ x; LOOP}; IF (clippedPart ¬ left + width - clipRight) > 0 THEN { width ¬ width - clippedPart; IF width <= 0 THEN {left ¬ x; LOOP}}; IF (clippedPart ¬ clipLeft - left) > 0 THEN { width ¬ width - clippedPart; IF width <= 0 THEN {left ¬ x; LOOP}; [bitmapOffset, bitmapBit] ¬ WindowOps.DIVMOD16[CARDINAL[clipLeft]]; [charOffset, charBit] ¬ WindowOps.DIVMOD16[ font.xInSegment[char] + clippedPart]} ELSE { [bitmapOffset, bitmapBit] ¬ WindowOps.Offset[left]; [charOffset, charBit] ¬ WindowOps.DIVMOD16[font.xInSegment[char]]}; bbPtr­ ¬ [ dst: [word: bitmapBase + bitmapOffset, bit: bitmapBit], src: [word: bits + charOffset, bit: charBit], dstBpl: ctx.bpl, height: height, width: width, srcDesc: [srcBpl[font.raster*16]], flags: flags]; BitBlt.BITBLT[bbPtr]; left ¬ x; ENDLOOP; positions ¬ MAX[positions, charCount]; newPlace.x ¬ left - window.place.x; ENDLOOP}; MeasureBlock: PUBLIC PROC [ window: Handle, block: Environment.Block, lineLength: INTEGER, place: Window.Place, font: WindowFont.Handle] RETURNS [ newPlace: Window.Place, positions: CARDINAL, why: Display.BreakReason] = { rightMargin: INTEGER = MIN[Display.infinity, place.x + lineLength]; chars: LONG POINTER TO PACKED ARRAY OF CHARACTER = LOOPHOLE[block.blockPointer]; pos: CARDINAL; IF font = NIL THEN font ¬ WindowFont.defaultFont; newPlace ¬ place; FOR pos IN [block.startIndex..block.stopIndexPlusOne) DO charWidth: INTEGER = font.width[chars[pos]]; newRight: INTEGER = newPlace.x + charWidth; SELECT TRUE FROM charWidth = 0 => RETURN[newPlace, pos - block.startIndex, stop]; newRight > rightMargin => RETURN[ newPlace, pos - block.startIndex, margin]; ENDCASE => newPlace.x ¬ newRight; REPEAT FINISHED => RETURN[newPlace, block.stopIndexPlusOne - block.startIndex, normal]; ENDLOOP}; ResolveBlock: PUBLIC PROC [ window: Handle, block: Environment.Block, offsets: LONG POINTER TO ARRAY CARDINAL [0..0) OF CARDINAL, font: WindowFont.Handle] RETURNS [positions: CARDINAL ¬ 0, why: Display.BreakReason] = { chars: LONG POINTER TO PACKED ARRAY OF CHARACTER = LOOPHOLE[block.blockPointer]; lastOffset: CARDINAL ¬ 0; pos: CARDINAL; IF font = NIL THEN font ¬ WindowFont.defaultFont; FOR pos IN [block.startIndex..block.stopIndexPlusOne) DO width: INTEGER = font.width[chars[pos]]; IF width = 0 THEN RETURN[pos - block.startIndex, stop]; offsets[pos - block.startIndex] ¬ lastOffset ¬ lastOffset + width; REPEAT FINISHED => RETURN[ block.stopIndexPlusOne - block.startIndex, normal]; ENDLOOP}; -- bitmaps Bitmap: PUBLIC PROC [ window: Handle, box: Window.Box, address: BitBlt.BitAddress, bitmapBitWidth: CARDINAL, flags: BitBlt.BitBltFlags] = { IF window.inTree THEN SpBitmap[window, box, address, bitmapBitWidth, flags]}; SpBitmap: PUBLIC ENTRY PROC [ window: Handle, box: Window.Box, address: BitBlt.BitAddress, bitmapBitWidth: CARDINAL, flags: BitBlt.BitBltFlags, context: SpecialDisplay.Special ¬ SpecialDisplay.defaultContext] = { ENABLE UNWIND => NULL; abs: WindowOps.ScreenBox = WindowOps.AbsoluteBox[window, box]; absOffset, absBit: INTEGER; flags.gray ¬ FALSE; [absOffset, absBit] ¬ WindowOps.Offset[abs.left]; FOR r: WindowOps.RecList ¬ WindowOps.DisplayList[window], r.link UNTIL r = NIL DO clipLeft: INTEGER = r.box.left - abs.left; clipTop: INTEGER = r.box.top - abs.top; clipRight: INTEGER = abs.right - r.box.right; clipBottom: INTEGER = abs.bottom - r.box.bottom; ctx: SpecialDisplay.Special = WindowOps.GetContext[r, context]; bbPtr­ ¬ [ dst: [word: ctx.bmAddress + absOffset + WindowOps.SpecialTimesWpl[ abs.top, ctx], bit: absBit], src: address, dstBpl: ctx.bpl, height: box.dims.h, width: box.dims.w, srcDesc: [srcBpl[bitmapBitWidth]], flags: flags]; IF clipTop > 0 THEN { LMOD16: PROC [lc: LONG CARDINAL] RETURNS [CARDINAL[0..16)] = INLINE { RETURN[Inline.LowHalf[lc] MOD 16]}; bump: LONG CARDINAL = Inline.LongMult[clipTop, bitmapBitWidth]; word: INTEGER; bbPtr.src.word ¬ bbPtr.src.word + bump/16; [word, bbPtr.src.bit] ¬ WindowOps.DIVMOD16[bbPtr.src.bit + LMOD16[bump]]; bbPtr.src.word ¬ bbPtr.src.word + word; bbPtr.height ¬ bbPtr.height - clipTop; bbPtr.dst.word ¬ bbPtr.dst.word + WindowOps.SpecialTimesWpl[ clipTop, ctx]}; IF clipBottom > 0 THEN bbPtr.height ¬ bbPtr.height - clipBottom; IF clipRight > 0 THEN bbPtr.width ¬ bbPtr.width - clipRight; IF clipLeft > 0 THEN { wordOffset, bitOffset, bit: INTEGER; [wordOffset, bitOffset] ¬ WindowOps.DIVMOD16[CARDINAL[clipLeft]]; bbPtr.src.word ¬ bbPtr.src.word + wordOffset; bbPtr.dst.word ¬ bbPtr.dst.word + wordOffset; [wordOffset, bit] ¬ WindowOps.DIVMOD16[ CARDINAL[bbPtr.src.bit + bitOffset]]; bbPtr.src ¬ [word: bbPtr.src.word + wordOffset, bit: bit]; [wordOffset, bit] ¬ WindowOps.DIVMOD16[ CARDINAL[bbPtr.dst.bit + bitOffset]]; bbPtr.dst ¬ [word: bbPtr.dst.word + wordOffset, bit: bit]; bbPtr.width ¬ bbPtr.width - clipLeft}; IF INTEGER[bbPtr.width] <= 0 OR INTEGER[bbPtr.height] <= 0 THEN LOOP; BitBlt.BITBLT[bbPtr]; ENDLOOP}; -- Utility for address calculation BitAddressFromPlace: PUBLIC PROC [ base: BitBlt.BitAddress, x, y: NATURAL, raster: CARDINAL] RETURNS [BitBlt.BitAddress] = { OPEN Inline; LocalBitAddress: TYPE = RECORD [word: LONG POINTER, bit: CARDINAL]; bitOffset: LongNumber = [ lc[LongMult[y, raster] + LOOPHOLE[base, LocalBitAddress].bit + x]]; RETURN[ LOOPHOLE[LocalBitAddress[ word: base.word + DBITSHIFT[bitOffset.lu, -4], bit: BITAND[bitOffset.lowbits, 15]]]]}; END.