;*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 = RECT.ASM
;*
;* DESCRIPTIVE NAME = Rectangle routines
;*
;*
;* VERSION      V2.0
;*
;* DATE         05/02/88
;*
;* DESCRIPTION  Utility functions for rectangles.
;*
;* FUNCTIONS    convert_rectl
;*              truncate_rectl
;*              validate_rectl
;*
;* 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/02/88                     Written by Hock Lee
;*   11/04/91                     Cliff Levesque [cliffl] Cleanup and convert to
;*                                386 and above flat model, protected mode
;*                                32 bit operation.
;*   02/09/93              60749  Hiword of SRC and DEST coord space flags
;*                                non zero if neg x and GPI bounds accum
;*                                hosing convert and returning world instead
;*                                of model coords. ( this can/should be optimized
;*                                and cleaned ).
;*
;*****************************************************************************/

        .386

        .xlist

INCL_GPITRANSFORMS      equ     1
INCL_GPIERRORS          equ     1
INCL_GRE_DEVMISC        equ     1
INCL_GRE_XFORMS         equ     1
INCL_DDICOMFLAGS        equ     1
INCL_DDIMISC            equ     1
INCL_DDIBUNDLES         equ     1
DINCL_ENABLE            equ     1
DINCL_BITMAP            equ     1

        include        pmgre.inc
        include driver.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

ptl0        equ        0
ptl1        equ        1 * (SIZE POINTL)
ptl2        equ        2 * (SIZE POINTL)
ptl3        equ        3 * (SIZE POINTL)

infinite_rectl        equ        this dword

        dd        MIN_COORDINATE,MIN_COORDINATE,MAX_COORDINATE,MAX_COORDINATE

.errnz        ($ - infinite_rectl) - (SIZE RECTL)

        .CODE

CVTC_SCREEN        equ        6                
MAXINT             equ        07fffh           
MININT             equ        08000h           

makemin macro      dest,src
        local      have_min
        cmp        dest,src
        jle        have_min
        mov        dest,src
have_min:
        endm

makemax macro      dest,src
        local      have_max
        cmp        dest,src
        jge        have_max
        mov        dest,src
have_max:
        endm

;/***************************************************************************
;*
;* FUNCTION NAME = truncate_long (MACRO)
;*
;* DESCRIPTION   = Truncate a LONG integer pointed to by ES:DI
;*                 The pointers DI is also advanced.
;*
;*                 The new range is 0xffff8000..0x7fff.
;*
;*                 Registers Preserved:
;*                        ECX
;*                 Registers Destroyed:
;*                        EAX,EBX,EDX,EDI,ESI
;*
;* INPUT         = EDI -> long integer to be truncated
;*                 ECX = MAXINT
;* OUTPUT        = EDI -> truncated integer
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

truncate_long        macro

        local      have_it

        assert     ecx,E,MAXINT          ;CX = maximum positive signed number
                                         ;     supported
        .errnz     MAXINT-07fffh
        .errnz     MININT-08000h

        mov        ax,WORD PTR [edi]
        cwd                              ;; DX = sign word
        xor        dx,WORD PTR [edi][2]
        jz         have_it               ;; Yes, done
        mov        ax,cx                 ;; Assume MAXINT
        test       WORD PTR [edi][2],8000h
        jz         have_it
        not        ax
have_it:
        stosw
        cwd
        xchg       ax,dx
        stosw
        endm

_TUNE SEGMENT DWORD FLAT PUBLIC 'CODE'
;/***************************************************************************
;*
;* FUNCTION NAME = convert_rectl
;*
;* DESCRIPTION   = Converts a RECTL from one coordinate space to another.  If
;*                 the transform includes a rotation, a bounding rectangle of
;*                 the rotated one will be returned.  The returned rectangle is
;*                 always well ordered. The given rectangle is converted in place.
;*                 A rectangle in DEVICE/SCREEN coordinates is taken as exclusive
;*                 on right/top. However, all rectangles in other coordinate
;*                 spaces are taken as inclusive on all edges.  A correct
;*                 rectangle in the right representation (inclusive/exclusive)
;*                 will be returned.
;*                 The inclusiveness of rectangles in coordinate spaces other
;*                 than device/screen space makes it impossible to represent
;*                 null rectangles in those spaces.
;*
;*                 Registers Destroyed:
;*                        EAX,EBX,ECX,EDX
;*
;* INPUT         = AH  = source coordinates
;*                 AL  = dest coordinates
;*                 ESI = ddc
;*                 EDI = rectl
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = CF = 0, EAX = 1
;* RETURN-ERROR  = CF = 1, EAX = 0
;*
;**************************************************************************/

