;*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     55,132
        TITLE    WINBITS.ASM
        SUBTITLE Header
;/*****************************************************************************
;*
;* SOURCE FILE NAME = WINBITS.ASM
;*
;* DESCRIPTIVE NAME = Bitmap Handler
;*
;*
;* VERSION      V2.0
;*
;* DATE         03/06/87
;*
;* DESCRIPTION  Handles bitmaps for winthorn.
;*
;* FUNCTIONS    Bitblt
;*              DrawBits
;*              do_corr
;*              ImageData
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   03/06/87                     Written by Charles Whitmer
;*   06/15/88                     Walt Moore [waltm] Added color==>mono
;*                                background color.  Rewrote it at that point.
;*   08/10/88                     Walt Moore [waltm] Invalid RECTLs passed to
;*                                Engine for DCR 24067.
;*   05/02/89                     Lee A. Newberg [leen] Skips a whole bunch of
;*                                stuff when COM_DRAW is clear.  Beware that
;*                                this means that many local varibles are not
;*                                being initialized!!
;*   10/20/89                     Viroon  Touranachun [viroont] Fixed bug--
;*                                restricted the driver to handle only a
;*                                monochrome bitmap that is located within a
;*                                single data segment. Also, limited the
;*                                flOptions to ; be either BBO_AND, BBO_OR,
;*                                or BBO_IGNORE, with its high word must be 0.
;*   10/22/89                     Viroon Touranachun [viroont] Handle a bitmap
;*                                source with a standard-format bitmap in it
;*                                (for DCR25020).
;*   10/23/89                     Viroon Touranachun [viroont] Convert 16-bit to
;*                                32-bit operations.
;*   10/27/89                     Viroon  Touranachun [viroont] Allowed a NULL
;*                                bitmapinfoheader if it was a NULL pbits.
;*   06/01/90                     Viroon Touranachun [viroont] Added
;*                                BLTMODE_SCR_DRAW flag to handle a call from
;*                                the DrawBits function. (when it wants to
;*                                draw directly to the screen with ROP=SRC_COPY.)
;*   06/01/90                     Viroon  Touranachun [viroont] Optimized the
;*                                function to handle compressed/uncompressed
;*                                bits which will be drawn to the screen directly.
;*   11/10/92              DCR37  Support for new background mixes:
;*                                BM_SRCTRANSPARENT and BM_DESTTRANSPARENT
;*   11/11/92              56520  COM_DRAW flag not alligned properly
;*   11/25/92                     Support BBO_PAL_COLORS
;*   11/25/92              57622  Enable passthru of flags BBO_PAL_COLORS
;*                                and BBO_NO_COLOR_INFO to lower bitblt code
;*                                if palette driver.
;*   11/26/92                     John Batty. Added DCAF changes.
;*   12/04/92              57695  David A Kerr [dkerr] Check grim reaper flag
;*                                for destination as well as source DCs.
;*   02/15/93              61938  Performance Problems with DrawBits and BitBlt
;*   03/08/93              61778  BBO_FLAGS NOT PASSED TO BITBLT WORKERS
;*   12/16/93  CHANGE TEAM 76410  If BM_SRCTRANSPARENT or BM_DESTTRANSPARENT in
;*                                RGB_MODE, convert background color from RGB
;*                                value to index value.
;*
;*****************************************************************************/

        .386

OPTION  OLDSTRUCTS

        .MODEL FLAT,SYSCALL
        ASSUME  SS:FLAT, DS:FLAT, CS:FLAT, ES:FLAT

DGROUP  group   _TABLE,_SEAMDATA2
CGROUP  group   _Text16,_CODE16

_TABLE  SEGMENT PUBLIC 'DATA'
_TABLE  ENDS
_SEAMDATA2  SEGMENT PUBLIC 'DATA'
_SEAMDATA2  ENDS
_Text16 SEGMENT DWORD USE16 PUBLIC 'CODE'
_Text16 ENDS
_CODE16 SEGMENT DWORD USE16 PUBLIC 'CODE'
_CODE16 ENDS

        .xlist
INCL_GRE_BITMAPS        equ     1
INCL_DDIMISC            equ     1
INCL_DDICOMFLAGS        equ     1
INCL_GPIREGIONS         equ     1
INCL_GPIBITMAPS         equ     1
INCL_GPIPRIMITIVES      equ     1
INCL_GRE_CLIP           equ     1
        include pmgre.inc
DINCL_BB_ROPS           equ     1
DINCL_BITMAP            equ     1
DINCL_ENABLE            equ     1

INCL_DEV                equ     1
        include pmdev.inc

        include driver.inc
        include extern.inc
        include protos.inc

        include oemblt.inc
        include assert.mac
        include tune.inc

MAX_BITMAP_DIMENSION    equ     00007fffh ; 32K
NUMBER_OF_POINTS        equ     4       ;Number of points specifying
MINSHORT_IN_LONG        equ     0ffff8000h      ;sign extended


.DATA
do_function     equ     this dword      ; low-level working functions
                dd      OFFSET do_bitblt
                dd      OFFSET do_drawbits
                dd      OFFSET do_stretchblt

        include bmi2.inc
        .list

page
_CODE   SEGMENT DWORD FLAT PUBLIC 'CODE'

;/***************************************************************************
;*
;* FUNCTION NAME = DrawBits
;*
;* DESCRIPTION   = Draw a standard format bitmap on the surface of a
;*                 device-context. The function actually validate/adjusts
;*                 parameters--pbmiInfoTable, pBits, lCount and aptlPoints--
;*                 before it passes them down to the BitBlt function to perform the drawing.
;*                 perform the drawing.
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = hdc             :DWORD
;*                 pBits           :DWORD
;*                 pbmi            :DWORD
;*                 lCount          :DWORD
;*                 aptlPoints      :DWORD
;*                 lRop            :DWORD
;*                 flOptions       :DWORD
;*                 hddc            :DWORD
;*                 FunN            :DWORD
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = GPI_OK      = 1 if successful
;*                       = GPI_HITS    = 2 if correlate and hit
;* RETURN-ERROR  = DX:AX = GPI_ERROR   = 0
;*                 error logged
;**************************************************************************/

DB_MAX_CLR_TBL  equ     256             ;the largest color table size (in bytes)

ALIGN 4
DrawBits PROC SYSCALL,
        hdc             :DWORD,
        pBits           :DWORD,
        pbmi            :DWORD,
        lCount          :DWORD,
        aptlPoints      :DWORD,
        lRop            :DWORD,
        flOptions       :DWORD,
        hddc            :DWORD,
        FunN            :DWORD

        LOCAL  DeltaX    :DWORD              ;the bitmap width
        LOCAL  DeltaY    :DWORD              ;the bitmap height
        LOCAL  cBitCount :DWORD              ;BPP
        LOCAL  cClrUsed  :DWORD              ;number of entries in the color table
        LOCAL  cbRGB     :DWORD              ;the RGB entry size (RGB or RGB2)
        LOCAL  aptlLocal[NUMBER_OF_POINTS]:POINTL
        LOCAL  abColor_XLate[DB_MAX_CLR_TBL]:BYTE ;the largest color table size (in bytes)

        DebugMsg <DrawBits SEL WINBITS.ASM>
        push    ebx
        push    edi
        push    esi

        ddc?    hddc
        cld

;/*
;** Enter the driver to obtain the exclusive use of ddc
;*/

db_enter_driver::
        mov     esi,hddc                          ; DS:SI => ddc
        mov     edx,esi

;/*
;** DX:AX=0 if error
;*/

        ENTER_DRIVER2

        jc      db_exit_no_lock                     ; non-available ddc


;/*
;**
;** Validation of passed parameters:
;**
;** pbmi      -   must have cbFix field equal the size of BITMAPINFOHEADER
;**               or a legal value for BITMAPINFOHEADER2 (determined by table
;**               in bmi2.inc)
;**               with cPlane = 1, and cBitCount = 1,4,8,or 24
;** lCount    -   must be 4
;** flOptions -   must be BBO_OR, BBO_AND, or BBO_IGNORE
;**
;*/

db_validate_bmi::
        mov     ebx,pbmi
                                                    ; if a null header,
        or      ebx,ebx                             ; need no checking
        jz      db_validate_flOptions
        mov     ecx,1                               ; check all fields
        INVOKE  check_bitmap_info
        jecxz   db_error_inv_table                  ; CX=0 if not valid


db_validate_flOptions::
        cmp     WORD PTR flOptions[2],0
        jnz     db_error_bitblt_style
        .errnz  BBO_OR-0
        .errnz  BBO_AND-1
        .errnz  BBO_IGNORE-2

;            Start
;       cmp     WORD PTR flOptions[0],BBO_IGNORE
;       ja      db_error_bitblt_style
        mov     ax,WORD PTR flOptions[0]
        and     ax,NOT(BBO_OR+BBO_AND+BBO_IGNORE+BBO_PAL_COLORS)
        jnz     db_error_bitblt_style
;            End

db_validate_lcount::
        .errnz  NUMBER_OF_POINTS-4
        cmp     lCount,NUMBER_OF_POINTS
        je      db_copy_local

;/*
;**
;** Errors in parameters list:
;** PMERR_INV_LENGTH_OR_COUNT or PMERR_INV_INFO_TABLE
;**
;*/

db_error_length_or_count::
        mov     eax,PMERR_INV_LENGTH_OR_COUNT
        jmp     db_log_error
ALIGN 4

db_error_bitblt_style::
        mov     eax,PMERR_INV_BITBLT_STYLE
        jmp     db_log_error
ALIGN 4

db_error_inv_table::
        mov     eax,PMERR_INV_INFO_TABLE
        jmp     db_log_error
ALIGN 4

;/*
;**
;** Copy the rectangles information because we are going to change them
;**
;*/

db_copy_local::
        mov     esi,aptlPoints                       ; DS:SI => aptlPoints[0]
        lea     edi,aptlLocal                        ; ES:DI => aptlLocal[0]

        .errnz  (NUMBER_OF_POINTS*(SIZE POINTL)/4) and 3
        mov     ecx,NUMBER_OF_POINTS*(SIZE POINTL)/4
        rep     movsd

;/*
;** Driver's Drawbits will handle a bitmap if:
;**   1) The bitmap is in the uncompressed format,
;**   2) The bitmap is in the compressed format with BCA_RLE4 or BCA_RLE8
;**       schemes,
;**   3) The bitmap will not be stretched; this is checked by the world co-
;**       ordinate unit of ddc to be in pels unit, ie., its ddc_fb field
;**       must be set with the DDC_UNIT_XFORM flag, and
;**   4) If it is monochrome, it must not cross a segment boundary, or
;**       If it is color, the destination must be the screen with ROP_SRCCOPY.
;** All other types will be passed back to the engine simulation.
;*/

        mov     esi,hddc                            ; DS:SI => ddc
        test    [esi].ddc_fb,DDC_UNIT_XFORM          ; Current unit must be pels
        jz      db_leave_driver                     ; Pass to engine

db_validate_rectl::

        lea     edi,aptlLocal                      ; ES:DI => aptlLocal[0]
        INVOKE  validate_rectl                     ; is rectangle valid?
        jc     db_leave_driver                     ; i.e., coordinates are
                                                   ; 1st point = (Left,Bottom)
                                                   ; 2nd point = (Right,Top)

;/*
;** It is a stretched drawing if the sizes source and destination drawing
;** area do not match.
;*/

db_match_rect_size::

        mov     edx,edi

         ASSUME  EDX:PTR BITBLTPARAMETERS


        inc     [edx].bbp_rclTarg.RECTL.rcl_xRight     ; Make the target become
        inc     [edx].bbp_rclTarg.RECTL.rcl_yTop       ; an exclusive rectangle

        mov     eax,[edx].bbp_rclTarg.RECTL.rcl_xRight
        sub     eax,[edx].bbp_rclTarg.RECTL.rcl_xLeft
        sub     eax,[edx].bbp_rclSrc.RECTL.rcl_xRight
        add     eax,[edx].bbp_rclSrc.RECTL.rcl_xLeft
        jnz     db_leave_driver

        mov     eax,[edx].bbp_rclTarg.RECTL.rcl_yTop
        sub     eax,[edx].bbp_rclTarg.RECTL.rcl_yBottom
        sub     eax,[edx].bbp_rclSrc.RECTL.rcl_yTop
        add     eax,[edx].bbp_rclSrc.RECTL.rcl_yBottom
        jnz     db_leave_driver

        ASSUME  EDX:NOTHING


;/*
;** We now want to get the bitmap information from the bitmap info structure
;** and cache them in the local parameter, if the bitmap is not null.
;*/

db_check_header::
        mov     ebx,pbmi                             ; ES:BX => bmi
                                       ; if a null header, we then
        or      ebx,ebx                               ; have to check if it is a
        jz      db_check_null_bits                  ; NULL bits

        ASSUME  EBX:PTR BITMAPINFOHEADER

        movzx   eax,[ebx].bmp_cx                  ; assume an old header
        movzx   ecx,[ebx].bmp_cy
        movzx   edx,[ebx].bmp_cBitCount

        ASSUME  EBX:PTR BITMAPINFOHEADER2

        cmp     [ebx].bmp2_cbFix,BITMAPINFO.bmi_argbColor
        je      db_have_info

        .erre   ((SIZE BITMAPINFOHEADER2) GT (SIZE BITMAPINFOHEADER))
        .errnz  (SIZE BITMAPINFOHEADER)-BITMAPINFO.bmi_argbColor

