;*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 = BOUNDS.ASM
;*
;* DESCRIPTIVE NAME = Bounding Rectangle Functions
;*
;*
;* VERSION      V2.0
;*
;* DATE         30-Jan-1988
;*
;* DESCRIPTION  Functions relating to bounding rectangles
;*
;* FUNCTIONS    AccumulateBounds
;*              ResetBounds
;*              GetBoundsData
;*              InnerAccumulateBounds
;*              InternalAccumBounds
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   01/30/88                     Written by Walt Moore
;*   03/07/88                     Charles Whitmer [chuckwh] Changed errors to asserts.
;*   05/25/88                     Greg Hitchcock [gregh] Changed GPI bounds to
;*                                32 bits for MODEL coordinates
;*   05/25/88                     Greg Hitchcock [gregh] Removed xform of
;*                                GPI bounds to MODEL space, as they are now being
;*                                accumulated in MODEL space.
;*   07/15/88                     Charles Whitmer [chuckwh] New DDI.  Modified to
;*                                accumulate in DEVICE coordinates, instead of
;*                                SCREEN coordinates.  We may want to accumulate
;*                                the GPI bounds in MODEL coordinates.  This depends
;*                                on what we want to happen when
;*                                the transform changes while accumulating bounds.
;*   09/06/88                     Lee A. Newberg [leen] Takes input in Model
;*                                Coordinates for GPI bounds when COM_TRANSFORM is
;*                                not set.
;*   08/04/89                     John Colleran [johnc] Removed conversion of
;*                                USER bounds from DEVICE to SCREEN they are now
;*                                stored in SCREEN coords
;*   10/23/89                     Viroon Touranachun [viroont]
;*                                Convert 16-bit to 32-bit operations.
;*   10/17/91                     Cliff Levesque [cliffl] Cleanup and convert to
;*                                386 and above flat model, protected mode
;*                                32 bit operation.
;*   11/26/92                     John Batty. Added DCAF changes.
;*
;*****************************************************************************/
    .386

    .xlist

INCL_GRE_XFORMS     equ    1
INCL_GRE_DEVMISC3   equ    1
ifdef DCAF                                                           ;          
INCL_GRE_LINES      equ     1                                        ;          
endif ;DCAF                                                          ;          
INCL_DDICOMFLAGS    equ    1
INCL_DDIMISC        equ    1
INCL_GPITRANSFORMS  equ    1
DINCL_ENABLE        equ    1
DINCL_BITMAP        equ    1
OS2P_DEFD           equ    1

        include    pmgre.inc
        include driver.inc
        include assert.mac
        include extern.inc
        include protos.inc

        .list

        .MODEL  FLAT

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

        .CODE

;/***************************************************************************
;*
;* FUNCTION NAME = ResetBounds
;*
;* DESCRIPTION   =  Resets the bounds rectangles to their default values.
;*
;*                  Registers Preserved:
;*                     ESI,EDI,EBP
;*
;*                  Registers Destroyed:
;*                     EAX,EBX,ECX,EDX,FLAGS
;*
;* INPUT         =  NONE
;* OUTPUT        =  NONE
;*
;* RETURN-NORMAL =  EDX:EAX = 1 if ok
;* RETURN-ERROR  =  EDX:EAX = 0 if error
;*
;**************************************************************************/

        ASSUME  ebx:PTR DDC

ALIGN 4
ResetBounds     PROC    SYSCALL USES EBX esi edi,   hdc:DWORD, fdType:DWORD,
                                                hddc:DWORD, funN:DWORD
        DebugMsg <ResetBounds CLIFFL>
        cld

        call    enter_driver_sem           ; User doesn't like call back here

        assert  NC

        mov     ebx,hddc
        cmp     [ebx].ddc_usId,DDC_IDENT    ; make sure ddc is good
        jz      @F                           ; good ddc

;/*
;** there is a collision error
;*/

        rip     text,<ResetBounds: Bad DDC - possible thread collision>

        mov     eax,PMERR_INV_HDC

        save_error_code

        xor     eax,eax
        jmp     rb_exit                ; return error
ALIGN 4
@@:

        mov     ebx,[ebx].ddc_prddc    ; EBX = RDDC

        ASSUME  ebx:PTR RDDC

        rddc?   ebx

;/*
;** Validate the bounds type
;*/

        .errnz  RB_GPI + RB_USER - 3

        assert  fdType,B,4

