;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = 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
;*   07/27/87                     Hock Lee [hockl] Modified for new DDI.
;*   08/18/87                     Wes Rupel [wesleyr]
;*   08/18/87                     Removed dependancy on old         color format.
;*   10/06/87                     Hock Lee [hockl] Added correlation.
;*   03/07/88                     Wes Rupel [wesleyr]
;*   03/07/88                     Implemented (background) Image Mixes using
;*   03/07/88                     two-pass Bitblt with transparency
;*   03/30/88                     Wes Rupel [wesleyr]
;*   03/30/88                     Made BackColor/ForeColor now 0/1 rather than 1/0
;*   06/05/88                     Walt Moore [waltm] Made bounds inclusive
;*   06/15/88                     Walt Moore [waltm] Added color==>mono
;*   06/15/88                     background color.  Rewrote it at that point.
;*   07/05/88                     Walt Moore [waltm] Reworked for bitblt rework.
;*   08/10/88                     Walt Moore [waltm] Invalid RECTLs passed to
;*   08/10/88                     Engine for DCR 24067.
;*   05/02/89                     Lee A. Newberg [leen] Skips a whole bunch of
;*   05/02/89                     stuff when COM_DRAW is clear.  Beware that
;*   05/02/89                     this means that many local variables are not
;*   05/02/89                     being initialized!!
;*   10/20/89                     Viroon  Touranachun [viroont] Fixed bug--
;*   10/20/89                     restricted the driver to handle only a
;*   10/20/89                     monochrome bitmap that is located within a
;*   10/20/89                     single data segment. Also, limited the
;*   10/20/89                     flOptions to ; be either BBO_AND, BBO_OR,
;*   10/20/89                     or BBO_IGNORE, with its high word must be 0.
;*   10/22/89                     Viroon Touranachun [viroont] Handle a bitmap
;*   10/22/89                     source with a standard-format bitmap in it
;*   10/22/89                     (for DCR25020).
;*   10/23/89                     Viroon Touranachun [viroont] Convert 16-bit to
;*   10/23/89                     32-bit operations.
;*   10/27/89                     Viroon  Touranachun [viroont] Allowed a NULL
;*   10/27/89                     bitmapinfoheader if it was a NULL pbits.
;*   06/01/90                     Viroon Touranachun [viroont] Added
;*   06/01/90                     BLTMODE_SCR_DRAW flag to handle a call from
;*   06/01/90                     the DrawBits function. (when it wants to
;*   06/01/90                     draw directly to the screen with ROP=SRC_COPY.)
;*   06/01/90                     Viroon  Touranachun [viroont] Optimized the
;*   06/01/90                     function to handle compressed/uncompressed
;*   06/01/90                     bits which will be drawn to the screen directly.
;*****************************************************************************/

        .286p
        .xlist
        include cmacros.inc
INCL_GRE_XFORMS         equ     1
INCL_GRE_BITMAPS        equ     1
INCL_GRE_DEVSUPPORT     equ     1
INCL_GRE_DEVMISC3       equ     1
INCL_DDIMISC            equ     1
INCL_DEV                equ     1
INCL_DDICOMFLAGS        equ     1
INCL_GPITRANSFORMS      equ     1
INCL_GPIREGIONS         equ     1
INCL_GPIBITMAPS         equ     1
INCL_GPILOGCOLORTABLE   equ     1
INCL_DDIBUNDLES         equ     1
INCL_GRE_CLIP           equ     1
        include pmgre.inc
DINCL_BB_ROPS           equ     1
DINCL_BITMAP            equ     1
DD_DRAWBITS             equ     1
        include driver.inc
        include oemblt.inc
        include display.inc
        include assert.mac
        include njmp.mac
        include bmi2.inc
ifdef PALMGR
        include palette.inc
endif
        .list

        externFP        GetDriverInfo
        externFP        DosAllocSeg
        externFP        DosFreeSeg

        errcode <BITMAP_IS_SELECTED,BITMAP_NOT_SELECTED,INV_HDC,INV_BITBLT_MIX>
        errcode <INV_IN_PATH,INV_IN_AREA,INV_IMAGE_DATA_LENGTH>
        errcode <INV_LENGTH_OR_COUNT,INV_RECT,INV_HBITMAP,BASE_ERROR>
        errcode <INV_COORDINATE,INV_BITBLT_STYLE,INV_SCAN_START>
        errcode <INSUFFICIENT_MEMORY,INV_INFO_TABLE,INV_BITMAP_DIMENSION>
        errcode <INV_COLOR_INDEX>

MAX_BITMAP_DIMENSION    equ     00007fffh ; 32K
NUMBER_OF_POINTS        equ     4       ;Number of points specifying
                                        ;source/target rectangles
sBegin  Data
        externB ddcInit
        externD pfnDefRectVisible
        externB fGrimReaper
        externD pfnDefBitblt
        externD pfnDefDrawBits
        externW npbmcMono
        externW anpabForeMix
        externW abAdjMixMapImage
ifdef PALMGR
        externW cPals
endif;PALMGR
sEnd    Data

sBegin  FarCode
        externW         FarCodeData
sEnd    FarCode

        externFP        far_check_bitmap_info           ;bmsup.asm
        externFP        alloc_bm                        ;memman.asm
        externFP        free_bm                         ;memman.asm
ifdef PALMGR
        externFP        MakePaletteMappingValid         ;palmap.asm
        externFP        HDBMDevPalMapper                ;palmap.asm
        externFP        MapDownPaletteIndex             ;colormat.asm
endif;PALMGR

sBegin  FarCode
        externNP        PropagateSysClrChange           ;phycolor.asm
sEnd

sBegin  Code
        assumes cs,Code
        externW         CodeData

        externNP        intersect_rcl
        externNP        enter_driver
        externNP        leave_driver
        externNP        AccumBoundsInDevCoords
        externNP        InnerAccumulateBounds
        externNP        recalc_correlate_rect
        externNP        do_bitblt
        externNP        do_drawbits
        externNP        do_stretchblt
        externNP        enumerate_clip_rects
        externNP        enter_driver
        externNP        double_enter_driver
        externNP        leave_driver
        externNP        MakeBrushValid
        externNP        MakeColorsValid
        externNP        validate_rectl
        externNP        rgb_to_ipc

do_function     equ     this word       ; low-level working functions
                dw      CodeOFFSET do_bitblt
                dw      CodeOFFSET do_drawbits
                dw      CodeOFFSET do_stretchblt

page

;/***************************************************************************
;*
;* 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         
;*           Calls:
;*                  double_enter_driver
;*                  GetDriverInfo
;*                  PropagateSysClrChange
;*                  MakeColorsValid
;*                  MakeBrushValid
;*                  AccumBoundsInDevCoords
;*                  InnerAccumulateBounds
;*                  enumerate_clip_rects
;*                  do_corr
;*                  leave_driver
;*
;* 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       
;*
;**************************************************************************/

        check   Bitblt,<hdc,hdcSrc,cptl,pbbp,lMix,flCmd,pbba,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   Bitblt,<PUBLIC,FAR,NODATA>

        parmD   hdc
        parmD   hdcSrc
        parmD   Count
        parmD   lpBitBltParm
        parmD   Mix
        parmD   Style
        parmD   lpAttrs
        parmD   hddc
        parmD   FunN

        localB  fbBitblt                 ;Flags as listed above
        localW  npddcSrc                 ;Source ddc if given and a ddc
        localW  npfnOverflowRestart      ;Dc origin restart address
        localD  ulGDIret                 ;GetDriverInfo return code
        localV  obbaBBlt,%(size OBB_ARGS);OEM bitblt parameter structure
        localV  rclDst,%(size RECTL)     ;Dest bounding rectangle, clipped
        localV  rclCorr,%(size RECTL)    ;Dest bounding rectangle, unclipped

        localV  stbParm,%(size STBLT)    ;StretchBlt information

cBegin
        CPUMode 386

        push    esi                     ;we are going to trash them
        push    edi

        CPUMode 286

        ddc?    hddc                    ;Make sure this is a ddc
        cld
        mov     ds,CodeData
        assumes ds,Data
        mov     si,hddc.lo              ;DS:SI --> ddc

        CPUMode 386

        mov     ulGDIret,-1             ;Assume error return
        mov     eax,hdcSrc
        shld    edx,eax,16              ; DX:AX = EAX = hdcSrc
        or      eax,eax
        jz      bb_no_source_dc

        CPUMode 286

        mov     di,Style.hi

ifdef   DD_DRAWBITS
        test    di,BLTMODE_SRC_HDBM shr 16    ; If the source is HDBM
        jnz     bb_source_hdbm                ; Yes, no check