ifdef FIREWALLS
        mov     esi,[ebx].bmp2_cbFix
        assert  esi,LE,64
        .errnz  (SIZE BITMAPINFOHEADER2)-64
        shr     esi,1
        assert  NC
        add     esi,OFFSET ok_cbFix
        movzx   esi,BYTE PTR [esi]
        assert  esi,NE,0
        assert  WORD PTR [ebx].bmp2_cbFix[2],E,0
endif;  FIREWALLS

        mov     eax,[ebx].bmp2_cx                 ; it is a new header
        mov     ecx,[ebx].bmp2_cy
        movzx   edx,[ebx].bmp2_cBitCount

ifdef   FIREWALLS
        assert  WORD PTR [ebx].bmp2_cx[2],E,0
        assert  WORD PTR [ebx].bmp2_cy[2],E,0
        cmp     [ebx].bmp2_cbFix,BITMAPINFO.bmi_argbColor    ; repeat to regain the flag
endif;  FIREWALLS

db_have_info::
        mov     DeltaX,eax                               ; cache these information
        mov     DeltaY,ecx                               ; so we do not have to check
        mov     cBitCount,edx                        ; the info type again

;/*
;** Now we check the bitmap compression format. For the old header, the bitmap
;** must always be in an uncompressed format. (The flag from the bitmap info
;** type checking above is still valid.) For the new header,
;** the bitmap is in a compressed form if it has the ulCompression and cbImage
;** fields with ulCompression set to other scheme than BCA_UNCOMP.
;*/

db_check_compression::
        je      db_uncomp_bm                  ;old header's always uncomp
        cmp     [ebx].bmp2_cbFix,BITMAPINFOHEADER2.bmp2_cxResolution
        jb      db_uncomp_bm

;/*
;** The driver handle only 3 types of compression schemes:
;**   a) Uncompressed for all bpp
;**   b) BCA_RLE8 if ROP = SRC_COPY and destination is screen
;**   c) BCA_RLE4 if ROP = SRC_COPY and destination is screen
;** The rest, we will just pass it back to engine.
;*/

        assert  WORD PTR [ebx].bmp2_ulCompression[2],E,0
        mov     eax,[ebx].bmp2_ulCompression    ;get the compression scheme
        cmp     eax,BCA_RLE8
        je      db_screen_test
        cmp     eax,BCA_RLE4
        je      db_screen_test
        cmp     eax,BCA_UNCOMP
        jne     db_leave_driver

db_uncomp_bm::
        cmp     edx,1                               ;check if it is monochrome
        jne     db_screen_test

;/*
;** The monochrome bitmap does not cross a segment boundary if the sum of its
;** size--Bytes per Scan times Height--and the offset of the starting bit
;** is smaller than 64K.
;*/

db_check_dimension::
        mov     eax,DeltaX
        cmp     eax,MAX_BITMAP_DIMENSION
        ja      db_error_inv_dimension
        cmp     ecx,MAX_BITMAP_DIMENSION
        ja      db_error_inv_dimension

        add     eax,31                               ; Add by 32-1 (bits)
        shr     eax,5                                ; Divided by 32 (bits)
        shl     eax,2                                ; Times 4 (bytes/dword)
        mul     ecx
        mov     ecx,pBits
        add     eax,ecx                              ; size+offset
        and     eax,0ffff0000h                 ; Cross Boundary?
        jz      db_fake_bm                     ; NO
                                               ; YES
;/*
;** The destination must be SCREEN and the ROP must be SRCCOPY.
;*/

db_screen_test::
        cmp     lRop,ROP_SRCCOPY
        jne     db_leave_driver

        mov     esi,hddc
        test    [esi].ddc_fb,DDC_DEVICE
        jz      db_leave_driver


;/*
;** we will have a screen draw
;*/

        or      WORD PTR flOptions[2],BLTMODE_SCR_DRAW shr 16

        jmp     db_fake_bm
ALIGN 4

;/*
;**
;** Pass everything back to engine
;**
;*/

db_leave_driver::

        INVOKE  leave_driver

        pop     esi
        pop     edi
        pop     ebx
        mov     esp,ebp
        pop     ebp
        jmp     pfnDefDrawBits                      ;Pass it back to the engine
ALIGN 4

;/*
;**
;** Check a null bits
;**
;*/

db_check_null_bits::

        mov     eax,pBits
        or      eax,eax                             ;if a non-null bits, we say
        jnz     db_error_inv_table                  ;it's an invalid header

        xor     ecx,ecx                               ;CX:SI = source hbm
        xor     esi,esi
        jmp     db_call_bitblt                      ;when we call BitBlt
ALIGN 4

;/*
;**
;** Error handling zone
;**
;*/

db_error_no_bm::
        and     WORD PTR flOptions[2],NOT(BLTMODE_SCR_DRAW shr 16)
        mov     eax,PMERR_INSUFFICIENT_MEMORY
        jmp     db_log_error
ALIGN 4

db_error_inv_dimension::
        mov     eax,PMERR_INV_BITMAP_DIMENSION
        jmp     db_log_error
ALIGN 4

;/*
;**
;** Fake a device bitmap by allocating a new header with a null bitmap,
;** storing the standard format bitmap as its bitmap, and modifying the
;** header fields with the information from pbmi
;**
;*/

db_fake_bm::

        INVOKE  alloc_bm
        jecxz   db_error_no_bm                      ; Cannot allocate a bm
        mov     esi,eax                             ; DS:SI => bitmap


        or      WORD PTR flOptions[2],BLTMODE_SRC_HDBM shr 16; we will have source bitmap


        mov     ecx,HDBM_IDENT                       ; CX:SI = source bitmap

;/*
;**
;** Non-bitmap-related information
;**
;*/

db_correct_Info::

        ASSUME  ESI:PBITMAP

        mov     [esi].bm_sd.sd_usId,SURFACE_IDENT
        mov     [esi].bm_sd.sd_npsd,esi
        xor     edx,edx                               ; handy zero
        mov     [esi].bm_sd.sd_fbAccel,dl         ; Irrelavant fields are zero
        mov     [esi].bm_sd.sd_dScan,edx
        mov     [esi].bm_sd.sd_cbFill,edx
        mov     [esi].bm_sd.sd_selIncr,edx
        mov     [esi].bm_sd.sd_fb,dl              ; Changed if NONNULL later
        mov     [esi].bm_cSelect,edx
        mov     [esi].bm_hddc,INVALID_ADDRESS

;/*
;** Bitmap-related information
;*/

        mov     eax,pBits
        mov     [esi].bm_sd.sd_pBits,eax
        mov     eax,DeltaX                          ;EAX=DeltaX
        mov     ecx,DeltaY
        mov     [esi].bm_sd.sd_cx,eax
        mul     cBitCount                       ;EDX:EAX=EAX*BPP
        add     eax,31                          ;Add by 32-1 (bits)
        shr     eax,5                           ;Divided by 32 (bits)
                                                ; for DWORD alignment
        assert  eax,L,80000h
        shl     eax,2                           ;*(4 bytes/dword) = #BYTES
        mov     [esi].bm_sd.sd_cbScan,eax       ; 
        mov     [esi].bm_sd.sd_cy,ecx           ;ECX=DeltaY
        mov     [esi].bm_sd.sd_cySeg,ecx        ;#scanlines that fit in 64K
        or      ecx,eax                         ; cx or cy must not be 0
        jz      db_call_bitblt                  ; for NONNULL bitmap
        mov     [esi].bm_sd.sd_fb,SD_NONNULL

;/*
;** If we are drawing to the screen, we need more information on bitmap
;** and its color table in the low-level drawing routine. So we'd better
;** prepare them now.
;*/

db_color_info::


        test    flOptions,BLTMODE_SCR_DRAW          ; are we drawing to the screen
        jz      db_call_bitblt                      ; no, no color info needed


        mov     eax,pbmi                            ; Pass the ptr to bitmap info
        mov     [esi].bm_sd.sd_pbmi,eax
        cmp     cBitCount,24

        je      db_call_bitblt

        mov     ebx,pbmi
        mov     eax,[ebx].bmp2_cbFix
        mov     edx,sizeof RGB                      ; assume the old header
        mov     ecx,cBitCount                       ; assume full rgb table
        cmp     eax,sizeof BITMAPINFOHEADER
        je      db_full_rgb_tab
        mov     edx,sizeof RGB2                        ; its a new header
        cmp     eax,BITMAPINFOHEADER2.bmp2_cclrUsed
        jbe     db_full_rgb_tab
        mov     eax,[ebx].bmp2_cclrUsed
        or      eax,eax                               ; if 0, full size table
        jnz     db_have_color_count

db_full_rgb_tab::
        mov     eax,1
        shl     eax,cl                               ; AX = 2^cBitCount

db_have_color_count::
        mov     cClrUsed,eax
        mov     cbRGB,edx


;/*
;**
;** We are here if we do not have any palette mapping table yet because:
;**   a) The bitmapinfo structure is old so we never support palette for them,
;**   b) It is a new structure but the bitmap is either 1 or 24 bpp,
;**   c) We tried to get the palette mapping table but failed.
;** So the best we can do right now is to use the physical color.
;**
;*/

db_physical_color::
        mov     ecx,cClrUsed
        lea     edi,abColor_XLate
                             ; ES:DI => local physical color table
                             ; save it
        mov     ebx,hddc                                ;          
        test    flOptions,BBO_PAL_COLORS                ;          
        jnz     @f                                      ;          
        test    [ebx].DDC.ddc_fbClrTbl,DDC_PALETTE      ;          
        jz      need_color_info                         ;          
@@:                                                     ;          
        mov     eax,edi                                 ;          
        jmp     db_have_color_table                     ;          
need_color_info:                                        ;          
        mov     ebx,pbmi

        ASSUME  EBX:NOTHING

        add     ebx,[ebx].BITMAPINFOHEADER2.bmp2_cbFix
        ; EBX => RGB color table

db_xlate_next_color::
        mov     ax,WORD PTR [ebx][0]    ; get blue and green
        mov     dl,BYTE PTR [ebx][2]    ; get red
        add     ebx,cbRGB               ; point to next triplet
        INVOKE  rgb_to_ipc              ; AL = physical color for RGB

        stosb                           ; save the translated color
        loop    db_xlate_next_color     ; do the next color
                                        ; restore it
        lea     eax,abColor_XLate       ; use it as the color mapping table

db_have_color_table::
        mov     [esi].bm_sd.sd_cySeg,eax          ; Store the pointer to the

;/*
;** It's about time to call BitBlt. Note that although we might be drawing
;** directly to the screen (BLTMODE_SCR_DRAW flag is set), we will have to
;** process the destination rectangle. This is perfectly done by the
;** high-level BitBlt code. The low-level DrawBits routine will be called
;** after we have each drawing area nicely clipped by enumerate_clip_rect.
;*/

db_call_bitblt::
        lea     edi,aptlLocal                        ; EDI => aptlLocal[0]
        mov     ebx,FunN
        mov     bx,NGreBitblt   ; this puts number in low word of EBX

        INVOKE  Bitblt,
                hdc,
                esi,            ;MyBM,
                lCount,
                edi,            ;Mybbp,
                lRop,
                flOptions,
                0,              ;Mybba,
                hddc,
                ebx             ;MyFunN

db_free_bm::
        or      esi,esi
        jz      db_done                 ;if a null bitmap, don't free it

        push    edx                      ;return value in DX:AX is destroyed
        push    eax
        INVOKE  free_bm
        pop     eax                      ;restore the return value
        pop     edx
        jmp     db_done
ALIGN 4

db_log_error::
        save_error_code
        xor     eax,eax         ; exit with EAX=0
db_done::

        INVOKE    leave_driver

db_exit_no_lock::
        pop     esi
        pop     edi
        pop     ebx
        ret
DrawBits ENDP

page
_CODE   ENDS
_TUNE   SEGMENT DWORD FLAT PUBLIC 'CODE'

