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