;*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         01/30/88
;*
;* DESCRIPTION  This file contains functions related to bounding rectangles.
;*
;* FUNCTIONS    Exported: AccumulateBounds 
;*                        ResetBounds      
;*                        GetBoundsData    
;*              Public:   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                     Walt Moore wrote initial version.
;*   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
;*   10/23/89                     Viroon Touranachun [viroont]
;*                                  Convert 16-bit to 32-bit operations
;*   08/04/89                     John Colleran [johnc]
;*                                  Removed conversion of PMWIN bounds from 
;*                                  DEVICE to SCREEN they are now stored in 
;*                                  SCREEN coords                                                
;*   05/25/88                     Greg Hitchcock [gregh]
;*                                  Removed xform of GPI bounds to MODEL 
;*                                  space, as they are now being accumulated 
;*                                  in MODEL space.                                            
;*   09/06/88                     Lee A. Newberg [leen]
;*                                  Takes input in Model Coordinates for GPI
;*                                  bounds when COM_TRANSFORM is not set.
;*   05/04/88                     Charles Whitmer [chuckwh]
;*                                  Broke the working part out into 
;*                                  InnerAccumulateBounds.
;*   12/16/87                     Greg Hitchcock [gregh]
;*                                  Moved to display driver.
;*   07/15/87                     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.
;*   07/10/88                     Walt Moore [waltm]
;*                                  Made it call AccumBoundsInDevCoords
;*   05/30/88                     Walt Moore [waltm]
;*                                  Made it call convert_rectl to handle 
;*                                  rotations.
;*   05/04/88                     Charles Whitmer [chuckwh]
;*                                  Broke it out of AccumulateBounds for 
;*                                  internal use.
;*
;*****************************************************************************/
 
        CPUMode 286
        .xlist

        include         cmacros.inc
INCL_GRE_XFORMS         equ        1
INCL_GRE_DEVMISC3       equ        1
INCL_DDICOMFLAGS        equ        1
INCL_DDIMISC            equ        1
INCL_GPITRANSFORMS      equ        1
        include         pmgre.inc
        include         driver.inc
        include         njmp.mac
        include         assert.mac
        .list

        errcode <INV_IN_AREA,INV_IN_PATH,BOUNDS_OVERFLOW,INV_HDC>

sBegin        Data

        externD pfnDefConvert

sEnd        Data

sBegin        Code
        assumes cs,Code

        externW  CodeData
        externNP enter_driver
        externNP enter_driver_sem
        externNP leave_driver
        externNP convert_rectl

;/***************************************************************************
;*
;* FUNCTION NAME = ResetBounds
;*
;* DESCRIPTION   = Resets the bounds rectangles to their default values. 
;*
;*                 Registers Preserved:        
;*                        SI,DI,DS,BP          
;*                 Registers Destroyed:        
;*                        AX,BX,CX,DX,ES,FLAGS 
;*                 Calls:                      
;*                        enter_driver_sem     
;*                        leave_driver         
;*
;* INPUT         = None
;* OUTPUT        = None
;*
;* RETURN-NORMAL = DX:AX = 1 if ok    
;* RETURN-ERROR  = DX:AX = 0 if error 
;*
;**************************************************************************/

        check        ResetBounds,<hdc,ulType,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc        ResetBounds,<PUBLIC,FAR,NODATA>,<di>
        parmD        hdc
        parmD        fdType
        parmD        hddc
        parmD        FunN
cBegin
        fw_zero <ds,es>
        cld
        mov        ds,CodeData
        assumes ds,Data
        call        enter_driver_sem        ; User doesn't like call back here
        assert        NC

        mov        bx,hddc.lo
        cmp        [bx].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        ax,PMERR_INV_HDC
        save_error_code
        xor        ax,ax
        jmp        short rb_exit                ; return error
@@:

        les        bx,[bx].ddc_prddc        ; ES:BX = RDDC
        assumes es,nothing
        rddc?        es,bx

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

        .errnz        RB_GPI + RB_USER - 3
        assert        fdType.hi,E,0
        assert        fdType.lo,B,4