;/*
;** Reset bounds by setting left > right and bottom > top
;*/

        mov     ecx,fdType
        shr     cl,1

        .errnz  RB_GPI-01h

        jnc     gpi_reset_done

        mov     [ebx].rddc_rclGpiBound.rcl_xLeft,MAX_COORDINATE
        mov     [ebx].rddc_rclGpiBound.rcl_yBottom,MAX_COORDINATE

        .errnz  RECTL.rcl_xLeft
        .errnz  RECTL.rcl_yBottom - 4

        mov     [ebx].rddc_rclGpiBound.rcl_xRight,not MAX_COORDINATE
        mov     [ebx].rddc_rclGpiBound.rcl_yTop,not MAX_COORDINATE

        .errnz  MIN_COORDINATE - (not MAX_COORDINATE)
        .errnz  RECTL.rcl_xRight - 8
        .errnz  RECTL.rcl_yTop - 12

gpi_reset_done:

        .errnz  RB_USER-00000010b

        assert  ecx,BE,1

        jecxz   user_reset_done

        mov     [ebx].rddc_rcsUsrBound.rcl_xLeft,MAXSHORT
        mov     [ebx].rddc_rcsUsrBound.rcl_yBottom,MAXSHORT
        mov     [ebx].rddc_rcsUsrBound.rcl_xRight,MINSHORT
        mov     [ebx].rddc_rcsUsrBound.rcl_yTop,MINSHORT


        .errnz  RECTL.rcl_xLeft
        .errnz  RECTL.rcl_yBottom - RECTL.rcl_xLeft - 4
        .errnz  RECTL.rcl_xRight - RECTL.rcl_yBottom - 4
        .errnz  RECTL.rcl_yTop - RECTL.rcl_xRight - 4

user_reset_done:

        mov     eax,1

rb_exit:
        call    leave_driver

        RET

ResetBounds     ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = GetBoundsData
;*
;* DESCRIPTION   = Retrieves the collected bounds data for either PMWIN or GPI.
;*                 User rectangle is returned in SCREEN coordinates.  GPI
;*                 rectangle is returned in MODEL coordinates.  The USER
;*                 rectangle is reset after it is read.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = EDX:EAX = 1 if ok
;* RETURN-ERROR  = EDX:EAX = 0 if error
;*                 Error logged
;***************************************************************************/

                ASSUME  ebx:PTR DDC

ALIGN 4
GetBoundsData   PROC    SYSCALL USES EBX esi edi, hdc:DWORD, fdType:DWORD,
                                                lpBoundsData:DWORD, hddc:DWORD,
                                                funN:DWORD
        DebugMsg <GetBoundsData CLIFFL bounds.asm>
        cld
        call    enter_driver_sem    ; User doesn't like call back if no bounds

        assert  NC

        mov     ebx,hddc
        cmp     [ebx].ddc_usId,DDC_IDENT    ; make sure ddc is good
        jz      @F            ; good ddc

;/*
;** there is a collision error
;*/

        rip     text,<GetBoundsData: Bad DDC - possible thread collision>

        mov     eax,PMERR_INV_HDC

save_error_code

        xor     eax,eax
        jmp     gbd_exit        ; return error
ALIGN 4
@@:

        mov     ebx,[ebx].ddc_prddc    ; EBX = RDDC

        ASSUME  ebx:PTR RDDC

        rddc?   ebx

;/*
;** Validate the bounds type
;*/

        mov     ecx,fdType

        .errnz  GBD_USER-1
        .errnz  GBD_GPI

        assert  ecx,B,2

        or      ecx,ecx
        jz      gbd_do_gpi_case

;/*
;** Handle USER case and the case of no data to be returned.  These
;** cases allow us to write directly into the given work area.  The
;** Gpi case must use the temporary stack space in case the back-
;** transform fails.
;*/

        rddc?   ebx

        cmp     [ebx].rddc_rcsUsrBound.rcl_xLeft,MAXSHORT
        je      gbd_no_data_case    ; doesn't matter if ddc is dirty

;/*
;** Return User bounds data.  User expects to see it in screen coordinates.
;** Extend ddc RECTS to GPI RECTL
;*/

        mov     edi,lpBoundsData
        lea     esi,[ebx].rddc_rcsUsrBound.rcl_xLeft
        mov     ecx,( SIZEOF RECTL ) / 4
        rep     movsd

       .errnz   RECTL.rcl_xLeft
       .errnz   RECTL.rcl_yBottom - RECTL.rcl_xLeft - 4
       .errnz   RECTL.rcl_xRight - RECTL.rcl_yBottom - 4
       .errnz   RECTL.rcl_yTop - RECTL.rcl_xRight - 4