;/***************************************************************************
;*
;* FUNCTION NAME = Bitblt
;*
;* DESCRIPTION   =
;*           A rectangle of bitmap data is processed according to the passed
;*           arguments.  The type of operations that are supported by the
;*           driver include the manipulation of the region on the destination,
;*           the manipulation of either a source or the fill attributes with
;*           the destination, or the manipulation of both a source and the
;*           fill attributes with the destination.  The specification of a
;*           raster operation controls how these are combined.
;*
;*           Both source and destination may refer to the same DC.  If this is
;*           the case, the copy will be non-destructive if the source and target
;*           rectangles overlap.
;*
;*           The DCs may be either memory DCs for this device (with a selected
;*           bitmap) or DCs for the physical device itself.  Since the Engine
;*           dispatches on the destination, the source DC (if present, which
;*           can be determined from the ROP), must be validated to make sure
;*           it belongs to this driver.
;*
;*           The current brush foreground and background bitmap colors of the
;*           target DC are used.
;*
;*           If any of the source data is not available, no error code is
;*           returned and the operation proceeds by reading what is there.
;*
;*           Only normal BLTs are supported. Stretch/compress BLT is passed
;*           to the default handler.
;*
;*           Input clipping to the extents of the bitmap or device must be
;*           performed to prevent addressing exceptions.
;*
;*           Registers Preserved:
;*                 SI,DI,DS,BP
;*           Registers Destroyed:
;*                 AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 1 if successful and no correlation
;*                 DX:AX = 2 if successful and correlation
;* RETURN-ERROR  = DX:AX = 0
;*
;**************************************************************************/

ALIGN 4
Bitblt PROC SYSCALL,
        hdc             :DWORD,
        hdcSrc          :DWORD,
        Count           :DWORD,
        lpBitBltParm    :DWORD,
        Mix             :DWORD,
        Style           :DWORD,
        lpAttrs         :DWORD,
        hddc            :DWORD,
        FunN            :DWORD

        LOCAL   fbBitblt:BYTE            ;Flags as listed above
        LOCAL   npddcSrc:DWORD           ;Source ddc if given and a ddc
        LOCAL   npfnOverflowRestart:DWORD ;Dc origin restart address
        LOCAL   ulGDIret:DWORD           ;GetDriverInfo return code
        LOCAL   obbaBBlt:OBB_ARGS        ;OEM bitblt parameter structure
        LOCAL   rclDst:RECTL            ;Dest bounding rectangle, clipped
        LOCAL   rclCorr:RECTL           ;Dest bounding rectangle, unclipped
        LOCAL   stbParm:STBLT           ;StretchBlt information

        push    ebx
        push    esi
        push    edi


        ddc?    hddc                    ;Make sure this is a ddc
        cld
        mov     esi,hddc                ;DS:SI --> ddc

        mov     ulGDIret,-1             ;Assume error return
        mov     eax,hdcSrc              ; EAX = hdcSrc
        shld    edx,eax,16              ; EDX <= (HI16)EAX
        or      eax,eax
        jz      bb_no_source_dc

        mov     edi,Style

        test    edi,BLTMODE_SRC_HDBM          ; If the source is HDBM
        jnz     bb_source_hdbm                ; Yes, no check


        and     edi,BLTMODE_SRC_BITMAP
        .errnz  (BLTMODE_SRC_BITMAP shr 16) - DI_HBITMAP
        .errnz  DI_HDC

        shr     edi,16

        INVOKE  GetDriverInfo,
                hdcSrc,                ;MySrcDC,
                edi,                   ;MyIndex,
                hdc


        mov     ulGDIret,eax            ;Save return code for later
        cmp     eax,GPI_ALTERROR
        jz      bb_no_source_dc         ;Source dc/bitmap does not exist
        or      edi,edi
        jnz     bb_no_source_dc         ;Source is a bitmap
        .errnz  DI_HDC
        .errnz  DI_HBITMAP-1
        mov     edi,eax                 ;EDI = source hddc
        jmp     bb_double_enter


ALIGN 4
bb_source_hdbm::
        or      Style,BLTMODE_SRC_BITMAP
        mov     eax,hdcSrc            ; We know that source is HDBM
        mov     ulGDIret,eax


bb_no_source_dc::
        mov     edi,esi                 ;Make DI = SI = source hddc
bb_double_enter::
        INVOKE  double_enter_driver     ;SI,DI = hddcs
        jc      bb_exit_no_lock         ;DX:AX = 0 on error

;/*
;** Perform some initial error checking
;*/

        mov     edx,0                   ;Zeros come in handy now and then
        mov     fbBitblt,dl

        mov     edi,FunN                ;Has COM_ flags in it

BLTMODE_VALID_FLAGS = BLTMODE_SRC_BITMAP  or BLTMODE_ATTRS_PRES

BLTMODE_VALID_FLAGS = BLTMODE_VALID_FLAGS or BLTMODE_SRC_HDBM or BLTMODE_SCR_DRAW


BLTMODE_WIN_SRC_COPY    equ     00800000h


BLTMODE_VALID_FLAGS = BLTMODE_VALID_FLAGS or BLTMODE_WIN_SRC_COPY

        mov     ebx,Style
        shr     ebx,16

        test    ebx,not (BLTMODE_VALID_FLAGS shr 16)
        jnz     bb_invalid_style
        test    ebx,((BLTMODE_SCR_DRAW or BLTMODE_WIN_SRC_COPY) shr 16)
        jnz     bb_validate_source
;           begin
        mov     bx,not(BBO_OR or BBO_AND or BBO_IGNORE)
        mov     eax,adDevCapsData[CAPS_ADDITIONAL_GRAPHICS*SIZE_DWORD]
        and     eax,CAPS_PALETTE_MANAGER
        je      @f
        and     bx,not(BBO_NO_COLOR_INFO or BBO_PAL_COLORS)
@@:
        and     bx,WORD PTR Style[0]
        jnz     bb_to_default_handler   ;Catches BBO_TARGWORLD and passes it on
;        cmp     WORD PTR Style[0],BBO_IGNORE
;        ja      bb_to_default_handler   ;Catches BBO_TARGWORLD and passes it on
;        .errnz  BBO_OR-0
;        .errnz  BBO_AND-1
;        .errnz  BBO_IGNORE-2
;           end

        test    edi,COM_PATH or COM_AREA ;This call is invalid in a path or area
        jnz     bb_path_or_area
        test    [esi].DDC.ddc_fb,DDC_PRESENT ;Must have a surface
        jz      bb_no_surface

        mov     eax,Count               ;If more than 4 points, let default
        cmp     eax,2                   ;  handler deal with the call
        jb      bb_error_bad_count
        cmp     eax,4
        jae     bb_to_default_handler

        mov     ebx,Mix
        cmp     ebx,GRAY_ROP
        je      bb_have_gray_rop
        test    ebx,0ffffff00h          ; only low byte should have value
        jz      bb_mix_is_good
        errn$   bb_bad_mix              ;If invalid mix, log an error

;/*
;** Once again, we find ourselves looking for a place to put error
;** handlers.
;*/

bb_bad_mix::
        mov     eax,PMERR_INV_BITBLT_MIX
        jmp     bb_log_error_in_ax

ALIGN 4
bb_invalid_style::
        mov     eax,PMERR_INV_BITBLT_STYLE
        jmp     bb_log_error_in_ax

ALIGN 4
bb_path_or_area::
        mov     eax,PMERR_INV_IN_PATH
        test    edi,COM_PATH
        jnz     bb_log_error_in_ax
        mov     eax,PMERR_INV_IN_AREA
        jmp     bb_log_error_in_ax

ALIGN 4
bb_error_bad_count::
        mov     eax,PMERR_INV_LENGTH_OR_COUNT

bb_log_error_in_ax::
        save_error_code

bb_exit_error_logged::
        mov     eax,0
        jmp     bb_exit_ax

ALIGN 4
bb_invalid_source::
        mov     eax,PMERR_INV_HDC
        test    fbBitblt,BBF_SRC_BITMAP
        jz      bb_log_error_in_ax
        mov     eax,PMERR_INV_HBITMAP
        jmp     bb_log_error_in_ax

ALIGN 4
bb_no_surface::
        mov     eax,PMERR_BITMAP_NOT_SELECTED
        jmp     bb_log_error_in_ax

ALIGN 4
bb_error_selected_bm::
        mov     eax,PMERR_BITMAP_IS_SELECTED
        jmp     bb_log_error_in_ax

;/*
;** The call must be passed to the default handler
;*/

ALIGN 4
bb_to_default_handler::

;/*
;** clear flag in case it is set by Drawbits
;*/

        and     WORD PTR Style[2],NOT ((BLTMODE_SCR_DRAW+BLTMODE_SRC_HDBM) shr 16)


        INVOKE  leave_driver

        pop     edi
        pop     esi                     ;we saved them at the beginning
        pop     ebx

        mov     esp,ebp                 ;clean up the frame
        pop     ebp
        jmp     pfnDefBitblt            ;Pass it back to the engine


;/*
;** This is the gray raster op (oops, I mean mix mode).
;**
;** Switch the encoding so it automatically falls thru to the right place.
;** The special code for the gray rop is at the same place as the special
;** code for DPx.  Bit 8000h will serve to distinguish gray_rop from DPx.
;** This switch has to be done early so that it is really treated like DPx.
;** For example, no source is passed in and the GrayRop low byte implies
;** that there is a source, so this call will get rejected if we don't
;** switch before that is detected.
;*/

ALIGN 4
bb_have_gray_rop::
        mov     fbBitblt,BBF_GRAY_ROP
        mov     ebx,BB_ROP_DPx          ;Driver wants to see this mix mode
        mov     Mix,ebx


;/*
;** Process the mix mode enough to determine if a source is needed.
;** If so, make sure they gave us one, and gave us enough points.
;**
;** This is tested by comparing the rop result bits with source (column A
;** below) vs. those without source (column B).  If the two cases are
;** identical, then the effect of the rop does not depend on the source,
;** so we don't have a source device.  Recall the rop construction from
;** input (pattern, source, target --> result):
;**
;**       P S T | R   A B         mask for A = 0CCh
;**       ------+--------         mask for B =  33h
;**       0 0 0 | x   0 x
;**       0 0 1 | x   0 x
;**       0 1 0 | x   x 0
;**       0 1 1 | x   x 0
;**       1 0 0 | x   0 x
;**       1 0 1 | x   0 x
;**       1 1 0 | x   x 0
;**       1 1 1 | x   x 0
;**
;*/

bb_mix_is_good::
        mov     obbaBBlt.obba_usMix,ebx ;Save mix mode for oem layer
        mov     bh,bl
        and     ebx,0CC33h              ;Isolate src dependent vs independent
        shr     bh,2                    ;Superpose bits for comparison
        cmp     bh,bl                   ;Does rop act differently between cases?
        jz      bb_preprocessed_source  ;  No, only a destination is involved
        cmp     al,3                    ;AX = number of points
        jb      bb_error_bad_count      ;Not enough points

;/*
;** A source is required for this bitblt operation.  Make sure we have
;** one and get it's handle.  If the source is the display and we're
;** dead (screen group switched away, then clear the COM_DRAW bit).
;** We don't worry about this on the destination ddc since the Window
;** Manager will have set the clip region to null.
;**
;**            We really should check the destination ddc too.
;*/

bb_validate_source::
        mov     eax,Style
        shr     eax,16

        and     eax,(BLTMODE_WIN_SRC_COPY or BLTMODE_SRC_BITMAP or BLTMODE_SRC_HDBM) shr 16
        .errnz  (BLTMODE_SRC_BITMAP shr 16) - DI_HBITMAP
        .errnz  DI_HDC
        .errnz  BBF_SRC_BITMAP-DI_HBITMAP
        .errnz  BBF_REVERSE_BMP-(BLTMODE_SRC_HDBM shr 16)
        .errnz  BBF_CMEM_TO_SCR-(BLTMODE_WIN_SRC_COPY shr 16)
        or      al,BBF_HAVE_SOURCE
        mov     fbBitblt,al
        mov     eax,ulGDIret            ;return code from GetDriverInfo
        cmp     eax,GPI_ALTERROR
        jz      bb_invalid_source
        xchg    eax,edi                 ;DI --> sd_ or ddc_
        xchg    eax,ecx                 ;CX = FunN.hi
        ror     ecx,16                  ;hi:COM_ flags lo:FunN           
        test    fbBitblt,BBF_SRC_BITMAP
        jz      @F

        ASSUME  EDI:NOTHING

        cmp     [edi].BITMAP.bm_cSelect,0       ;The bitmap source must not be selected
        jmp     bb_have_source_surface
ALIGN 4
@@:

        mov     al,[edi].DDC.ddc_fb
        test    al,DDC_PRESENT
        jz      bb_no_surface           ;No surface in ddc, error
        test    al,DDC_DEVICE
        jnz     @F                      ;is a device, could be dead ;          
        test    [esi].DDC.ddc_fb,DDC_DEVICE ; Check destination too ;          
        jz      bb_have_source_surface  ;both bitmaps, cannot be dead
@@:                                                                 ;          
        cmp     fGrimReaper,WE_BE_DEAD  ;If we're dead, then clear the
        jne     bb_have_source_surface  ;  COM_DRAW flag
        and     cl,not COM_DRAW SHR 16
        .errnz  high COM_DRAW

bb_have_source_surface::
        mov     npddcSrc,edi            ;Source ddc or bitmap pointer

        ASSUME  EDI:NOTHING

        mov     edi,[edi].DDC.ddc_npsd  ;DS:DI --> sd_
        .errnz  SURFACE.sd_npsd-DDC.ddc_npsd
        mov     obbaBBlt.obba_psdSrc,edi
        mov     al,[edi].SURFACE.sd_fb          ;If NULL surface, clear COM_DRAW
        mov     ah,al
        or      al,not COM_DRAW SHR 16
        and     cl,al
        .errnz  high COM_DRAW
        .errnz  SD_NONNULL - COM_DRAW SHR 16
        and     ah,SD_COLOR
        or      fbBitblt,ah
        .errnz  BBF_COLOR_SRC-SD_COLOR
        ror     ecx,16                  ;hi:COM_ flags lo:FunN           
        mov     edi,ecx                 ;Put COM_ flags back in DI

