; ; File: DeviceLoop.a ; ; Contains: _DeviceLoop, a trap to assist in multi-device drawing ; ; Written by: Chris Derossi ; ; Copyright: © 1990-1991 by Apple Computer, Inc., all rights reserved. ; ; Change History (most recent first): ; ; <8> 1/13/92 PN Adding the quick draw "DeviceLoop" into ROM ; <7> 3/26/91 dba csd: take out VisRgnChanged, since I didnÕt really understand ; <6> 9/14/90 csd Used the interfaces instead of local definitions. ; <5> 8/20/90 dba call VisRgnChanged, now that it exists ; <4> 7/16/90 DC Fixed bug which I so graciously introduced into this code with ; change <3> Used d0 to hold first GDevice to check in stead of ; A4. ; <3> 7/12/90 DC changed loop priming to use TheGDevice instead of DeviceList ; whe TheGDevice is not equal to MainDevice (off-screen case) ; <2> 4/11/90 dba put in the trap number ; <1> 4/11/90 dba made it a linked patch ; print push,off load 'StandardEqu.d' include 'LinkedPatchMacros.a' print pop ;---------------------------------------------------------------------------------------------- ; PROCEDURE DeviceLoop(drawingRgn : RgnHandle; drawingProc : ProcPtr; ; userData : LongInt; flags : DeviceLoopFlags); ;---------------------------------------------------------------------------------------------- ; When DeviceLoop gets called, it searches all the active screen devices for the ; ones that intersect the drawingRgn. The drawingRgn is in local coordinates, and ; will usually be a portÕs visRgn (after a BeginUpdate call). For each device which ; intersects drawingRgn, the drawingProc routine is called. When the drawingProc is called, ; the current portÕs visRgn will be the intersection of the original visRgn and the ; intersecting portions of the device. ; The drawingProc should be declared as follows: ; ; PROCEDURE DrawingProc(depth : Integer; deviceFlags : Integer; targetDevice : GDHandle; ; userData : LongInt); ; ; where depth will be the pixelSize of the device, and flags are the gdFlags from ; the GDevice. The userData passed to DeviceLoop is also passed to the drawingProc. ; ; When called from a machine without Color QuickDraw, the targetDevice parameter passed to the ; drawing proc is set to NIL. ; ; The following flags may be passed to DeviceLoop: ; ; singleDevices If this flag is set, then similar devices are not grouped together when the ; drawingProc is called. If this flag is not set, DeviceLoop will only call ; the drawingProc once for each set of similar devices, but only the first ; one found is passed as targetDevice. It is assumed to be representative of ; all the similar devices. ; dontMatchSeeds If this flag is set, then color table seeds are not considered significant ; when comparing devices for similarity. Device similarity is based on color ; table depth and important gdevice flags (at this time, only the ; monochrome/color flag is considered important). This flag is ignored if ; the singleDevices flag is set. ; allDevices When this flag is set, the drawingRgn is ignored and DeviceLoop will call ; the drawingProc for all active screen gdevices. Whether or not similar ; devices are grouped together for a single call to the drawingProc depends ; on the setting of the singleDevices flag. The current portÕs visRgn is not ; affected when this flag is set. ;---------------------------------------------------------------------------------------------- ; Register Use: ; D3 current deviceÕs ordinal number for indexing into finished bitmap ; D4 RgnHandle for working region ; D5 bitmap of devices weÕve done ; D6 depth of current device (high word) & flags of current device (low word) ; D7 ctSeed of current device ; A2 current port ; A3 pointer to current device ; A4 handle to current device ;---------------------------------------------------------------------------------------------- DeviceLoop patchproc _DeviceLoop,(Plus,SE,II,Portable,IIci) activeScreenMask EQU $A000 importantFlagsMask EQU $A001 fakeDeviceFlags EQU $A801 DeviceLoopFrame RECORD {A6Link},DECR StartParams EQU * drawingRgn DS.L 1 drawingProc DS.L 1 userData DS.L 1 flags DS.L 1 ParamSize EQU StartParams-* Return DS.L 1 A6Link DS.L 1 savedVis DS.L 1 localRect DS.W 4 callerRegs DS.L 8 visAndDrawRgn DS.L 1 LocalSize EQU * ENDR with DeviceLoopFrame link A6, #LocalSize movem.l D3-D7/A2-A4, callerRegs(A6) ; save the callers registers machine MC68030 move.l ([$2b6],$1fc),a0 machine MC68020 tst.b $b5(a0) beq.s @noShield move.l drawingRgn(a6),d0 beq.s @noConversion move.l d0,a0 move.l (a0),a0 move.l $2(a0),localRect+0(a6) move.l $6(a0),localRect+4(a6) pea localRect+0(a6) _LocalToGlobal pea localRect+4(a6) _LocalToGlobal bra.s @proceedWithShield @noConversion move.l #$80008000,localRect+0(a6) move.l #$7fff7fff,localRect+4(a6) @proceedWithShield pea localRect+0(a6) clr.l -(sp) _ShieldCursor @noShield move.l TheGDevice, D0 ; Get the handle to the current GDevice move.l MainDevice, D1 ; Get the handle to the main device cmp.l D0, D1 ; if the two are not equalÉ bne.s @checkForOne ; we use TheGDevice to prime our device loop move.l DeviceList, D0 ; otherwise, we use DeviceList @checkForOne movea.l D0, A0 ; D0 here contains the first GDevice of the list we will use. move.l (A0), A0 tst.l gdNextGD(A0) ; is there a second device? beq @oneDevice ; if not, quick exit move.l D0, A4 ; put the beginning of the device list we are using in A4 move.l (A5), A2 ; point to QD globals move.l thePort(A2), A2 ; point to current port move.l flags(A6), D0 ; what are the current options? btst #allDevicesBit, D0 ; are we ignoring drawingRgn? bnz.s @regionsReady ; if so, thereÕs no region work move.l visRgn(A2), savedVis(A6) ; save the untouched visRgn subq #4, SP ; room for region handle _NewRgn move.l (SP)+, visRgn(A2) ; new working visRgn subq #4, SP ; room for region handle _NewRgn move.l (SP)+, D4 ; new device rect region move.l savedVis(A6), -(SP) ; current real visRgn move.l drawingRgn(A6), -(SP) ; callerÕs drawing region subq #4, SP ; room for region handle _NewRgn move.l (SP), visAndDrawRgn(A6) ; for intersection of vis and drawing regions _SectRgn ; calculate clipped drawing region @regionsReady moveq #0, D5 ; clear finished bitmap moveq #0, D3 ; weÕre starting with device 0 @deviceIntersect move.l A4, D0 ; is the GDHandle NIL? beq @noMore ; if so, no more devices move.l (A4), A3 ; point at the GDevice record bsr TestAndIntersect ; is device good for drawing? bz @nextDevice ; if not, keep searching move.l flags(A6), D0 ; get the callerÕs options btst #allDevicesBit, D0 ; are we ignoring regions? bnz @visRgnSetup ; if so, donÕt change the visRgn move.l D4, -(SP) ; rectangle region handle pea localRect(A6) ; this device (local coords) _RectRgn ; region = device rect (local) move.l D4, -(SP) ; device rect region (local) move.l visAndDrawRgn(A6), -(SP) ; ANDed with clipped drawing region move.l visRgn(A2), -(SP) ; turns into portÕs visRgn _SectRgn move.l (A4), A3 ; fix GDevicePtr @visRgnSetup move.l gdPMap(A3), A0 ; deviceÕs PixMapHandle move.l (A0), A0 ; deviceÕs PixMapPtr move.w pmPixelSize(A0), D6 ; deviceÕs depth swap D6 ; put depth high move.w gdFlags(A3), D6 ; get device flags in low word move.l pmTable(A0), A0 ; deviceÕs color table handle move.l (A0), A0 move.l ctSeed(A0), D7 ; stash deviceÕs ctab seed move.l flags(A6), D0 ; get callerÕs flags btst #singleDevicesBit, D0 ; should we group devices? bnz @groupingDone ; if not, donÕt call AddSimilar bsr AddSimilarDevices ; find all the like devices @groupingDone movem.l D3-D7/A2-A4/A6, -(SP) ; save OUR registers bsr NewFunc1 move D2,-(SP) swap D6 move.l D6, -(SP) ; pass depth and flags move.l A4, -(SP) ; and the GDHandle move.l userData(A6), -(SP) ; and finally the userÕs long move.l drawingProc(A6), A0 ; pointer to drawing procedure movem.l callerRegs(A6), D3-D7/A2-A4 ; restore callerÕs registers move.l A6Link(A6), A6 ; and restore callerÕs A6 jsr (A0) ; call the drawing procedure move (SP)+,D2 bsr NewFunc2 movem.l (SP)+, D3-D7/A2-A4/A6 ; get OUR register set back move.l (A4), A3 ; fix GDevicePtr @nextDevice move.l gdNextGD(A3), A4 ; get next device in chain addq #1, D3 ; increment device number bra.s @deviceIntersect ; try this one @oneDevice move.l A6, -(SP) ; save our stack frame ptr move.l gdPMap(A0), A1 ; PixMapHandle move.l (A1), A1 ; PixMapPtr move.w pmPixelSize(A1), -(SP) ; pass depth move.w gdFlags(A0), -(SP) ; and gdflags move.l D0, -(SP) ; and the GDHandle @simpleDeviceCommon move.l userData(A6), -(SP) ; and the userÕs long move.l drawingProc(A6), A0 ; the procedureÕs address move.l A6Link(A6), A6 ; and restore callerÕs A6 jsr (A0) ; call the drawing code move.l (SP)+, A6 ; restore access to our stack frame bra.s @exit @noMore move.l flags(A6), D0 ; what are the current options? btst #allDevicesBit, D0 ; are we ignoring drawingRgn? bnz.s @exit ; if so, no regions to clean up move.l visRgn(A2), -(SP) ; temp working visRgn _DisposRgn move.l visAndDrawRgn(A6), -(SP) ; temp clipped drawingRgn _DisposRgn move.l D4, -(SP) ; temp device rect rgn _DisposRgn move.l savedVis(A6), visRgn(A2) ; put original visRgn back @exit machine MC68030 move.l ([$2b6],$1fc),a0 machine MC68020 tst.b $b5(a0) beq.s @noShow _ShowCursor @noShow movem.l callerRegs(A6), D3-D7/A2-A4 ; restore regs unlk A6 move.l (SP)+, A0 ; clean stack and return lea ParamSize(SP), SP jmp (A0) AddSimilarDevices ; Starting with gdNextGD(A3), find all the devices that: ; have the same depth as D6 (high word) ; have the same important flags as D6 (low word) ; optionally have the same ctSeed as D7 ; havenÕt yet been drawn to ; are active screens (automatic because the flag bit for active is in importantFlagsMask) ; intersect drawingRgn(A6) ; ; When such a device is found, do: ; visRgn(A2) := visRgn(A2) | (gdRect & clipped drawingRgn) ; mark doneDevices bitmap (D5.L) so we donÕt do this one again movem.l A3-A4/D3/D6, -(SP) ; save original state andi.w #importantFlagsMask, D6 ; keep only pertinent flags move.l A3, A1 move.l gdNextGD(A3), A4 ; start with next device addq #1, D3 ; which is next in number, too @addLoop move.l A4, D0 ; is there a GDHandle? bz @noMore ; if NIL, then weÕre done move.l (A4), A3 ; handle->ptr move.l A1, -(SP) bsr TestAndIntersect ; see if device is okay by itself move.l (SP)+, A1 bz @nextDevice ; if not, try next one move.w gdFlags(A3), D0 ; get device attributes andi.w #importantFlagsMask, D0 ; strip unimportant ones cmp.w D0, D6 ; is this device similar to test device? bne @nextDevice ; if not, donÕt use it move.l gdPMap(A3), A0 ; get deviceÕs PixMapHandle move.l (A0), A0 ; get deviceÕs PixMapPtr move.l D6, D0 ; get depth and flags swap D0 ; get depth into low word cmp.w pmPixelSize(A0), D0 ; save depth as test device? bne @nextDevice ; if not, donÕt use it move.l flags(A6), D0 ; get the option flags btst #dontMatchSeedsBit, D0 ; should we check ctSeeds? bnz.s @seedsChecked ; if not, skip this next check move.l pmTable(A0), A0 ; handle to color table move.l (A0), A0 cmp.l ctSeed(A0), D7 ; are the seeds the same? bne @nextDevice ; if not, donÕt use this one @seedsChecked move.l A3, A0 move.l $22(A1), D0 cmp $24(A0), D0 bgt.s @L4 blt.s @L1 swap D0 cmp $22(A0), D0 bgt.s @L5 blt.s @L2 move.l $26(A1), D0 cmp $28(A0), D0 blt.s @L6 bgt.s @L3 bra.s @nextDevice @L1 swap D0 cmp $22(A0), D0 bgt.s @doneWhateverThatWas @L2 move.l $26(A1), D0 cmp $28(A0), D0 blt.s @doneWhateverThatWas @L3 swap D0 cmp $26(A0), D0 blt.s @doneWhateverThatWas bra.s @nextDevice @L4 swap D0 cmp $22(A0), D0 blt.s @doneWhateverThatWas @L5 move.l $26(A1), D0 cmp $28(A0), D0 bgt.s @doneWhateverThatWas @L6 swap D0 cmp $26(A0), D0 bgt.s @doneWhateverThatWas bra.s @nextDevice @doneWhateverThatWas move.l flags(A6), D0 ; what are the current options? btst #allDevicesBit, D0 ; are we ignoring drawingRgn? bnz.s @visRgnSetup ; if so, no regions to setup move.l A1, -(SP) move.l D4, -(SP) ; rectangle region handle pea localRect(A6) ; this device (local coords) _RectRgn ; region = device rect (local) move.l D4, -(SP) ; device rect region (local) move.l visAndDrawRgn(A6), -(SP) ; ANDed with clipped drawing region move.l D4, -(SP) ; turns into intersected rect region _SectRgn move.l D4, -(SP) ; intersected device rect region move.l visRgn(A2), -(SP) ; and previously setup visRgn move.l (SP), -(SP) ; get ORed together _XorRgn ; XOr is a fast way to Union when guaranteed no overlap move.l (A4), A3 ; fix GDevicePtr move.l (SP)+, A1 @visRgnSetup bset.l D3, D5 ; mark this device done @nextDevice move.l gdNextGD(A3), A4 ; get next device in chain addq #1, D3 ; increment device number bra.s @addLoop ; try this one @noMore movem.l (SP)+, A3-A4/D3/D6 ; restore callerÕs state rts TestAndIntersect ; Inputs: ; A3 device to test (dereferenced GDHandle) ; D3 this deviceÕs ordinal number ; Outputs: ; CCs zero if not okay, non-zero if okay ; localRect(A6) is set to devices rectangle in local coordinates btst.l D3, D5 ; this device already done? bnz.s @fail ; if so, itÕs not okay move.w gdFlags(A3), D0 ; get this deviceÕs flags andi.w #activeScreenMask, D0 ; extract screen & active bits cmpi.w #activeScreenMask, D0 ; are both bits set? bne.s @fail ; if not, donÕt use device move.l gdRect(A3), localRect(A6) ; copy topLeft of device rect move.l gdRect+4(A3), localRect+4(A6) ; and bottomRight pea localRect(A6) ; push address of copied device rect _GlobalToLocal ; and convert it to local coords. pea localRect+bottom(A6) ; push address of copied device rect bottomRight _GlobalToLocal ; and convert it to local coords. move.l flags(A6), D0 ; get the options btst #allDevicesBit, D0 ; should we accept all screens? bnz.s @exit ; if set, exit with CCs non-zero subq #2, SP ; room for boolean result pea localRect(A6) ; local version of GDRect move.l drawingRgn(A6), -(SP) ; region to test _RectInRgn ; does device intersect region? tst.b (SP)+ ; see if it does bra.s @exit @fail moveq #0, D0 @exit rts NewFunc1 moveq #0, D2 move.l (DeviceList), D0 beq.s @return moveq #0, D1 @L0 movea.l D0, A0 movea.l (A0), A0 cmp D3, D1 beq.s @L8 tst $14(A0) bpl.s @L8 movea.l (A4), A1 move.l $22(A1), D0 cmp $24(A0), D0 bgt.s @L4 blt.s @L1 swap D0 cmp $22(A0), D0 bgt.s @L5 blt.s @L2 move.l $26(A1), D0 cmp $28(A0), D0 blt.s @L6 bgt.s @L3 bra.s @L7 @L1 swap D0 cmp $22(A0), D0 bgt.s @L8 @L2 move.l $26(A1), D0 cmp $28(A0), D0 blt.s @L8 @L3 swap D0 cmp $26(A0), D0 blt.s @L8 bra.s @L7 @L4 swap D0 cmp $22(A0), D0 blt.s @L8 @L5 move.l $26(A1), D0 cmp $28(A0), D0 bgt.s @L8 @L6 swap D0 cmp $26(A0), D0 bgt.s @L8 @L7 bclr.s #7, $14(A0) bset.l D1, D2 @L8 addq #1, D1 move.l $1E(A0), D0 bne.s @L0 @return Rts NewFunc2 tst D2 beq.s @return move.l (DeviceList), D0 beq.s @return @L10 move.l D0, A0 move.l (A0), A0 lsr #1, D2 bcc.s @L11 bset.s #7, $14(A0) tst D2 beq.s @return @L11 move.l $1E(A0), D0 bne.s @L10 @return Rts END