endif;  DD_DRAWBITS

        and     di,BLTMODE_SRC_BITMAP shr 16
        .errnz  (BLTMODE_SRC_BITMAP shr 16) - DI_HBITMAP
        .errnz  DI_HDC
        farPtr  MyIndex,0,di
        farPtr  MySrcDC,dx,ax
        cCall   GetDriverInfo,<MySrcDC,MyIndex,hdc>
        mov     ulGDIret.hi,dx          ;Save return code for later
        mov     ulGDIret.lo,ax
        and     dx,ax
        inc     dx
        jz      bb_no_source_dc         ;Source dc/bitmap does not exist
        or      di,di
        jnz     bb_no_source_dc         ;Source is a bitmap
        .errnz  DI_HDC
        .errnz  DI_HBITMAP-1
        mov     di,ax                   ;DI = source hddc
        jmp     short bb_double_enter

ifdef   DD_DRAWBITS

        CPUMode 386

bb_source_hdbm:
        or      Style.hi,BLTMODE_SRC_BITMAP shr 16
        mov     eax,hdcSrc            ; We know that source is HDBM
        mov     ulGDIret,eax

endif;  DD_DRAWBITS

        CPUMode 286

bb_no_source_dc:
        mov     di,si                   ;Make DI = SI = source hddc
bb_double_enter:
        call    double_enter_driver     ;SI,DI = hddcs
        njc     bb_exit_no_lock         ;DX:AX = 0 on error

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

        xor     dx,dx                   ;Zeros come in handy now and then
        mov     fbBitblt,dl
        mov     di,FunN.hi              ;Has COM_ flags in it

        CPUMode 386
BLTMODE_VALID_FLAGS = BLTMODE_SRC_BITMAP  or BLTMODE_ATTRS_PRES
ifdef   DD_DRAWBITS
BLTMODE_VALID_FLAGS = BLTMODE_VALID_FLAGS or BLTMODE_SRC_HDBM or BLTMODE_SCR_DRAW
endif;  DD_DRAWBITS

BLTMODE_WIN_SRC_COPY    equ     00800000h

ifdef BLTMODE_WIN_SRC_COPY
BLTMODE_VALID_FLAGS = BLTMODE_VALID_FLAGS or BLTMODE_WIN_SRC_COPY
endif;BLTMODE_WIN_SRC_COPY

        mov     bx,Style.hi
        test    bx,not (BLTMODE_VALID_FLAGS shr 16)
        jnz     bb_invalid_style
        test    bx,((BLTMODE_SCR_DRAW or BLTMODE_WIN_SRC_COPY) shr 16)
        jnz     bb_validate_source
        cmp     Style.lo,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
        CPUMode 286

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

        cmp     Count.hi,dx             ;If more than 4 points, let default
        jne     bb_to_default_handler   ;  handler deal with the call
        mov     ax,Count.lo
        cmp     ax,2
        jb      bb_error_bad_count
        cmp     ax,4
        ja      bb_to_default_handler

        cmp     Mix.hi,dx               ;If invalid mix, log an error
        jne     bb_bad_mix
        mov     bx,Mix.lo
        cmp     bx,GRAY_ROP
        je      bb_have_gray_rop
        or      bh,bh
        jz      bb_mix_is_good
        errn$   bb_bad_mix
      
;/*
;** Once again, we find ourselves looking for a place to put error
;** handlers.
;*/

bb_bad_mix:
        mov     ax,PMERR_INV_BITBLT_MIX
        jmp     short bb_log_error_in_ax

bb_invalid_style:
        mov     ax,PMERR_INV_BITBLT_STYLE
        jmp     short bb_log_error_in_ax

bb_path_or_area:
        mov     ax,PMERR_INV_IN_PATH
        test    di,COM_PATH
        jnz     bb_log_error_in_ax
        mov     ax,PMERR_INV_IN_AREA
        jmp     short bb_log_error_in_ax

bb_error_bad_count:
        mov     ax,PMERR_INV_LENGTH_OR_COUNT

bb_log_error_in_ax:
        save_error_code

bb_exit_error_logged:
        xor     ax,ax
        jmp     bb_exit_ax

bb_invalid_source:
        mov     ax,PMERR_INV_HDC
        test    fbBitblt,BBF_SRC_BITMAP
        jz      bb_log_error_in_ax
        mov     ax,PMERR_INV_HBITMAP
        jmp     bb_log_error_in_ax

bb_no_surface:
        mov     ax,PMERR_BITMAP_NOT_SELECTED
        jmp     bb_log_error_in_ax

bb_error_selected_bm:
        mov     ax,PMERR_BITMAP_IS_SELECTED
        jmp     bb_log_error_in_ax

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

bb_to_default_handler:

ifdef   DD_DRAWBITS                     ;clear flag in case it is set by Drawbits

        and     Style.hi,NOT ((BLTMODE_SCR_DRAW+BLTMODE_SRC_HDBM) shr 16)

endif;  DD_DRAWBITS

        call    leave_driver
        mov     ax,ds
        mov     es,ax

        CPUMode 386

        pop     edi
        pop     esi                     ;we saved them at the beginning

        CPUMode 286

        cleanframe
        assumes ds,nothing
        assumes es,Data
        jmp     pfnDefBitblt            ;Pass it back to the engine

        assumes ds,Data
        assumes es,nothing


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

bb_have_gray_rop:
        mov     fbBitblt,BBF_GRAY_ROP
        mov     bx,BB_ROP_DPx           ;Driver wants to see this mix mode
        mov     Mix.lo,bx


;/*
;**  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,bx  ;Save mix mode for oem layer
        mov     bh,bl
        and     bx,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.
;*/

