;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = ENUMCLIP.ASM
;*
;* DESCRIPTIVE NAME = Clipping region enumeration.
;*
;*
;* VERSION      V2.0
;*
;* DATE         05/12/87
;*
;* DESCRIPTION  Enumerates the clip region by calling the engine.
;*
;*
;* FUNCTIONS    do_exttextout
;*              do_bitblt
;*              do_drawbits
;*              do_stretchblt
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   05/12/87                     Written by Charles Whitmer
;*   05/21/87                     Hock Lee [hockl] Added internal enumerate
;*                                clip rects.
;*   11/05/87                     Walt Moore [waltm] Temp bitmap kludge
;*
;*   03/17/88                     Charles Whitmer [chuckwh] Added correct
;*                                coordinate flip.
;*   05/08/89                     Lee A. Newberg [leen] Allowed for non-visible
;*                                (i.e. INFO) DC's.  PTR HM377
;*   07/08/89                     Walt Moore  [waltm] Remove bitmap kludge.
;*                                Changed for new oem bitblt structure definition
;*                                Added return code from called routine
;*   80/14/90                     Viroon Touranachun [viroont] Switched from
;*                                Instance Data segment to CompileCode segment.
;*   10/25/91                     Cliff Levesque [cliffl] Cleanup and convert
;*                                to 386 and above flat model, protected mode
;*                                32 bit operation.
;*   08/31/92              51671  Fixed problem with eagle bitmap in klondike.
;*   11/26/92                     John Batty. Added DCAF changes.
;*   03/19/93              63057  If the surface is the device and our screen
;*                                group is switched out we had better not try
;*                                and write to the device ( A RIP is not enuf )
;*
;*****************************************************************************/

        .386

        .xlist

INCL_GRE_CLIP           equ     1
INCL_FONTFILEFORMAT     equ     1
INCL_DEV                equ     1
INCL_GPIREGIONS         equ     1
ifdef DCAF                                                           ;          
INCL_DDICOMFLAGS        equ     1                                    ;          
endif ;DCAF                                                          ;          
DINCL_ENABLE            equ     1
DINCL_BITMAP            equ     1

        include pmgre.inc
        include driver.inc
        include oemblt.inc
        include assert.mac
        include extern.inc
        include protos.inc
        include tune.inc
        .list

        .MODEL FLAT

        ASSUME  CS:FLAT,SS:FLAT,DS:FLAT,ES:FLAT

        .DATA

NRECTS                  equ     NUM_CLIP_RECTS+84       ;Must be bigger than NUM_CLIP_RECTS

        PUBLIC  arclBuf

arclBuf DWORD   ( NRECTS * ( sizeof RECTL / 4 ) ) dup ( 0 )

        .CODE
_TUNE SEGMENT DWORD FLAT PUBLIC 'CODE'
;/***************************************************************************
;*
;* FUNCTION NAME = enumerate_clip_rects
;*
;* DESCRIPTION   = Calls the given routine with a clip RECTS that intersect
;*                 the given given RECTL.  Passes the given SI and DI to the
;*                 routine. This routine will exit when there are no more
;*                 clip rectangles or when the passed routine returns zero in AX.
;*
;*                 Registers Preserved:
;*                       ESI,EDI,EBP
;*
;*                 Registers Destroyed:
;*                       EBX,EDX
;*
;* INPUT         = ECX = rectangle enumeration direction - 1
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = EAX from called routine
;*                 ECX from called routine
;* RETURN-ERROR  = EAX = 0
;*
;**************************************************************************/

ALIGN 4
enumerate_clip_rects    PROC    SYSCALL USES esi edi, npddc:DWORD,
                                                      prclClip:DWORD,
                                                      pfn:DWORD
                        LOCAL   crcsClip:DWORD,
                                hdcTemp:DWORD,
                                SavedDI:DWORD,
                                SavedSI:DWORD,
                                ulRetCode:DWORD,
                                Control:RGNRECT,
                                flags:DWORD

        DebugMsg <enumerate_clip_rects ENUMCLIP CLIFFL>