;/* 
;** Reset bounds by setting left > right and bottom > top
;*/ 
        mov        cx,fdType.lo
        shr        cl,1
        .errnz        RB_GPI-01h
        jnc        gpi_reset_done
        lea        di,[bx].rddc_rclGpiBound

        CPUMode 386

        mov     eax,MAX_COORDINATE
        stosd
        .errnz        rcl_xLeft
        stosd
        .errnz        rcl_yBottom - 4

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

        CPUMode 286

gpi_reset_done:
        mov        ax,MAXSHORT
        .errnz        RB_USER-00000010b
        assert        cx,BE,1
        jcxz        user_reset_done
        lea        di,[bx].rddc_rcsUsrBound
        stosw
        .errnz        rcs_pts1.pts_x
        stosw
        .errnz        rcs_pts1.pts_y-rcs_pts1.pts_x-2
        mov        ax,MINSHORT
        stosw
        .errnz        rcs_pts2.pts_x-rcs_pts1.pts_y-2
        stosw
        .errnz        rcs_pts2.pts_y-rcs_pts2.pts_x-2
user_reset_done:
        mov        ax,1

rb_exit:
        cwd
        call        leave_driver
        fw_zero <cx,ds,es>
cEnd

;/***************************************************************************
;*                 
;* 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 
;*                 PMWIN rectangle is reset after it is read.
;*                 
;*                 Registers Preserved:
;*                        SI,DI,DS,BP
;*                 Registers Destroyed:
;*                        AX,BX,CX,DX,ES,FLAGS
;*                 Calls: enter_driver_sem
;*                        leave_driver
;*                 
;* INPUT         = None
;* OUTPUT        = None
;*                 
;* RETURN-NORMAL = DX:AX = 1 if ok
;* RETURN-ERROR  = DX:AX = 0 if error
;*                 Error logged
;*
;**************************************************************************/

        check        GetBoundsData,<hdc,ulType,prcl,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc        GetBoundsData,<PUBLIC,FAR,NODATA>,<di,si>

        parmD        hdc
        parmD        fdType
        parmD        lpBoundsData
        parmD        hddc
        parmD        FunN
cBegin
        fw_zero <ds,es>
        cld
        mov        ds,CodeData
        assumes ds,Data
        call        enter_driver_sem        ; User doesn't like call back if no bounds
        assert        NC
        mov        bx,hddc.lo
        cmp        [bx].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        ax,PMERR_INV_HDC
        save_error_code
        xor        ax,ax
        jmp        gbd_exit                ; return error
@@:

        lds        bx,[bx].ddc_prddc        ; DS:BX = RDDC
        assumes ds,nothing
        rddc?        ds,bx
;/* 
;**  Validate the bounds type
;*/ 

        mov        cx,fdType.lo
        .errnz        GBD_USER-1
        .errnz        GBD_GPI
        assert        fdType.hi,E,0
        assert        cx,B,2
        or        cx,cx
        jz        gbd_do_gpi_case

;/*
;** Handle PMWIN 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?        ds,bx
        cmp        [bx].rddc_rcsUsrBound.rcs_pts1.pts_x,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
;*/

        CPUMode 386

        les        di,lpBoundsData
        lea        si,[bx].rddc_rcsUsrBound.rcs_pts1.pts_x
        lodsw                                ; left
        cwde
        stosd

        lodsw                                ; bottom
        cwde
        stosd

        lodsw                                ; right
        cwde
        stosd

        lodsw                                ; top
        cwde
        stosd

        CPUMode 286

        .errnz rddc_rcsUsrBound.rcs_pts1.pts_y - rddc_rcsUsrBound.rcs_pts1.pts_x - 2
        .errnz rddc_rcsUsrBound.rcs_pts2.pts_x - rddc_rcsUsrBound.rcs_pts1.pts_y - 2
        .errnz rddc_rcsUsrBound.rcs_pts2.pts_y - rddc_rcsUsrBound.rcs_pts2.pts_x - 2

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

