DIRECTORY Basics, BitBlt, PrincOps; BitBltImpl: MONITOR IMPORTS Basics EXPORTS BitBlt = BEGIN OPEN Basics; BitAddress: TYPE = PrincOps.BitAddress; BitBltInc: TYPE = RECORD[wVal, bitVal: INT, easy: BOOL]; -- easy if value MOD bitsPerWord = 0 srcAddr: BitAddress; -- address of source word at beginning of line dstAddr: BitAddress; -- address of 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); InvalidBitBltCall: ERROR = CODE; BITBLT: PUBLIC ENTRY PROC[bbt: PrincOps.BitBltTablePtr] = { ENABLE UNWIND, ABORTED => NULL; grayHeightMod: CARDINAL; lineNum: CARDINAL _ DoSetup[bbt]; -- which line do we start with IF isGray THEN grayHeightMod _ grayParam.heightMinusOne+1; WHILE lineNum IN [0..bbt.height) DO sInc: BitBltInc; IF isGray THEN BltOneLineForwardGray[] ELSE IF goingForward THEN BltOneLineForward[] 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]; } ELSE Recompute[bbt, sInc]; ENDLOOP; }; DoSetup: PROC[bbt: PrincOps.BitBltTablePtr] 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; 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 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; 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; }; 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 = BITAND[lMask, rMask]; curVal _ BITAND[dst^, BITNOT[doubleMask]]; dstValue _ BITAND[dstValue, doubleMask]; dst^ _ BITOR[curVal, dstValue]; RETURN; }; dstValue _ BITAND[dstValue, lMask]; -- at left side, so do left mask curVal _ BITAND[dst^, BITNOT[lMask]]; dstValue _ BITOR[curVal, dstValue]; DO -- store full words in this loop dst^ _ dstValue; dst _ LOOPHOLE[dst + 1]; longSrc _ 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 _ BITAND[dst^, BITNOT[rMask] ]; dstValue _ BITAND[dstValue, rMask]; -- at right side, so do right mask dst^ _ BITOR[curVal, 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 = BITAND[lMask, rMask]; curVal _ BITAND[dst^, BITNOT[doubleMask]]; dstValue _ BITAND[dstValue, doubleMask]; dst^ _ BITOR[curVal, dstValue]; RETURN; }; dstValue _ BITAND[dstValue, lMask]; -- at left side, so do left mask curVal _ BITAND[dst^, BITNOT[lMask]]; dstValue _ BITOR[curVal, dstValue]; DO -- store full words in this loop dst^ _ dstValue; dst _ LOOPHOLE[dst + 1]; longSrc _ 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 _ BITAND[dst^, BITNOT[rMask] ]; dstValue _ BITAND[dstValue, rMask]; -- at right side, so do right mask dst^ _ BITOR[curVal, 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 = BITAND[lMask, rMask]; curVal _ BITAND[dst^, BITNOT[doubleMask]]; dstValue _ BITAND[dstValue, doubleMask]; dst^ _ BITOR[curVal, dstValue]; RETURN; }; dstValue _ BITAND[dstValue, rMask]; -- at right side, so do right mask curVal _ BITAND[dst^, BITNOT[rMask] ]; dstValue _ BITOR[curVal, dstValue]; DO -- store full words in this loop dst^ _ dstValue; dst _ LOOPHOLE[dst-1]; longSrc _ 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.hi _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; dstValue _ BITAND[dstValue, lMask]; -- at left side, so do left mask curVal _ BITAND[dst^, BITNOT[lMask]]; dst^ _ BITOR[curVal, 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 _ BITNOT[srcWord]; dstValue _ SELECT dstFunc FROM null => srcWord, and => BITAND[srcWord, dst^], or => BITOR[srcWord, dst^], xor =>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 1 => RETURN[100000B]; 2 => RETURN[140000B]; 3 => RETURN[160000B]; 4 => RETURN[170000B]; 5 => RETURN[174000B]; 6 => RETURN[176000B]; 7 => RETURN[177000B]; 8 => RETURN[177400B]; 9 => RETURN[177600B]; 10 => RETURN[177700B]; 11 => RETURN[177740B]; 12 => RETURN[177760B]; 13 => RETURN[177770B]; 14 => RETURN[177774B]; 15 => RETURN[177776B]; ENDCASE => ERROR InvalidBitBltCall; }; END. ΘBitBltImpl.mesa Copyright (C) 1986 by Xerox Corporation. All rights reserved. Willie-Sue, September 11, 1986 3:32:54 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 bitsPerWord > dst.bit mod bitsPerWord then left else right 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 Κ?˜™J™>Icode™-—J™J™LJ˜šΟk ˜ J˜J˜J˜ —J˜šΟn œ˜Jšœ˜J˜Jšœ˜J˜Jšœœœ˜—J˜Jšœ œ˜'Jš œ œœœœΟc$˜]J˜JšœŸ.˜DJšœŸ3˜IJšœ!˜!Jšœ!˜!Jšœ˜Jšœœœ˜J˜JšœœœŸ&˜>Jšœœ˜ Jšœœ˜ Jšœœ˜ šœœŸ7˜QJšœ&™&JšœB™BJšœ.™.Jšœq™q—šœ#œ˜(JšœH™HJ™J™HJ™I——J˜Jšœœœ˜Jšœ˜Jšœ˜Jšœ˜J˜J˜Jšžœœœ˜!J˜šœœœœ"˜;Jšœœœœ˜Jšœœ˜Jšœ œŸ˜AJšœœ,˜:J˜šœœ˜#Jšœ˜šœœ˜&Jšœœœ˜H—Jšœœœœ˜5šœœ˜Jšœ œœ œ ˜FJšœ˜ —šœ œ œ˜#Jšœ'˜'Jšœ)˜)J˜Jšœ˜—Jšœ˜—J˜—J˜šžœœœ œ˜JJšœ™šœœ˜0Jšœœ˜/Jš œœœœœŸ™QJšœ œœœœœœœ˜M—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˜——šœœ œ˜.J˜,Jšœ˜—Jšœ œœœ˜3J™Jšœ9™9š˜Jšœ œ˜-šœ!˜!Jšœ;œ˜D—Jšœ˜Jšœ'˜'Jšœœ œœ ˜>JšœA˜AJšœA˜AJšœ˜Jšœ%œ˜+šœœ˜Jšœ8œ˜=Jšœœ˜$šœ˜ šœœ˜+Jšœœ˜———Jšœ˜—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š œœœœœœ˜3Jš œœœœœœ˜3Jšœ'˜'Jšœœ˜ Jšœœ ˜J˜Jšœ˜Jšœœ˜šœœ˜Jšœ˜Jšœœ˜J˜—Jšœ@˜@J˜šœœ˜Jšœ œœ˜(Jšœ œœ˜*Jšœ œ˜(Jšœœ˜Jšœ˜J˜—J˜Jšœ œŸ ˜EJšœ œœ ˜%Jšœ œ˜#J˜šœŸ ˜$Jšœ˜Jšœœ ˜J˜Jšœ Ÿ˜8Jšœ œœ˜Jšœ˜Jšœ@˜@Jšœœ˜Jšœ˜Jšœ˜—J˜Jšœœ˜+Jšœ@˜@Jšœ œœ ˜&Jšœ œŸ"˜GJšœœ˜Jšœ˜—J˜šžœœœ˜'Jš œœœœœœ˜3Jš œœœœœœ˜3Jšœ'˜'Jšœœ˜ Jšœœ ˜Jšœœ˜J˜Jšœ˜Jšœ&˜&šœœ˜Jšœ˜Jšœ&˜&J˜—Jšœ@˜@J˜šœœ˜Jšœ œœ˜(Jšœ œœ˜*Jšœ œ˜(Jšœœ˜Jšœ˜J˜—J˜Jšœ œŸ ˜EJšœ œœ ˜%Jšœ œ˜#J˜šœŸ ˜$Jšœ˜Jšœœ ˜J˜Jšœ Ÿ˜8Jšœ œœ˜Jšœ˜Jšœ@˜@Jšœ&˜&Jšœ˜Jšœ˜—J˜Jšœœ˜+Jšœ@˜@J˜Jšœ œœ ˜&Jšœ œŸ"˜GJšœœ˜Jšœ˜—J˜šžœœœ˜$Jš œœœœœœ˜@Jš œœœœœœ˜@Jšœ'˜'Jšœœ˜ Jšœœ ˜J˜Jšœ˜šœœ˜Jšœœ˜Jšœ˜Jšœœ˜J˜—Jšœ@˜@J˜šœœ˜Jšœ œœ˜(Jšœ œœ˜*Jšœ œ˜(Jšœœ˜Jšœ˜J˜—J˜Jšœ œŸ"˜GJšœ œœ ˜&Jšœ œ˜#J˜šœŸ ˜$Jšœ˜Jšœœ˜J˜Jšœ Ÿ˜8Jšœ œœ˜Jšœ˜Jšœœ˜Jšœ@˜@Jšœ˜Jšœ˜—J™Jšœœ˜+Jšœ@˜@J˜Jšœ œŸ ˜EJšœ œœ ˜%Jšœœ˜Jšœ˜J˜—š žœœ"œœœœ˜LJšœœ3œ˜DJšœ3˜3Jšœ˜Jšœœ œ ˜7šœ œ ˜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šœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ ˜Jšœœ˜#—J˜—J˜šœ˜J˜——…—+„?‹