ifdef FIREWALLS

;/*
;** Must only be called for ddcs that are not completely clipped away.
;** This is designed so that it will NOT catch ICs when we are doing
;** correlation.
;**
;** We better not be here if dead and a display ddc.
;**
;** The enumeration direction must be valid.
;*/

        push    ebx
        mov     ebx,npddc

        ASSUME  ebx:PTR DDC

        ddc?    ebx

        cmp     [ebx].ddc_crcsClip,0
        jnz     @F

        rip     text,<enum clip called with no clip rectangles>
@@:
        cmp     fGrimReaper,WE_BE_DEAD
        jne     @F
        test    [ebx].ddc_fb,DDC_DEVICE
        jz      @F

        rip     text,<Enumerating clip rects for display while dead>

;*   03/19/93              63057  Start

        mov     eax,1
        ret

;*   03/19/93              63057  End

@@:
        assert  ecx,LE,RECTDIR_RTLF_BOTTOP-1

        pop     ebx

        ASSUME  ebx:NOTHING

endif


;/*
;** If only one clip rectangle, or all rectangles are contained within
;** the ddc and the direction is correct, then we can use those rectangles
;** stored in the ddc.  Otherwise, we'll have to get them from the Engine.
;*/

        cld
        mov     SavedDI,edi
        mov     SavedSI,esi
        mov     eax,1
        mov     ulRetCode,eax           ;Assume success incase nothing shows
        mov     esi,npddc
        mov     esi,[esi].DDC.ddc_npsd
        mov     dl,[esi].SURFACE.sd_fb
        mov     BYTE PTR flags[0],dl

        ASSUME  esi:PTR DDC
        mov     esi,npddc

        mov     edx,[esi].ddc_crcsClip  ;EDX = num clip rects for ddc
        cmp     edx,eax
        je      use_our_rects           ;One rect doesn't require direction
        cmp     ecx,RECTDIR_LFRT_BOTTOP-1;Our rects are this direction only
        jne     cant_use_our_rects
        cmp     edx,NUM_CLIP_RECTS      ;Too many clip rects?
        jbe     use_our_rects

cant_use_our_rects:

        jmp     get_engine_rects
ALIGN 4

use_our_rects:

        mov     esi,[esi].ddc_prddc     ;ESI --> RDDC

        ASSUME  esi:PTR RDDC

        lea     esi,[esi].rddc_arcsClip ;ESI --> source clip rects

        ASSUME  esi:PTR RECTL

        mov     ecx,prclClip
        jecxz   copy_first_rect         ;No rectangle given
        mov     edi,ecx                 ;EDI --> bounding rectangle

        ASSUME  edi:PTR RECTL

copy_first_rect:

        push    ebp
        lea     ebp,arclBuf             ;EBP --> buffer area

        ASSUME  ebp:PTR RECTL

        .errnz  high NUM_CLIP_RECTS     ;DH = Numer of clip rectangle copied
                                        ;DL = Number of rects in clip area

;/*
;** Copy and intersect our clip rectangles with the passed rectangle
;*/

copy_next_rect:

        lodsd

        .errnz  RECTL.rcl_xLeft

        jecxz   @F
        mov     ebx,[edi].rcl_xLeft
        cmp     eax,ebx
        jge     @F
        xchg    eax,ebx
@@:     mov     [ebp].rcl_xLeft,eax

        lodsd

        .errnz  RECTL.rcl_yBottom - RECTL.rcl_xLeft - 4

        jecxz   @F
        mov     ebx,[edi].rcl_yBottom
        cmp     eax,ebx
        jg      @F
        xchg    eax,ebx
@@:     mov     [ebp].rcl_yBottom,eax

        lodsd

        .errnz  RECTL.rcl_xRight - RECTL.rcl_yBottom - 4

        jecxz   @F
        mov     ebx,[edi].rcl_xRight
        cmp     eax,ebx
        jl      @F
        xchg    eax,ebx