;/* 
;**  reset PMWIN bounds!
;*/ 
        rddc?        ds,bx                        ; DS:BX -> ddc
        mov        [bx].rddc_rcsUsrBound.rcs_pts1.pts_x,MAXSHORT
        mov        [bx].rddc_rcsUsrBound.rcs_pts1.pts_y,MAXSHORT
        mov        [bx].rddc_rcsUsrBound.rcs_pts2.pts_x,MINSHORT
        mov        [bx].rddc_rcsUsrBound.rcs_pts2.pts_y,MINSHORT
        jmp        short gbd_ok

;/* 
;**  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?        ds,bx
        lea        si,[bx].rddc_rclGpiBound
        les        di,lpBoundsData
        assumes es,nothing
        .errnz  (size RECTL) and 3
        mov        cx,(size RECTL) / 4

        CPUMode 386

        rep        movsd

        jmp        short gbd_ok

;/* 
;**  handle the case with no data - reset the rect
;*/ 
gbd_no_data_case:
        les        di,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

        CPUMode 286

gbd_ok:
        mov        ax,1
gbd_exit:
        cwd
        mov        ds,CodeData                ; leave_driver expects this
        assumes ds,Data
        call        leave_driver
gbd_exit_no_lock:
        fw_zero <cx,ds,es>
cEnd

;/***************************************************************************
;*                 
;* 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         = hdc,prcl,hddc,FunN
;* OUTPUT        = None
;*                 
;* RETURN-NORMAL = None
;* RETURN-ERROR  = None
;*
;**************************************************************************/

        check        AccumulateBounds,<hdc,prcl,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc        AccumulateBounds,<PUBLIC,FAR,NODATA>,<di,si>
        parmD        hdc
        parmD        lpRect
        parmD        hddc
        parmD        FunN
cBegin

;/* 
;** !!! firewall to see if we have the screen semaphore locked!
;*/ 
        fw_zero <ds,es>
        cld
        mov        ds,CodeData
        assumes ds,Data
        mov        si,hddc.lo                ; DS:SI --> DDC
        mov        dx,si
        call        enter_driver
        njc        ab_exit_no_lock                ; DX:AX = 0 on error

        les        di,lpRect
        assumes es,nothing

;/*
;** If the COM_TRANSFORM bit is clear, then GPI BOUNDS have been
;** supplied in MODEL COORDINATES.  PMWIN 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.hi,COM_TRANSFORM
        jnz        use_InnerAccumulate
        test        FunN.hi,COM_BOUND
        jz        use_InnerAccumulate

ifdef FIREWALLS
        test        FunN.hi,COM_ALT_BOUND
        assert        Z
endif        ;FIREWALLS


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

        CPUMode 386

        lds        bx,[si].ddc_prddc        ; DS:BX = RDDC
        assumes ds,nothing
        rddc?        ds,bx

        mov        eax,es:[di].rcl_xLeft
        sub        eax,[bx].rddc_rclGpiBound.rcl_xLeft
        jge        @F
        add        [bx].rddc_rclGpiBound.rcl_xLeft,eax
@@:
        mov        eax,es:[di].rcl_yBottom
        sub        eax,[bx].rddc_rclGpiBound.rcl_yBottom
        jge        @F
        add        [bx].rddc_rclGpiBound.rcl_yBottom,eax
@@:
        mov        eax,es:[di].rcl_xRight
        sub        eax,[bx].rddc_rclGpiBound.rcl_xRight
        jl        @F
        add        [bx].rddc_rclGpiBound.rcl_xRight,eax
@@:
        mov        eax,es:[di].rcl_yTop
        sub        eax,[bx].rddc_rclGpiBound.rcl_yTop
        jl        @F
        add        [bx].rddc_rclGpiBound.rcl_yTop,eax
@@:

        mov        ds,CodeData                ; restore DS
        assumes ds,Data
        ddc?        si
        jmp        short ab_return_ok

        CPUMode 286

use_InnerAccumulate:

;/* 
;**  pick up the rectangle
;*/ 
        mov        ax,es:[di].rcl_xLeft.lo
        mov        bx,es:[di].rcl_yBottom.lo
        mov        cx,es:[di].rcl_xRight.lo
        mov        dx,es:[di].rcl_yTop.lo