;/*
;** We're about to update the COM_ flags.  We may later pass these to the
;** engine if we detect a stretch blt, but this should not be a problem
;** since we know any bit we cleared would be changed at some later point
;*/

bb_preprocessed_source::
        assert  esi,E,hddc

        ASSUME  ESI:PDDC

        mov     al,[esi].ddc_fb         ;Clear COM_DRAW bit if dest invisible
        or      eax,not COM_DRAW SHR 16
        shl     eax,16
        and     edi,eax
        mov     FunN,edi
        .errnz  DDC_VISIBLE - COM_DRAW SHR 16

;/*
;** We do not need to do anything with the color attributes if it is src_copy
;** from color memory to screen. Just skip to get other parameters
;*/

        test    fbBitblt,BBF_CMEM_TO_SCR
        jnz     bb_its_color_mem_to_screen

;/*
;** The source has been validated.  Now validate the system colors
;** and the brush/image data colors of the destination ddc.
;** If we're not drawing then color validation is just a performance
;** hit.  Skip it.  (See PTR's 6747 and SM83838.)
;*/

        test    edi,COM_DRAW
        jz      bb_colors_done

        test    WORD PTR Style[2],BLTMODE_ATTRS_PRES shr 16
        jnz     bb_override_colors

;/*
;** The color attributes in the ddc are to be used.  We try to optimize
;** the path through the following code to only make one jump if nothing
;** needs to be realized.
;*/

        mov     eax,obbaBBlt.obba_usMix
        shl     eax,4
        shl     ah,4
        cmp     al,ah                       ; AL = AH = no pattern involved
        jnz     bb_consider_update_color    ; if not, nedd to realize brush
        mov     al,fbBitblt
        mov     ebx,[esi].ddc_npsd

;/*                                                                      ;76410
;** If mode is RGB_MODE                                                  ;76410
;**   If background mix is BM_SRCTRANSPARENT or BM_DESTTRANSPARENT       ;76410
;**       Convert background color from RGB value to index value.        ;76410
;*/                                                                      ;76410
        test    [esi].DDC.ddc_fbClrTbl,DDC_RGB_MODE                      ;76410
        jz      bb_skip_rgb_to_index                                     ;76410
        cmp     [esi].ddc_pa.pa_ba.ba_bkmix,BM_DESTTRANSPARENT           ;76410
        jz      bb_rgb_to_index                                          ;76410
        cmp     [esi].ddc_pa.pa_ba.ba_bkmix,BM_SRCTRANSPARENT            ;76410
        jz      bb_rgb_to_index                                          ;76410
        jmp     bb_skip_rgb_to_index                                     ;76410
bb_rgb_to_index::                                                        ;76410
        LEA     EBX,[ESI].DDC.ddc_pa.pa_ba                               ;76410
        INVOKE  MakeColorsValid                                          ;76410
        js      bb_skip_rgb_to_index                                     ;76410
        mov     word ptr [esi].ddc_pa.pa_ba.ba_clrBack,ax                ;76410
bb_skip_rgb_to_index::                                                   ;76410

        ASSUME  EDI:PSURFACE
        ASSUME  EBX:NOTHING

        mov     ah,[ebx].SURFACE.sd_fb
        and     eax,BBF_COLOR_SRC + (SD_COLOR shl 8)
        .errnz  BBF_COLOR_SRC-SD_COLOR
        xor     al,ah                       ; if it is not a mono <=> color blt
        jz     bb_colors_done              ; need not realize anything

bb_consider_update_color::
        mov     eax,[esi].ddc_iSysClr
        cmp     eax,ddcInit.ddc_iSysClr
        jne     bb_update_dest_sys_colors
        test    [esi].ddc_ia.ia_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV
        jnz     bb_update_dest_image_colors
        test    [esi].ddc_pa.pa_ba.ba_fb,BA_REREALIZE
        jz      bb_dest_colors_valid
        jmp     bb_update_dest_pat_colors
ALIGN 4
bb_update_dest_sys_colors::
        INVOKE  PropagateSysClrChange
bb_update_dest_image_colors::
        lea     ebx,[esi].ddc_ia.ia_ba
        INVOKE  MakeColorsValid
        js      bb_exit_error_logged_relay
        test    [esi].ddc_pa.pa_ba.ba_fb,BA_REREALIZE
        jz      bb_dest_colors_valid
bb_update_dest_pat_colors::
        xor     cl,cl
        INVOKE  MakeBrushValid,
                eax

        or      eax,eax
        jns     bb_dest_colors_valid

bb_exit_error_logged_relay::
        jmp     bb_exit_error_logged

;/*
;** The colors are to be overridden with the passed parameters
;*/

ALIGN 4
bb_override_colors::
        mov     eax,[esi].ddc_iSysClr
        cmp     eax,ddcInit.ddc_iSysClr

        je      @F
        INVOKE  PropagateSysClrChange
@@:
        mov     cl,0FFh                 ;Use the passed colors
        INVOKE  MakeBrushValid,
                lpAttrs

        or      [esi].ddc_pa.pa_ba.ba_fb,BA_REREALIZE or BA_CLR_INVALID or BA_CLR_BACK_INV
        or      eax,eax                 ;Check for error
bb_exit_error_logged_relay_s::
        js      bb_exit_error_logged_relay
        mov     ax,word ptr [esi].ddc_pa.pa_ba.ba_ipc
        mov     word ptr [esi].ddc_ia.ia_ba.ba_ipc,ax
        mov     ax,word ptr [esi].ddc_pa.pa_ba.ba_ipcBack
        mov     word ptr [esi].ddc_ia.ia_ba.ba_ipcBack,ax
        or      [esi].ddc_ia.ia_ba.ba_fb,BA_REREALIZE or BA_CLR_INVALID or BA_CLR_BACK_INV
bb_dest_colors_valid::


;/*
;** Select the correct color for color==>mono conversion.  If the source
;** was a DC, then use the image data background color, else use the
;** destination's image data background color.
;**
;** If we are not going color to mono, we don't even bother stuffing the
;** value into the obba structure.  Same if COM_DRAW is cleared since we
;** won't attempt to draw anything.
;*/

        assert  esi,E,hddc
        assert  edi,E,FunN
        test    WORD PTR Style[2],BLTMODE_SCR_DRAW shr 16
        jnz     bb_have_bgndIPC
        mov     al,fbBitblt
        test    al,BBF_COLOR_SRC        ;Will be 0 when no source is present
        jz      bb_have_bgndIPC
        mov     ebx,[esi].ddc_npsd

        ASSUME  EBX:PSURFACE

        test    [ebx].sd_fb,SD_COLOR
        jnz     bb_have_bgndIPC

;/*
;** We will be going color to mono, and may actually attempt the blt.
;*/

        test    al,BBF_SRC_BITMAP
        jnz     bb_set_bgndIPC          ;Use dest's image background color
        mov     esi,npddcSrc
        mov     eax,[esi].ddc_iSysClr
        cmp     eax,ddcInit.ddc_iSysClr

        jne     bb_update_src_sys_colors
        test    [esi].ddc_ia.ia_ba.ba_fb,BA_REREALIZE
        jz      bb_set_bgndIPC
        jmp     bb_update_src_image_colors
ALIGN 4
bb_update_src_sys_colors::
        INVOKE  PropagateSysClrChange
bb_update_src_image_colors::
        lea     ebx,[esi].ddc_ia.ia_ba
        INVOKE  MakeColorsValid
        js      bb_exit_error_logged_relay_s
bb_set_bgndIPC::
        mov     ax,word ptr [esi].ddc_ia.ia_ba.ba_ipcBack
        mov     obbaBBlt.obba_ipcBkgnd,eax
bb_have_bgndIPC::
bb_colors_done::

;/*
;** The source and colors have been validated.  Validate the incoming
;** points, looking for a stretch blt, invalid points, ....  The DC
;** origin will be added in later.  Special care must be taken with
;** the DC origin to deal with any overflow.
;**
;** We save the destination as a RECTL so we can pass it off to the
;** clipping code for the bounding rectangle.  As we process the DC
;** origin and surface clipping, the .hi portions may become invalid.
;** We will clean this up later.
;**
;** For the source, we only really care about the starting point.  If
;** the fourth point is given, we will use it to detect a stretch blt
;** operation.
;**
;** Any rectangle which is not correctly ordered will be passed to the
;** engine so that they can decide on the correct action to be taken.
;*/

        mov     esi,lpBitBltParm

        .errnz  RECTL.rcl_xLeft
        lodsd                           ; bbp_rclTarg.rcl_xLeft
        movsx   edi,ax                  ; DI = xLeft
        cmp     eax,edi
        jne     bb_inv_coordinate
        mov     rclDst.rcl_xLeft,eax

        .errnz  RECTL.rcl_yBottom-RECTL.rcl_xLeft-4
        lodsd                           ;bbp_rclTarg.rcl_yBottom
        movsx   ebx,ax                  ; BX = yBottom
        cmp     eax,ebx
        jne     bb_inv_coordinate
        mov     rclDst.rcl_yBottom,eax

        .errnz  RECTL.rcl_xRight-RECTL.rcl_yBottom-4
        lodsd                           ;bbp_rclTarg.rcl_xRight
        movsx   ecx,ax                  ; CX = xRight (exclusive)
        cmp     eax,ecx
        jne     bb_inv_coordinate
        mov     rclDst.rcl_xRight,eax
        sub     cx,di
        jle     bb_null_or_inv_rect     ;xLeft >= xRight
        movsx   ecx,cx
        mov     obbaBBlt.obba_cxExt,ecx

        .errnz  RECTL.rcl_yTop-RECTL.rcl_xRight-4
        lodsd                           ;bbp_rclTarg.rcl_yTop
        movsx   ecx,ax                  ; CX = yTop (exclusive)
        cmp     eax,ecx
        jne     bb_inv_coordinate
        mov     rclDst.rcl_yTop,eax
        sub     cx,bx
        jle     bb_null_or_inv_rect     ;yBottom >= yTop
        movsx   ecx,cx
        mov     obbaBBlt.obba_cyExt,ecx

        test    fbBitblt,BBF_HAVE_SOURCE
        jnz     bb_validate_source_coords
        jmp     bb_validate_done

;/*
;** Some more of those famous error handlers
;*/


ALIGN 4
bb_inv_coordinate::
        mov     eax,PMERR_INV_COORDINATE

bb_log_error_in_ax_relay::
        jmp     bb_log_error_in_ax
ALIGN 4

bb_null_or_inv_rect::
        jnz     bb_to_default_handler           ;Invalid RECTL, give to Engine
        errn$   bb_exit_ok

bb_exit_ok::
        mov     eax,1

bb_exit_ax_relay::
        jmp     bb_exit_ax
ALIGN 4


;/*
;** There are source coordinates to be converted.  If there is only one
;** point, we will synthesize the second point.  This will allow us to
;** check to make sure we don't go over 16 bits on the source.
;**
;** If there is a second point, we will check to see if this is a
;** stretch blt operation.  If it is, we'll pass the call off to the
;** default handler.
;*/


bb_validate_source_coords::

        .errnz  BITBLTPARAMETERS.bbp_rclSrc-BITBLTPARAMETERS.bbp_rclTarg-(sizeof RECTL)
        .errnz  RECTL.rcl_xLeft
        lodsd                           ;bbp_rclSrc.rcl_xLeft
        mov     obbaBBlt.obba_xSrc,eax
        movsx   edi,ax                  ;DI = xLeft
        cmp     eax,edi
        jne     bb_inv_coordinate

        .errnz  RECTL.rcl_yBottom-RECTL.rcl_xLeft-4
        lodsd                           ;bbp_rclSrc.rcl_yBottom
        mov     obbaBBlt.obba_ySrc,eax
        movsx   ebx,ax                  ;BX = yBottom
        cmp     eax,ebx
        jne     bb_inv_coordinate

        cmp     Count,4
        jl      bb_synthesize_point

        .errnz  RECTL.rcl_xRight-RECTL.rcl_yBottom-4
        lodsd                           ;bbp_rclSrc.rcl_xRight
        movsx   ecx,ax                  ;CX = xRight (exclusive)
        cmp     eax,ecx
        jne     bb_inv_coordinate
        sub     ecx,edi                 ;CX = extent
        jle     bb_null_or_inv_rect     ;xLeft >= xRight
        sub     ecx,obbaBBlt.obba_cxExt

        .errnz  RECTL.rcl_yTop-RECTL.rcl_xRight-4
        lodsd                           ;bbp_rclTarg.rcl_yTop
        movsx   edx,ax                  ;DX = yTop
        cmp     eax,edx
        jne     bb_inv_coordinate
        sub     edx,ebx
        jle     bb_null_or_inv_rect     ;yBottom >= yTop
        sub     edx,obbaBBlt.obba_cyExt

        or      ecx,edx                 ;non-stretchblt iff CX=DX=0
        jz      bb_validate_done