;/*
;** reset USER bounds!
;*/

        rddc?   ebx            ; EBX -> ddc

        mov     [ebx].rddc_rcsUsrBound.rcl_xLeft,MAXSHORT
        mov     [ebx].rddc_rcsUsrBound.rcl_yBottom,MAXSHORT
        mov     [ebx].rddc_rcsUsrBound.rcl_xRight,MINSHORT
        mov     [ebx].rddc_rcsUsrBound.rcl_yTop,MINSHORT
        jmp     gbd_ok
ALIGN 4

;/*
;** now do GPI case
;*/

gbd_do_gpi_case:

;/*
;** Copy the bounds directly from the ddc to the user data area
;** It doesn't matter if we have a dirty ddc here
;*/

        rddc?   ebx

        lea     esi,[ebx].rddc_rclGpiBound
        mov     edi,lpBoundsData

        .errnz  (size RECTL) and 3

        mov     ecx,(SIZEOF RECTL) / 4
        rep     movsd
        jmp     gbd_ok
ALIGN 4

;/*
;** handle the case with no data - reset the rect
;*/

gbd_no_data_case:

        mov     edi,lpBoundsData

        mov     eax,MAX_COORDINATE
       stosd                                ; xmin = MAX_COORDINATE
       stosd                                ; ymin = MAX_COORDINATE
       not      eax

       .errnz   MIN_COORDINATE - (not MAX_COORDINATE)

       stosd                                ; xmax = MIN_COORDINATE
       stosd                                ; ymax = MIN_COORDINATE

gbd_ok:

       mov      eax,1

gbd_exit:

       call     leave_driver

gbd_exit_no_lock:

        fw_zero <ecx>

        RET

GetBoundsData   ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = AccumulateBounds(hdc,prcl,hddc,FunN)
;*
;* DESCRIPTION   = Accumulates new bounds data. We are passed the new rectangle
;*                 in SCREEN coordinates.  We accumulate in SCREEN coordinates
;*                 !!CR We store bounds in MODEL coordinates for GPI.
;*
;*                 Note: This routine takes INCLUSIVE rectangles.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

                ASSUME  esi:PTR DDC, ebx:PTR RDDC, edi:PTR RECTL

ALIGN 4
AccumulateBounds PROC   SYSCALL USES EBX esi edi,   hdc:DWORD, lpRect:DWORD,
                                                hddc:DWORD, FunN:DWORD

;/*
;** Firewall to see if we have the screen semaphore locked!
;*/
        DebugMsg <AccumulateBounds CLIFFL>
        cld
        mov     esi,hddc        ; ESI --> DDC
        mov     edx,esi
        call    enter_driver
        jc      ab_exit_no_lock        ; EDX:EAX = 0 on error

        mov     edi,lpRect

;/*
;** If the COM_TRANSFORM bit is clear, then GPI BOUNDS have been
;** supplied in MODEL COORDINATES.  USER bounds are supplied
;** in SCREEN COORDINATES independent of the COM_TRANSFORM bit.
;** Therefore it is illegal to call this function without COM_TRANSFORM
;** if both bounds are being accumulated to.
;*/

        test    FunN,COM_TRANSFORM
        jnz     use_InnerAccumulate
        test    FunN,COM_BOUND
        jz      use_InnerAccumulate

ifdef FIREWALLS

        test    FunN,COM_ALT_BOUND

        assert  Z

endif                                    ;FIREWALLS

;/*
;** Accumulate the GPI bounds in Model coordinates.
;** See note about overflows in AccumBoundsInDevCoords.
;*/

        mov     ebx,[esi].ddc_prddc    ; EBX = RDDC

        rddc?   ebx

        mov     eax,[edi].rcl_xLeft
        sub     eax,[ebx].rddc_rclGpiBound.rcl_xLeft
        jge     @F
        add     [ebx].rddc_rclGpiBound.rcl_xLeft,eax
@@:
        mov     eax,[edi].rcl_yBottom
        sub     eax,[ebx].rddc_rclGpiBound.rcl_yBottom
        jge     @F
        add     [ebx].rddc_rclGpiBound.rcl_yBottom,eax