;/* 
;**  call the inner routine
;*/ 
        mov        di,FunN.hi
        call        InnerAccumulateBounds
        or        ax,ax
        jz        ab_return_error

;/* 
;**  return OK
;*/ 
ab_return_ok:
        mov        ax,1
ab_return_error:
        cwd
        call        leave_driver
ab_exit_no_lock:
        fw_zero <cx,ds,es>
cEnd

cProc        far_AccumBoundsInDevCoords,<PUBLIC,FAR,NODATA,NONWIN>
cBegin
        call        AccumBoundsInDevCoords
cEnd

;/***************************************************************************
;*                 
;* FUNCTION NAME = AccumBoundsInDevCoords
;*                 
;* DESCRIPTION   = Accumulates new bounds data. We are passed the new 
;*                 rectangle in DEVICE coordinates.  We accumulate in 
;*                 SCREEN coordinates.
;*                 
;*                 Note: This routine takes INCLUSIVE rectangles.
;*                 Registers Preserved:  
;*                        DI,SI,BP,DS,ES 
;*                 Registers Destroyed:  
;*                        AX,BX,CX,DX,GS 
;*                 Calls:                
;*                        convert_rectl  
;*
;* INPUT         = (AX,BX)-(CX,DX) = RECTS to accumulate
;*                 DS:SI = DDC
;*                 DI    = Command flags
;* OUTOUT        = None
;*
;* RETURN-NORMAL = DX:AX = 1 if ok 
;* RETURN-ERROR  = DX:AX = 0 if error 
;*                 Error logged       
;*
;***************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc        AccumBoundsInDevCoords,<PUBLIC,NEAR>
cBegin        <nogen>

        ddc?        si

;/*
;** 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
;*/ 
        CPUMode 386
        lgs        si,[si].ddc_prddc
        assumes gs,nothing
        rddc?        gs,si                        ; GS:SI = RDDC
        offset_bounds  ax,gs:[si].rddc_ptsOrg.pts_x
        offset_bounds  bx,gs:[si].rddc_ptsOrg.pts_y
        offset_bounds  cx,gs:[si].rddc_ptsOrg.pts_x
        offset_bounds  dx,gs:[si].rddc_ptsOrg.pts_y
        mov        si,gs:[si].rddc_npddc        ; SI = DDC
        CPUMode 286

;/* 
;**         jmp        InnerAccumulateBounds
;*//




;          errn$        InnerAccumulateBounds
cEnd        <nogen>


;/***************************************************************************
;*                 
;* 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.
;*                 Registers Preserved:  
;*                        DI,SI,BP,DS,ES 
;*                 Registers Destroyed:  
;*                        AX,BX,CX,DX,GS 
;*                 Calls:                
;*                        convert_rectl  
;*
;* INPUT         = (AX,BX)-(CX,DX) = RECTS to accumulate
;*                 DS:SI = DDC
;*                 DI    = Command flags
;* OUTPUT        = None
;*
;* RETURN-NORMAL = DX:AX = 1 if ok 
;* RETURN-ERROR  = DX:AX = 0 if error 
;*                 Error logged       
;*
;***************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc        InnerAccumulateBounds,<PUBLIC,NEAR>
        localV        rclTmp,%(size RECTL)
cBegin

        ddc?        si

;/* 
;**  make sure the rectangle is legal
;*/ 
        assert        ax,LE,cx
        assert        bx,LE,dx

        CPUMode 386