ALIGN 4
convert_rectl   PROC SYSCALL USES esi edi
                LOCAL   xform_requested:DWORD,
                        xform_type:DWORD,
                        hddc:DWORD,
                        prcl:DWORD,
                        aptl[4]:POINTL

        DebugMsg <convert_rectl CLIFFL rect.asm>

;/*
;** do assertion first
;*/

        ddc?    esi

ifdef FIREWALLS

;/*
;** actually we should firewall null rectangles in device coordinates too.
;*/

        pushad

        assert  ah,BE,CVTC_SCREEN

        assert  al,BE,CVTC_SCREEN

        call    validate_rectl                ; make sure rectangle is good
        jnc     good_rect

        rip     text,<Engine Error: bad rectangle in convert_rectl>

good_rect:

        popad
endif

        mov     prcl,edi
        mov     hddc,esi

        movzx   eax,ax                        ;             60749

        mov     xform_requested,eax

;/*
;** do not convert infinite rectangle!
;*/

        push    esi
        push    edi
        lea     esi,infinite_rectl

        .errnz  (size RECTL) and 3

        mov     ecx,(size RECTL)/4
        repe    cmpsd
        pop     edi
        pop     esi                        ; don't touch zero flag!
        jz      convert_rectl_good_exit

;/*
;** convert src rectangle from screen to device if it's in screen coordinates
;*/

        cmp     byte ptr xform_requested[1],CVTC_SCREEN
        jnz     src_not_screen

        ASSUME  esi:PTR DDC, edi:PTR RECTL

        mov     ebx,[esi].ddc_prddc

        ASSUME  ebx:PTR RDDC

        mov     eax,[ebx].rddc_ptsOrg.ptl_x      ; EAX = DC origin X
        mov     ebx,[ebx].rddc_ptsOrg.ptl_y      ; EBX = DC origin Y

screen_to_device_loop:

        sub     [edi].rcl_xLeft,eax              
        jo      convert_rectl_overflow_error     
        sub     [edi].rcl_yBottom,ebx            
        jo      convert_rectl_overflow_error     
        sub     [edi].rcl_xRight,eax             
        jo      convert_rectl_overflow_error     
        sub     [edi].rcl_yTop,ebx               
        jo      convert_rectl_overflow_error     
src_not_screen:

;/*
;** make source rectangle inclusive if it's in screen/device space
;*/

        cmp     byte ptr xform_requested[1],CVTC_DEVICE
        jb      scr_rect_inclusive

        .erre   CVTC_SCREEN GT CVTC_DEVICE

        sub     [edi].rcl_xRight,1               
        jo      convert_rectl_overflow_error
        sub     [edi].rcl_yTop,1                 
        jo      convert_rectl_overflow_error

scr_rect_inclusive:

;/*
;** wo do special cases for identity transform between WORLD and
;** DEVICE/SCREEN coordinates only
;*/

        test    [esi].ddc_fb,DDC_UNIT_XFORM
        jz      its_complex_xform                ; not a identity transform
        mov     eax,xform_requested
        mov     ebx,CVTC_WORLD*100h + CVTC_SCREEN
        cmp     eax,ebx                          ; world -> screen?
        jz      its_unit_xform
        xchg    bh,bl
        cmp     eax,ebx                          ; screen -> world?
        jz      its_unit_xform
        dec     bh
        cmp     eax,ebx                        ; device -> world?
        jz      its_unit_xform
        xchg    bh,bl
        cmp     eax,ebx                        ; world -> device?
        jnz     its_complex_xform

        errnz        CVTC_SCREEN-CVTC_DEVICE-1

its_unit_xform:

        jmp     do_target_rectangle
ALIGN 4

convert_rectl_overflow_error:

        mov     eax,PMERR_COORDINATE_OVERFLOW

convert_rectl_error:

        save_error_code

convert_rectl_bad_exit:

        xor     eax,eax
        stc
        jmp     convert_rectl_exit
ALIGN 4

;/*
;** Complex Transform
;** fill the four point rectangle
;*/