@@:
        mov     eax,[edi].rcl_xRight
        sub     eax,[ebx].rddc_rclGpiBound.rcl_xRight
        jl      @F
        add     [ebx].rddc_rclGpiBound.rcl_xRight,eax
@@:
        mov     eax,[edi].rcl_yTop
        sub     eax,[ebx].rddc_rclGpiBound.rcl_yTop
        jl      @F
        add    [ebx].rddc_rclGpiBound.rcl_yTop,eax
@@:

        ddc?   esi

        jmp    ab_return_ok
ALIGN 4

use_InnerAccumulate:

;/*
;** pick up the rectangle
;*/

        mov     eax,[edi].rcl_xLeft
        mov     ebx,[edi].rcl_yBottom
        mov     ecx,[edi].rcl_xRight
        mov     edx,[edi].rcl_yTop

;/*
;** call the inner routine
;*/
        mov     edi,FunN
ifdef DCAF                                                           ;          
;/*                                                                  ;          
;** AccumulateScreenBounds is an exported routine that the engine    ;          
;** may call.  When it does so it must relate to some primitive      ;          
;** that we have already drawn (and hence will already have          ;          
;** accumulated the (clipped) screen bounds).  Thus we do not want   ;          
;** to include these bounds in our screen accumulation.              ;          
;*/                                                                  ;          
        and     edi, not COM_SCR_BOUND   ; Turn off SCREEN acc.      ;          
endif ; DCAF                                                         ;          
        call    InnerAccumulateBounds
        or      eax,eax
        jz      ab_return_error

;/*
;** return OK
;*/

ab_return_ok:

        mov     eax,1

ab_return_error:

        call    leave_driver

ab_exit_no_lock:

        fw_zero <ecx>

        RET

AccumulateBounds        ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = AccumBoundsInDevCoords
;*
;* DESCRIPTION   = Accumulates new bounds data. We are passed the new rectangle in
;*
;*                 Registers Preserved:
;*                    EDI,ESI,EBP
;*
;*                 Registers Destroyed:
;*                    EAX,EBX,ECX,EDX
;*
;* INPUT         =  EAX   = RECTL.rcl_xLeft
;*                  EBX   = RECTL.rcl_yBottom
;*                  ECX   = RECTL.rcl_xRight
;*                  EDX   = RECTL.rcl_yTop
;*                  ESI   = DDC
;*                  EDI   = Command flags
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = EDX:EAX = 1 if ok
;* RETURN-ERROR  = EDX:EAX = 0 if error
;*                 Error logged
;**************************************************************************/
                ASSUME  esi:PTR DDC

ALIGN 4
AccumBoundsInDevCoords PROC     SYSCALL

        ddc?    esi

;/*
;** offset bound value in REG by roffset, and making sure the result
;** value stays in the 16 bit range 08001h and 07FFEh.
;** Entry: upper_limit = MAXSHORT-1 (07FFEh)
;**        lower_limit = MINSHORT+1 (08001h)
;** Return:  REG = value + offset
;*/

 offset_bounds macro   REG,roffset

        local   overflow,save_it

        add     REG,roffset        ; add offset
        jo      overflow         ; check overflow
        cmp     REG,MAXSHORT-1        ; catch 07FFFh and 08000h
        jg      overflow
        cmp     REG,MINSHORT+1
        jge     save_it

 overflow:

        mov     REG,MINSHORT+1        ; assume 08001h
        cmp     roffset,0
        jl      save_it
        mov     REG,MAXSHORT-1        ; it's 07FFEh

 save_it:
        endm

;/*
;** Convert DEVICE coords to SCREEN coords
;*/

        mov    esi,[esi].ddc_prddc

        ASSUME  esi:PTR RDDC

        rddc?    esi            ; ESI = RDDC

    offset_bounds  eax,[esi].rddc_ptsOrg.ptl_x[0]
        movsx   EAX,AX
    offset_bounds  ebx,[esi].rddc_ptsOrg.ptl_y[0]
        movsx   EBX,BX
    offset_bounds  ecx,[esi].rddc_ptsOrg.ptl_x[0]
        movsx   ECX,CX
    offset_bounds  edx,[esi].rddc_ptsOrg.ptl_y[0]
        movsx   EDX,DX

        mov    esi,[esi].rddc_npddc    ; ESI = DDC

        CALL    InnerAccumulateBounds

                        RET