bb_validate_source:
        mov     ax,Style.hi
        and     ax,(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     dx,ulGDIret.hi          ;return code from GetDriverInfo
        mov     ax,ulGDIret.lo
        and     dx,ax
        inc     dx
        jz      bb_invalid_source
        xchg    ax,di                   ;DI --> sd_ or ddc_
        xchg    ax,cx                   ;CX = FunN.hi
        test    fbBitblt,BBF_SRC_BITMAP
        jz      @F
        cmp     [di].bm_cSelect,0       ;The bitmap source must not be selected
        jmp     short bb_have_source_surface
@@:

        mov     al,[di].ddc_fb
        test    al,DDC_PRESENT
        jz      bb_no_surface           ;No surface in ddc, error
        test    al,DDC_DEVICE
        jz      bb_have_source_surface  ;Bitmap, 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
        .errnz  high COM_DRAW

bb_have_source_surface:
        mov     npddcSrc,di             ;Source ddc or bitmap pointer
        mov     di,[di].ddc_npsd        ;DS:DI --> sd_
        .errnz  sd_npsd-ddc_npsd
        mov     obbaBBlt.obba_psdSrc.off,di
        mov     obbaBBlt.obba_psdSrc.sel,ds
        mov     al,[di].sd_fb           ;If NULL surface, clear COM_DRAW
        mov     ah,al
        or      al,not COM_DRAW
        and     cl,al
        .errnz  high COM_DRAW
        .errnz  SD_NONNULL-COM_DRAW
        and     ah,SD_COLOR
        or      fbBitblt,ah
        .errnz  BBF_COLOR_SRC-SD_COLOR
        mov     di,cx                   ;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  si,E,hddc.lo
        mov     al,[si].ddc_fb          ;Clear COM_DRAW bit if dest invisible
        or      ax,not COM_DRAW
        and     di,ax
        mov     FunN.hi,di
        .errnz  DDC_VISIBLE-COM_DRAW

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

        CPUMode 386
        test    fbBitblt,BBF_CMEM_TO_SCR
        jnz     bb_its_color_mem_to_screen
        CPUMode 286

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

        test    di,COM_DRAW
        njz     bb_colors_done

        test    Style.hi,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     ax,obbaBBlt.obba_usMix
        shl     ax,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     bx,[si].ddc_npsd
        mov     ah,[bx].sd_fb
        and     ax,BBF_COLOR_SRC + (SD_COLOR shl 8)
        .errnz  BBF_COLOR_SRC-SD_COLOR
        xor     al,ah                       ; if it is not a mono <=> color blt
        njz     bb_colors_done              ; need not realize anything

bb_consider_update_color:
        mov     ax,[si].ddc_iSysClr
        cmp     ax,ddcInit.ddc_iSysClr
        jne     bb_update_dest_sys_colors
        test    [si].ddc_ia.ia_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV
        jnz     bb_update_dest_image_colors
        test    [si].ddc_pa.pa_ba.ba_fb,BA_REREALIZE
        jz      bb_dest_colors_valid
        jmp     short bb_update_dest_pat_colors
bb_update_dest_sys_colors:
        cCall   PropagateSysClrChange
bb_update_dest_image_colors:
        lea     bx,[si].ddc_ia.ia_ba
        call    MakeColorsValid
        js      bb_exit_error_logged_relay
        test    [si].ddc_pa.pa_ba.ba_fb,BA_REREALIZE
        jz      bb_dest_colors_valid
bb_update_dest_pat_colors:
        xor     cl,cl
        cCall   MakeBrushValid,<ax,ax>      ; argument unused
        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
;*/

bb_override_colors:
        mov     ax,[si].ddc_iSysClr
        cmp     ax,ddcInit.ddc_iSysClr
        je      @F
        cCall   PropagateSysClrChange
@@:
        mov     cl,0FFh                 ;Use the passed colors
        cCall   MakeBrushValid,<lpAttrs>
        or      [si].ddc_pa.pa_ba.ba_fb,BA_REREALIZE or BA_CLR_INVALID or BA_CLR_BACK_INV
        or      ax,ax                   ;Check for error
bb_exit_error_logged_relay_s:
        js      bb_exit_error_logged_relay
        mov     ax,word ptr [si].ddc_pa.pa_ba.ba_ipc
        mov     word ptr [si].ddc_ia.ia_ba.ba_ipc,ax
        mov     ax,word ptr [si].ddc_pa.pa_ba.ba_ipcBack
        mov     word ptr [si].ddc_ia.ia_ba.ba_ipcBack,ax
        or      [si].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  si,E,hddc.lo
        assert  di,E,FunN.hi
        test    Style.hi,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     bx,[si].ddc_npsd
        test    [bx].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     si,npddcSrc
        mov     ax,[si].ddc_iSysClr
        cmp     ax,ddcInit.ddc_iSysClr
        jne     bb_update_src_sys_colors
        test    [si].ddc_ia.ia_ba.ba_fb,BA_REREALIZE
        jz      bb_set_bgndIPC
        jmp     short bb_update_src_image_colors
bb_update_src_sys_colors:
        cCall   PropagateSysClrChange
bb_update_src_image_colors:
        lea     bx,[si].ddc_ia.ia_ba
        call    MakeColorsValid
        js      bb_exit_error_logged_relay_s
bb_set_bgndIPC:
        mov     ax,word ptr [si].ddc_ia.ia_ba.ba_ipcBack
        mov     obbaBBlt.obba_ipcBkgnd,ax
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.
;*/

        CPUMode 386

        les     si,lpBitBltParm
        assumes es,nothing

        .errnz  rcl_xLeft
        lods    es:bbp_rclTarg.rcl_xLeft
        movsx   edi,ax                  ; DI = xLeft
        cmp     eax,edi
        jne     bb_inv_coordinate
        mov     rclDst.rcl_xLeft,eax

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

        .errnz  rcl_xRight-rcl_yBottom-4
        lods    es: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
        mov     obbaBBlt.obba_cxExt,cx

        .errnz  rcl_yTop-rcl_xRight-4
        lods    es: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
        mov     obbaBBlt.obba_cyExt,cx

        test    fbBitblt,BBF_HAVE_SOURCE
        jnz     bb_validate_source_coords
        jmp     bb_validate_done

        CPUMode 286

bb_inv_coordinate:
        mov     ax,PMERR_INV_COORDINATE

bb_log_error_in_ax_relay:
        jmp     bb_log_error_in_ax

        CPUMode 386

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

        CPUMode 286

bb_exit_ok:
        mov     ax,1

bb_exit_ax_relay:
        jmp     bb_exit_ax


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

        CPUMode 386

bb_validate_source_coords:

        .errnz  bbp_rclSrc-bbp_rclTarg-(size RECTL)
        .errnz  rcl_xLeft
        lods    es:bbp_rclSrc.rcl_xLeft
        mov     obbaBBlt.obba_xSrc,ax
        movsx   edi,ax                  ;DI = xLeft
        cmp     eax,edi
        jne     bb_inv_coordinate

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

        cmp     Count.lo,4
        jl      bb_synthesize_point

        .errnz  rcl_xRight-rcl_yBottom-4
        lods    es:bbp_rclSrc.rcl_xRight
        movsx   ecx,ax                  ;CX = xRight (exclusive)
        cmp     eax,ecx
        jne     bb_inv_coordinate
        sub     cx,di                   ;CX = extent
        jle     bb_null_or_inv_rect     ;xLeft >= xRight
        sub     cx,obbaBBlt.obba_cxExt

        .errnz  rcl_yTop-rcl_xRight-4
        lods    es:bbp_rclTarg.rcl_yTop
        movsx   edx,ax                  ;DX = yTop
        cmp     eax,edx
        jne     bb_inv_coordinate
        sub     dx,bx
        jle     bb_null_or_inv_rect     ;yBottom >= yTop
        sub     dx,obbaBBlt.obba_cyExt

        or      cx,dx                   ;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.lo,ROP_SRCCOPY
        jne     bb_to_default_handler
        cmp     Style.lo,BBO_IGNORE
        jne     bb_to_default_handler
        mov     si,obbaBBlt.obba_psdSrc.off ;DS:SI => source surface
        test    [si].sd_fb,SD_DEVICE
        jnz     bb_to_default_handler
        mov     si,hddc.lo
        mov     si,[si].ddc_npsd            ;DS:SI => destination surface
        test    [si].sd_fb,SD_DEVICE
        jz      bb_to_default_handler
        or      fbBitblt,BBF_STRETCHBLT     ;we can handle the stretching
        jmp     short bb_validate_done

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

bb_its_color_mem_to_screen:
        assert  Mix.lo,E,ROP_SRCCOPY
        mov     obbaBBlt.obba_usMix,ROP_SRCCOPY ;it's always source copy
        lgs     si,lpBitBltParm                 ;rectangle passed by caller
        assumes gs,nothing
        push    ss
        pop     es
        assumes es,nothing
        lea     di,rclDst                       ;local copy of destination rect
        mov     ax,gs:[si].rcl_xRight.lo
        sub     ax,gs:[si].rcl_xLeft.lo
        mov     obbaBBlt.obba_cxExt,ax
        mov     ax,gs:[si].rcl_yTop.lo
        sub     ax,gs:[si].rcl_yBottom.lo
        mov     obbaBBlt.obba_cyExt,ax
        mov     cx,(size RECTL)/4
        rep     movs dword ptr es:[di],dword ptr gs:[si]

        mov     edi,gs:[si].rcl_xLeft
        mov     obbaBBlt.obba_xSrc,di
        mov     ebx,gs:[si].rcl_yBottom
        mov     obbaBBlt.obba_ySrc,bx
        jmp     short bb_validate_done

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

bb_exit_ok_relay_again:
        mov     ax,1
bb_exit_ax_relay_again:
        jmp     bb_exit_ax

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

bb_synthesize_point:
        movsx   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

        movsx   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:

        CPUMode 286

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

        mov     si,hddc.lo
        mov     di,FunN.hi
        test    di,COM_BOUND+COM_ALT_BOUND
        jz      bb_done_bounds          ;No bounds needed
        mov     ax,rclDst.rcl_xLeft.lo
        mov     bx,rclDst.rcl_yBottom.lo
        mov     cx,rclDst.rcl_xRight.lo
        mov     dx,rclDst.rcl_yTop.lo
        dec     cx                      ;Bounds is inclusive
        dec     dx
        test    di,COM_TRANSFORM
        jnz     bb_rectl_in_dev_coords
        call    InnerAccumulateBounds
        jmp     short bb_check_bounds_ret_code
bb_rectl_in_dev_coords:
        call    AccumBoundsInDevCoords
bb_check_bounds_ret_code:
        or      ax,ax
        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  si,E,hddc.lo
        assert  di,E,FunN.hi
        cmp     [si].ddc_crcsClip,0
        je      bb_exit_ok_relay_again
        test    di,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.
;*/

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

        CPUMode 386

        movsx   esi,obbaBBlt.obba_cxExt
        movsx   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

        CPUMode 286

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

        mov     npfnOverflowRestart,CodeOFFSET bb_dc_org_src_lhs_restart
bb_dc_org_src_lhs_restart:
        mov     ax,obbaBBlt.obba_xSrc
        mov     dx,ax                   ;remember the original value
        mov     cx,es:[bx].rddc_ptsOrg.pts_x
        add     ax,cx
        jo      bb_dc_org_lhs_ov_relay  ;lhs overflow or underflow
        mov     obbaBBlt.obba_xSrc,ax
        sub     stbParm.stb_xSrcDel,dx
        add     stbParm.stb_xSrcDel,ax  ;the x-source transform value
        mov     npfnOverflowRestart,CodeOFFSET bb_dc_org_src_rhs_restart
        or      cx,cx
        js      bb_dc_org_src_rhs_restart; rhs overflow impossible
        add     ax,si                   ;Compute rhs
        njo     bb_dc_org_rhs_ov        ;rhs overflowed (cannot underflow)
bb_dc_org_src_rhs_restart:

        mov     npfnOverflowRestart,CodeOFFSET bb_dc_org_src_bot_restart
bb_dc_org_src_bot_restart:
        rddc?   es,bx
        mov     ax,obbaBBlt.obba_ySrc
        mov     dx,ax                   ;remember the original value
        mov     cx,es:[bx].rddc_ptsOrg.pts_y
        add     ax,cx
        jo      bb_dc_org_bottom_ov_relay ;Bottom overflow or underflow
        mov     obbaBBlt.obba_ySrc,ax
        sub     stbParm.stb_ySrcDel,dx
        add     stbParm.stb_ySrcDel,ax  ;the y-source transform value
        mov     npfnOverflowRestart,CodeOFFSET bb_src_dc_origin_done
        or      cx,cx
        js      bb_src_dc_origin_done
        add     ax,di                   ;Compute top
        jo      bb_dc_org_top_ov        ;Top overflowed

bb_src_dc_origin_done:
        mov     bx,hddc.lo
        les     bx,[bx].ddc_prddc
        assumes es,nothing
        rddc?   es,bx

        mov     npfnOverflowRestart,CodeOFFSET bb_dc_org_dest_lhs_restart
bb_dc_org_dest_lhs_restart:
        mov     ax,rclDst.rcl_xLeft.lo
        mov     dx,ax                   ;remember the original value
        mov     cx,es:[bx].rddc_ptsOrg.pts_x
        add     ax,cx
bb_dc_org_lhs_ov_relay:
        jo      bb_dc_org_lhs_ov
        mov     rclDst.rcl_xLeft.lo,ax
        sub     stbParm.stb_xDstDel,dx
        add     stbParm.stb_xDstDel,ax  ;the x-destination transform value
        mov     npfnOverflowRestart,CodeOFFSET bb_dc_org_dest_rhs_restart
        or      cx,cx
        jz      bb_dc_org_dest_rhs_restart
        add     ax,si
        jo      bb_dc_org_rhs_ov
bb_dc_org_dest_rhs_restart:

        mov     npfnOverflowRestart,CodeOFFSET bb_dc_org_dest_bot_restart
bb_dc_org_dest_bot_restart:
        rddc?   es,bx
        mov     ax,rclDst.rcl_yBottom.lo
        mov     dx,ax                   ;remember the original value
        mov     cx,es:[bx].rddc_ptsOrg.pts_y
        add     ax,cx
bb_dc_org_bottom_ov_relay:
        jo      bb_dc_org_bottom_ov
        mov     rclDst.rcl_yBottom.lo,ax
        sub     stbParm.stb_yDstDel,dx
        add     stbParm.stb_yDstDel,ax  ;the y-destination transform value
        mov     npfnOverflowRestart,CodeOFFSET bb_origins_done
        add     ax,di
        jno     bb_origins_done

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

bb_dc_org_top_ov:
        sub     ax,MAXSHORT             ;AX = amount of overflow on top
bb_adjust_y_ext:
        sub     di,ax                   ;Update y extent
        jbe     bb_exit_ok_relay        ;Nothing shows anymore
        xor     ax,ax
        jmp     npfnOverflowRestart

bb_dc_org_rhs_ov:
        sub     ax,MAXSHORT             ;AX = amount of overflow on rhs
bb_adjust_x_ext:
        sub     si,ax                   ;Update x extent
        jbe     bb_exit_ok_relay        ;Nothing shows anymore
        jmp     npfnOverflowRestart

bb_dc_org_lhs_ov:
        js      bb_exit_ok_relay        ;If overflow, we're done with the blt
        mov     bx,MINSHORT
        sub     bx,ax
        xchg    ax,bx                   ;BX = amount to move start to the
bb_adjust_lhs:                          ;  right and to adjust extents by
        add     obbaBBlt.obba_xSrc,ax
        add     rclDst.rcl_xLeft.lo,ax
        sub     si,ax                   ;Update x extent
        jbe     bb_exit_ok_relay        ;Nothing shows anymore
bb_do_restart:
        xor     ax,ax                   ;New lhs aor bottom is zero
        jmp     npfnOverflowRestart

bb_dc_org_bottom_ov:
        js      bb_exit_ok_relay        ;If overflow, we're done with the blt
        mov     bx,MINSHORT
        sub     bx,ax
        xchg    ax,bx
bb_adjust_bottom:
        add     obbaBBlt.obba_ySrc,ax
        add     rclDst.rcl_yBottom.lo,ax
        sub     di,ax                   ;Update y extent
        jnbe    bb_do_restart
bb_exit_ok_relay:
        jmp     bb_exit_ok


;/*
;** 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:
        fw_zero <es>
        test    FunN.hi,COM_CORRELATE
        jz      bb_no_correlation_to_do
        assert  si,G,0
        assert  di,G,0

        CPUMode 386

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

        CPUMode 286

;/*
;** 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     bx,hddc.lo
        test    [bx].ddc_fb,DDC_SSB_CALL
        jnz     bb_source_clipped
        mov     bx,obbaBBlt.obba_psdSrc.off
        mov     ax,obbaBBlt.obba_xSrc
        or      ax,ax
        js      bb_src_clip_lhs
bb_src_lhs_clipped:
        add     ax,si                   ;AX = rhs
        sub     ax,[bx].sd_cx           ;AX = amount of overflow
        jg      bb_src_clip_rhs         ;Equal condition just fits
bb_src_rhs_clipped:
        mov     ax,obbaBBlt.obba_ySrc
        or      ax,ax
        js      bb_src_clip_bot
bb_src_bot_clipped:
        add     ax,di                   ;AX = top
        sub     ax,[bx].sd_cy           ;AX = amount of overflow
        jg      bb_src_clip_top         ;Equal condition just fits
bb_source_clipped:
        mov     bx,hddc.lo
        mov     bx,[bx].ddc_npsd
        mov     ax,rclDst.rcl_xLeft.lo
        or      ax,ax
        js      bb_dst_clip_lhs
bb_dst_lhs_clipped:
        add     ax,si                   ;AX = rhs
        sub     ax,[bx].sd_cx           ;AX = amount of overflow
        jg      bb_dst_clip_rhs         ;Equal condition just fits
bb_dst_rhs_clipped:
        mov     ax,rclDst.rcl_yBottom.lo
        or      ax,ax
        js      bb_dst_clip_bot
bb_dst_bot_clipped:
        add     ax,di                   ;AX = top
        sub     ax,[bx].sd_cy           ;AX = amount of overflow
        jle     bb_clipped_to_surfaces

bb_dst_clip_top:
        mov     npfnOverflowRestart,CodeOFFSET bb_clipped_to_surfaces
        jmp     bb_adjust_y_ext

bb_dst_clip_bot:
        mov     npfnOverflowRestart,CodeOFFSET bb_dst_bot_clipped
        neg     ax
        jmp     bb_adjust_bottom

bb_dst_clip_lhs:
        mov     npfnOverflowRestart,CodeOFFSET bb_dst_lhs_clipped
        neg     ax
        jmp     bb_adjust_lhs

bb_dst_clip_rhs:
        mov     npfnOverflowRestart,CodeOFFSET bb_dst_rhs_clipped
        jmp     bb_adjust_x_ext

bb_src_clip_top:
        mov     npfnOverflowRestart,CodeOFFSET bb_source_clipped
        jmp     bb_adjust_y_ext

bb_src_clip_bot:
        mov     npfnOverflowRestart,CodeOFFSET bb_src_bot_clipped
        neg     ax
        jmp     bb_adjust_bottom

bb_src_clip_lhs:
        mov     npfnOverflowRestart,CodeOFFSET bb_src_lhs_clipped
        neg     ax
        jmp     bb_adjust_lhs

bb_src_clip_rhs:
        mov     npfnOverflowRestart,CodeOFFSET bb_src_rhs_clipped
        jmp     bb_adjust_x_ext



;/*
;** 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,si
        mov     obbaBBlt.obba_cyExt,di
        assert  si,G,0                  ;Both extents must be > 0
        assert  di,G,0
        xor     ax,ax
        mov     rclDst.rcl_xLeft.hi,ax
        mov     rclDst.rcl_yBottom.hi,ax

        CPUMode 386

        movzx   eax,rclDst.rcl_xLeft.lo
        mov     obbaBBlt.obba_xDst,ax
        add     esi,eax
        mov     rclDst.rcl_xRight,esi
        movzx   edx,rclDst.rcl_yBottom.lo
        mov     obbaBBlt.obba_yDst,dx
        add     edi,edx
        mov     rclDst.rcl_yTop,edi

        test    fbBitblt,BBF_STRETCHBLT
        jz      short bb_dest_surface
        mov     ebx,lpBitBltParm                ;ptr to the bltting rectangles
        mov     stbParm.stb_lpRectl,ebx
        lea     bx,stbParm                      ;ptr to stretchblt param
        mov     obbaBBlt.obba_ySrc,bx           ;override the x/ySrc fields
        mov     obbaBBlt.obba_xSrc,ss           ;of the obbaBBlt

bb_dest_surface:
        mov     bx,hddc.lo
        mov     obbaBBlt.obba_pddcDst.off,bx
        mov     obbaBBlt.obba_pddcDst.sel,ds

        CPUMode 286

;/*
;** 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.hi,COM_DRAW
        njz     bb_been_drawn
        mov     cx,RECTDIR_LFRT_BOTTOP-1 ;Favored direction

ifdef   DD_DRAWBITS

        test    Style.hi,(BLTMODE_SCR_DRAW shr 16)
        jnz     bb_enum_parm

endif;  DD_DRAWBITS

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

        mov     si,[bx].ddc_npsd
        cmp     si,obbaBBlt.obba_psdSrc.off
        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     cx,cx
        cmp     dx,obbaBBlt.obba_ySrc   ;'C' if dest is below source
        adc     cx,cx
        .errnz  BOTTOP-00000010b
        cmp     obbaBBlt.obba_xSrc,ax   ;'C' if dest is to the right of source
        adc     cx,cx
        .errnz  RTLF-00000001b

bb_have_direction:
        mov     al,fbBitblt
        xor     ah,ah
        mov     obbaBBlt.obba_fsBlt,ax

ifdef PALMGR

;/*
;** Palette mapping is only necessary when there is a source involved in the blt.
;** Furthermore, it's only necessary when there are palettes selected into the
;** driver. The lower level Bitblt code will omit palette mapping if
;** pmappal == 0.
;*/

        xchg    ax,dx                   ;save fbBitblt in DL
        xor     ax,ax                   ;prepare DI:AX for no palette mapping
        xor     di,di

        test    dl,BBF_HAVE_SOURCE
        jz      bb_call_enumeration
        cmp     cPals,0
        jz      bb_call_enumeration

        save    <bx,cx,ds>
        cCall   MakePaletteMappingValid,<npddcSrc,bx>
        xchg    dx,di

bb_call_enumeration:
        mov     obbaBBlt.obba_pmappal.lo,ax
        mov     obbaBBlt.obba_pmappal.hi,di

endif;  PALMGR

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

        CPUMode 386

bb_enum_parm:
        assert  bx,E,hddc.lo            ;Set DC or Bitmap handle into BX
        test    Style.hi,BLTMODE_SCR_DRAW shr 16;AH = 1 if screen DrawBits
        setnz   ah
        test    fbBitblt,BBF_STRETCHBLT ;AL = 1 if stretchBlt
        setnz   al
        add     al,al                   ;make AX = 0 if normal bitblt
        or      al,ah                   ;          1 if screen DrawBits
        cbw                             ;          2 if stretchBlt
        add     ax,ax                   ;then make it word offset
        xchg    ax,bx                   ;AX = hddc.lo
        lea     di,obbaBBlt
        lea     dx,rclDst

        arg     ax                      ;hddc.lo
        arg     ss
        arg     dx                      ;destination clipped rectl
        arg     do_function[bx]         ;low-level function
        cCall   enumerate_clip_rects

        CPUMode 286

bb_been_drawn:


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

        test    FunN.hi,COM_CORRELATE
        jz      bb_good_exit            ;No correlation needed
        mov     si,hddc.lo
        lea     bx,rclDst
        farPtr  prcl,ss,bx
        cCall   <far ptr far_do_corr>,<hdc,prcl,hddc>
        and     ax,2                    ;Make sure this is correct
        jnz     bb_exit_ax
bb_good_exit:
        mov     ax,1                    ;Good return code

bb_exit_ax:
        cwd
        call    leave_driver
bb_exit_no_lock:
        fw_zero <cx,es>

        CPUMode 386

        pop     edi
        pop     esi                     ;we saved them at the beginning

        CPUMode 286
cEnd

page

;/***************************************************************************
;*
;* 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. 
;*                 
;*                 Registers Preserved:        
;*                       SI,DI,DS,BP           
;*                 Registers Destroyed:        
;*                       AX,BX,CX,DX,ES,FLAGS  
;*                 Calls:
;*                       BitBlt
;*                       enter_driver
;*                       leave_driver
;*                       alloc_bm
;*                       free_bm
;*                       far_check_bitmap_info
;*                       validate_rectl
;*
;* 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             
;**************************************************************************/

        check   DrawBits,<hdc,pbBits,pbmiInfoTable,lCount,aptlPoints,lRop,flOptions,hddc,ulFunN>

        assumes cs,Code
        assumes ds,nothing
        assumes es,nothing

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

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

        parmD   hdc
        parmD   pBits
        parmD   pbmi
        parmD   lCount
        parmD   aptlPoints
        parmD   lRop
        parmD   flOptions
        parmD   hddc
        parmD   FunN

        localW  cX                      ;the bitmap width
        localW  cY                      ;the bitmap height
        localW  cBitCount               ;BPP
        localW  cClrUsed                ;number of entries in the color table
        localW  cbRGB                   ;the RGB entry size (RGB or RGB2)
        localV  aptlLocal,%((SIZE POINTL)*NUMBER_OF_POINTS)
        localV  abColor_XLate,DB_MAX_CLR_TBL;the largest color table size (in bytes)
ifdef PALMGR
        localB  fbPal
DB_PALETTE      equ     00000001b       ;dest DC has palette selected
DB_PAL_INDICES  equ     00000010b       ;bmih has palette indices, not RGBs
endif

cBegin
        fw_zero <es,ds>
        ddc?    hddc
        cld


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

db_enter_driver:
        mov     ds,CodeData
        assumes ds,Data
        mov     si,hddc.lo                          ; DS:SI => ddc
        mov     dx,si
        call    enter_driver                        ; DX:AX=0 if error
        njc     db_exit_no_lock                     ; non-available ddc

ifdef PALMGR
        xor     al,al
        test    [si].ddc_fbBelow,DDC_PALETTE
        jz      @F
        inc     al
        .errnz  DB_PALETTE - 1
@@:     mov     fbPal,al
endif

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

        CPUMode 386

db_validate_bmi:
        les     bx,pbmi
        mov     ax,es                               ; if a null header,
        or      ax,bx                               ; need no checking
        jz      db_validate_flOptions
        assumes es,nothing
        mov     cx,1                                ; check all fields
        call    far_check_bitmap_info
        jcxz    db_error_inv_table                  ; CX=0 if not valid

ifdef PALMGR
        cmp     es:[bx].bmp2_cbFix,bmp2_ulColorEncoding
        jbe     db_validate_flOptions
        cmp     es:[bx].bmp2_ulColorEncoding,BCE_PALETTE
        jne     db_validate_flOptions
        test    fbPal,DB_PALETTE
        jz      db_error_inv_table
        or      fbPal,DB_PAL_INDICES
endif

db_validate_flOptions:
        cmp     flOptions.hi,0
        jnz     db_error_bitblt_style
        .errnz  BBO_OR-0
        .errnz  BBO_AND-1
        .errnz  BBO_IGNORE-2
        cmp     flOptions.lo,BBO_IGNORE
        ja      db_error_bitblt_style


db_validate_lcount:
        .errnz  NUMBER_OF_POINTS-4
        cmp     lCount.lo,NUMBER_OF_POINTS
        jne     db_error_length_or_count
        cmp     lCount.hi,0
        je      db_copy_local

        CPUMode 286

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

db_error_length_or_count:
        mov     ax,PMERR_INV_LENGTH_OR_COUNT
        jmp     db_log_error

db_error_bitblt_style:
        mov     ax,PMERR_INV_BITBLT_STYLE
        jmp     db_log_error

db_error_inv_table:
        mov     ax,PMERR_INV_INFO_TABLE
        jmp     db_log_error

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

db_copy_local:
        lds     si,aptlPoints                       ; DS:SI => aptlPoints[0]
        mov     ax,ss
        mov     es,ax
        lea     di,aptlLocal                        ; ES:DI => aptlLocal[0]
        assumes es,nothing
        assumes ds,nothing

        CPUMode 386

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

        CPUMode 286

;/*
;** 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     ds,CodeData
        assumes ds,Data
        mov     si,hddc.lo                          ; DS:SI => ddc
        test    [si].ddc_fb,DDC_UNIT_XFORM          ; Current unit must be pels
        njz     db_leave_driver                     ; Pass to engine

db_validate_rectl:

ifdef   FIREWALLS
        mov     ax,es
        mov     dx,ss
        assert  ax,E,dx
endif;  FIREWALLS

        lea     di,aptlLocal                        ; ES:DI => aptlLocal[0]
        call    validate_rectl                      ; is rectangle valid?
        njc     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:

        CPUMode 386

        xor     edx,edx
        mov     dx,di
        inc     es:[edx].bbp_rclTarg.rcl_xRight     ; Make the target become
        inc     es:[edx].bbp_rclTarg.rcl_yTop       ; an exclusive rectangle

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

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

;/*
;** 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:
        les     bx,pbmi                             ; ES:BX => bmi
        mov     ax,es                               ; if a null header, we then
        or      ax,bx                               ; have to check if it is a
        jz      db_check_null_bits                  ; NULL bits
        assumes es,nothing

        movzx   eax,es:[bx].bmp_cx                  ; assume an old header
        movzx   ecx,es:[bx].bmp_cy
        mov     dx,es:[bx].bmp_cBitCount
        cmp     es:[bx].bmp2_cbFix,bmi_argbColor
        je      short db_have_info

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

ifdef FIREWALLS
        assumes ds,Data
        mov     si,es:[bx].bmp2_cbFix.lo
        assert  si,LE,64
        .errnz  (SIZE BITMAPINFOHEADER2)-64
        shr     si,1
        assert  NC
        add     si,DataOFFSET ok_cbFix
        movzx   si,[si]
        assert  si,NE,0
        assert  es:[bx].bmp2_cbFix.hi,E,0
endif;  FIREWALLS

        mov     eax,es:[bx].bmp2_cx                 ; it is a new header
        mov     ecx,es:[bx].bmp2_cy
        mov     dx,es:[bx].bmp2_cBitCount

ifdef   FIREWALLS
        assert  es:[bx].bmp2_cx.hi,E,0
        assert  es:[bx].bmp2_cy.hi,E,0
        cmp     es:[bx].bmp2_cbFix,bmi_argbColor    ; repeat to regain the flag
endif;  FIREWALLS

db_have_info:
        mov     cX,ax                               ; cache these information
        mov     cY,cx                               ; so we do not have to check
        mov     cBitCount,dx                        ; 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      short db_uncomp_bm                  ;old header's always uncomp
        cmp     es:[bx].bmp2_cbFix,bmp2_cxResolution
        jb      short 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  es:[bx].bmp2_ulCompression.hi,E,0
        mov     ax,es:[bx].bmp2_ulCompression.lo    ;get the compression scheme
        cmp     ax,BCA_RLE8
        je      short db_screen_test
        cmp     ax,BCA_RLE4
        je      short db_screen_test
        cmp     ax,BCA_UNCOMP
        jne     short db_leave_driver

db_uncomp_bm:
        cmp     dx,1                                ;check if it is monochrome
        jne     short 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:
        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
        movzx   ecx,pBits.lo
        add     eax,ecx                              ; size+offset
        and     eax,0ffff0000h
        jz      short db_fake_bm                     ; do not cross boundary

;/*
;** The destination must be SCREEN and the ROP must be SRCCOPY.
;*/

db_screen_test:
        cmp     lRop,ROP_SRCCOPY
        jne     short db_leave_driver

ifdef   FIREWALLS
        mov     ax,ds
        assert  ax,E,CodeData
endif;  FIREWALLS

        mov     si,hddc.lo
        test    [si].ddc_fb,DDC_DEVICE
        jz      short db_leave_driver

ifdef   DD_DRAWBITS
        or      flOptions.hi,BLTMODE_SCR_DRAW shr 16  ; we will have a screen draw
endif;  DD_DRAWBITS

        jmp     short db_fake_bm

        CPUMode 286

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

db_leave_driver:

ifdef   FIREWALLS
        mov     ax,ds
        assert  ax,E,CodeData
endif;  FIREWALLS

        call    leave_driver
        mov     ax,ds
        mov     es,ax
        cleanframe
        assumes ds,nothing
        assumes es,Data
        jmp     pfnDefDrawBits                      ;Pass it back to the engine

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

db_check_null_bits:

        CPUMode 386

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

        CPUMode 286

        xor     cx,cx                               ;CX:SI = source hbm
        xor     si,si
        jmp     db_call_bitblt                      ;when we call BitBlt

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

db_error_no_bm:
        assumes ds,Data
        assumes es,nothing
        and     flOptions.hi,NOT(BLTMODE_SCR_DRAW shr 16)
        mov     ax,PMERR_INSUFFICIENT_MEMORY
        jmp     db_log_error

db_error_inv_dimension:
        mov     ax,PMERR_INV_BITMAP_DIMENSION
        jmp     db_log_error

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

ifdef   FIREWALLS
        mov     ax,ds
        assert  ax,E,CodeData
        assumes ds,Data
endif;  FIREWALLS

        call    alloc_bm
        jcxz    db_error_no_bm                      ; Cannot allocate a bm
        mov     si,ax                               ; DS:SI => bitmap

ifdef   DD_DRAWBITS
        or      flOptions.hi,BLTMODE_SRC_HDBM shr 16; we will have source bitmap
endif;  DD_DRAWBITS

        mov     cx,HDBM_IDENT                       ; CX:SI = source bitmap

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

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

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

        CPUMode 386

        mov     eax,pBits
        mov     ds:[si].bm_sd.sd_pBits,eax
        mov     ax,cX
        mov     cx,cY
        mov     ds:[si].bm_sd.sd_cx,ax
        mul     cBitCount
        add     ax,31
        adc     dx,0
        shrd    ax,dx,5                             ; DWORD alignment
        assert  dx,L,00001000b
        shl     ax,2
        mov     ds:[si].bm_sd.sd_cbScan,ax
        mov     ds:[si].bm_sd.sd_cy,cx
        mov     ds:[si].bm_sd.sd_cySeg,cx
        or      cx,ax                               ; cx or cy must not be 0
        jz      db_call_bitblt                      ; for NONNULL bitmap
        mov     ds:[si].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:

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

        mov     eax,pbmi                            ; Pass the ptr to bitmap info
        mov     dword ptr ds:[si].bm_sd.sd_pbmi,eax
        cmp     cBitCount,24

ifdef   PALMGR
        jne     db_not_24_bpp

;/*
;** If 24 bpp, just store the pPalSeg.
;*/

        test    fbPal,DB_PALETTE
        jz      db_call_bitblt                      ; no palette selected into DC
        mov     bx,hddc.lo
        mov     bx,[bx].ddc_npdevpal
        mov     ax,[bx].devpal_pPalSeg.lo
        mov     dx,[bx].devpal_pPalSeg.hi
        jmp     db_have_color_table

db_not_24_bpp:

else
        je      db_call_bitblt
endif;  PALMGR

        les     bx,pbmi
        assumes es,nothing
        mov     ax,es:[bx].bmp2_cbFix.lo
        mov     dx,size RGB                         ; assume the old header
        mov     cx,cBitCount                        ; assume full rgb table
        cmp     ax,size BITMAPINFOHEADER
        je      short db_full_rgb_tab
        mov     dx,size RGB2                        ; its a new header
        cmp     ax,bmp2_cclrUsed
        jbe     short db_full_rgb_tab
        mov     ax,es:[bx].bmp2_cclrUsed.lo
        or      ax,ax                               ; if 0, full size table
        jnz     short db_have_color_count

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

db_have_color_count:
        mov     cClrUsed,ax
        mov     cbRGB,dx

ifdef   PALMGR
        cmp     cBitCount,1
        je      db_physical_color       ; no palette for 1 bpp
        test    fbPal,DB_PALETTE
        jz      db_physical_color       ; no palette selected into DC

;/*
;** See if the color encoding is BCE_PALETTE.  If it is, then create the color
;** table mapping by compressing the color table into an array of bytes (just
;** truncate the high three bytes).
;*/

        test    fbPal,DB_PAL_INDICES
        jz      db_not_palette_indices

;/*
;** DS:SI --> source color table
;** SS:DI --> destination xlat table
;** ES:DX --> palseg
;**    CX  =  # colors used
;*/

        push    ds
        push    si
        mov     cx,cClrUsed             ;get count before it's decremented
        dec     cClrUsed                ;convenient value

        mov     bx,hddc.lo
        mov     bx,[bx].ddc_npdevpal
        mov     dx,[bx].devpal_pPalSeg.lo
        mov     es,[bx].devpal_pPalSeg.hi
        assumes es,nothing
        lea     di,abColor_XLate
        lds     si,pbmi
        assumes ds,nothing
        add     si,ds:[si].bmp2_cbFix.lo; DS:SI => RGB color table

@@:
        mov     bx,dx
        lodsd
        index?  db_error_inv_index,es,bx,cClrUsed
        palOff  ax
        add     bx,ax
        mov     al,es:[bx].palseg_apalclr.palclr_bCur
        mov     ss:[di],al
        inc     di
        loop    @B

        inc     cClrUsed                ;restore original value
        pop     si
        pop     ds
        mov     dx,ss
        lea     ax,abColor_XLate        ; use it as the color mapping table
        jmp     short db_have_color_table

db_error_inv_index:
        pop     si
        pop     ds
        mov     ax,PMERR_INV_COLOR_INDEX
        jmp     db_log_error

db_not_palette_indices:
        mov     dx,hddc.lo
        arg     si                      ; source bitmap
        arg     dx                      ; destination device
        arg     ax                      ; AX = color used
        arg     cbRGB                   ; number of bytes in an RGB
        save    <si>
        cCall   HDBMDevPalMapper        ; get palette mapping vector
        mov     cx,ax                   ; as the color mapping table
        or      cx,dx                   ; if we have one
        jnz     db_have_color_table     ; we now have color table

endif;  PALMGR

;/*
;** 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     cx,cClrUsed
        lea     di,abColor_XLate
        push    ss
        pop     es                      ; ES:DI => local physical color table
        push    ds                      ; save it
        lds     bx,pbmi
        assumes ds,nothing
        add     bx,ds:[bx].bmp2_cbFix.lo; DS:BX => RGB color table

db_xlate_next_color:
        mov     ax,ds:[bx][0]           ; get blue and green
        mov     dl,ds:[bx][2]           ; get red
        add     bx,cbRGB                ; point to next triplet
        cCall   rgb_to_ipc              ; AL = physical color for RGB

ifdef   CGA
        and     al,MONO_BIT             ;test just the mono color bit
        cmp     al,MONO_BIT             ;carry set if color = 0
        cmc                             ;carry set if color was 1
        sbb     al,al                   ;desired return value
endif;  CGA

        stosb                           ; save the translated color
        loop    db_xlate_next_color     ; do the next color
        pop     ds                      ; restore it
        mov     dx,es
        lea     ax,abColor_XLate        ; use it as the color mapping table

db_have_color_table:
        mov     ds:[si].bm_sd.sd_cySeg,ax           ; Store the pointer to the
        mov     ds:[si].bm_sd.sd_selIncr,dx         ; color mapping table in
        .errnz  sd_selIncr-sd_cySeg-2               ; the overlay field in SD
        .errnz  sd_pClrTab-sd_cySeg

        CPUMode 286

;/*
;** 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:
        check   Bitblt,<hdc,hdcSrc,cptl,pbbp,lMix,flCmd,pbba,hddc,ulFunN>
        xor     ax,ax
        lea     di,aptlLocal                        ; SS:DI => aptlLocal[0]
        farPtr  MyBM,cx,si
        farPtr  Mybbp,ss,di
        farPtr  Mybba,ax,ax
        farPtr  MyFunN,FunN.hi,off_Bitblt
        cCall   Bitblt,<hdc,MyBM,lCount,Mybbp,lRop,flOptions,Mybba,hddc,MyFunN>

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

ifdef   FIREWALLS
        mov     bx,ds
        assert  bx,E,CodeData
        assumes ds,Data
endif;  FIREWALLS

        push    dx                      ;return value in DX:AX is destroyed
        push    ax
        call    free_bm
        pop     ax                      ;restore the return value
        pop     dx
        jmp     short db_done

db_log_error:
        save_error_code
        xor     ax,ax
        cwd                             ; exit with DX:AX=0

db_done:

ifdef   FIREWALLS
        mov     bx,ds
        assert  bx,E,CodeData
        assumes ds,Data
endif;  FIREWALLS

        call    leave_driver

db_exit_no_lock:
        fw_zero <es>

cEnd

sEnd    Code

page

;/***************************************************************************
;*
;* 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 
;*                 Calls:
;*                       far_recalc_correlate_rect
;*                       intersect_rcl
;*                       RectVisible
;*
;* 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 
;*
;**************************************************************************/

sBegin  FarCode
        assumes cs,FarCode

        assumes ds,Data
        assumes es,nothing

cProc   far_do_corr,<FAR,PUBLIC,NODATA,NONWIN>
        parmD   hdc
        parmD   prclToCorr
        parmD   hddc
cBegin
        cCall    do_corr,<hdc,prclToCorr,hddc>
cEnd

cProc   do_corr,<NEAR,PUBLIC,NODATA,NONWIN>,<si,di>
        parmD   hdc
        parmD   prclToCorr
        parmD   hddc
cBegin
        ddc?    si
        test    [si].ddc_fb,DDC_CORR_INV
        jz      dco_have_corr_rect         ; Have corr rect in ddc
        cCall   recalc_correlate_rect      ; Get the corr rect
        jcxz    dco_exit                   ; Null pick window (corr rect)
dco_have_corr_rect:

        lds     si,[si].ddc_prddc
        assumes ds,nothing
        lea     si,[si].rddc_rcsCorr.rcs_yTop
        mov     cx,(size OurRECTS)/2
        .errnz  (size OurRECTS) and 1
        std
dco_make_rcl_loop:
        lodsw
        cwd
        push    dx
        push    ax
        loop    dco_make_rcl_loop
        cld                             ;Before we forget
        .errnz  hi-2
        .errnz  lo
        .errnz  rcs_xLeft
        .errnz  rcs_yBottom-rcs_xLeft-2
        .errnz  rcs_xRight-rcs_yBottom-2
        .errnz  rcs_yTop-rcs_xRight-2

        mov     di,sp                   ;ES:DI-> dst_rcl
        mov     ax,ss
        mov     es,ax
        assumes es,nothing
        lds     si,prclToCorr           ;DS:SI-> src_rcl
        assumes ds,nothing

        mov     bx,1                    ;Want 0 returned if null intersection
        cCall   intersect_rcl
        mov     ds,FarCodeData
        assumes ds,Data
        or      ax,ax
        jz      dco_fix_sp              ;No intersection

        farPtr  prclTemp,es,di
        cCall   pfnDefRectVisible,<hdc,prclTemp,hddc,GreRectVisible>
        assert  ax,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     sp,size RECTL

dco_exit:
cEnd

page

sEnd    FarCode

sBegin  BlueMoon
        assumes cs,BlueMoon

        externW BlueMoonData

;/***************************************************************************
;*
;* 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
;*                 Calls:
;*                       enter_driver
;*                       PropagateSysClrChange
;*                       MakeColorsValid
;*                       AccumBoundsInDevCoords
;*                       enumerate_clip_rects
;*                       do_corr
;*                       leave_driver
;*
;* 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    
;*
;**************************************************************************/

        check   ImageData,<hdc,pbImage,cBits,lRow,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

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

        parmD   hdc
        parmD   lpData
        parmD   N
        parmD   Row
        parmD   hddc
        parmD   FunN

        localV  rclTemp,%(size RECTL)   ;Destination bounding rectangle
        localV  obbaImage,%(size OBB_ARGS)
        localV  sdImage,%(size SURFACE)
        localW  selBitsTemp
cBegin
        ddc?    hddc
        cld
        mov     selBitsTemp,0           ; No selector allocated
        mov     ds,BlueMoonData
        assumes ds,Data
        mov     si,hddc.lo              ;DS:SI --> ddc
        mov     dx,si
        call    enter_driver
        njc     id_exit_no_lock         ; DX:AX = 0 on error

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

        xor     cx,cx
        mov     di,FunN.hi
        test    di,COM_PATH or COM_AREA ;This call is invalid in a path or area
        jnz     id_path_or_area
        test    [si].ddc_fb,DDC_PRESENT ;Must have a surface
        jz      id_no_surface
        cmp     N.hi,cx
        jne     id_invalid_image_length ;Length of data must be 0:32767
        cmp     N.lo,cx
        jl      id_invalid_image_length
        jz      id_good_exit_relay_again;Width of data is zero, nothing to do
        mov     ax,Row.lo               ;Row must be properly sign extended
        cwd
        cmp     dx,Row.hi
        jne     id_inv_row

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

        mov     ax,[si].ddc_iSysClr
        cmp     ax,ddcInit.ddc_iSysClr
        jne     id_update_sys_colors
        test    [si].ddc_ia.ia_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV
        jz      id_colors_are_valid
        jmp     short id_update_colors
id_update_sys_colors:
        cCall   PropagateSysClrChange
id_update_colors:
        lea     bx,[si].ddc_ia.ia_ba
        call    MakeColorsValid
        jns     id_colors_are_valid
        jmp     short id_error_logged_exit


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

id_good_exit_relay_again:
        jmp     id_good_exit

id_path_or_area:
        mov     ax,PMERR_INV_IN_PATH
        test    di,COM_PATH
        jnz     id_log_error_in_ax
        mov     ax,PMERR_INV_IN_AREA
        jmp     short id_log_error_in_ax

id_inv_row:
        mov     ax,PMERR_INV_SCAN_START
        jmp     short id_log_error_in_ax

id_invalid_image_length:
        mov     ax,PMERR_INV_IMAGE_DATA_LENGTH
        jmp     short id_log_error_in_ax

id_no_surface:
        mov     ax,PMERR_BITMAP_NOT_SELECTED
        jmp     short id_log_error_in_ax

id_inv_coordinate:
        mov     ax,PMERR_INV_COORDINATE
        errn$   id_log_error_in_ax

id_log_error_in_ax:
        save_error_code
id_error_logged_exit:
        xor     ax,ax
        jmp     id_exit


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

id_colors_are_valid:

        les     si,[si].ddc_prddc       ; ES:SI = RDDC
        assumes es,nothing
ifdef CUR_POS_IN_DEV_COORDS
        mov     ax,es:[si].rddc_ptsCurPos.pts_x
        mov     bx,es:[si].rddc_ptsCurPos.pts_y
else
        mov     ax,es:[si].rddc_ptsCurPos.pts_x
        sub     ax,es:[si].rddc_ptsOrg.pts_x
        jo      id_inv_coordinate
        mov     bx,es:[si].rddc_ptsCurPos.pts_y
        sub     bx,es:[si].rddc_ptsOrg.pts_y
        jo      id_inv_coordinate
endif
        mov     si,hddc.lo              ; SI = DDC
        fw_zero <es>

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

        sub     bx,Row.lo
        jo      id_inv_coordinate

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

        mov     dx,bx                   ;yTop is the same as yBottom
        mov     cx,ax                   ;xRight = xLeft + count
        add     cx,N.lo
        jo      id_inv_coordinate
        dec     cx                      ;Bounds expects an inclusive rectangle

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

id_check_bounds:                        ;FunN - MSW is commands
        assert  si,E,hddc.lo
        assert  di,E,FunN.hi
        test    di,COM_BOUND+COM_ALT_BOUND
        jz      id_done_bounds
        call    AccumBoundsInDevCoords
        or      ax,ax
        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     bx,bx
        cmp     [si].ddc_crcsClip,bx
        je      id_good_exit_relay
        test    di,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.hi,bx  ;All coordinates will be 0:32767
        mov     rclTemp.rcl_xLeft.hi,bx
        mov     rclTemp.rcl_xRight.hi,bx
        mov     rclTemp.rcl_yBottom.hi,bx
        mov     obbaImage.obba_ySrc,bx
        mov     obbaImage.obba_cyExt,1

        mov     cx,N.lo
        les     si,[si].ddc_prddc
        assumes es,nothing
        mov     ax,es:[si].rddc_ptsCurPos.pts_x
ifdef CUR_POS_IN_DEV_COORDS
        add     ax,es:[si].rddc_ptsOrg.pts_x
        jo      id_good_exit_relay      ;Off the screen in some direction
else
        or      ax,ax
endif
        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                   ;Start here in the image data
        xor     ax,ax                   ;lhs is 0
id_lhs_on_surface:
        mov     rclTemp.rcl_xLeft.lo,ax
        mov     obbaImage.obba_xDst,ax
        mov     obbaImage.obba_xSrc,bx
        add     ax,cx                   ;Exclusive rhs
        mov     dx,ax                   ;rhs for clipping rectangle
        jno     id_rhs_on_surface       ;rhs fits within +32K
        mov     dx,MAXSHORT             ;new rhs
        sub     ax,dx                   ;AX = amount of rhs overhang
        sub     cx,ax
        jle     id_good_exit_relay      ;Nothing will show
id_rhs_on_surface:
        mov     obbaImage.obba_cxExt,cx ;Extent of blt
        mov     rclTemp.rcl_xRight.lo,dx

        mov     ax,es:[si].rddc_ptsCurPos.pts_y
ifdef CUR_POS_IN_DEV_COORDS
        add     ax,es:[si].rddc_ptsOrg.pts_y
        fw_zero <es>
        jo      id_good_exit_relay      ;Off the screen in some direction
endif
        sub     ax,Row.lo
        jl      id_good_exit_relay      ;If below the surface, all done
        mov     rclTemp.rcl_yBottom.lo,ax
        mov     obbaImage.obba_yDst,ax
        inc     ax                      ;7FFF is invisible, and we cannot
        jo      id_good_exit_relay      ; have a RECTL of 7FFF : 8000
        mov     rclTemp.rcl_yTop.lo,ax

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

id_check_draw:
        mov     si,hddc.lo              ; SI = DDC
        mov     al,[si].ddc_fb
        and     ax,di
        and     al,COM_DRAW
        jnz     id_draw_image
        jmp     id_drawing_done
        .errnz  DDC_VISIBLE-COM_DRAW

id_good_exit_relay:
        jmp     id_good_exit

id_draw_image:

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

;/*
;** Because Bitblt expects a 4 byte padding we must copy the bits to a new
;** buffer if the offset is less than 4 bytes
;** when BITBLT_PIPELINE_WORKS the copy code can be removed
;/*
        push    es

id_check_lpData:
        mov     ax,lpData.off
        cmp     ax,4
        jge     id_use_lpData
        lsl     ax,lpData.sel
        or      ax,ax
        jz      id_use_lpData               ; whole segments are OK

        mov     cx,N.lo
        assert  cx,LE,32767
        add     cx,71                       ; 7 + 64; 7 to round up and 64
                                            ;   for the extra 8 bytes;
                                            ;   4 bytes on each end
        shr     cx,3                        ; convert number of bits to bytes
                                            ;   CX = size of data in bytes + 8

        lea     ax,selBitsTemp
        farPtr  MypSel,ss,ax
        cCall   DosAllocSeg,<cx,MypSel,0>

        or      ax,ax
        jz      @F
        mov     bx,ax
        mov     ax,PMERR_BASE_ERROR
        jmp     id_log_error_in_ax
@@:

;/*
;** Copy the bits to the new buffer
;*/

        push    si
        push    ds
        lds     si,lpData
        mov     es,selBitsTemp
        mov     di,4                        ; account for extra leading 4 bytes
        sub     cx,8                        ; account for buffer space

        shr     cx,1                        ; convert bytes to words
        rep     movsw

        rcl     cx,1
        rep     movsb

        pop     ds
        pop     si
        mov     sdImage.sd_pBits.lo,4
        mov     ax,selBitsTemp
        mov     sdImage.sd_pBits.hi,ax

        jmp     short id_pBits_set

id_use_lpData:
        mov     ax,lpData.lo
        mov     sdImage.sd_pBits.lo,ax
        mov     ax,lpData.hi
        mov     sdImage.sd_pBits.hi,ax

id_pBits_set:

        mov     ax,N.lo
        mov     sdImage.sd_cx,ax

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

        mov     bx,CodeBASE
        mov     es,bx
        assumes es,Code

        mov     bx,npbmcMono
        mov     cl,es:[bx].bmc_cRound   ;Round to a dword multiple
        xor     ch,ch
        add     ax,cx
        not     cx
        and     ax,cx
        mov     cl,es:[bx].bmc_cShr
        pop     es
        assumes es,nothing

        shr     ax,cl
        mov     sdImage.sd_cbScan,ax
        mov     sdImage.sd_dScan,ax

id_create_parms:
        mov     obbaImage.obba_pddcDst.off,si
        mov     obbaImage.obba_pddcDst.sel,ds
        lea     ax,sdImage
        mov     obbaImage.obba_psdSrc.off,ax
        mov     obbaImage.obba_psdSrc.sel,ss


;/*
;**  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,[si].ddc_ia.ia_ba.ba_bmix
        assert  al,L,FM_ONE             ;Did GSS miss DEF_FMIX_IMAGE change?
        mov     bx,anpabForeMix[(PRIM_IMAGE-1)*SIZE_WORD]
        xlat    ds:[bx]
        xor     ah,ah                   ;AX = Bitblt rop
        mov     cx,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     [si].ddc_ia.ia_ba.ba_bkmix,BA_IS_OPAQUE
        jnz     id_adjust_foreground_rop
        mov     cx,BBF_SRC_BITMAP or BBF_HAVE_SOURCE
        jmp     short id_adjust_foreground_rop

id_rop_is_nop:
        mov     al,BB_ROP_DSa
        jmpnext
id_rop_is_invert:
        mov     al,BB_ROP_DSx
        jmpnext
id_rop_is_0:
        mov     al,BB_ROP_Sn
        jmpnext
id_rop_is_1:
        mov     al,BB_ROP_S
        jmpnext stop
        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,cx

id_have_foreground_rop:
        mov     obbaImage.obba_usMix,ax

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

        mov     cx,RECTDIR_LFRT_BOTTOP-1 ;Favored direction
        lea     di,obbaImage
        lea     dx,rclTemp
        farPtr  prclClip,ss,dx
        cCall   enumerate_clip_rects,<si,prclClip,CodeOFFSET do_bitblt>
        cmp     ax,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     [si].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.
;*/

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     cx,RECTDIR_LFRT_BOTTOP-1 ;Favored direction
        lea     di,obbaImage
        lea     dx,rclTemp
        farPtr  prclClip,ss,dx
        cCall   enumerate_clip_rects,<si,prclClip,CodeOFFSET do_bitblt>
id_drawing_done:

        cmp     selBitsTemp,0
        jz      id_check_corr
        push    ax
        cCall   DosFreeSeg,<selBitsTemp>
        pop     ax

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

id_check_corr:
        test    FunN.hi,COM_CORRELATE
        jz      id_good_exit            ;No correlation needed
        lea     ax,rclTemp
        farPtr  prclTemp,ss,ax
        cCall   do_corr,<hdc,prclTemp,hddc>
        and     ax,2
        jnz     id_exit
id_good_exit:
        mov     ax,1

id_exit:
        cwd
        call    leave_driver
id_exit_no_lock:
        fw_zero <es,cx>
cEnd

sEnd    BlueMoon

ifdef FIREWALLS
        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
ifdef PALMGR
        public  bb_call_enumeration
endif
        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_check_lpData
        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