;/* 
;**  accumulate for PMWIN if requested
;*/ 
        test        di,COM_ALT_BOUND
        jz        no_user_bounds

        lgs        si,[si].ddc_prddc            ; GS:SI = RDDC
        assumes ds,nothing
        rddc?        gs,si

        cmp        ax,gs:[si].rddc_rcsUsrBound.rcs_pts1.pts_x
        jg        have_user_min_x
        mov        gs:[si].rddc_rcsUsrBound.rcs_pts1.pts_x,ax
have_user_min_x:
        cmp        bx,gs:[si].rddc_rcsUsrBound.rcs_pts1.pts_y
        jg        have_user_min_y
        mov        gs:[si].rddc_rcsUsrBound.rcs_pts1.pts_y,bx
have_user_min_y:
        cmp        cx,gs:[si].rddc_rcsUsrBound.rcs_pts2.pts_x
        jl        have_user_max_x
        mov        gs:[si].rddc_rcsUsrBound.rcs_pts2.pts_x,cx
have_user_max_x:
        cmp        dx,gs:[si].rddc_rcsUsrBound.rcs_pts2.pts_y
        jl        have_user_max_y
        mov        gs:[si].rddc_rcsUsrBound.rcs_pts2.pts_y,dx
have_user_max_y:

        mov        si,gs:[si].rddc_npddc            ; DS:SI = DDC
        mov        ds,CodeData
        assumes ds,Data
no_user_bounds:

;/* 
;**     accumulate for GPI if requested
;*/
        test        di,COM_BOUND
        njz        no_gpi_bounds

        push        es                        ; Preserve ES
        push        di
        push        ss
        pop        es
        assumes es,nothing

        lea        di,rclTmp

        movsx   eax,ax
        stosd
        movsx   eax,bx
        stosd
        movsx   eax,cx
        stosd
        movsx   eax,dx
        stosd
        sub        di,size RECTL

;/*
;** 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        rclTmp.rcl_xRight,1
        assert        NO
        add        rclTmp.rcl_yTop,1
        assert        NO

        mov        ah,CVTC_SCREEN
        mov        al,CVTC_MODEL
        call        convert_rectl                    ; DS:SI must = DDC

        jc        return_error

        lgs        si,[si].ddc_prddc            ; GS:SI = RDDC
        assumes gs,nothing
        rddc?        gs,si

        lea        di,rclTmp

;/*
;** 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. 
;*/

        mov        eax,es:[di].rcl_xLeft
        sub        eax,gs:[si].rddc_rclGpiBound.rcl_xLeft
        jge        have_gpi_min_x
        add        gs:[si].rddc_rclGpiBound.rcl_xLeft,eax
have_gpi_min_x:
        mov        eax,es:[di].rcl_yBottom
        sub        eax,gs:[si].rddc_rclGpiBound.rcl_yBottom
        jge        have_gpi_min_y
        add        gs:[si].rddc_rclGpiBound.rcl_yBottom,eax
have_gpi_min_y:
        mov        eax,es:[di].rcl_xRight
        sub        eax,gs:[si].rddc_rclGpiBound.rcl_xRight
        jl        have_gpi_max_x
        add        gs:[si].rddc_rclGpiBound.rcl_xRight,eax
have_gpi_max_x:
        mov        eax,es:[di].rcl_yTop
        sub        eax,gs:[si].rddc_rclGpiBound.rcl_yTop
        jl        have_gpi_max_y
        add        gs:[si].rddc_rclGpiBound.rcl_yTop,eax

have_gpi_max_y:
        mov        si,gs:[si].rddc_npddc        ; SI = DDC
        CPUMode 286

        pop        di
        pop        es
        jmp        short no_gpi_bounds
return_error:
        pop        di
        pop        es
        jmp        short abidc_return
no_gpi_bounds:
        mov        ax,1
abidc_return:
        cwd

        ddc?        si
cEnd

cProc        far_InnerAccumulateBounds,<PUBLIC,FAR,NODATA,NONWIN>
cBegin
        cCall         InnerAccumulateBounds
cEnd

sEnd        Code

        end