@@:     mov     [ebp].rcl_xRight,eax

        lodsd

        .errnz  RECTL.rcl_yTop - RECTL.rcl_xRight - 4

        jecxz   @F
        mov     ebx,[edi].rcl_yTop
        cmp     eax,ebx
        jl      @F
        xchg    eax,ebx
@@:     mov     [ebp].rcl_yTop,eax

        cmp     eax,[ebp].rcl_yBottom
        jle     skip_null_rect
        mov     eax,[ebp].rcl_xRight
        cmp     eax,[ebp].rcl_xLeft
        jle     skip_null_rect
        inc     dh
        add     ebp,size RECTL

skip_null_rect:

        dec     dl
        jnz     copy_next_rect
        pop     ebp
        xchg    dh,dl
        mov     Control.rgnrc_crcReturned,edx
        jmp     call_routine
ALIGN 4

;/*
;** We must get the rectangles from the Engine.  We will loop getting
;** as many as will fit within our buffer.
;*/

get_engine_rects:
        ASSUME  esi:PTR DDC
        mov     eax,[esi].ddc_hdc
        mov     hdcTemp,eax
        mov     Control.rgnrc_ircStart,1
        mov     Control.rgnrc_crc,NRECTS
        inc     ecx
        mov     Control.rgnrc_ulDirection,ecx

;/*
;** Get the next bunch of rectangle from the Engine
;*/

get_more_loop:

        INVOKE  PFNDefGetClipRects PTR pfnDefGetClipRects,
                hdcTemp,
                prclClip,
                ADDR Control,
                ADDR arclBuf,
                0,
                NGreGetClipRects

ifdef FIREWALLS

        or      eax,eax
        jnz     @F

        rip     text,<GetClipRects returns error>
@@:

endif


;/*
;** Call routine for each rectangle in the buffer
;*/

call_routine:

        mov     ecx,Control.rgnrc_crcReturned
ifdef DCAF                                                           ;          
        ; We can't use jecxz as this is no longer a short jump!      ;          
        or      ecx,ecx                                              ;          
        jz      enumerate_done                                       ;          
else
        jecxz   enumerate_done
endif ;DCAF                                                          ;          
        mov     crcsClip,ecx
        add     Control.rgnrc_ircStart,ecx
        lea     ebx,arclBuf                     ;EBX --> first RECTL

        ASSUME  ebx:PTR RECTL

call_loop:

ifdef FIREWALLS

        mov     ecx,[ebx].rcl_yTop
        cmp     ecx,[ebx].rcl_yBottom
        jg      @F

        rip     text,<Enumerated a null rectangle in Y>
@@:
        mov     ecx,[ebx].rcl_xRight
        cmp     ecx,[ebx].rcl_xLeft
        jg      @F

        rip     text,<Enumerated a null rectangle in X>
@@:

endif
ifdef DCAF                                                           ;          
;/*                                                                  ;          
;** Accumulate screen bounds if required                             ;          
;** Assume ebx->next clipped rectangle to accumulate.                ;          
;*/                                                                  ;          
screen_bounds_test:                                                  ;          
        test    ulGlobalCOMFlags,COM_SCR_BOUND                       ;          
        jz      bounds_done                                          ;          
                                                                     ;          
        mov     esi,npddc                                            ;          
        ASSUME  esi:PTR DDC                                          ;          
        mov     edi,ulGlobalCOMFlags                                 ;          
                                                                     ;          
        pushem  eax,ebx,ecx,edx                                      ;          
        mov     eax,[ebx].rcl_xLeft                                  ;          
        mov     ecx,[ebx].rcl_xRight                                 ;          
        mov     edx,[ebx].rcl_yTop                                   ;          
        mov     ebx,[ebx].rcl_yBottom                                ;          
        dec     ecx                      ;Bounds need to be inclusive;          
        dec     edx                                                  ;          
                                                                     ;          