;/*
;** We are going to handle the stretchblt only if
;**   1) the source is memory
;**   2) the destination is screen
;**   3) ROP is SRCCOPY
;**   4) Style is BBO_IGNORE
;*/

bb_check_stretch::
        cmp     Mix,ROP_SRCCOPY
        jne     bb_to_default_handler
        cmp     WORD PTR Style[0],BBO_IGNORE
        jne     bb_to_default_handler

;/*
;**            Start
;** Check for background mixes of BM_SRCTRANSPARENT or BM_DESTTRANSPARENT.
;** BM_SRCTRANSPARENT will result in pels from the source bitmap matching
;** the presentation space background color NOT to be copied to the
;** destination bitmap. (OVERLAY)
;** BM_DESTTRANSPARENT will result in pels from the source bitmap ONLY
;** being copied to the destination pels that match the presentation space
;** background color. (UNDERLAY)
;** If either is requested, pass the call off to the default handler.
;*/

        ASSUME  esi:PDDC
        mov     esi,hddc
        cmp     [esi].ddc_pa.pa_ba.ba_bkmix,BM_DESTTRANSPARENT
        jnz     @f
        jmp     bb_to_default_handler
@@:
        cmp     [esi].ddc_pa.pa_ba.ba_bkmix,BM_SRCTRANSPARENT
        jnz     @f
        jmp     bb_to_default_handler
@@:

;/*
;**            End
;*/

        mov     esi,obbaBBlt.obba_psdSrc    ;ESI => source surface
        ASSUME  ESI:PSURFACE
        test    [esi].sd_fb,SD_DEVICE
        jnz     bb_to_default_handler

        ASSUME  ESI:PDDC

        mov     esi,hddc
        mov     esi,[esi].ddc_npsd            ;DS:SI => destination surface

        ASSUME  ESI:PSURFACE

        test    [esi].sd_fb,SD_DEVICE
        jz      bb_to_default_handler
        or      fbBitblt,BBF_STRETCHBLT     ;we can handle the stretching
        jmp     bb_validate_done
ALIGN 4

;/*
;** Here we found a perfect (?) place to stuff in the following code.
;** Since we assume that BLTMODE_WIN_SRC_COPY is only set by PMWIN, we
;** have skipped several parameter validations. Now it's time to stuff
;** valid parameters for oem layer.
;*/

ALIGN 4
bb_its_color_mem_to_screen::
        assert  Mix,E,ROP_SRCCOPY
        mov     obbaBBlt.obba_usMix,ROP_SRCCOPY ;it's always source copy
        mov     esi,lpBitBltParm             ;rectangle passed by caller
        lea     edi,rclDst                   ;local copy of destination rect

        ASSUME  ESI:PRECTL

        mov     eax,[esi].rcl_xRight
        sub     eax,[esi].rcl_xLeft
        mov     obbaBBlt.obba_cxExt,eax
        mov     eax,[esi].rcl_yTop
        sub     eax,[esi].rcl_yBottom
        mov     obbaBBlt.obba_cyExt,eax
        mov     ecx,(size RECTL)/4
        rep     movsd

        mov     edi,[esi].rcl_xLeft
        mov     obbaBBlt.obba_xSrc,edi
        mov     ebx,[esi].rcl_yBottom
        mov     obbaBBlt.obba_ySrc,ebx
        jmp     bb_validate_done
ALIGN 4

;/*
;** A couple of vectors thrown in where they'll fit
;*/

bb_exit_ok_relay_again::
        mov     eax,1
bb_exit_ax_relay_again::
        jmp     bb_exit_ax
ALIGN 4

;/*
;** Back to what we were doing a minute ago....
;**
;** There were only three points.  Synthesize the fourth and validate it
;*/

bb_synthesize_point::
        mov     eax,obbaBBlt.obba_cxExt
        add     eax,edi                 ;EDI = src xLeft
        movsx   ecx,ax
        cmp     ecx,eax
bb_inv_coordinate_relay_ne::
        jne     bb_inv_coordinate

        mov     eax,obbaBBlt.obba_cyExt
        add     eax,ebx                 ;EBX = src yBottom
        movsx   ecx,ax
        cmp     ecx,eax
        jne     bb_inv_coordinate_relay_ne
bb_validate_done::

;/*
;** Hey, coordinates have been validated!  Bounds is performed on
;** unclipped primitives, so perform it now before we start to adjust
;** the rclDst rectangle and screwing around with DC origins.
;**
;** If the transform bit isn't set, then the rectangle we just computed
;** is in screen coordinates and we'll have to use the alternate bounds
;** accumulation routine.
;*/


        ASSUME  ESI:PDDC

        mov     esi,hddc
        mov     edi,FunN

        test    edi,COM_BOUND  + COM_ALT_BOUND
        jz      bb_done_bounds          ;No bounds needed
        mov     eax,rclDst.rcl_xLeft
        mov     ebx,rclDst.rcl_yBottom
        mov     ecx,rclDst.rcl_xRight
        mov     edx,rclDst.rcl_yTop
        dec     ecx                     ;Bounds is inclusive
        dec     edx
ifdef DCAF                                                           ;          
;/*                                                                  ;          
;** Since the real drawing is performed under the control of         ;          
;** enumerate_clip_rects, SCREEN bounds will be accumulated          ;          
;** there (after clipping).  Thus we don't want to accumulate the    ;          
;** unclipped bounds here, so turn off the COM_SCR_BOUND bit.        ;          
;*/                                                                  ;          
        and     edi, not COM_SCR_BOUND                               ;          
endif ; DCAF                                                         ;          
        test    edi,COM_TRANSFORM
        jnz     bb_rectl_in_dev_coords
        INVOKE  InnerAccumulateBounds
        jmp     bb_check_bounds_ret_code
ALIGN 4
bb_rectl_in_dev_coords::
        INVOKE  AccumBoundsInDevCoords
bb_check_bounds_ret_code::
        or      eax,eax
        jz      bb_exit_ax_relay_again
bb_done_bounds::


;/*
;** Quick out.  If the destination is invisible, then we don't need to
;** proceed any futher.  We won't be drawing anything, and we won't be
;** doing correlation since correlation is performed on clipped primitives
;*/

        assert  esi,E,hddc
ifdef DCAF                                                           ;          
;/*                                                                  ;          
;** The assert that was here needs dropping because we have          ;          
;** zero'd the COM_SCR_BOUND bit above, so it is possible            ;          
;** that the assert will fail without this being an error.           ;          
;*/                                                                  ;          
else  ; DCAF                                                         ;          
        assert  edi,E,FunN
endif ; DCAF                                                         ;          


        ASSUME  ESI:PDDC

        cmp     [esi].ddc_crcsClip,0
        je      bb_exit_ok_relay_again
        test    edi,COM_DRAW or COM_CORRELATE
        jz      bb_exit_ok_relay_again


;/*
;** We must take any DC origin into account before we clip the source
;** and/or destination.
;**
;** We will adjust the extents of the blt if the rhs or top gets clipped,
;** and will adjust the starting coordinate and extents if the lhs or
;** bottom gets clipped.
;**
;** The extent is kept as an unsigned int.  If the DC origin moves us
;** left/down, then we know that the rhs/top cannot overflow.  We can
;** actually skip adding in the DC origin to check the top/rhs in this
;** case.
;*/

        mov     ecx,0                   ;Another handy zero
        mov     stbParm.stb_xSrcDel,ecx ;assume origin is not transformed
        mov     stbParm.stb_ySrcDel,ecx
        mov     stbParm.stb_xDstDel,ecx
        mov     stbParm.stb_yDstDel,ecx
        assert  obbaBBlt.obba_cxExt,A,ecx
        assert  obbaBBlt.obba_cyExt,A,ecx
        test    edi,COM_TRANSFORM       ;Clear 'Z' if in screen coordinates

        mov     esi,obbaBBlt.obba_cxExt
        mov     edi,obbaBBlt.obba_cyExt
        jz      bb_origins_done
        mov     bl,fbBitblt
        xor     bl,BBF_HAVE_SOURCE
        test    bl,BBF_HAVE_SOURCE or BBF_SRC_BITMAP or BBF_CMEM_TO_SCR
        jnz     bb_src_dc_origin_done
        mov     ebx,npddcSrc

        ASSUME  EBX:NOTHING

        ddc?    ebx
        mov     ebx,[ebx].DDC.ddc_prddc ; ES:BX = RDDC
        rddc?   ebx

        mov     npfnOverflowRestart,OFFSET bb_dc_org_src_lhs_restart
bb_dc_org_src_lhs_restart::
        mov     eax,obbaBBlt.obba_xSrc
        mov     edx,eax                 ;remember the original value
        mov     ecx,[ebx].RDDC.rddc_ptsOrg.ptl_x
        add     ax,cx
        movsx   eax,ax
        jo      bb_dc_org_lhs_ov_relay  ;lhs overflow or underflow

        mov     obbaBBlt.obba_xSrc,eax
        sub     stbParm.stb_xSrcDel,edx
        add     stbParm.stb_xSrcDel,eax ;the x-source transform value

        mov     npfnOverflowRestart,OFFSET bb_dc_org_src_rhs_restart
        or      ecx,ecx
        js      bb_dc_org_src_rhs_restart; rhs overflow impossible if negative
        add     ax,si                   ;Compute rhs
        movsx   eax,ax
        jo      bb_dc_org_rhs_ov        ;rhs overflowed (cannot underflow)
bb_dc_org_src_rhs_restart::

        mov     npfnOverflowRestart,OFFSET bb_dc_org_src_bot_restart
bb_dc_org_src_bot_restart::
        rddc?   ebx
        mov     eax,obbaBBlt.obba_ySrc
        mov     edx,eax                 ;remember the original value
        mov     ecx,[ebx].RDDC.rddc_ptsOrg.ptl_y
        add     ax,cx
        movsx   eax,ax
        jo      bb_dc_org_bottom_ov_relay ;Bottom overflow or underflow

        mov     obbaBBlt.obba_ySrc,eax
        sub     stbParm.stb_ySrcDel,edx
        add     stbParm.stb_ySrcDel,eax ;the y-source transform value
        mov     npfnOverflowRestart,OFFSET bb_src_dc_origin_done
        or      ecx,ecx
        js      bb_src_dc_origin_done
        add     ax,di                   ;Compute top
        movsx   eax,ax
        jo      bb_dc_org_top_ov        ;Top overflowed

bb_src_dc_origin_done::
        mov     ebx,hddc
        mov     ebx,[ebx].DDC.ddc_prddc
        rddc?   ebx

        mov     npfnOverflowRestart,OFFSET bb_dc_org_dest_lhs_restart
bb_dc_org_dest_lhs_restart::
        mov     eax,rclDst.rcl_xLeft
        mov     edx,eax                 ;remember the original value
        mov     ecx,[ebx].RDDC.rddc_ptsOrg.ptl_x
        add     ax,cx
        movsx   eax,ax
bb_dc_org_lhs_ov_relay::
        jo      bb_dc_org_lhs_ov

        mov     rclDst.rcl_xLeft,eax
        sub     stbParm.stb_xDstDel,edx
        add     stbParm.stb_xDstDel,eax ;the x-destination transform value
        mov     npfnOverflowRestart,OFFSET bb_dc_org_dest_rhs_restart
        or      ecx,ecx
        jz      bb_dc_org_dest_rhs_restart
        add     ax,si
        movsx   eax,ax
        jo      bb_dc_org_rhs_ov
bb_dc_org_dest_rhs_restart::

        mov     npfnOverflowRestart,OFFSET bb_dc_org_dest_bot_restart
bb_dc_org_dest_bot_restart::
        rddc?   ebx
        mov     eax,rclDst.rcl_yBottom
        mov     edx,eax                 ;remember the original value
        mov     ecx,[ebx].RDDC.rddc_ptsOrg.ptl_y
        add     ax,cx
        movsx   eax,ax
bb_dc_org_bottom_ov_relay::
        jo      bb_dc_org_bottom_ov

        mov     rclDst.rcl_yBottom,eax
        sub     stbParm.stb_yDstDel,edx
        add     stbParm.stb_yDstDel,eax ;the y-destination transform value
        mov     npfnOverflowRestart,OFFSET bb_origins_done
        add     ax,di
        movsx   eax,ax
        jno     bb_origins_done

;/*
;** We'll slip the overflow handlers in here
;*/

bb_dc_org_top_ov::
        AND     EAX,0000ffffh           ;SEL 1-24-92
        sub     eax,MAXSHORT            ;AX = amount of overflow on top
bb_adjust_y_ext::
        sub     edi,eax                 ;Update y extent
        jbe     bb_exit_ok_relay        ;Nothing shows anymore
        xor     eax,eax
        jmp     npfnOverflowRestart
ALIGN 4