AccumBoundsInDevCoords  ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = InnerAccumulateBounds
;*
;* DESCRIPTION   = Accumulates new bounds data.    We are passed the new rectangle
;*                 in SCREEN coordinates.  We accumulate in SCREEN coordinates.
;*
;*                 Note: This routine takes INCLUSIVE rectangles.
;*
;*
;* INPUT         = EAX   = xLeft
;*                 EBX   = yBottom
;*                 ECX   = xRight
;*                 EDX   = yTop
;*                 ESI   = DDC
;*                 EDI   = Command flags
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = EDX:EAX = 1 if ok
;* RETURN-ERROR  = EDX:EAX = 0 if error
;*                 Error logged
;**************************************************************************/

                ASSUME  esi:PTR DDC

ALIGN 4
InnerAccumulateBounds   PROC    SYSCALL USES EDI
                        LOCAL   rclTemp:RECTL

        ddc?    esi

;/*
;** make sure the rectangle is legal
;*/
        assert  eax,LE,ecx
        assert  ebx,LE,edx

ifdef DCAF                                                           ;          
;/*                                                                  ;          
;** If DCAF is not enabled then skip straight to the normal bounds   ;          
;** code.                                                            ;          
;*/                                                                  ;          
        test    edi,COM_SCR_BOUND                                    ;          
        jz      do_normal_bounds                                     ;          
                                                                     ;          
;/*                                                                  ;          
;** Do some simple (device specific) tests to see if                 ;          
;** there is any likelihood of the screen being changed.             ;          
;**                                                                  ;          
;*/                                                                  ;          
        test    [esi].ddc_fb,DDC_DEVICE  ; Is this the screen?       ;          
        jz      do_normal_bounds                                     ;          
                                                                     ;          
        test    edi, COM_DRAW                                        ;          
        jz      do_normal_bounds                                     ;          
                                                                     ;          
        test    [esi].ddc_fb, DDC_VISIBLE                            ;          
        jz      do_normal_bounds                                     ;          
                                                                     ;          
                                                                     ;          
;/*                                                                  ;          
;** We have not been able to trivially reject this call as being     ;          
;** unable to affect the screen, so we must pass the data to         ;          
;** the accumulation function.                                       ;          
;**                                                                  ;          
;*/                                                                  ;          
        pushem  eax,ebx,ecx,edx,esi ; Save unclipped rectangle & esi ;          
                                                                     ;          
;/*                                                                  ;          
;** Certain drawing functions pass in an unclipped bounding          ;          
;** rectangle with COM_SCR_BOUND set.                                ;          
;** If one of these functions is calling then clip the bounds        ;          
;** to the screen (at least).                                        ;          
;*/                                                                  ;          
        cmp     di,NGrePolyLine                                      ;          
        jz      clip_bounds                                          ;          
        cmp     di,NGreDisjointLines                                 ;          
        jz      clip_bounds                                          ;          
        cmp     di,NGreDrawLinesInPath                               ;          
        jnz     clipping_done                                        ;          
                                                                     ;          
clip_bounds:                                                         ;          
;/*                                                                  ;          
;** If we have just a single clip rect in the DC then clip to that,  ;          
;** else we simply clip to the screen size.                          ;          
;**                                                                  ;          
;*/                                                                  ;          
        cmp     [esi].ddc_crcsClip,1                                 ;          
        jne     screen_clip_only                                     ;          
                                                                     ;          
;/*                                                                  ;          
;** Do the clipping to the single clip rect in the DC.               ;          
;** Remember that since the coords passed are unclipped, then they   ;          
;** can in fact be negative.  Hence the use of signed comparisons    ;          
;** in the following lines which do the clipping.                    ;          
;**                                                                  ;          
;*/                                                                  ;          
        mov     esi,[esi].ddc_prddc         ; ESI = RDDC             ;          
        ASSUME  esi:PTR RDDC                                         ;          
        rddc?   esi                                                  ;          
                                                                     ;          
        cmp     eax,[esi].rddc_arcsClip[0].rcl_xLeft                 ;          
        jg      @F                                                   ;          
        mov     eax,[esi].rddc_arcsClip[0].rcl_xLeft                 ;          
@@:                                                                  ;          
        cmp     ebx,[esi].rddc_arcsClip[0].rcl_yBottom               ;          
        jg      @F                                                   ;          
        mov     ebx,[esi].rddc_arcsClip[0].rcl_yBottom               ;          