accumulate_bounds:                                                   ;          
        call    InnerAccumulateBounds                                ;          
        or      eax,eax                                              ;          
        mov     ulRetCode,eax                                        ;          
        popem   eax,ebx,ecx,edx                                      ;          
        jz      short enumerate_done                                 ;          
bounds_done:                                                         ;          
                                                                     ;          
;/*                                                                  ;          
;** Call the given function                                          ;          
;*/                                                                  ;          
endif ; DCAF                                                         ;          

        mov     esi,SavedSI
        mov     edi,SavedDI

        INVOKE  enum_dispatch,pfn,flags

        mov     ulRetCode,eax
;        or      eax,eax                ;           functions cannot fail
;        jz      enumerate_done         ;           functions cannot fail
        add     ebx,size RECTL
        dec     crcsClip
        jnz     call_loop
        cmp     Control.rgnrc_crcReturned,NRECTS
        je      get_more_loop

enumerate_done:

        mov     eax,ulRetCode

        RET

enumerate_clip_rects    ENDP

page
;/***************************************************************************
;*
;* FUNCTION NAME = do_exttextout
;*
;* DESCRIPTION   = This routine is called by enumerate_clip_rects to actually do
;*                 the exttextouts.
;*
;* INPUT         = EBX = clip RECTL
;*                 EDI -> exttextout_args
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = EAX = 1
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

                OPTION  PROLOGUE:None
                OPTION  EPILOGUE:None

ALIGN 4
do_exttextout   PROC    SYSCALL

        ASSUME  ebx:PTR RECTL

        DebugMsg <do_exttextout ENUMCLIP CLIFFL>

;/*
;** Make a copy of the arguments
;*/

        mov     esi,edi                 ;ESI -> exttextout_args
        sub     esp,size eto_args
        mov     edi,esp

        .errnz  (size eto_args) and 3   ; insure DWORD boundary

        mov     ecx,(size eto_args) / 4
        cld
        rep     movsd
        sub     edi,size eto_args

;/*
;** Fill in the actual clip rectangle.  We will have to convert it into
;** a RECTS until exttextout is changed !!!!
;*/

        ASSUME  edi:PTR eto_args

        mov     [edi].eto_lpClipRect,ebx

;/*
;** Flip the coordinate system over for the old Window's way where 0,0 is
;** the upper left corner (you know, the way hardware works!)
;*/

        mov     esi,[edi].eto_lpDestDev ; ESI -> sd_

        ASSUME  esi:PTR SURFACE

        mov     edx,[esi].sd_cy
        mov     eax,edx                 ;Flip clip rectangle
        sub     eax,[ebx].rcl_yBottom
        sub     edx,[ebx].rcl_yTop
        mov     [ebx].rcl_yTop,eax
        mov     [ebx].rcl_yBottom,edx

;/*
;** Make the exttextout call and exit
;*/

        call    ExtTextOut
        mov     eax,1           ; so we don't quit in enumerate_clip_rects

        add     esp,size eto_args

                RET

do_exttextout   ENDP

page

;/***************************************************************************
;*
;* FUNCTION NAME = do_bitblt
;*
;* DESCRIPTION   = This routine is called by enumerate_clip_rects to invoke the oem
;*                 bitblt with the passed clipped rectangle.
;*
;*                 Registers Preserved:
;*                       EBP
;*
;*                 Registers Destroyed:
;*                       EAX,EBX,ECX,EDX,ESI,EDI
;*
;* INPUT         = EBX --> clip RECTL
;*                 EDI --> OBB_ARGS structure
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = EAX from called routine
;* RETURN-ERROR  = EAX = 0
;*
;**************************************************************************/

ALIGN 4
do_bitblt       PROC    SYSCALL


;/*
;** Leave room for the arguments we'll copy to the stack
;*/

        mov     esi,edi                 ;DS:SI --> OBB_ARGS
        sub     esp,sizeof OBB_ARGS
        mov     edi,esp