bb_dc_org_rhs_ov::
        AND     EAX,0000ffffh           ;SEL 1-24-92
        sub     eax,MAXSHORT            ;AX = amount of overflow on rhs
bb_adjust_x_ext::
        sub     esi,eax                 ;Update x extent
        jbe     bb_exit_ok_relay        ;Nothing shows anymore
        jmp     npfnOverflowRestart
ALIGN 4

bb_dc_org_lhs_ov::
        js      bb_exit_ok_relay        ;If overflow, we're done with the blt
        mov     ebx,MINSHORT            ;8000h SEL 1-24-92
        sub     ebx,eax
        xchg    eax,ebx                 ;BX = amount to move start to the
bb_adjust_lhs::                         ;  right and to adjust extents by
        add     obbaBBlt.obba_xSrc,eax
        add     rclDst.rcl_xLeft,eax
        sub     esi,eax                 ;Update x extent
        jbe     bb_exit_ok_relay        ;Nothing shows anymore
bb_do_restart::
        xor     eax,eax                 ;New lhs aor bottom is zero
        jmp     npfnOverflowRestart
ALIGN 4

bb_dc_org_bottom_ov::
        js      bb_exit_ok_relay        ;If overflow, we're done with the blt
        mov     ebx,MINSHORT
        sub     ebx,eax
        xchg    eax,ebx
bb_adjust_bottom::
        add     obbaBBlt.obba_ySrc,eax
        add     rclDst.rcl_yBottom,eax
        sub     edi,eax                 ;Update y extent
        jnbe    bb_do_restart
bb_exit_ok_relay::
        jmp     bb_exit_ok
ALIGN 4


;/*
;** HEY! We used to believe that we should do source clipping before
;** correlation, but we now believe different.  Instead of futzing
;** around and trying to shuffle return codes and the such, we will
;** just save the unclipped destination and extent, and get it later
;** if needed.
;*/

bb_origins_done::
        test    FunN,COM_CORRELATE
        jz      bb_no_correlation_to_do
        assert  esi,G,0
        assert  edi,G,0

        mov     eax,rclDst.rcl_xLeft
        mov     rclCorr.rcl_xLeft,eax
        add     eax,esi
        mov     rclCorr.rcl_xRight,eax
        mov     eax,rclDst.rcl_yBottom
        mov     rclCorr.rcl_yBottom,eax
        add     eax,edi
        mov     rclCorr.rcl_yTop,eax

;/*
;** The DC origin has been processed.  Now clip to the extents of the
;** surface.
;** We'll first clip the source.  Once we've clipped the source, we are
;** guaranteed that we will stay within the bounds of the surface when
;** we clip the destination.  If RestoreScreenBits is calling, we won't
;** clip the source.
;**
;** Since we will perform the source clipping here, there is no longer
;** a need to do it in the lower levels of bitblt.
;*/

bb_no_correlation_to_do::
        mov     al,fbBitblt
        xor     al,BBF_HAVE_SOURCE      ;invert this bit
        test    al,BBF_HAVE_SOURCE or BBF_STRETCHBLT or BBF_CMEM_TO_SCR
        jnz     bb_source_clipped
        mov     ebx,hddc

        ASSUME  EBX:PDDC

        test    [ebx].ddc_fb,DDC_SSB_CALL
        jnz     bb_source_clipped
        mov     ebx,obbaBBlt.obba_psdSrc

        ASSUME  EBX:PSURFACE

        mov     eax,obbaBBlt.obba_xSrc
        or      eax,eax
        js      bb_src_clip_lhs
bb_src_lhs_clipped::
        add     eax,esi                 ;AX = rhs

        sub     eax,[ebx].sd_cx         ;AX = amount of overflow
        jg      bb_src_clip_rhs         ;Equal condition just fits
bb_src_rhs_clipped::
        mov     eax,obbaBBlt.obba_ySrc
        or      eax,eax
        js      bb_src_clip_bot
bb_src_bot_clipped::
        add     eax,edi                 ;AX = top
        sub     eax,[ebx].sd_cy         ;AX = amount of overflow
        jg      bb_src_clip_top         ;Equal condition just fits
bb_source_clipped::
        mov     ebx,hddc

        ASSUME  EBX:PDDC

        mov     ebx,[ebx].ddc_npsd

        ASSUME  EBX:PSURFACE

        mov     eax,rclDst.rcl_xLeft
        or      eax,eax
        js      bb_dst_clip_lhs
bb_dst_lhs_clipped::
        add     eax,esi                 ;AX = rhs
        sub     eax,[ebx].sd_cx         ;AX = amount of overflow
        jg      bb_dst_clip_rhs         ;Equal condition just fits
bb_dst_rhs_clipped::
        mov     eax,rclDst.rcl_yBottom
        or      eax,eax
        js      bb_dst_clip_bot
bb_dst_bot_clipped::
        add     eax,edi                 ;AX = top
        sub     eax,[ebx].sd_cy         ;AX = amount of overflow
        jle     bb_clipped_to_surfaces

bb_dst_clip_top::
        mov     npfnOverflowRestart,OFFSET bb_clipped_to_surfaces
        jmp     bb_adjust_y_ext

ALIGN 4
bb_dst_clip_bot::
        mov     npfnOverflowRestart,OFFSET bb_dst_bot_clipped
        neg     eax
        jmp     bb_adjust_bottom

ALIGN 4
bb_dst_clip_lhs::
        mov     npfnOverflowRestart,OFFSET bb_dst_lhs_clipped
        neg     eax
        jmp     bb_adjust_lhs

ALIGN 4
bb_dst_clip_rhs::
        mov     npfnOverflowRestart,OFFSET bb_dst_rhs_clipped
        jmp     bb_adjust_x_ext

ALIGN 4
bb_src_clip_top::
        mov     npfnOverflowRestart,OFFSET bb_source_clipped
        jmp     bb_adjust_y_ext

ALIGN 4
bb_src_clip_bot::
        mov     npfnOverflowRestart,OFFSET bb_src_bot_clipped
        neg     eax
        jmp     bb_adjust_bottom

ALIGN 4
bb_src_clip_lhs::
        mov     npfnOverflowRestart,OFFSET bb_src_lhs_clipped
        neg     eax
        jmp     bb_adjust_lhs

ALIGN 4
bb_src_clip_rhs::
        mov     npfnOverflowRestart,OFFSET bb_src_rhs_clipped
        jmp     bb_adjust_x_ext
ALIGN 4



;/*
;** We're all clipped now.  The destination rectangle is now in the range
;** 0:32767.  We have to compute the actual rhs and top of it, and make
;** sure everything is properly sign extended.
;**
;** Any votes for saving the extents??
;*/

bb_clipped_to_surfaces::
        mov     obbaBBlt.obba_cxExt,esi
        mov     obbaBBlt.obba_cyExt,edi
        assert  esi,G,0                 ;Both extents must be > 0
        assert  edi,G,0

        mov     eax,rclDst.rcl_xLeft
        mov     obbaBBlt.obba_xDst,eax
        add     esi,eax
        mov     rclDst.rcl_xRight,esi
        mov     edx,rclDst.rcl_yBottom
        mov     obbaBBlt.obba_yDst,edx
        add     edi,edx
        mov     rclDst.rcl_yTop,edi
        test    fbBitblt,BBF_STRETCHBLT
        jz      bb_dest_surface
        mov     ebx,lpBitBltParm                ;ptr to the bltting rectangles
        mov     stbParm.stb_lpRectl,ebx
        lea     ebx,stbParm                     ;ptr to stretchblt param
        mov     obbaBBlt.obba_ySrc,ebx          ;override the x/ySrc fields

bb_dest_surface::
        mov     ebx,hddc
        mov     obbaBBlt.obba_pddcDst,ebx

;/*
;** Perform the actual drawing if required.  We need to determine a
;** direction for scaning the clip rectangles.  If the surfaces are
;** disjoint or there isn't a source, we'll enumerate clip rectangles
;** left to right, bottom to top, which is the best way for the region
;** code and will also allow us to use the rectangles cached in our ddc.
;*/

bb_check_draw::
        test    FunN,COM_DRAW
        jz      bb_been_drawn
        mov     ecx,RECTDIR_LFRT_BOTTOP-1 ;Favored direction

        test    Style,BLTMODE_SCR_DRAW
        jnz     bb_enum_parm

        test    fbBitblt,BBF_HAVE_SOURCE
        jz      bb_have_direction
        test    fbBitblt,BBF_STRETCHBLT or BBF_CMEM_TO_SCR
        jnz     bb_have_direction

;/*
;** The bitmap handle may actually be to a bitmap selected into the
;** ddc.  We'll compare surface pointers to see if the same surface.
;*/


        ASSUME  EBX:NOTHING


        mov     esi,[ebx].DDC.ddc_npsd
        cmp     esi,obbaBBlt.obba_psdSrc
        jne     bb_have_direction

;/*
;** The surfaces seem to be the same.  Will have to determine which
;** direction to blt.  Since all coordinates are 0:32767, we can perform
;** unsigned compares and propagate the carry flag around to generate
;** the clipping direction.
;**
;** We want to alter the destination rectangle before we alter the source
;** rectangle.
;*/

BOTTOP  equ     00000010b               ;Enumerate bottom to top
RTLF    equ     00000001b               ;Enumerate right to left
        .errnz  RECTDIR_LFRT_TOPBOT-1
        .errnz  RECTDIR_RTLF_TOPBOT-1 - (RTLF)
        .errnz  RECTDIR_LFRT_BOTTOP-1 - (BOTTOP)
        .errnz  RECTDIR_RTLF_BOTTOP-1 - (RTLF or BOTTOP)

        or      fbBitblt,BBF_SAME_SD
        xor     ecx,ecx
        cmp     edx,obbaBBlt.obba_ySrc  ;'C' if dest is below source
        adc     ecx,ecx
        .errnz  BOTTOP-00000010b
        cmp     obbaBBlt.obba_xSrc,eax  ;'C' if dest is to the right of source
        adc     ecx,ecx
        .errnz  RTLF-00000001b

bb_have_direction::
        mov     eax,0
        mov     al,fbBitblt
        test    Style,BBO_NO_COLOR_INFO ;          
        jz      @F                      ;          
        or      eax,BBF_NO_COLOR_INFO   ;          
@@:     mov     obbaBBlt.obba_fsBlt,eax ;          

;/*
;** The BLTMODE_SCR_DRAW flag was set by the high-level DrawBits function
;** to indicate that it would like to share the above code and the
;** enum_clip_rects function to process the source/target rectangles.
;** Hence, we have to indicate the enum_clip_rects function to correctly
;** dispatch to the low-level DrawBits routine here.
;*/

bb_enum_parm::

        test    Style,BLTMODE_SCR_DRAW    ;          
        jz      @f                        ;          
        mov     eax,Style                 ;          
        mov     obbaBBlt.obba_fsBlt,eax   ;          
@@:                                       ;          

        test    Style,BLTMODE_SCR_DRAW  ;AH = 1 if screen DrawBits
        setnz   ah
        test    fbBitblt,BBF_STRETCHBLT ;AL = 1 if stretchBlt
        setnz   al
        add     al,al                   ;make EAX = 0 if normal bitblt
        or      al,ah                   ;           1 if screen DrawBits
                                        ;           2 if stretchBlt
        movzx   ebx,al
        shl     ebx,2                   ;then make it dword offset

        lea     edi,obbaBBlt
        lea     edx,rclDst


ifdef DCAF                                                           ;          
        ; Store the FunN in a global variable so that                ;          
        ; enumerate_clip_rects can check the COM_SCR_BOUNDS flag.    ;          
        mov     eax,FunN                                             ;          
        mov     ulGlobalCOMFlags,eax                                 ;          
endif ;DCAF                                                          ;          

        INVOKE  enumerate_clip_rects,
                hddc,                   ;hddc
                edx,                    ;destination clipped rectl
                do_function[ebx]        ;low-level function

ifdef DCAF                                                           ;          
        ; Reset the global COM flags so that other (non-DCAF)        ;          
        ; calls to enumerate_clip_rects work OK.                     ;          
        mov     ulGlobalCOMFlags,0                                   ;          
endif ;DCAF                                                          ;          

bb_been_drawn::


;/*
;** Time for correlation
;*/

        test    FunN,COM_CORRELATE
        jz      bb_good_exit            ;No correlation needed
        mov     esi,hddc
        lea     ebx,rclDst

        INVOKE  do_corr,
                hdc,
                ebx,
                hddc


        and     eax,2                   ;Make sure this is correct
        jnz     bb_exit_ax
bb_good_exit::
        mov     eax,1                   ;Good return code

bb_exit_ax::
        INVOKE  leave_driver
bb_exit_no_lock::
        fw_zero <ecx>

        pop     edi
        pop     esi                     ;we saved them at the beginning
        pop     ebx
        ret
Bitblt ENDP

page
_TUNE ends
_CODE   SEGMENT DWORD FLAT PUBLIC 'CODE'