its_complex_xform:

        mov     eax,[edi].rcl_xLeft
        mov     aptl[ptl0].ptl_x,eax
        mov     aptl[ptl1].ptl_x,eax

        mov     eax,[edi].rcl_yBottom
        mov     aptl[ptl0].ptl_y,eax
        mov     aptl[ptl2].ptl_y,eax

        mov     eax,[edi].rcl_xRight
        mov     aptl[ptl2].ptl_x,eax
        mov     aptl[ptl3].ptl_x,eax

        mov     eax,[edi].rcl_yTop
        mov     aptl[ptl1].ptl_y,eax
        mov     aptl[ptl3].ptl_y,eax

;/*
;** convert the points
;*/

transform_points:

        ddc?    esi

        lea     edi,aptl
        xor     eax,eax                          ; general purpose null parameter
        mov     edx,xform_requested              ; DL = target space
        mov     bl,dh                            ; BL = source space
        mov     dh,al                            ; DX = target space
        mov     bh,al                            ; BX = source space
        cmp     edx,CVTC_SCREEN
        cmc
        sbb     dx,ax                            ; convert screen to device
        cmp     ebx,CVTC_SCREEN
        cmc
        sbb     bx,ax                            ; convert screen to device
        movzx   ebx,bx
        movzx   edx,dx

        errnz   CVTC_SCREEN-CVTC_DEVICE-1


        INVOKE  PFNDefConvert PTR pfnDefConvert,
                [esi].ddc_hdc,
                ebx,
                edx,
                edi, ;Charles says swap these 2
                4,   ;Charles says swap these 2
                0,
                NGreConvert

        or      ax,ax
        jz      convert_rectl_bad_exit           ; encountered an error in Convert

;/*
;** get a good ordering rectange
;*/

;/*
;** find the max and min X
;*/

        mov     eax,aptl[ptl0].ptl_x             ; EAX = min X
        mov     edx,eax                          ; EDX = max X
        mov     ebx,aptl[ptl3].ptl_x             ; EBX = test X
        makemin eax,ebx
        makemax edx,ebx
        mov     ebx,aptl[ptl1].ptl_x             ; EBX = test X
        makemin eax,ebx
        makemax edx,ebx
        mov     ebx,aptl[ptl2].ptl_x             ; EBX = test X
        makemin eax,ebx
        makemax edx,ebx

;/*
;** EAX = min X
;** EDX = max X
;*/

have_x_values:

        mov        edi,prcl
        mov        [edi].rcl_xLeft,eax
        mov        [edi].rcl_xRight,edx

;/*
;** find the max and min Y
;*/

        mov        eax,aptl[ptl0].ptl_y          ; EAX = min Y
        mov        edx,eax                       ; EDX = max Y
        mov        ebx,aptl[ptl3].ptl_y          ; EBX = test Y
        makemin eax,ebx
        makemax edx,ebx
        mov     ebx,aptl[ptl1].ptl_y          ; EBX = test Y
        makemin eax,ebx
        makemax edx,ebx
        mov     ebx,aptl[ptl2].ptl_y          ; EBX = test Y
        makemin eax,ebx
        makemax edx,ebx

;/*
;** EAX = min Y
;** EDX = max Y
;** make new Y's inclusive/exclusive
;*/

have_y_values:

        mov     edi,prcl
        mov     [edi].rcl_yBottom,eax
        mov     [edi].rcl_yTop,edx

do_target_rectangle:

;/*
;** convert dest rectangle from device to screen if needed
;*/

        cmp     byte ptr xform_requested[0],CVTC_SCREEN
        jnz     dest_not_screen
        mov     esi,hddc
        mov     ebx,[esi].ddc_prddc
        mov     eax,[ebx].rddc_ptsOrg.ptl_x        ; EAX = DC origin X
        mov     ebx,[ebx].rddc_ptsOrg.ptl_y        ; EBX = DC origin Y

device_to_screen_loop:

        add     [edi].rcl_xLeft,eax                
        jo      jmp_convert_rectl_overflow_error   
        add     [edi].rcl_yBottom,ebx              
        jo      jmp_convert_rectl_overflow_error   
        add     [edi].rcl_xRight,eax               
        jo      jmp_convert_rectl_overflow_error   
        add     [edi].rcl_yTop,ebx                 
        jo      jmp_convert_rectl_overflow_error   

dest_not_screen:

;/*
;** Separate DEVICE and SCREEN for further processing:
;*/

        cmp     byte ptr xform_requested[0],CVTC_DEVICE
        jb      got_dst_rect

        .erre   CVTC_SCREEN GT CVTC_DEVICE
        .erre   CVTC_WORLD  LT CVTC_DEVICE
        .erre   CVTC_MODEL  LT CVTC_DEVICE
        .erre   CVTC_PAGE   LT CVTC_DEVICE
        .erre   CVTC_DEFAULTPAGE LT CVTC_DEVICE

; coordinates must fit in 16 bits

check_16_loop:


        movsx   eax,WORD PTR [edi].rcl_xRight[0]
        cmp     eax,[edi].rcl_xRight
        jnz     jmp_convert_rectl_overflow_error

        movsx   eax,WORD PTR [edi].rcl_yTop[0]
        cmp     eax,[edi].rcl_yTop
        jnz     jmp_convert_rectl_overflow_error

        movsx   eax,WORD PTR [edi].rcl_yBottom[0]
        cmp     eax,[edi].rcl_yBottom
        jnz     jmp_convert_rectl_overflow_error

        movsx   eax,WORD PTR [edi].rcl_xLeft[0]
        cmp     eax,[edi].rcl_xLeft
        jnz     jmp_convert_rectl_overflow_error

; make dest rectangle exclusive if needed

        mov     eax,1
        add     [edi].rcl_xRight,eax          
        jo      jmp_convert_rectl_overflow_error
        add     [edi].rcl_yTop,eax            
        jno     got_dst_rect

jmp_convert_rectl_overflow_error:

        jmp     convert_rectl_overflow_error
ALIGN 4

got_dst_rect:

convert_rectl_good_exit:

        mov     eax,1
        clc

convert_rectl_exit:

ifdef FIREWALLS

;/*
;** make sure rectangle is good
;** actually we should firewall null rectangles in device coordinates too.
;*/

        jc      skip_validate_rectl
        pushfd
        pushad

        call    validate_rectl                ; make sure rectangle is good
        jnc     good_rectangle

        rip     text,<Invalid rectangle passed to convert_rectl>

good_rectangle:

        popad
        popfd

skip_validate_rectl:

endif
                RET

convert_rectl   ENDP
_TUNE ENDS

;/***************************************************************************
;*
;* FUNCTION NAME = truncate_rectl()
;*
;* DESCRIPTION   = Truncate a RectL to the 16 bit coordiate system.
;*                 Coodinates which are too large or too small are truncated.
;*
;*                 The minimum and maximum coordinates are 0xffff8000 and 0x7fff
;*
;*                 Registers Preserved:
;*                        ESI,EDI
;*                 Registers Destroyed:
;*                        EAX,EBX,ECX,EDX
;*
;* INPUT         = EDI -> RectL to be truncated
;* OUTPUT        = EDI -> truncated Rectl
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

ALIGN 4
truncate_rectl  PROC    SYSCALL USES edi

;/*
;** EDI -> RectL
;*/

        mov        ecx,MAXINT

        truncate_long                ; left
        truncate_long                ; bottom
        truncate_long                ; right
        truncate_long                ; top

        .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

        RET

truncate_rectl  ENDP
_TUNE SEGMENT DWORD FLAT PUBLIC 'CODE'
;/***************************************************************************
;*
;* FUNCTION NAME = validate_rectl()
;*
;* DESCRIPTION   = Check if a RectL is a good rectangle (i.e. no cross edges).
;*                 An empty rectangle in device coordinates is also valid.  Note
;*                 also that there is no representation of null rectangles in other
;*                 coordinate spaces.
;*
;*                 Registers Preserved:
;*                        ESI,EDI
;*                 Registers Destroyed:
;*                        EAX,EBX
;*
;* INPUT         = EDI -> RectL
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = CF = 0
;* RETURN-ERROR  = CF = 1
;*                 EAX = Engine error code (PMERR_INV_RECT)
;**************************************************************************/

ALIGN 4
validate_rectl  PROC    SYSCALL

        mov     eax,PMERR_INV_RECT
        mov     ebx,[edi].rcl_xRight          ; verify the X ordering
        sub     ebx,[edi].rcl_xLeft
        js      validate_bad_rect
        mov     ebx,[edi].rcl_yTop            ; verify the Y ordering
        sub     ebx,[edi].rcl_yBottom
        clc
        jns     validate_exit

validate_bad_rect:

        stc

validate_exit:

                RET

validate_rectl  ENDP
_TUNE ENDS
        end