;/*
;** Get arguments onto our stack.  They are in our old stack segment.
;*/

        .errnz  (size OBB_ARGS) and 3

        mov     ecx,(size OBB_ARGS) / 4
        cld
        rep     movsd
        sub     edi,size OBB_ARGS

;/*
;** The arguments have been copied from our automatic data segment onto the
;** compile code data fake stack.  RECTL is on the old stack frame (references
;** off of [BX]).  obba_* is on the new stack frame (references off of [DI]).
;**
;** Compute the new rectangle
;*/

        ASSUME  ebx:PTR RECTL, edi:PTR OBB_ARGS

        mov     eax,[ebx].rcl_xLeft
        mov     edx,[ebx].rcl_xRight
        sub     edx,eax                 ;New X extent
        mov     [edi].obba_cxExt,edx
        mov     ecx,eax                 ;Save a copy of new lhs
        xchg    eax,[edi].obba_xDst     ;Set new dest lhs
        sub     ecx,eax                 ;How much we moved right
        add     [edi].obba_xSrc,ecx     ;New source lhs

        mov     eax,[ebx].rcl_yBottom
        mov     edx,[ebx].rcl_yTop
        sub     edx,eax                 ;New Y extent
        mov     [edi].obba_cyExt,edx
        mov     ecx,eax                 ;Save a copy of new bottom
        xchg    eax,[edi].obba_yDst     ;Set new dest bottom
        sub     ecx,eax                 ;How much we moved up
        add     [edi].obba_ySrc,ecx     ;New source bottom

;/*
;** Flip the coordinate system over for the old Window's way where 0,0 is
;** the upper left corner (you know, the way hardware works!)
;*/

        mov     esi,[edi].obba_pddcDst ;ES:SI --> DDC

        ASSUME  esi:PTR DDC

        mov     esi,[esi].ddc_npsd      ;Need surface definition part

        ASSUME  esi:PTR SURFACE

        mov     eax,[esi].sd_cy
        sub     eax,[edi].obba_yDst
        sub     eax,edx                 ;DX = obba_cy
        mov     [edi].obba_yDst,eax

        mov     bl,[esi].sd_fb          ; fetch dest device flags

        test    [edi].obba_fsBlt,BBF_HAVE_SOURCE
        jz      @F
        mov     esi,[edi].obba_psdSrc
        mov     eax,[esi].sd_cy
        sub     eax,[edi].obba_ySrc
        sub     eax,edx                 ;DX = obba_cy
        mov     [edi].obba_ySrc,eax
@@:

;/*
;** Make the Bitblt call and then restore the stack frame
;*/

        cmp     fGrimReaper,WE_BE_DEAD  ;If we're dead, then
        jne     do_me
        test    bl,SD_DEVICE            ; destination is the device ?
        jnz     @F

do_me:
        call    OEMBitblt
@@:


        add     esp,sizeof OBB_ARGS

                RET

do_bitblt       ENDP
_TUNE ENDS
;/***************************************************************************
;*
;* FUNCTION NAME = do_drawbits
;*
;* DESCRIPTION   = This routine is called by enumerate_clip_rects to invoke the oem
;*                 drawbits with the passed clipped rectangle.
;*
;*                 Registers Preserved:
;*                       EBP
;*
;*                 Registers Destroyed:
;*                       EAX,EBX,ECX,EDX,ESI,EDX,EDI
;*
;* INPUT         = EBX --> clip RECTL
;*                 EDI --> OBB_ARGS structure
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = EAX from called routine
;* RETURN-ERROR  = EAX = 0
;*
;**************************************************************************/

ALIGN 4
do_drawbits     PROC    SYSCALL

;/*
;** Make a copy of the argument for the current rectangle.
;*/

        mov     esi,edi                         ;SS:SI --> OBB_ARGS
        sub     esp,sizeof ODB_ARGS
        mov     edi,esp

        .errnz  (size ODB_ARGS) and 3

        mov     ecx,(size ODB_ARGS) / 4
        cld
        rep     movsd
        sub     edi,sizeof ODB_ARGS