;/***************************************************************************
;*
;* FUNCTION NAME = do_corr
;*
;* DESCRIPTION   = The passed rectangle is intersected with the correlation
;*                 rectangle and checked for visibility if the intersection is
;*                 none-null.
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = DS:SI = hddc
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 2 or 3 if correlation
;*                 DX:AX = 1 if no correlation
;* RETURN-ERROR  = DX:AX = 0 if error
;*
;**************************************************************************/

ALIGN 4
do_corr PROC SYSCALL USES ESI EDI,
        hdc             :DWORD,
        prclToCorr      :DWORD,
        hddc            :DWORD

        ddc?    esi

        ASSUME  ESI:NOTHING

        test    [esi].DDC.ddc_fb,DDC_CORR_INV
        jz      dco_have_corr_rect         ; Have corr rect in ddc
        INVOKE  recalc_correlate_rect      ; Get the corr rect
        jecxz   dco_exit                   ; Null pick window (corr rect)
dco_have_corr_rect::

        mov     esi,[esi].DDC.ddc_prddc
        lea     esi,[esi].RDDC.rddc_rcsCorr.rcl_yTop    ;RECTL Now
        mov     ecx,(sizeof OurRECTS)/4
        .errnz  (sizeof OurRECTS) and 3
        std
dco_make_rcl_loop::
        lodsd
        push    eax
        loop    dco_make_rcl_loop
        cld                             ;Before we forget
        .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

        mov     edi,esp                 ;EDI-> dst_rcl
        mov     esi,prclToCorr          ;ESI-> src_rcl

        mov     ebx,1                   ;Want 0 returned if null intersection
        INVOKE  intersect_rcl
        or      eax,eax
        jz      dco_fix_sp              ;No intersection

        INVOKE  PFNDefRectVisible PTR pfnDefRectVisible,
                hdc,
                edi,
                hddc,
                NGreRectVisible

        assert  eax,BE,3
        .errnz  RVIS_ERROR-0            ;Resurn codes form GreRectVisible
        .errnz  RVIS_INVISIBLE-1
        .errnz  RVIS_PARTIAL-2
        .errnz  RVIS_VISIBLE-3

dco_fix_sp::
        add     esp,sizeof RECTL

dco_exit::
        ret
do_corr ENDP

page

;/***************************************************************************
;*
;* FUNCTION NAME = ImageData
;*
;* DESCRIPTION   = Draws a row of image data on the destination device or
;*                 bitmap. Image data is the equivalent of a monochrome bitmap.
;*                 The image attributes will be used for the drawing.  The
;*                 given row is relative to the current position.
;*                 The drawing will occur only if the DRAW bit in the command
;*                 dword is set.  Bounds detection will occur if the BOUNDS
;*                 bit is set in the control word. If COM_CORRELATE is set in
;*                 the command dword, then correlation will be performed.
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = hdc     :DWORD
;*                 lpData  :DWORD
;*                 N       :DWORD
;*                 Row     :DWORD
;*                 hddc    :DWORD
;*                 FunN    :DWORD
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 1 if successful and no correlation
;*                 DX:AX = 2 if successful and correlation
;* RETURN-ERROR  = DX:AX = 0
;*
;**************************************************************************/

ALIGN 4
ImageData PROC SYSCALL USES EDI ESI EBX,
        hdc     :DWORD,
        lpData  :DWORD,
        N       :DWORD,
        Row     :DWORD,
        hddc    :DWORD,
        FunN    :DWORD

        LOCAL   rclTemp         :RECTL        ;Destination bounding rectangle
        LOCAL   obbaImage       :OBB_ARGS
        LOCAL   sdImage         :SURFACE

        DebugMsg <ImageData SEL WINBITS.ASM>

        ddc?    hddc
        cld
        mov     esi,hddc                ;DS:SI --> ddc

        ASSUME  ESI:PDDC

        mov     edx,esi
        ENTER_DRIVER2
        jc      id_exit_no_lock         ; DX:AX = 0 on error

;/*
;** Perform some initial error checking
;*/

        mov     edi,FunN

        test    edi,COM_PATH or COM_AREA  ;This call is invalid in a path or area
        jnz     id_path_or_area
        test    [esi].ddc_fb,DDC_PRESENT ;Must have a surface
        jz      id_no_surface
        mov     ecx,N
        test    ecx,0ffff8000h
        jnz     id_invalid_image_length ;Length of data must be 0:32767
        cmp     ecx,0
        jz      id_good_exit_relay_again;Width of data is zero, nothing to do
        mov     eax,Row                 ;Row must be properly sign extended
        movsx   edx,ax
        cmp     edx,eax
        jne     id_inv_row

;/*
;** Make sure the image data colors are valid
;*/

        mov     eax,[esi].ddc_iSysClr
        cmp     eax,ddcInit.ddc_iSysClr

        jne     id_update_sys_colors
        test    [esi].ddc_ia.ia_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV
        jz      id_colors_are_valid
        jmp     id_update_colors
ALIGN 4
id_update_sys_colors::
        INVOKE  PropagateSysClrChange
id_update_colors::
        lea     ebx,[esi].ddc_ia.ia_ba
        INVOKE  MakeColorsValid
        jns     id_colors_are_valid
        jmp     id_error_logged_exit
ALIGN 4

;/*
;** More error handlers and vectors.
;*/

id_good_exit_relay_again::
        jmp     id_good_exit
ALIGN 4

id_path_or_area::
        mov     eax,PMERR_INV_IN_PATH
        test    edi,COM_PATH
        jnz     id_log_error_in_ax
        mov     eax,PMERR_INV_IN_AREA
        jmp     id_log_error_in_ax
ALIGN 4

id_inv_row::
        mov     eax,PMERR_INV_SCAN_START
        jmp     id_log_error_in_ax
ALIGN 4

id_invalid_image_length::
        mov     eax,PMERR_INV_IMAGE_DATA_LENGTH
        jmp     id_log_error_in_ax
ALIGN 4

id_no_surface::
        mov     eax,PMERR_BITMAP_NOT_SELECTED
        jmp     id_log_error_in_ax
ALIGN 4

id_inv_coordinate::
        mov     eax,PMERR_INV_COORDINATE
        errn$   id_log_error_in_ax

id_log_error_in_ax::
        save_error_code
id_error_logged_exit::
        xor     eax,eax
        jmp     id_exit
ALIGN 4


;/*
;** First compute the bounding rectangle for bounds accumulation, and
;** to perform error checking on the coordinates of the image data.
;*/

id_colors_are_valid::

        mov     esi,[esi].ddc_prddc     ; ES:SI = RDDC

        ASSUME  ESI:PRDDC

        mov     eax,[esi].rddc_ptsCurPos.ptl_x
        mov     ecx,[esi].rddc_ptsOrg.ptl_x
        sub     ax,cx
        jo      id_inv_coordinate
        movsx   eax,ax
        mov     ebx,[esi].rddc_ptsCurPos.ptl_y
        mov     ecx,[esi].rddc_ptsOrg.ptl_y
        sub     bx,cx
        jo      id_inv_coordinate
        movsx   ebx,bx

        mov     esi,hddc                ; SI = DDC

;/*
;** Now compute which row the drawing will take place on.  A positive
;** count moves us down the screen, so we must subtract the row off
;** of the current position.
;*/

        mov     ecx,Row
        sub     bx,cx
        jo      id_inv_coordinate
        movsx   ebx,bx

;/*
;** Finish computing the rectangle for bounds.  Note that we already
;** checked the width for zero.
;*/

        mov     edx,ebx                 ;yTop is the same as yBottom
        mov     ecx,eax                 ;xRight = xLeft + count

        add     cx,WORD PTR N[0]        
        jo      id_inv_coordinate
        movsx   ecx,cx
        dec     ecx                     ;Bounds expects an inclusive rectangle

;/*
;** Perform bounds if needed
;*/

id_check_bounds::                       ;FunN - MSW is commands
        assert  esi,E,hddc
        assert  edi,E,FunN

        test    edi,COM_BOUND + COM_ALT_BOUND
        jz      id_done_bounds
ifdef DCAF                                                           ;          
;/*                                                                  ;          
;** Since the real drawing is performed under the control of         ;          
;** enumerate_clip_rects, SCREEN bounds will be accumulated          ;          
;** there (after clipping).  Thus we don't want to accumulate the    ;          
;** unclipped bounds here, so turn off the COM_SCR_BOUND bit.        ;          
;*/                                                                  ;          
        and     edi, not COM_SCR_BOUND                               ;          
endif ; DCAF                                                         ;          
        INVOKE  AccumBoundsInDevCoords
        or      eax,eax
        jz      id_error_logged_exit
id_done_bounds::


;/*
;** Quick out.  If nothing is visible, nothing will be drawn and nothing
;** will be correlated against
;*/

        xor     ebx,ebx

        ASSUME  ESI:PDDC

        cmp     [esi].ddc_crcsClip,ebx
        je      id_good_exit_relay
        test    edi,COM_DRAW or COM_CORRELATE
        jz      id_good_exit_relay


;/*
;** Now compute where on the screen the data will actually go.  If we
;** encounter any overflow here, we'll clip (it could only be caused by
;** the dc origin, which cannot cause a real overflow error).
;**
;** The only other overflow we could get is in the bounding rectangle
;** when we're to draw at scan 7FFF.  This will be treated as an invisible
;** scan.
;*/

        mov     rclTemp.rcl_yTop,ebx    ;All coordinates will be 0:32767
        mov     rclTemp.rcl_xLeft,ebx
        mov     rclTemp.rcl_xRight,ebx
        mov     rclTemp.rcl_yBottom,ebx
        mov     obbaImage.obba_ySrc,ebx
        mov     obbaImage.obba_cyExt,1

        mov     ecx,N
        mov     esi,[esi].ddc_prddc

        ASSUME  ESI:PRDDC

        mov     eax,[esi].rddc_ptsCurPos.ptl_x
        or      ax,ax   ;sel 5/15

        jge     id_lhs_on_surface       ;lhs is on the screen
        add     cx,ax                   ;Reduce length by lhs overhang
        jle     id_good_exit_relay      ;Nothing will show

        sub     bx,ax   ;sel 5/15       ;Start here in the image data
        xor     eax,eax                 ;lhs is 0
id_lhs_on_surface::
        movsx   eax,ax  ;sel
        movsx   ebx,bx  ;sel
        mov     rclTemp.rcl_xLeft,eax
        mov     obbaImage.obba_xDst,eax
        mov     obbaImage.obba_xSrc,ebx
        add     ax,cx                   ;Exclusive rhs
;sel    movsx   eax,ax
        mov     edx,eax                 ;rhs for clipping rectangle
        jno     id_rhs_on_surface       ;rhs fits within +32K

        mov     edx,MAXSHORT            ;new rhs
        sub     ax,dx                   ;AX = amount of rhs overhang
        sub     cx,ax
        jle     id_good_exit_relay      ;Nothing will show
;sel        movsx   ecx,cx
id_rhs_on_surface::
        movsx   ecx,cx  ;SEL
        movsx   edx,dx  ;SEL
        mov     obbaImage.obba_cxExt,ecx ;Extent of blt
        mov     rclTemp.rcl_xRight,edx

        mov     eax,[esi].rddc_ptsCurPos.ptl_y
        mov     ecx,Row
        sub     ax,cx
        jl      id_good_exit_relay      ;If below the surface, all done
        movsx   eax,ax
        mov     rclTemp.rcl_yBottom,eax
        mov     obbaImage.obba_yDst,eax
        inc     ax                      ;7FFF is invisible, and we cannot
        jo      id_good_exit_relay      ; have a RECTL of 7FFF : 8000
        movsx   eax,ax
        mov     rclTemp.rcl_yTop,eax


;/*
;** If we are to actually draw the bitmap, then finish filling in the
;** OBB_ARGS structure and make the call.
;*/

        ASSUME  ESI:NOTHING


id_check_draw::
        mov     esi,hddc                ; SI = DDC
        mov     al,[esi].DDC.ddc_fb
        shl     eax,16
        and     eax,edi
        and     eax,COM_DRAW
        jnz     id_draw_image
        jmp     id_drawing_done
ALIGN 4
.errnz  DDC_VISIBLE - COM_DRAW SHR 16

id_good_exit_relay::
        jmp     id_good_exit
ALIGN 4

id_draw_image::

ifdef FIREWALLS
        mov     sdImage.sd_npsd,INVALID_ADDRESS
endif
        mov     sdImage.sd_usId,SURFACE_IDENT
        mov     eax,1
        mov     word ptr sdImage.sd_fb,ax
        .errnz  SD_NONNULL-1
        .errnz  SURFACE.sd_fbAccel-SURFACE.sd_fb-1
        mov     sdImage.sd_cy,eax       ;Only one scan

id_use_lpData::
        mov     eax,lpData
        mov     sdImage.sd_pBits,eax

id_pBits_set::

        mov     eax,N
        mov     sdImage.sd_cx,eax

;/*
;** Dynamically round the width to the correct byte multiple
;*/

        mov     ebx,pbmcMono

        ASSUME  EBX:NOTHING

        xor     ecx,ecx
        mov     cl,[ebx].BMC.bmc_cRound ;Round to a dword multiple
        add     eax,ecx
        not     ecx
        and     eax,ecx
        mov     cl,[ebx].BMC.bmc_cShr
        shr     eax,cl

        mov     sdImage.sd_cbScan,eax
        mov     sdImage.sd_dScan,eax

