mac-rom/QuickDraw/DeviceLoop.a

499 lines
16 KiB
Plaintext

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