;/*
;** Compute the new rectangle
;*/

        ASSUME  ebx:PTR RECTL, edi:PTR ODB_ARGS

        mov     eax,[ebx].rcl_xLeft
        mov     edx,[ebx].rcl_xRight
        sub     edx,eax                 ;New X extent
        mov     [edi].odba_cxExt,edx
        mov     ecx,eax                 ;Save a copy of new lhs
        xchg    eax,[edi].odba_xDst     ;Set new dest lhs
        sub     ecx,eax                 ;How much we moved right
        add     [edi].odba_xSrc,ecx     ;New source lhs

        mov     eax,[ebx].rcl_yBottom
        mov     edx,[ebx].rcl_yTop
        sub     edx,eax                 ;New Y extent
        mov     [edi].odba_cyExt,edx
        mov     ecx,eax                 ;Save a copy of new bottom
        xchg    eax,[edi].odba_yDst     ;Set new dest bottom
        sub     ecx,eax                 ;How much we moved up
        add     [edi].odba_ySrc,ecx     ;New source bottom

;/*
;** Flip the coordinate system over for the old Window's way where 0,0 is
;** the upper left corner (you know, the way hardware works!). Only the
;** destination need to be flipped, the source already have the starting
;** pel at the lowest byte(s).
;*/

        mov     esi,[edi].odba_pddcDst  ;ESI --> DDC

        ASSUME  esi:PTR DDC

        mov     esi,[esi].ddc_npsd      ;Need surface definition part

        ASSUME  esi:PTR SURFACE

        mov     eax,[esi].sd_cy
        sub     eax,[edi].odba_yDst
        sub     eax,edx                 ;DX = obba_cyExt
        mov     [edi].odba_yDst,eax

;/*
;** Make the DrawBits call.
;*/

        call    OEMDrawBits
        add     esp,sizeof ODB_ARGS

                RET

do_drawbits     ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = do_stretchblt
;*
;* DESCRIPTION   = This routine is called by enumerate_clip_rects to invoke the oem
;*                 stretchblt with the passed clipped rectangle.
;*
;*                 Registers Preserved:
;*                       EBP
;*
;*                 Registers Destroyed:
;*                       EAX,EBX,ECX,EDX,ESI,EDI
;*
;* INPUT         = EBX --> clip RECTL
;*                 EDI --> OBB_ARGS structure
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = EAX from called routine
;* RETURN-ERROR  = EAX = 0
;*
;**************************************************************************/

ALIGN 4
do_stretchblt   PROC    SYSCALL

;/*
;** Make a copy of the argument for the current rectangle.
;*/

        DebugMsg <do_stretchblt CLIFFL enumclip.asm>

        mov     esi,edi                 ;SS:SI --> OBB_ARGS
        sub     esp,sizeof OSB_ARGS
        mov     edi,esp

        .errnz  (size OSB_ARGS) and 3

        mov     ecx,(size OSB_ARGS) / 4

        cld
        rep     movsd
        sub     edi,size OSB_ARGS

;/*
;** Compute the new rectangle
;*/

        ASSUME  ebx:PTR RECTL, edi:PTR OSB_ARGS

        mov     eax,[ebx].rcl_xLeft
        mov     edx,[ebx].rcl_xRight
        sub     edx,eax                 ;New X extent
        mov     [edi].osba_cxExt,edx
        mov     [edi].osba_xDst,eax     ;Set new dest lhs

        mov     eax,[ebx].rcl_yBottom
        mov     edx,[ebx].rcl_yTop
        sub     edx,eax                 ;New Y extent
        mov     [edi].osba_cyExt,edx
        mov     [edi].osba_yDst,eax     ;Set new dest bottom

;/*
;** Make the Bitblt call and then restore the stack frame
;*/

        call    OEMStretchBlt
        add     esp,sizeof OSB_ARGS

                RET

do_stretchblt    ENDP

end