@@:                                                                  ;          
;/*                                                                  ;          
;** The clipped rectangle is stored exclusive, so adjust it          ;          
;** to be inclusive coordinates temporarily.                         ;          
;** We adjust the stored value, not the values in ecx and edx        ;          
;** because cx, dx could change to 0 in the increment                ;          
;** (but the stored rectangle can never drop from 0 to -1!)          ;          
;*/                                                                  ;          
        dec     [esi].rddc_arcsClip[0].rcl_xRight ; make it inclusive;          
        dec     [esi].rddc_arcsClip[0].rcl_yTop   ; make it inclusive;          
        cmp     ecx,[esi].rddc_arcsClip[0].rcl_xRight                ;          
        jl      @F                                                   ;          
        mov     ecx,[esi].rddc_arcsClip[0].rcl_xRight                ;          
@@:                                                                  ;          
        cmp     edx,[esi].rddc_arcsClip[0].rcl_yTop                  ;          
        jl      @F                                                   ;          
        mov     edx,[esi].rddc_arcsClip[0].rcl_yTop                  ;          
@@:                                                                  ;          
;/*                                                                  ;          
;** Undo the exclusive decrements                                    ;          
;*/                                                                  ;          
        inc     [esi].rddc_arcsClip[0].rcl_xRight ; restore exclusive;          
        inc     [esi].rddc_arcsClip[0].rcl_yTop   ; restore exclusive;          
        jmp     check_for_NULL                                       ;          
                                                                     ;          
screen_clip_only:                                                    ;          
;/*                                                                  ;          
;** Clip xLeft (in eax) to zero                                      ;          
;*/                                                                  ;          
        and     eax,eax                                              ;          
        jns     @f              ; jump if positive                   ;          
        xor     eax,eax         ; replace with zero                  ;          
@@:                                                                  ;          
;/*                                                                  ;          
;** Clip yBottom (in ebx) to zero                                    ;          
;*/                                                                  ;          
        and     ebx,ebx                                              ;          
        jns     @f              ; jump if positive                   ;          
        xor     ebx,ebx         ; replace with zero                  ;          
@@:                                                                  ;          
;/*                                                                  ;          
;** Clip xRight (in ecx) to right of screen                          ;          
;*/                                                                  ;          
        cmp     ecx, SCREEN_CX                                       ;          
        jl      @f              ; jump if positive                   ;          
        mov     ecx, SCREEN_CX                                       ;          
        dec     ecx                                                  ;          
@@:                                                                  ;          
;/*                                                                  ;          
;** Clip yTop (in edx) to top of screen                              ;          
;*/                                                                  ;          
        cmp     edx, SCREEN_CY                                       ;          
        jl      @f              ; jump if positive                   ;          
        mov     edx, SCREEN_CY                                       ;          
        dec     edx                                                  ;          
@@:                                                                  ;          
                                                                     ;          
check_for_NULL:                                                      ;          
;/*                                                                  ;          
;** Clipping may have produced a NULL rectangle, because the line    ;          
;** may have been totally clipped out.                               ;          
;** If so, then we don't want to accumulate this !                   ;          
;** NULL rectangles have badly ordered coordinates.                  ;          
;** Again because we started with signed values, then we may still   ;          
;** have signed values here, so used signed comparisons.             ;          
;*/                                                                  ;          
        cmp     eax,ecx                                              ;          
        jg      restore_unclipped                                    ;          
        cmp     ebx,edx                                              ;          
        jg      restore_unclipped                                    ;          
                                                                     ;          
clipping_done:                                                       ;          
                                                                     ;          
;/*                                                                  ;          
;** Store the rectangle into the local RECTL structure.              ;          
;*/                                                                  ;          
        mov     rclTemp.rcl_xLeft, eax                               ;          
        mov     rclTemp.rcl_yBottom, ebx                             ;          
        mov     rclTemp.rcl_xRight, ecx                              ;          
        mov     rclTemp.rcl_yTop, edx                                ;          
                                                                     ;          
                                                                     ;          
;/*                                                                  ;          
;** Call the function to accumulate the screen bounds.               ;          
;*/                                                                  ;          
        INVOKE  AccumulateScreenBound, ADDR rclTemp                  ;          
                                                                     ;          
