sys7.1-doc-wip/QuickDraw/DeviceLoop.a

351 lines
14 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; 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 didnt 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 ports visRgn (after a BeginUpdate call). For each device which
; intersects drawingRgn, the drawingProc routine is called. When the drawingProc is called,
; the current ports 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 ports visRgn is not
; affected when this flag is set.
;----------------------------------------------------------------------------------------------
; Register Use:
; D3 current devices ordinal number for indexing into finished bitmap
; D4 RgnHandle for working region
; D5 bitmap of devices weve 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
btst #6, ROM85 ; Color QuickDraw available?
bnz @classicQD ; if not, handle old case
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, theres 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) ; callers 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 ; were 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.s @nextDevice ; if not, keep searching
move.l flags(A6), D0 ; get the callers options
btst #allDevicesBit, D0 ; are we ignoring regions?
bnz.s @visRgnSetup ; if so, dont 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 ports visRgn
_SectRgn
move.l (A4), A3 ; fix GDevicePtr
@visRgnSetup
move.l gdPMap(A3), A0 ; devices PixMapHandle
move.l (A0), A0 ; devices PixMapPtr
move.w pmPixelSize(A0), D6 ; devices depth
swap D6 ; put depth high
move.w gdFlags(A3), D6 ; get device flags in low word
move.l pmTable(A0), A0 ; devices color table handle
move.l (A0), A0
move.l ctSeed(A0), D7 ; stash devices ctab seed
move.l flags(A6), D0 ; get callers flags
btst #singleDevicesBit, D0 ; should we group devices?
bnz.s @groupingDone ; if not, dont call AddSimilar
bsr AddSimilarDevices ; find all the like devices
@groupingDone
movem.l D3-D7/A2-A4/A6, -(SP) ; save OUR registers
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 users long
move.l drawingProc(A6), A0 ; pointer to drawing procedure
movem.l callerRegs(A6), D3-D7/A2-A4 ; restore callers registers
move.l A6Link(A6), A6 ; and restore callers A6
jsr (A0) ; call the drawing procedure
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
@classicQD
move.l A6, -(SP) ; save our stack frame ptr
move.w #1, -(SP) ; pass depth (always 1)
move.w #fakeDeviceFlags, -(SP) ; and gdflags (something reasonable)
clr.l -(SP) ; NIL for GDHandle
bra.s @simpleDeviceCommon
@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 users long
move.l drawingProc(A6), A0 ; the procedures address
move.l A6Link(A6), A6 ; and restore callers 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
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
; havent 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 dont do this one again
movem.l A3-A4/D3/D6, -(SP) ; save original state
andi.w #importantFlagsMask, D6 ; keep only pertinent flags
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.s @noMore ; if NIL, then were done
move.l (A4), A3 ; handle->ptr
bsr.s TestAndIntersect ; see if device is okay by itself
bz.s @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.s @nextDevice ; if not, dont use it
move.l gdPMap(A3), A0 ; get devices PixMapHandle
move.l (A0), A0 ; get devices 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.s @nextDevice ; if not, dont 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.s @nextDevice ; if not, dont use this one
@seedsChecked
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 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
@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 callers state
rts
TestAndIntersect
; Inputs:
; A3 device to test (dereferenced GDHandle)
; D3 this devices 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, its not okay
move.w gdFlags(A3), D0 ; get this devices flags
andi.w #activeScreenMask, D0 ; extract screen & active bits
cmpi.w #activeScreenMask, D0 ; are both bits set?
bne.s @fail ; if not, dont 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
END