id_create_parms::
        mov     obbaImage.obba_pddcDst,esi
        lea     eax,sdImage
        mov     obbaImage.obba_psdSrc,eax


;/*
;** We will call bitblt twice.  Once with BBF_TRANS and the foreground
;** image mix as the bitblt mix.  This will take care of the "1" bits in
;** the image, and leave the destination unchanged where the image has
;** "0" bits.  Then we will make the second bitblt call with the bitblt
;** rop equal to the image background mix plus  BBF_ANTI_TRANS.  This
;** takes care of the image "0" bits.
;**
;** The confusion has occured of thinking that since the foreground
;** mix applies where there are "1" bits then there are only 4 possible
;** foreground mixes.  The flaw here is not realizing that the "1" bit
;** in the source means "foreground color", which can be any mixture
;** of ones and zeros.
;**
;** The oem layer has the option of terminating after the first call if
;** it is capable of performing the seperate foreground/background mixes
;** in hardware.
;*/

        mov     al,[esi].DDC.ddc_ia.ia_ba.ba_bmix
        assert  al,L,FM_ONE             ;Did GSS miss DEF_FMIX_IMAGE change?

        mov     ebx,anpabForeMix[(PRIM_IMAGE-1)*sizeof DWORD]
        xlatb                           ;AL <- [EBX+AL]
        movzx     eax,al
                                        ;EAX = Bitblt rop

        mov     ecx,BBF_IMAGE_DATA or BBF_TRANS or BBF_SRC_BITMAP or BBF_HAVE_SOURCE

;/*
;** Some bitblt rops don't involve the source.  ImageData uses some of
;** these:
;**
;**     5   LEAVEALONE    BB_ROP_D      (Leave Alone)  -->  BB_ROP_DSa
;**     9   ZERO          BB_ROP_DDx    (All Zeros)    -->  BB_ROP_Sn
;**    12   INVERT        BB_ROP_Dn     (NOT dest)     -->  BB_ROP_DSx
;**    17   ONE           BB_ROP_DDxn   (All Ones)     -->  BB_ROP_S
;**
;** But in ImageData the rop only applies where the source has a "1" bit.
;** So the source cannot be ignored.  To accomplish our goal, we will
;** convert these bitblt rops into other bitblt rops that involve the
;** source, but produce identical results when the source is "1".  To
;** make sure the source is not altered we must set a bit which tells
;** bitblt not to color convert (and as with all ImageData bitblt calls
;** we will turn on bitblt transparency.)
;*/

        inc     al
        jz      id_rop_is_1
        .errnz  BB_ROP_DDxn-0FFh
        dec     al
        jz      id_rop_is_0
        .errnz  BB_ROP_DDx
        cmp     al,BB_ROP_Dn
        je      id_rop_is_invert
        cmp     al,BB_ROP_D             ;We will still pass this on incase
        je      id_rop_is_nop           ;  bk rop is opaque and hardware assist

;/*
;** Special test for OVERPAINT foreground and background which can be
;** done in one pass as a normal bitblt operation
;*/

        cmp     al,BB_ROP_S
        jne     id_adjust_foreground_rop
        cmp     [esi].DDC.ddc_ia.ia_ba.ba_bkmix,BA_IS_OPAQUE
        jnz     id_adjust_foreground_rop
        mov     ecx,BBF_SRC_BITMAP or BBF_HAVE_SOURCE
        jmp     id_adjust_foreground_rop
ALIGN 4

id_rop_is_nop::
        mov     al,BB_ROP_DSa
        jmp     jstop
ALIGN 4
id_rop_is_invert::
        mov     al,BB_ROP_DSx
        jmp     jstop
ALIGN 4
id_rop_is_0::
        mov     al,BB_ROP_Sn
        jmp     jstop
ALIGN 4
id_rop_is_1::
        mov     al,BB_ROP_S
jstop:
        or      ch,high BBF_TRANS_NO_CC
        .errnz  low BBF_TRANS_NO_CC

;/*
;** We would not have a color converion for monochrome destination. To solve
;** this problem, we have to adjust the ROP properly by converting the
;** source if the image foreground color is mapped to black and leave the
;** ROP as it is if white.
;*/


id_adjust_foreground_rop::
        mov     obbaImage.obba_fsBlt,ecx

       ASSUME  EDI:PSURFACE
       ASSUME  ESI:PDDC

id_have_foreground_rop::
        mov     obbaImage.obba_usMix,eax

;/*
;** We have mapped the rop as needed and set the appropriate bitblt flags.
;** Call the enumeration routine to perform the actual bitblt operation.
;*/

        mov     ecx,RECTDIR_LFRT_BOTTOP-1 ;Favored direction
        lea     edi,obbaImage
        lea     edx,rclTemp

ifdef DCAF                                                           ;          
        ; Store the FunN in a global variable so that                ;          
        ; enumerate_clip_rects can check the COM_SCR_BOUNDS flag.    ;          
        mov     eax,FunN                                             ;          
        mov     ulGlobalCOMFlags,eax                                 ;          
endif ;DCAF                                                          ;          

        INVOKE  enumerate_clip_rects,
                esi,
                edx,                    ;prclClip
                OFFSET do_bitblt

ifdef DCAF                                                           ;          
        ; Reset the global COM flags so that other (non-DCAF)        ;          
        ; calls to enumerate_clip_rects work OK.                     ;          
        mov     ulGlobalCOMFlags,0                                   ;          
endif ;DCAF                                                          ;          

        cmp     eax,BBRC_SKIP_PASS_TWO
        je      id_drawing_done

;/*
;** Okay, do the second bitblt with BBF_ANTI_TRANS.  Presently we only
;** support two background rops, overpaint and leave_alone.  If it is
;** leave_alone then we can skip the second bitblt altogether.  For
;** overpaint we use bitblt mix = srccopy.
;*/

        cmp     [esi].ddc_ia.ia_ba.ba_bkmix,BA_IS_OPAQUE
        jnz     id_drawing_done         ;Transparent => we're done
        mov     obbaImage.obba_usMix,BB_ROP_S

;/*
;** As in the case of foreground, we need to reverse the rop if for
;** monochrome destination the background color is mapped to white.
;*/

        assert  esi,E,hddc


id_bk_blt::
XYZZY   equ     BBF_ANTI_TRANS or BBF_IMAGE_DATA or BBF_SRC_BITMAP or BBF_HAVE_SOURCE
        mov     obbaImage.obba_fsBlt,XYZZY

        mov     ecx,RECTDIR_LFRT_BOTTOP-1 ;Favored direction
        lea     edi,obbaImage
        lea     edx,rclTemp

ifdef DCAF                                                           ;          
        ; Store the FunN in a global variable so that                ;          
        ; enumerate_clip_rects can check the COM_SCR_BOUNDS flag.    ;          
        mov     eax,FunN                                             ;          
        mov     ulGlobalCOMFlags,eax                                 ;          
endif ;DCAF                                                          ;          

        INVOKE  enumerate_clip_rects,
                esi,
                edx,                    ;prclClip
                OFFSET do_bitblt

ifdef DCAF                                                           ;          
        ; Reset the global COM flags so that other (non-DCAF)        ;          
        ; calls to enumerate_clip_rects work OK.                     ;          
        mov     ulGlobalCOMFlags,0                                   ;          
endif ;DCAF                                                          ;          

id_drawing_done::

;/*
;** Drawing has been done.  Now do any correlation for the image
;*/

id_check_corr::
        test    FunN,COM_CORRELATE
        jz      id_good_exit            ;No correlation needed

        INVOKE  do_corr,
                hdc,
                ADDR rclTemp,           ;prclTemp
                hddc

        and     eax,2
        jnz     id_exit
id_good_exit::
        mov     eax,1

id_exit::
        INVOKE  leave_driver
id_exit_no_lock::
        fw_zero <ecx>
        ret
ImageData ENDP
_CODE   ENDS

ifdef FIREWALLS
        public  bb_validate_source
        public  bb_no_source_dc
        public  bb_double_enter
        public  bb_bad_mix
        public  bb_invalid_style
        public  bb_path_or_area
        public  bb_error_bad_count
        public  bb_log_error_in_ax
        public  bb_exit_error_logged
        public  bb_invalid_source
        public  bb_no_surface
        public  bb_to_default_handler
        public  bb_have_gray_rop
        public  bb_mix_is_good
        public  bb_have_source_surface
        public  bb_preprocessed_source
        public  bb_update_dest_sys_colors
        public  bb_update_dest_image_colors
        public  bb_update_dest_pat_colors
        public  bb_exit_error_logged_relay
        public  bb_override_colors
        public  bb_exit_error_logged_relay_s
        public  bb_dest_colors_valid
        public  bb_update_src_sys_colors
        public  bb_update_src_image_colors
        public  bb_set_bgndIPC
        public  bb_have_bgndIPC
        public  bb_colors_done
        public  bb_inv_coordinate
        public  bb_log_error_in_ax_relay
        public  bb_null_or_inv_rect
        public  bb_exit_ok
        public  bb_exit_ax_relay
        public  bb_validate_source_coords
        public  bb_exit_ok_relay_again
        public  bb_exit_ax_relay_again
        public  bb_synthesize_point
        public  bb_inv_coordinate_relay_ne
        public  bb_validate_done
        public  bb_rectl_in_dev_coords
        public  bb_check_bounds_ret_code
        public  bb_done_bounds
        public  bb_dc_org_src_lhs_restart
        public  bb_dc_org_src_rhs_restart
        public  bb_dc_org_src_bot_restart
        public  bb_src_dc_origin_done
        public  bb_dc_org_dest_lhs_restart
        public  bb_dc_org_lhs_ov_relay
        public  bb_dc_org_dest_rhs_restart
        public  bb_dc_org_dest_bot_restart
        public  bb_dc_org_bottom_ov_relay
        public  bb_dc_org_top_ov
        public  bb_adjust_y_ext
        public  bb_dc_org_rhs_ov
        public  bb_adjust_x_ext
        public  bb_dc_org_lhs_ov
        public  bb_adjust_lhs
        public  bb_do_restart
        public  bb_dc_org_bottom_ov
        public  bb_adjust_bottom
        public  bb_exit_ok_relay
        public  bb_origins_done
        public  bb_no_correlation_to_do
        public  bb_src_lhs_clipped
        public  bb_src_rhs_clipped
        public  bb_src_bot_clipped
        public  bb_source_clipped
        public  bb_dst_lhs_clipped
        public  bb_dst_rhs_clipped
        public  bb_dst_bot_clipped
        public  bb_dst_clip_top
        public  bb_dst_clip_bot
        public  bb_dst_clip_lhs
        public  bb_dst_clip_rhs
        public  bb_src_clip_top
        public  bb_src_clip_bot
        public  bb_src_clip_lhs
        public  bb_src_clip_rhs
        public  bb_clipped_to_surfaces
        public  bb_check_draw
        public  bb_have_direction
        public  bb_been_drawn
        public  bb_good_exit
        public  bb_exit_ax
        public  bb_exit_no_lock
        public  db_enter_driver
        public  db_validate_bmi
        public  db_validate_flOptions
        public  db_validate_lcount
        public  db_error_length_or_count
        public  db_error_bitblt_style
        public  db_error_inv_table
        public  db_copy_local
        public  db_validate_rectl
        public  db_match_rect_size
        public  db_check_header
        public  db_have_info
        public  db_check_compression
        public  db_uncomp_bm
        public  db_check_dimension
        public  db_screen_test
        public  db_leave_driver
        public  db_check_null_bits
        public  db_error_no_bm
        public  db_error_inv_dimension
        public  db_fake_bm
        public  db_correct_Info
        public  db_color_info
        public  db_full_rgb_tab
        public  db_have_color_count
        public  db_physical_color
        public  db_xlate_next_color
        public  db_have_color_table
        public  db_call_bitblt
        public  db_free_bm
        public  db_log_error
        public  db_done
        public  dco_have_corr_rect
        public  dco_make_rcl_loop
        public  dco_fix_sp
        public  dco_exit
        public  id_update_sys_colors
        public  id_update_colors
        public  id_good_exit_relay_again
        public  id_path_or_area
        public  id_inv_row
        public  id_invalid_image_length
        public  id_no_surface
        public  id_inv_coordinate
        public  id_log_error_in_ax
        public  id_error_logged_exit
        public  id_colors_are_valid
        public  id_check_bounds
        public  id_done_bounds
        public  id_lhs_on_surface
        public  id_rhs_on_surface
        public  id_check_draw
        public  id_good_exit_relay
        public  id_draw_image
        public  id_use_lpData
        public  id_pBits_set
        public  id_create_parms
        public  id_rop_is_nop
        public  id_rop_is_invert
        public  id_rop_is_0
        public  id_rop_is_1
        public  id_have_foreground_rop
        public  id_drawing_done
        public  id_check_corr
        public  id_good_exit
        public  id_exit
        public  id_exit_no_lock
endif
end