restore_unclipped:                                                   ;          
        popem   eax,ebx,ecx,edx,esi   ; Restore unclipped rect & esi ;          
        ASSUME  esi:PTR DDC                                          ;          
                                                                     ;          
do_normal_bounds:                                                    ;          
endif ; DCAF                                                         ;          
                                                                     ;          
;/*
;** accumulate for USER if requested
;*/
        test    edi,COM_ALT_BOUND
        jz      no_user_bounds

        mov     esi,[esi].ddc_prddc        ; ESI = RDDC

        ASSUME  esi:PTR RDDC

        rddc?   esi

        cmp     eax,[esi].rddc_rcsUsrBound.rcl_xLeft
        jg      have_user_min_x
        mov     [esi].rddc_rcsUsrBound.rcl_xLeft,eax

have_user_min_x:

        cmp     ebx,[esi].rddc_rcsUsrBound.rcl_yBottom
        jg      have_user_min_y
        mov     [esi].rddc_rcsUsrBound.rcl_yBottom,ebx

have_user_min_y:

        cmp     ecx,[esi].rddc_rcsUsrBound.rcl_xRight
        jl      have_user_max_x
        mov     [esi].rddc_rcsUsrBound.rcl_xRight,ecx

have_user_max_x:

        cmp     edx,[esi].rddc_rcsUsrBound.rcl_yTop
        jl      have_user_max_y
        mov     [esi].rddc_rcsUsrBound.rcl_yTop,edx

have_user_max_y:

        mov     esi,[esi].rddc_npddc        ; ESI = DDC

        ASSUME  esi:PTR DDC

no_user_bounds:

;/*
;** accumulate for GPI if requested
;*/

        test    edi,COM_BOUND
        jz      no_gpi_bounds

        mov     rclTemp.rcl_xLeft,eax
        mov     rclTemp.rcl_yBottom,ebx
        mov     rclTemp.rcl_xRight,ecx
        mov     rclTemp.rcl_yTop,edx

;/*
;** Back transform the GPI rectangle to MODEL space.  convert_rectl will
;** turn the rectangle into an inclusive rectangle, so we counter here
;** by incrementing the top right before hand.  This incrementing should
;** never be able to overflow because somewhere these coordinates had to
;** have been exclusive.
;*/

        add     rclTemp.rcl_xRight,1

        assert  NO

        add     rclTemp.rcl_yTop,1

        assert  NO

        mov     ah,CVTC_SCREEN
        mov     al,CVTC_MODEL
        lea     edi,rclTemp
        call    convert_rectl             ; ESI must = DDC

        jc      return_error

        mov     esi,[esi].ddc_prddc        ; ESI = RDDC

        ASSUME  esi:PTR RDDC

        rddc?   esi

;/*
;** Update the ddc GPI rectangle
;**
;** Note: In the following sequence of code, we can get an overflow in the adc.
;**    This overflow will be matched by an overflow from the sbb, which
;**    cancels the original overflow.    Think about it.
;*/

        mov     eax,rclTemp.rcl_xLeft
        sub     eax,[esi].rddc_rclGpiBound.rcl_xLeft
        jge     have_gpi_min_x
        add     [esi].rddc_rclGpiBound.rcl_xLeft,eax

have_gpi_min_x:

        mov     eax,rclTemp.rcl_yBottom
        sub     eax,[esi].rddc_rclGpiBound.rcl_yBottom
        jge     have_gpi_min_y
        add     [esi].rddc_rclGpiBound.rcl_yBottom,eax

have_gpi_min_y:

        mov     eax,rclTemp.rcl_xRight
        sub     eax,[esi].rddc_rclGpiBound.rcl_xRight
        jl      have_gpi_max_x
        add     [esi].rddc_rclGpiBound.rcl_xRight,eax

have_gpi_max_x:
        mov     eax,rclTemp.rcl_yTop
        sub     eax,[esi].rddc_rclGpiBound.rcl_yTop
        jl      have_gpi_max_y
        add     [esi].rddc_rclGpiBound.rcl_yTop,eax
have_gpi_max_y:
        mov     esi,[esi].rddc_npddc    ; ESI = DDC
        jmp     no_gpi_bounds
ALIGN 4
return_error:
        jmp     abidc_return
ALIGN 4
no_gpi_bounds:
        mov     eax,1
abidc_return:
        ddc?    esi
        RET
InnerAccumulateBounds   ENDP
        end
