DIRECTORY Basics, BitBltOps, PrincOps; BitBltOpsImpl: PROGRAM IMPORTS Basics EXPORTS BitBltOps = BEGIN OPEN Basics; BitAddress: TYPE = PrincOps.BitAddress; BitBltInc: TYPE = RECORD[wVal, bitVal: INT, easy: BOOL]; -- easy if value MOD bitsPerWord = 0 nulBitAddress: BitAddress = [NIL, 0, 0]; srcAddr: BitAddress; -- address of source word at beginning of line dstAddr: BitAddress; -- address of destination word at beginning of line goodDstAddr: BitAddress; -- address of good destination word at beginning of line srcFunc: PrincOps.SrcFunc _ null; dstFunc: PrincOps.DstFunc _ null; srcInc, dstInc: BitBltInc; goingForward: BOOL _ TRUE; isThin: BOOL _ FALSE; -- true if dest is all within one word lMask: WORD; rMask: WORD; skew: NAT; dWidth, sWidth: INTEGER; -- width in words, including left & right partial words extraWordAtLeft, extraWordAtRight: BOOL; isGray: BOOL _ FALSE; grayParam: PrincOps.GrayParm; grayWidth: BitBltInc; grayBump: BitBltInc; lastGray: [0..15); lastBBT: PrincOps.BitBltTable; InvalidBitBltCall: ERROR = CODE; HardCase: SIGNAL = CODE; BadValueForward: SIGNAL[ATOM] = CODE; BadValueBackward: SIGNAL[ATOM] = CODE; BadValueThin: SIGNAL = CODE; debugging: BOOL _ FALSE; BitBltOpCheck: PUBLIC PROC[bbt: PrincOps.BitBltTablePtr, goodDest: BitAddress] = { grayHeightMod: CARDINAL; lineNum: CARDINAL _ DoSetup[bbt, goodDest]; -- which line do we start with IF isGray THEN grayHeightMod _ grayParam.heightMinusOne+1; WHILE lineNum IN [0..bbt.height) DO sInc: BitBltInc; IF goingForward THEN { IF isGray THEN BltOneLineForwardGrayCheck[] ELSE BltOneLineForwardCheck[] } ELSE BltOneLineBackward[]; lineNum _ lineNum + (IF goingForward THEN 1 ELSE -1); sInc _ IF bbt.flags.gray THEN IF (lineNum MOD grayHeightMod) = lastGray THEN grayBump ELSE grayWidth ELSE srcInc; IF sInc.easy AND dstInc.easy THEN { srcAddr _ BitBltAddrInc[srcAddr, sInc]; dstAddr _ BitBltAddrInc[dstAddr, dstInc]; goodDstAddr _ BitBltAddrInc[goodDstAddr, dstInc]; } ELSE RecomputeCheck[bbt, goodDest, sInc]; ENDLOOP; }; BitBltOp: PUBLIC PROC[bbt: PrincOps.BitBltTablePtr] = { grayHeightMod: CARDINAL; lineNum: CARDINAL _ DoSetup[bbt, nulBitAddress]; -- which line do we start with IF isGray THEN grayHeightMod _ grayParam.heightMinusOne+1; WHILE lineNum IN [0..bbt.height) DO sInc: BitBltInc; IF goingForward THEN { IF isGray THEN BltOneLineForwardGray[] ELSE BltOneLineForward[] } ELSE BltOneLineBackwardCheck[]; lineNum _ lineNum + (IF goingForward THEN 1 ELSE -1); sInc _ IF bbt.flags.gray THEN IF (lineNum MOD grayHeightMod) = lastGray THEN grayBump ELSE grayWidth ELSE srcInc; IF sInc.easy AND dstInc.easy THEN { srcAddr _ BitBltAddrInc[srcAddr, sInc]; dstAddr _ BitBltAddrInc[dstAddr, dstInc]; } ELSE Recompute[bbt, sInc]; ENDLOOP; }; DoSetup: PROC[bbt: PrincOps.BitBltTablePtr, goodDest: BitAddress] RETURNS[lineNum: CARDINAL] = { IF bbt.flags.reserved # 0 OR bbt.reserved # 0 OR bbt.src.reserved # 0 OR bbt.dst.reserved # 0 OR bbt.width > LAST[NAT] OR bbt.height > LAST[NAT] THEN ERROR InvalidBitBltCall; lastBBT _ bbt^; goingForward _ bbt.flags.direction = forward; srcFunc _ bbt.flags.srcFunc; dstFunc _ bbt.flags.dstFunc; srcAddr _ bbt.src; -- true for either real source or gray IF (isGray _ bbt.flags.gray) THEN { grayParam _ LOOPHOLE[bbt.srcDesc]; IF grayParam.widthMinusOne # 0 OR grayParam.reserved # 0 OR ~goingForward OR ~bbt.flags.disjoint OR bbt.dstBpl < 0 THEN ERROR InvalidBitBltCall; grayWidth.easy _ TRUE; grayWidth.wVal _ grayParam.widthMinusOne+1; grayWidth.bitVal _ grayWidth.wVal * bitsPerWord; grayBump.easy _ TRUE; grayBump.wVal _ -grayWidth.wVal*grayParam.heightMinusOne; grayBump.bitVal _ grayBump.wVal * bitsPerWord; } ELSE { srcI: INTEGER = LOOPHOLE[bbt.srcDesc]; IF srcI < 0 THEN srcInc.easy _ (-srcI MOD bitsPerWord) = 0 ELSE srcInc.easy _ (srcI MOD bitsPerWord) = 0; srcInc.wVal _ IF srcInc.easy THEN srcI/bitsPerWord ELSE -1; srcInc.bitVal _ srcI; IF (goingForward AND (srcInc.bitVal < 0 OR bbt.dstBpl < 0)) OR (~goingForward AND (srcInc.bitVal > 0 OR bbt.dstBpl > 0)) THEN ERROR InvalidBitBltCall; }; IF bbt.dstBpl < 0 THEN dstInc.easy _ (-bbt.dstBpl MOD bitsPerWord) = 0 ELSE dstInc.easy _ (bbt.dstBpl MOD bitsPerWord) = 0; dstInc.bitVal _ bbt.dstBpl; dstInc.wVal _ IF dstInc.easy THEN bbt.dstBpl/bitsPerWord ELSE -1; dstAddr _ bbt.dst; IF goodDest.word # NIL THEN goodDstAddr _ goodDest; IF isGray THEN lastGray _ IF goingForward THEN grayParam.heightMinusOne - grayParam.yOffset ELSE grayParam.yOffset; lineNum _ IF goingForward THEN 0 ELSE bbt.height-1; BEGIN bitSkew: INTEGER = srcAddr.bit - dstAddr.bit; finalDstInFirstLine: BitAddress _ BitBltAddrInc[bbt.dst, [wVal: -1, bitVal: bbt.width, easy: FALSE] ]; lMask _ LMask[dstAddr.bit]; rMask _ RMask[finalDstInFirstLine.bit]; skew _ IF bitSkew < 0 THEN bitsPerWord + bitSkew ELSE bitSkew; dWidth _ (dstAddr.bit + bbt.width + bitsPerWord - 1)/bitsPerWord; sWidth _ (srcAddr.bit + bbt.width + bitsPerWord - 1)/bitsPerWord; isThin _ (dWidth = 1); extraWordAtLeft _ extraWordAtRight _ FALSE; SELECT TRUE FROM sWidth > dWidth => extraWordAtLeft _ extraWordAtRight _ TRUE; sWidth < dWidth, sWidth = 1 => NULL; ENDCASE => IF bitSkew >= 0 THEN extraWordAtLeft _ TRUE ELSE extraWordAtRight _ TRUE; IF ~dstInc.easy AND dstInc.bitVal < 0 AND debugging THEN SIGNAL HardCase; END; }; BitBltAddrInc: PROC[base: BitAddress, offset: BitBltInc] RETURNS[ba: BitAddress] = { IF offset.easy THEN { ba.word _ LOOPHOLE[base.word + offset.wVal]; ba.bit _ base.bit; } ELSE { add: LongNumber = LOOPHOLE[base.bit + offset.bitVal]; wordPart: LongNumber _ LOOPHOLE[DoubleShift[add, -logBitsPerWord]]; wordPart.hi _ add.hi; -- makes negative if add was negative ba.word _ LOOPHOLE[base.word + LOOPHOLE[wordPart, INT]]; ba.bit _ BITAND[add.lo, bitsPerWord-1]; }; }; Recompute: PROC[bbt: PrincOps.BitBltTablePtr, sInc: BitBltInc] = { bitSkew: INTEGER; finalDstAddrInLine: BitAddress; srcAddr _ BitBltAddrInc[srcAddr, [wVal: sInc.wVal, bitVal: sInc.bitVal, easy: sInc.easy] ]; dstAddr _ BitBltAddrInc[dstAddr, [wVal: dstInc.wVal, bitVal: dstInc.bitVal, easy: dstInc.easy] ]; bitSkew _ srcAddr.bit - dstAddr.bit; skew _ IF bitSkew < 0 THEN bitsPerWord + bitSkew ELSE bitSkew; finalDstAddrInLine _ BitBltAddrInc[dstAddr, [wVal: -1, bitVal: bbt.width, easy: FALSE] ]; lMask _ LMask[dstAddr.bit]; rMask _ RMask[finalDstAddrInLine.bit]; dWidth _ (dstAddr.bit + bbt.width + bitsPerWord - 1)/bitsPerWord; sWidth _ (srcAddr.bit + bbt.width + bitsPerWord - 1)/bitsPerWord; isThin _ dWidth = 1; extraWordAtLeft _ extraWordAtRight _ FALSE; SELECT TRUE FROM sWidth > dWidth => extraWordAtLeft _ extraWordAtRight _ TRUE; sWidth < dWidth, sWidth = 1 => NULL; ENDCASE => IF bitSkew >= 0 THEN extraWordAtLeft _ TRUE ELSE extraWordAtRight _ TRUE; }; RecomputeCheck: PROC[ bbt: PrincOps.BitBltTablePtr, goodDestBase: BitAddress, sInc: BitBltInc] = { bitSkew: INTEGER; finalDstAddrInLine: BitAddress; srcAddr _ BitBltAddrInc[srcAddr, [wVal: sInc.wVal, bitVal: sInc.bitVal, easy: sInc.easy] ]; dstAddr _ BitBltAddrInc[dstAddr, [wVal: dstInc.wVal, bitVal: dstInc.bitVal, easy: dstInc.easy] ]; IF goodDestBase.word # NIL THEN goodDstAddr _ BitBltAddrInc[goodDstAddr, [wVal: dstInc.wVal, bitVal: dstInc.bitVal, easy: dstInc.easy] ]; bitSkew _ srcAddr.bit - dstAddr.bit; skew _ IF bitSkew < 0 THEN bitsPerWord - bitSkew ELSE bitSkew; finalDstAddrInLine _ BitBltAddrInc[dstAddr, [wVal: -1, bitVal: bbt.width, easy: FALSE] ]; lMask _ LMask[dstAddr.bit]; rMask _ RMask[finalDstAddrInLine.bit]; dWidth _ (dstAddr.bit + bbt.width + bitsPerWord - 1)/bitsPerWord; sWidth _ (srcAddr.bit + bbt.width + bitsPerWord - 1)/bitsPerWord; isThin _ dWidth = 1; extraWordAtLeft _ extraWordAtRight _ FALSE; SELECT TRUE FROM sWidth > dWidth => extraWordAtLeft _ extraWordAtRight _ TRUE; sWidth < dWidth, sWidth = 1 => NULL; ENDCASE => IF bitSkew >= 0 THEN extraWordAtLeft _ TRUE ELSE extraWordAtRight _ TRUE; }; BltOneLineForward: PROC = TRUSTED { src: LONG POINTER TO WORD _ LOOPHOLE[srcAddr.word]; dst: LONG POINTER TO WORD _ LOOPHOLE[dstAddr.word]; longSrc, shiftedSrc: Basics.LongNumber; dstValue, srcWord, curVal: WORD; width: INTEGER _ dWidth; longSrc.hi _ longSrc.lo _ src^; src _ LOOPHOLE[src+1]; IF extraWordAtLeft THEN { longSrc.lo _ src^; src _ LOOPHOLE[src+1]; }; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; IF isThin THEN { doubleMask: WORD = Basics.BITAND[lMask, rMask]; curVal _ Basics.BITAND[dst^, Basics.BITNOT[doubleMask]]; dstValue _ Basics.BITAND[dstValue, doubleMask]; dst^ _ Basics.BITOR[curVal, dstValue]; RETURN; }; dstValue _ Basics.BITAND[dstValue, lMask]; -- at left side, so do left mask curVal _ Basics.BITAND[dst^, BITNOT[lMask]]; dstValue _ Basics.BITOR[curVal, dstValue]; DO -- store full words in this loop dst^ _ dstValue; dst _ LOOPHOLE[dst + 1]; longSrc _ Basics.SwapHalves[longSrc]; -- cheaper than shifting IF width <=2 THEN EXIT; longSrc.lo _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; src _ LOOPHOLE[src+1]; width _ width - 1; ENDLOOP; IF extraWordAtRight THEN longSrc.lo _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; curVal _ Basics.BITAND[dst^, Basics.BITNOT[rMask] ]; dstValue _ Basics.BITAND[dstValue, rMask]; -- at right side, so do right mask dst^ _ Basics.BITOR[curVal, dstValue]; }; BltOneLineForwardCheck: PROC = TRUSTED { src: LONG POINTER TO WORD _ LOOPHOLE[srcAddr.word]; dst: LONG POINTER TO WORD _ LOOPHOLE[dstAddr.word]; goodDst: LONG POINTER TO WORD _ LOOPHOLE[goodDstAddr.word]; longSrc, shiftedSrc: Basics.LongNumber; dstValue, srcWord, curVal: WORD; width: INTEGER _ dWidth; first: BOOL _ TRUE; longSrc.hi _ longSrc.lo _ src^; src _ LOOPHOLE[src+1]; IF extraWordAtLeft THEN { longSrc.lo _ src^; src _ LOOPHOLE[src+1]; }; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; IF isThin THEN { doubleMask: WORD = Basics.BITAND[lMask, rMask]; goodMaskedVal: WORD = Basics.BITAND[goodDst^, doubleMask]; dstValue _ Basics.BITAND[dstValue, doubleMask]; IF dstValue # goodMaskedVal THEN SIGNAL BadValueThin; curVal _ Basics.BITAND[dst^, Basics.BITNOT[doubleMask]]; dst^ _ Basics.BITOR[curVal, dstValue]; RETURN; }; DO -- store full words in this loop IF first THEN { goodMaskedVal: WORD = Basics.BITAND[goodDst^, lMask]; dstValue _ Basics.BITAND[dstValue, lMask]; -- at left side, so do left mask curVal _ Basics.BITAND[dst^, BITNOT[lMask]]; IF dstValue # goodMaskedVal THEN SIGNAL BadValueForward[$left]; dstValue _ Basics.BITOR[curVal, dstValue]; first _ FALSE; } ELSE IF dstValue # goodDst^ THEN SIGNAL BadValueForward[$middle]; dst^ _ dstValue; dst _ LOOPHOLE[dst + 1]; goodDst _ LOOPHOLE[goodDst + 1]; longSrc _ Basics.SwapHalves[longSrc]; -- cheaper than shifting IF width <=2 THEN EXIT; longSrc.lo _ src^; src _ LOOPHOLE[src+1]; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; width _ width - 1; ENDLOOP; IF extraWordAtRight THEN longSrc.lo _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; BEGIN goodMaskedVal: WORD = Basics.BITAND[goodDst^, rMask]; curVal _ Basics.BITAND[dst^, Basics.BITNOT[rMask] ]; dstValue _ Basics.BITAND[dstValue, rMask]; -- at right side, so do right mask IF dstValue # goodMaskedVal THEN SIGNAL BadValueForward[$right]; dstValue _ Basics.BITOR[curVal, dstValue]; END; dst^ _ dstValue; }; BltOneLineForwardGray: PROC = TRUSTED { src: LONG POINTER TO WORD _ LOOPHOLE[srcAddr.word]; dst: LONG POINTER TO WORD _ LOOPHOLE[dstAddr.word]; longSrc, shiftedSrc: Basics.LongNumber; dstValue, srcWord, curVal: WORD; width: INTEGER _ dWidth; count: CARDINAL _ 0; longSrc.hi _ longSrc.lo _ src^; src _ GrayInc[src, count _ count + 1]; IF extraWordAtLeft THEN { longSrc.lo _ src^; src _ GrayInc[src, count _ count + 1]; }; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; IF isThin THEN { doubleMask: WORD = Basics.BITAND[lMask, rMask]; curVal _ Basics.BITAND[dst^, Basics.BITNOT[doubleMask]]; dstValue _ Basics.BITAND[dstValue, doubleMask]; dst^ _ Basics.BITOR[curVal, dstValue]; RETURN; }; dstValue _ Basics.BITAND[dstValue, lMask]; -- at left side, so do left mask curVal _ Basics.BITAND[dst^, BITNOT[lMask]]; dstValue _ Basics.BITOR[curVal, dstValue]; DO -- store full words in this loop dst^ _ dstValue; dst _ LOOPHOLE[dst + 1]; longSrc _ Basics.SwapHalves[longSrc]; -- cheaper than shifting IF width <=2 THEN EXIT; longSrc.lo _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; src _ GrayInc[src, count _ count + 1]; width _ width - 1; ENDLOOP; IF extraWordAtRight THEN longSrc.lo _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; curVal _ Basics.BITAND[dst^, Basics.BITNOT[rMask] ]; dstValue _ Basics.BITAND[dstValue, rMask]; -- at right side, so do right mask dst^ _ Basics.BITOR[curVal, dstValue]; }; BltOneLineForwardGrayCheck: PROC = TRUSTED { src: LONG POINTER TO WORD _ LOOPHOLE[srcAddr.word]; dst: LONG POINTER TO WORD _ LOOPHOLE[dstAddr.word]; goodDst: LONG POINTER TO WORD _ LOOPHOLE[goodDstAddr.word]; longSrc, shiftedSrc: Basics.LongNumber; dstValue, srcWord, curVal: WORD; width: INTEGER _ dWidth; first: BOOL _ TRUE; count: CARDINAL _ 0; longSrc.hi _ longSrc.lo _ src^; src _ GrayInc[src, count _ count + 1]; IF extraWordAtLeft THEN { longSrc.lo _ src^; src _ GrayInc[src, count _ count + 1]; }; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; IF isThin THEN { doubleMask: WORD = Basics.BITAND[lMask, rMask]; goodMaskedVal: WORD = Basics.BITAND[goodDst^, doubleMask]; dstValue _ Basics.BITAND[dstValue, doubleMask]; IF dstValue # goodMaskedVal THEN SIGNAL BadValueThin; curVal _ Basics.BITAND[dst^, Basics.BITNOT[doubleMask]]; dst^ _ Basics.BITOR[curVal, dstValue]; RETURN; }; DO -- store full words in this loop IF first THEN { goodMaskedVal: WORD = Basics.BITAND[goodDst^, lMask]; dstValue _ Basics.BITAND[dstValue, lMask]; -- at left side, so do left mask curVal _ Basics.BITAND[dst^, BITNOT[lMask]]; IF dstValue # goodMaskedVal THEN SIGNAL BadValueForward[$left]; dstValue _ Basics.BITOR[curVal, dstValue]; first _ FALSE; } ELSE IF dstValue # goodDst^ THEN SIGNAL BadValueForward[$middle]; dst^ _ dstValue; dst _ LOOPHOLE[dst + 1]; goodDst _ LOOPHOLE[goodDst + 1]; longSrc _ Basics.SwapHalves[longSrc]; -- cheaper than shifting IF width <=2 THEN EXIT; longSrc.lo _ src^; src _ GrayInc[src, count _ count + 1]; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; width _ width - 1; ENDLOOP; IF extraWordAtRight THEN longSrc.lo _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; BEGIN goodMaskedVal: WORD = Basics.BITAND[goodDst^, rMask]; curVal _ Basics.BITAND[dst^, Basics.BITNOT[rMask] ]; dstValue _ Basics.BITAND[dstValue, rMask]; -- at right side, so do right mask IF dstValue # goodMaskedVal THEN SIGNAL BadValueForward[$right]; dstValue _ Basics.BITOR[curVal, dstValue]; END; dst^ _ dstValue; }; BltOneLineBackward: PROC = TRUSTED { src: LONG POINTER TO WORD _ LOOPHOLE[srcAddr.word + sWidth - 1]; dst: LONG POINTER TO WORD _ LOOPHOLE[dstAddr.word + dWidth - 1]; longSrc, shiftedSrc: Basics.LongNumber; dstValue, srcWord, curVal: WORD; width: INTEGER _ dWidth; longSrc.hi _ longSrc.lo _ src^; src _ LOOPHOLE[src-1]; IF extraWordAtRight THEN { longSrc.hi _ src^; src _ LOOPHOLE[src-1]; }; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; IF isThin THEN { doubleMask: WORD = Basics.BITAND[lMask, rMask]; curVal _ Basics.BITAND[dst^, Basics.BITNOT[doubleMask]]; dstValue _ Basics.BITAND[dstValue, doubleMask]; dst^ _ Basics.BITOR[curVal, dstValue]; RETURN; }; dstValue _ Basics.BITAND[dstValue, rMask]; -- at right side, so do right mask curVal _ Basics.BITAND[dst^, Basics.BITNOT[rMask] ]; dstValue _ Basics.BITOR[curVal, dstValue]; DO -- store full words in this loop dst^ _ dstValue; dst _ LOOPHOLE[dst-1]; longSrc _ Basics.SwapHalves[longSrc]; -- cheaper than shifting IF width <=2 THEN EXIT; longSrc.hi _ src^; src _ LOOPHOLE[src-1]; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; width _ width - 1; ENDLOOP; IF extraWordAtLeft THEN longSrc.lo _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; dstValue _ Basics.BITAND[dstValue, lMask]; -- at left side, so do left mask curVal _ Basics.BITAND[dst^, BITNOT[lMask]]; dst^ _ Basics.BITOR[curVal, dstValue]; }; BltOneLineBackwardCheck: PROC = TRUSTED { src: LONG POINTER TO WORD _ LOOPHOLE[srcAddr.word + sWidth - 1]; dst: LONG POINTER TO WORD _ LOOPHOLE[dstAddr.word + dWidth - 1]; goodDst: LONG POINTER TO WORD _ LOOPHOLE[goodDstAddr.word + dWidth - 1]; longSrc, shiftedSrc: Basics.LongNumber; dstValue, srcWord, curVal: WORD; width: INTEGER _ dWidth; first: BOOL _ TRUE; longSrc.hi _ longSrc.lo _ src^; src _ LOOPHOLE[src-1]; IF extraWordAtRight THEN { longSrc.hi _ src^; src _ LOOPHOLE[src-1]; }; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; IF isThin THEN { doubleMask: WORD = Basics.BITAND[lMask, rMask]; goodMaskedVal: WORD = Basics.BITAND[goodDst^, doubleMask]; dstValue _ Basics.BITAND[dstValue, doubleMask]; IF dstValue # goodMaskedVal THEN SIGNAL BadValueThin; curVal _ Basics.BITAND[dst^, Basics.BITNOT[doubleMask]]; dst^ _ Basics.BITOR[curVal, dstValue]; RETURN; }; dstValue _ Basics.BITAND[dstValue, rMask]; -- at right side, so do right mask curVal _ Basics.BITAND[dst^, Basics.BITNOT[rMask] ]; DO -- store full words in this loop IF first THEN { goodMaskedVal: WORD = Basics.BITAND[goodDst^, rMask]; IF dstValue # goodMaskedVal THEN SIGNAL BadValueBackward[$right]; dstValue _ Basics.BITOR[curVal, dstValue]; first _ FALSE; } ELSE IF dstValue # goodDst^ THEN SIGNAL BadValueBackward[$middle]; dst^ _ dstValue; dst _ LOOPHOLE[dst-1]; goodDst _ LOOPHOLE[goodDst-1]; longSrc _ Basics.SwapHalves[longSrc]; -- cheaper than shifting IF width <=2 THEN EXIT; longSrc.hi _ src^; src _ LOOPHOLE[src-1]; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; width _ width - 1; ENDLOOP; IF extraWordAtLeft THEN longSrc.lo _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; BEGIN goodMaskedVal: WORD = Basics.BITAND[goodDst^, lMask]; curVal _ Basics.BITAND[dst^, BITNOT[lMask]]; dstValue _ Basics.BITAND[dstValue, lMask]; -- at left side, so do left mask IF dstValue # goodMaskedVal THEN SIGNAL BadValueBackward[$left]; dstValue _ Basics.BITOR[curVal, dstValue]; END; dst^ _ dstValue; }; ComputeDstValue: PROC[longSrc: Basics.LongNumber, dst: LONG POINTER TO WORD] RETURNS[shiftedSrc: Basics.LongNumber, srcWord, dstValue: WORD] = { shiftedSrc _ Basics.DoubleShiftLeft[longSrc, skew]; srcWord _ shiftedSrc.hi; IF srcFunc = complement THEN srcWord _ Basics.BITNOT[srcWord]; dstValue _ SELECT dstFunc FROM null => srcWord, and => Basics.BITAND[srcWord, dst^], or => Basics.BITOR[srcWord, dst^], xor =>Basics.BITXOR[srcWord, dst^], ENDCASE => ERROR InvalidBitBltCall; }; GrayInc: PROC[src: LONG POINTER TO WORD, count: INT] RETURNS[LONG POINTER TO WORD] = { inc: INT; IF grayWidth.wVal = 1 THEN RETURN[src] -- special case ELSE inc _ count MOD grayWidth.wVal; RETURN[LOOPHOLE[src+inc]]; }; LMask: PROC[bitNum: [0..bitsPerWord)] RETURNS[WORD] = { SELECT bitNum FROM 0 => RETURN[177777B]; 1 => RETURN[ 77777B]; 2 => RETURN[ 37777B]; 3 => RETURN[ 17777B]; 4 => RETURN[ 7777B]; 5 => RETURN[ 3777B]; 6 => RETURN[ 1777B]; 7 => RETURN[ 777B]; 8 => RETURN[ 377B]; 9 => RETURN[ 177B]; 10 => RETURN[ 77B]; 11 => RETURN[ 37B]; 12 => RETURN[ 17B]; 13 => RETURN[ 7B]; 14 => RETURN[ 3B]; 15 => RETURN[ 1B]; ENDCASE => ERROR InvalidBitBltCall; }; RMask: PROC[bitNum: [0..bitsPerWord)] RETURNS[WORD] = { SELECT bitNum FROM 0 => RETURN[177777B]; -- really bit 16 ENDCASE => RETURN[BITNOT[LMask[bitNum]] ]; }; END. XBitBltOpsImpl.mesa Copyright (C) 1986 by Xerox Corporation. All rights reserved. Willie-Sue, September 11, 1986 3:27:06 pm PDT Cedar code to implement the BitBlt operation as defined (almost) by PrincOps dWidth & sWidth differ by ar most +/-1 dWidth > 2 => left partial, dWidth-2 full words, and right partial dWidth = 2 => left partial, right partial only dWidth = 1 => entire destination within one word - special case as both masks need to be applied at the same time If sWidth = dWidth+1, an extra source word must be fetched at both ends. If sWidth = dWidth-1 or sWidth = 1, no extra source words need be fetched. If sWidth = dWidth # 1, an extra source word must be fetched at one end: if src.bit mod 20 > dst.bit mod 20 then left else right ENABLE UNWIND, ABORTED => NULL; ENABLE UNWIND, ABORTED => NULL; check for legality (~bbt.flags.gray AND LOOPHOLE[bbt.srcDesc, INTEGER] = 0) OR -- bbt.dstBpl = 0 OR more checking checking for thin case, setting up masks, widths for line what we really want here is arithemtic right shift, but alas, we'll have to fake it we know that base.bit + offset.bitVal is no more than 16 bits IF add.hi < 0 THEN wordPart.hi _ 177777B; either srcBpl or dstBpl was not a multiple of bitsPerWord; recompute masks for this line either srcBpl or dstBpl was not a multiple of bitsPerWord; recompute masks for this line Κ‹˜™J™>Icode™-—J™J™LJ˜šΟk ˜ J˜J˜ J˜ —J˜šΟn œ˜š˜J˜—š˜J˜ —J˜Jšœœœ˜—J˜Jšœ œ˜'Jš œ œœœœΟc$˜]J˜Jšœœ˜(JšœŸ.˜DJšœŸ3˜IJšœŸ8˜QJšœ!˜!Jšœ!˜!Jšœ˜Jšœœœ˜J˜JšœœœŸ&˜>Jšœœ˜ Jšœœ˜ Jšœœ˜ šœœŸ7˜QJšœ&™&JšœB™BJšœ.™.Jšœq™q—šœ#œ˜(JšœH™HJ™J™HJ™7——J˜Jšœœœ˜Jšœ˜Jšœ˜Jšœ˜J˜Jšœ˜J˜Jšžœœœ˜!Jšžœœœ˜Jšžœœœœ˜%Jšžœœœœ˜&Jšž œœœ˜J˜Jšœ œœ˜J˜šž œœœ8˜RJšœœœœ™Jšœœ˜Jšœ œŸ˜LJšœœ,˜:J˜šœœ˜#Jšœ˜šœœ˜Jšœœœ˜IJšœœ˜—J˜Jšœœœœ˜5šœœ˜Jšœ œœ œ ˜FJšœ˜ —šœ œ œ˜#Jšœ'˜'Jšœ)˜)Jšœ1˜1J˜Jšœ%˜)—Jšœ˜—J˜—J˜šžœœœ"˜7Jšœœœœ™Jšœœ˜Jšœ œ!Ÿ˜PJšœœ,˜:J˜šœœ˜#Jšœ˜šœœ˜Jšœœœ˜?Jšœœ˜!—Jšœœœœ˜5šœœ˜Jšœ œœ œ ˜FJšœ˜ —šœ œ œ˜#Jšœ'˜'Jšœ)˜)J˜Jšœ˜—Jšœ˜—J˜—J˜šžœœ4˜AJšœœ œ˜Jšœ™šœœ˜0Jšœœ˜/Jš œœœœœŸ™QJšœ œœœœœœœ˜M—J˜Jšœ˜Jšœ-˜-J˜J˜JšœŸ&˜:šœœ˜#Jšœ œ˜"Jšœ ™ šœœ˜;Jš œœœœœ˜T—Jšœœ˜Jšœ+˜+Jšœ0˜0Jšœœ˜Jšœ9˜9Jšœ.˜.J˜šœ˜Jšœœœ˜&šœ œœ˜:Jšœœ˜.—Jšœœ œœ˜;Jšœ˜šœœœ˜>šœœœ˜>Jšœœ˜——J˜—šœœœ˜FJšœœ˜4—Jšœ˜Jšœœ œœ˜AJ˜Jšœ˜šœœœ˜3J˜——šœœ œ˜.J˜,Jšœ˜—Jšœ œœœ˜3J™Jšœ9™9š˜Jšœ œ˜-šœ!˜!Jšœ;œ˜D—Jšœ˜Jšœ'˜'Jšœœ œœ ˜>JšœA˜AJšœA˜AJšœ˜Jšœ%œ˜+šœœ˜Jšœ8œ˜=Jšœœ˜$šœ˜ šœœ˜+Jšœœ˜———Jš œœœ œœ ˜IJšœ˜—J˜—J˜šž œœ&œ˜Tšœ œ˜Jšœ œ˜,Jšœ˜J˜šœ˜Jšœœ˜5Jšœœ$˜CJ™SJšœ=™=J™)JšœŸ%˜JšœPœ˜YJšœ˜Jšœ&˜&JšœA˜AJšœA˜AJšœ˜Jšœ%œ˜+šœœ˜Jšœ8œ˜=Jšœœ˜$šœ˜ šœœ˜+Jšœœ˜———J˜—J˜šžœœ˜JšœL˜LJšœX™XJ™Jšœ œ˜Jšœ˜Jšœ[˜[Jšœa˜ašœœœ)˜HJšœ@˜@—J˜Jšœ$˜$Jšœœ œœ ˜>JšœPœ˜YJšœ˜Jšœ&˜&JšœA˜AJšœA˜AJšœ˜Jšœ%œ˜+šœœ˜Jšœ8œ˜=Jšœœ˜$šœ˜ šœœ˜+Jšœœ˜———J˜—J˜šžœœœ˜#Jš œœœœœœ˜3Jš œœœœœœ˜3Jšœ'˜'Jšœœ˜ Jšœœ ˜J˜Jšœ˜Jšœœ˜šœœ˜Jšœ˜Jšœœ˜J˜—Jšœ@˜@J˜šœœ˜Jšœ œ œ˜/Jšœœœ˜8Jšœœ˜/Jšœœ˜&Jšœ˜J˜—J˜JšœœŸ ˜LJšœœœ ˜,Jšœœ˜*J˜šœŸ ˜$Jšœ˜Jšœœ ˜J˜Jšœ'Ÿ˜?Jšœ œœ˜Jšœ˜Jšœ@˜@Jšœœ˜Jšœ˜Jšœ˜—J˜Jšœœ˜+Jšœ@˜@J˜Jšœœœ ˜4JšœœŸ"˜NJšœœ˜&Jšœ˜—J˜šžœœœ˜(Jš œœœœœœ˜3Jš œœœœœœ˜3Jš œ œœœœœ˜;Jšœ'˜'Jšœœ˜ Jšœœ ˜Jšœœœ˜J˜Jšœ˜Jšœœ˜šœœ˜Jšœ˜Jšœœ˜J˜—Jšœ@˜@J˜šœœ˜Jšœ œ œ˜/Jšœœ œ˜:Jšœœ˜/Jšœœœ˜5Jšœœœ˜8Jšœœ˜&Jšœ˜J˜—J˜šœŸ ˜$šœœ˜Jšœœ œ˜5JšœœŸ ˜LJšœœœ ˜,Jšœœœ˜?Jšœœ˜*Jšœœ˜J˜Jšœœœœ˜A—Jšœ˜Jšœœ ˜Jšœ œ˜ J˜Jšœ'Ÿ˜?Jšœ œœ˜Jšœ˜Jšœœ˜Jšœ@˜@Jšœ˜Jšœ˜—J˜Jšœœ˜+Jšœ@˜@J™š˜Jšœœ œ˜5Jšœœœ ˜4JšœœŸ"˜NJšœœœ˜@Jšœœ˜*Jšœ˜—Jšœ˜Jšœ˜—J˜šžœœœ˜'Jš œœœœœœ˜3Jš œœœœœœ˜3Jšœ'˜'Jšœœ˜ Jšœœ ˜Jšœœ˜J˜Jšœ˜Jšœ&˜&šœœ˜Jšœ˜Jšœ&˜&J˜—Jšœ@˜@J˜šœœ˜Jšœ œ œ˜/Jšœœœ˜8Jšœœ˜/Jšœœ˜&Jšœ˜J˜—J˜JšœœŸ ˜LJšœœœ ˜,Jšœœ˜*J˜šœŸ ˜$Jšœ˜Jšœœ ˜J˜Jšœ'Ÿ˜?Jšœ œœ˜Jšœ˜Jšœ@˜@Jšœ&˜&Jšœ˜Jšœ˜—J˜Jšœœ˜+Jšœ@˜@J˜Jšœœœ ˜4JšœœŸ"˜NJšœœ˜&Jšœ˜—J˜šžœœœ˜,Jš œœœœœœ˜3Jš œœœœœœ˜3Jš œ œœœœœ˜;Jšœ'˜'Jšœœ˜ Jšœœ ˜Jšœœœ˜Jšœœ˜J˜Jšœ˜Jšœ&˜&šœœ˜Jšœ˜Jšœ&˜&J˜—Jšœ@˜@J˜šœœ˜Jšœ œ œ˜/Jšœœ œ˜:Jšœœ˜/Jšœœœ˜5Jšœœœ˜8Jšœœ˜&Jšœ˜J˜—J˜šœŸ ˜$šœœ˜Jšœœ œ˜5JšœœŸ ˜LJšœœœ ˜,Jšœœœ˜?Jšœœ˜*Jšœœ˜J˜Jšœœœœ˜A—Jšœ˜Jšœœ ˜Jšœ œ˜ J˜Jšœ'Ÿ˜?Jšœ œœ˜Jšœ˜Jšœ&˜&Jšœ@˜@Jšœ˜Jšœ˜—J™Jšœœ˜+Jšœ@˜@J™š˜Jšœœ œ˜5Jšœœœ ˜4JšœœŸ"˜NJšœœœ˜@Jšœœ˜*Jšœ˜—Jšœ˜Jšœ˜—J˜šžœœœ˜$Jš œœœœœœ˜@Jš œœœœœœ˜@Jšœ'˜'Jšœœ˜ Jšœœ ˜J˜Jšœ˜šœœ˜Jšœœ˜Jšœ˜Jšœœ˜J˜—Jšœ@˜@J˜šœœ˜Jšœ œ œ˜/Jšœœœ˜8Jšœœ˜/Jšœœ˜&Jšœ˜J˜—J˜JšœœŸ"˜NJšœœœ ˜4Jšœœ˜*J˜šœŸ ˜$Jšœ˜Jšœœ˜J˜Jšœ'Ÿ˜?Jšœ œœ˜Jšœ˜Jšœœ˜Jšœ@˜@Jšœ˜Jšœ˜—J™Jšœœ˜*Jšœ@˜@J™JšœœŸ ˜LJšœœœ ˜,Jšœœ˜&Jšœ˜J˜—šžœœœ˜)Jš œœœœœœ˜@Jš œœœœœœ˜@Jš œ œœœœœ ˜HJšœ'˜'Jšœœ˜ Jšœœ ˜Jšœœœ˜J˜Jšœ˜Jšœœ˜šœœ˜Jšœ˜Jšœœ˜J˜—J˜Jšœ@˜@J˜šœœ˜Jšœ œ œ˜/Jšœœ œ˜:Jšœœ˜/Jšœœœ˜5Jšœœœ˜8Jšœœ˜&Jšœ˜J˜—J˜JšœœŸ"˜NJšœœœ ˜4J˜šœŸ ˜$šœœ˜Jšœœ œ˜5Jšœœœ˜AJšœœ˜*Jšœœ˜J˜Jšœœœœ˜B—Jšœ˜Jšœœ˜Jšœ œ ˜J˜Jšœ'Ÿ˜?Jšœ œœ˜Jšœ˜Jšœœ˜Jšœ@˜@Jšœ˜Jšœ˜—J˜Jšœœ˜*Jšœ@˜@J˜š˜Jšœœ œ˜5Jšœœœ ˜,JšœœŸ ˜LJšœœœ˜@Jšœœ˜*Jšœ˜—Jšœ˜Jšœ˜—J˜š žœœ"œœœœ˜LJšœœ3œ˜DJšœ3˜3Jšœ˜Jšœœœ ˜>šœ œ ˜Jšœ˜Jšœœ˜$Jšœ œ˜"Jšœ œ˜#Jšœœ˜#—J˜—J˜šžœœœœœœ œ˜4Jš œœœœœœ˜"Jšœœ˜ šœœœŸ˜7Jšœ œ˜$—Jšœœ ˜J˜—J˜šžœœœœ˜7šœ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ˜#—J˜J˜—šžœœœœ˜7šœ˜Jšœœ Ÿ˜(Jšœœœ˜*—J˜—J˜šœ˜J˜——…—LΘk«