;*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 = BMSUP.ASM 
;*
;* DESCRIPTIVE NAME = Bitmap support 
;*
;*
;* VERSION      V2.0
;*
;* DATE         1/13/88
;*
;* DESCRIPTION  This file contains the routines which manage bitmaps. 
;*
;* FUNCTIONS    Exported:   DeviceCreateBitmap
;*                          DeviceDeleteBitmap
;*                          DeviceSelectBitmap 
;*                          SetBitmapBits 
;*                          GetBitmapBits 
;*              
;*              Public:     deselect_bitmap
;*                          check_bitmap_info
;*                          save_bitmap
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   01/13/88                     First version written by Walt Moore
;*   02/22/88                     Brian Conte 
;*                                 Added hBitmap parameter.
;*   03/21/88                     Martin Picha
;*                                 Implemented DCR 23453.
;*   07/13/88                     Bob Grudem
;*                                 Changed error returned in case of     
;*                                 bitmap dimensions from INV_INFO_TABLE 
;*                                 to INV_BITMAP_DIMENSION.  We now check 
;*                                 for a valid value in bmp_cbFix, and 
;*                                 return INV_LENGTH_OR_COUNT if we don't 
;*                                 find one.
;*   08/09/88                     Lee A. Newberg - Calls bmc_int_to_ext 
;*                                 (instead of bmc_ext_to_int!)
;*   11/15/88                     David Cook
;*                                 Rewrote check_bitmap_info to check fields 
;*                                 of BITMAPINFOHEADER2.
;*
;*   01/09/89                     Walt Moore rewrote
;*   03/22/90                     Viroon Touranachun wrote alloc_uncomp_buffer
;*****************************************************************************/
        .286p
        .xlist

        include        cmacros.inc
INCL_DDIMISC            equ        1
INCL_GRE_BITMAPS        equ        1
INCL_GPIBITMAPS         equ        1
INCL_GPILOGCOLORTABLE   equ        1
INCL_DEV                equ        1
INCL_GRE_DEVSUPPORT     equ        1    ;for off_ConvertBitmapData
INCL_DDICOMFLAGS        equ        1
        include        pmgre.inc
DINCL_BITMAP            equ        1
        include driver.inc
        include njmp.mac
        include assert.mac
        include bmi2.inc
ifdef PALMGR
        include palette.inc
endif
        .list

        ??_out        bmsup

        errcode <INSUFFICIENT_MEMORY,BITMAP_NOT_SELECTED>
        errcode <INCORRECT_DC_TYPE,INV_HBITMAP,INV_INFO_TABLE>
        errcode <INV_IN_PATH, INV_IN_AREA,INV_BITMAP_DIMENSION>
        errcode <INV_LENGTH_OR_COUNT,INV_OR_INCOMPAT_OPTIONS>

MAX_REASONABLE_FMT        equ        24        ;Max format user can request
MAX_BITMAP_DIMENSION    equ     7fffh   ;32K

        externFP        InnerGreEntry
        externFP        GetDriverInfo
        externFP        far_enter_driver
        externFP        far_enter_driver_sem
        externFP        far_leave_driver
        externFP        far_global_alloc
        externFP        far_global_free
        externFP        alloc_bm
        externFP        free_bm
        externFP        far_private_alloc
        externFP        far_private_free

        externA         DOSHUGEINCR
        externA         DOSPAGESIZE

sBegin        Data
        externW npbmcDev                ;Parameters for device's format bitmap
        externW npbmcMono                ;Parameters for mono         format bitmap
        externW npbmcColor                ;Parameters for color         format bitmap
sEnd        Data



sBegin        Bitmap
        assumes cs,Bitmap

        externW BitmapData

        externNP        alloc_far_mem
        externNP        free_far_mem
        externNP        bmc_ext_to_int
        externNP        bmc_int_to_ext


bmp2_check_point    label   byte
        db      dcb_bogus_length_or_count - dcb_bogus_length_or_count
        db      dcb_cBitCount - dcb_bogus_length_or_count
        db      dcb_ulCompression - dcb_bogus_length_or_count
        db      dcb_cbImage - dcb_bogus_length_or_count
        db      dcb_cxResolution - dcb_bogus_length_or_count
        db      dcb_cyResolution - dcb_bogus_length_or_count
        db      dcb_cclrUsed - dcb_bogus_length_or_count
        db      dcb_cclrImportant - dcb_bogus_length_or_count
        db      dcb_usUnits - dcb_bogus_length_or_count
        db      dcb_usReserved - dcb_bogus_length_or_count
        db      dcb_usRecording - dcb_bogus_length_or_count
        db      dcb_usRendering - dcb_bogus_length_or_count
        db      dcb_cSize1 - dcb_bogus_length_or_count
        db      dcb_cSize2 - dcb_bogus_length_or_count
        db      dcb_ulColorEncoding - dcb_bogus_length_or_count
        db      dcb_ulIdentifier - dcb_bogus_length_or_count

bmi2_check_point    label   byte
        db      cbmi_invalid_format - cbmi_ulIdentifier
        db      cbmi_cBitCount - cbmi_ulIdentifier
        db      cbmi_ulCompression - cbmi_ulIdentifier
        db      cbmi_cbImage - cbmi_ulIdentifier
        db      cbmi_cxResolution - cbmi_ulIdentifier
        db      cbmi_cyResolution - cbmi_ulIdentifier
        db      cbmi_cclrUsed - cbmi_ulIdentifier
        db      cbmi_cclrImportant - cbmi_ulIdentifier
        db      cbmi_usUnits - cbmi_ulIdentifier
        db      cbmi_usReserved - cbmi_ulIdentifier
        db      cbmi_usRecording - cbmi_ulIdentifier
        db      cbmi_usRendering - cbmi_ulIdentifier
        db      cbmi_cSize1 - cbmi_ulIdentifier
        db      cbmi_cSize2 - cbmi_ulIdentifier
        db      cbmi_ulColorEncoding - cbmi_ulIdentifier
        db      cbmi_ulIdentifier - cbmi_ulIdentifier

page

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceCreateBitmap
;*
;* DESCRIPTION   = Asks the device driver to create a bitmap.  The device 
;*                 driver may create it in system RAM, or in its own 
;*                 hardware.  The bitmap may be kept in any format.  The 
;*                 device driver returns a handle for the bitmap. The 
;*                 handle is private to the device and will be used only to
;*                 identify the bitmap in calls to the driver. Optionally, 
;*                 the device may be requested to initialize the bitmap.
;*                 Registers Preserved: 
;*                 SI,DI,DS,BP          
;*                 Registers Destroyed:                                                                        
;*                 AX,BX,CX,DX,ES,FLAGS
;* INPUT         = None
;* OUTPUT        = None
;* RETURN-NORMAL = DX:AX = Handle to bitmap
;* RETURN-ERROR  = DX:AX = 0    
;*                 error logged 
;**************************************************************************/

        check        DeviceCreateBitmap,<hdc,pbmih,flCmd,pbBits,pbmi,hddc,ulFunN>

        assumes ds,nothing
        assumes        es,nothing

cProc        DeviceCreateBitmap,<PUBLIC,FAR,NODATA>,<di>

        parmD        hdc
        parmD        lpInfoHdr
        parmD        Usage
        parmD        lpBits
        parmD        lpInitInfo
        parmD        hddc
        parmD        FunN

        localV        bmTemp,%(size BITMAP)        ;Create bitmap header here
        localV  bmiDecomp,%(bmp2_ulCompression + (256*size RGB2))
        localB  fConvBM                 ;indicate there was a bitmap conversion

        DCBF_CONV_BM    equ     00000001b   ;indicate bitmap conversion

cBegin

        CPUMode 386
        push    esi                     ; Save it first
        CPUMode 286
;/*
;** GPI defines the usage bit as CBM_INIT wheras we use BITMAP_USAGE_TRANSLATE
;** everywhere.
;*/

        .errnz        BITMAP_USAGE_TRANSLATE - CBM_INIT

        fw_zero <es,ds>
        ddc?        hddc

        cld
        mov     fConvBM,0               ;clear the flag
        mov        ax,ss                        ;Initialize the temporary bitmap
        mov        es,ax                        ; structure
        assumes es,nothing
        lea        di,bmTemp.bm_sd
        .errnz        bm_sd - 0                ;Surface definition must be first
        mov        ax,SURFACE_IDENT
        stosw
        .errnz        sd_usId                 ;Must be first word of sd_
        mov        ax,INVALID_ADDRESS        ;Make surface pointer be bogus
        stosw                                ;  It will have to be fixed up
        .errnz        sd_npsd-sd_usId-2        ;  once real memory is allocated
        mov        ax,SD_NONNULL                ;Assume cx <> 0 and cy <> 0
        stosw                                ;  until we find out otherwise
        .errnz         sd_fb-sd_npsd-2
        .errnz         sd_fbAccel-sd_fb-1
        xor        ax,ax
        mov        cx,((size BITMAP)/2)-3        ;We just set first three words
        .errnz        (size BITMAP) and 1        ;Must be a word multiple
        rep        stosw
        dec        ax                        ;Default selector is FFFFh
        .erre        INVALID_SEL eq 0FFFFh
        mov     bmTemp.bm_sd.sd_pBits.sel,ax
        mov        bmTemp.bm_hddc,ax        ;Unowned bitmap
        .errnz        INVALID_SEL - (INVALID_ADDRESS and 0FFFFh)


;/* 
;**  Validation of passed parameters:
;** 
;**    Anything less than 0 for planes or bits-per-pixel is considered
;**    an error.  Anything greater than a reasonable number is considered
;**    an error.  0 for planes or bits-per-pixel will be mapped to our
;**    favored format (monochrome or color depending on the display).
;** 
;**    If the passed color format is not one of our internal bitmap
;**    formats, map it to the nearest format.  We will map anything
;**    which isn't a monochrome bitmap to our four plane format (except
;**    0,0 as noted above).
;** 
;**    The maximum allowed extent of the bitmap is 32K-1.
;*/
        les        di,lpInfoHdr
        assumes es,nothing
        CPUMode 386
        mov     esi,es:[di].bmp2_cbFix
        cmp     esi,SIZE BITMAPINFOHEADER
        CPUMode 286
        jne     dcb_new_header
        cmp        es:[di].bmp_cPlanes,MAX_REASONABLE_FMT
        ja        dcb_bogus_format
        cmp        es:[di].bmp_cBitCount,MAX_REASONABLE_FMT
        ja        dcb_bogus_format
        cmp     es:[di].bmp_cx,MAX_BITMAP_DIMENSION
        ja      dcb_bogus_dimension           ;Height and width must be < 32K
        cmp     es:[di].bmp_cy,MAX_BITMAP_DIMENSION
        ja      dcb_bogus_dimension           ;Height and width must be < 32K
        mov     ax,es:[di].bmp_cPlanes
        mov     bx,es:[di].bmp_cBitCount
        mov        si,es:[di].bmp_cx
        mov        di,es:[di].bmp_cy
        jmp     dcb_header_check_done

dcb_bogus_dimension:
        mov        ax,PMERR_INV_BITMAP_DIMENSION
        jmp        dcb_log_error
dcb_bogus_length_or_count:
        mov        ax,PMERR_INV_LENGTH_OR_COUNT
        jmp        dcb_log_error
dcb_bogus_format:
        mov        ax,PMERR_INV_INFO_TABLE
        jmp        dcb_log_error

dcb_new_header:
        CPUMode 386
        cmp     esi,SIZE BITMAPINFOHEADER2
        ja      dcb_bogus_length_or_count
        je      dcb_ulIdentifier
        mov        ds,BitmapData
        assumes ds,Data
        shr     si,1
        jc      dcb_bogus_format
        add     si,DataOFFSET ok_cbFix
        movzx   si,[si]
        add        si,BitmapOFFSET bmp2_check_point
        movzx   si,cs:[si]
        add        si,BitmapOFFSET dcb_bogus_length_or_count
        jmp     si
        assumes ds,nothing
dcb_ulIdentifier:
dcb_ulColorEncoding:
ifdef PALMGR
        cmp     es:[di].bmp2_ulColorEncoding,BCE_RGB
        je        dcb_cSize1
        cmp        es:[di].bmp2_ulColorEncoding,BCE_PALETTE
        jne     dcb_bogus_format
else
        cmp     es:[di].bmp2_ulColorEncoding,BCE_RGB
        jne     dcb_bogus_format
endif
dcb_cSize1:
dcb_cSize2:
dcb_usRendering:
        cmp     es:[di].bmp2_usRendering,BRH_NOTHALFTONED
        jne     dcb_bogus_format
dcb_usRecording:
        cmp     es:[di].bmp2_usRecording,BRA_BOTTOMUP
        jne     dcb_bogus_format
dcb_usReserved:
        cmp     es:[di].bmp2_usReserved,0
        jne     dcb_bogus_format
dcb_usUnits:
        cmp     es:[di].bmp2_usUnits,BRU_METRIC
        jne     dcb_bogus_format
dcb_cclrImportant:
        mov        cx,es:[di].bmp2_cBitCount
        mov     eax,1
        shl     eax,cl              ;CL is taken mod 32 by the instruction
        cmp     es:[di].bmp2_cclrImportant,eax
        ja      dcb_bogus_format
        jmp     SHORT dcb_computed_max_colors_already
dcb_cclrUsed:
        mov        cx,es:[di].bmp2_cBitCount
        mov     eax,1
        shl     eax,cl              ;CL is taken mod 32 by the instruction
dcb_computed_max_colors_already:
        cmp     es:[di].bmp2_cclrUsed,eax
        ja      dcb_bogus_format
dcb_cyResolution:
dcb_cxResolution:
dcb_cbImage:
        cmp     es:[di].bmp2_ulCompression,BCA_UNCOMP
        je      dcb_cBitCount
        cmp     es:[di].bmp2_ulCompression,BCA_RLE24
        jg      dcb_bogus_format
        cmp     es:[di].bmp2_cbImage,0
        jne     dcb_cBitCount
        jmp     dcb_bogus_format
dcb_ulCompression:
        cmp     es:[di].bmp2_ulCompression,BCA_UNCOMP
        jne     dcb_bogus_format
dcb_cBitCount:
        cmp        es:[di].bmp2_cPlanes,MAX_REASONABLE_FMT
        ja        dcb_bogus_format
        cmp        es:[di].bmp2_cBitCount,MAX_REASONABLE_FMT
        ja        dcb_bogus_format
        cmp     es:[di].bmp2_cx,MAX_BITMAP_DIMENSION
        ja      dcb_bogus_dimension           ;Height and width must be < 32K
        cmp     es:[di].bmp2_cy,MAX_BITMAP_DIMENSION
        ja      dcb_bogus_dimension           ;Height and width must be < 32K
        CPUMode 286
        mov     ax,es:[di].bmp2_cPlanes
        mov     bx,es:[di].bmp2_cBitCount
        mov        si,es:[di].bmp2_cx.lo
        mov        di,es:[di].bmp2_cy.lo
dcb_header_check_done:
        mov        bmTemp.bm_sd.sd_cx,si
        mov        bmTemp.bm_sd.sd_cy,di
        or        si,si                   ; check x dimension

NONULL        equ        1                        ;!!! if we decide to disallow null
ifdef        NONULL                               ;    bitmaps, some special casing
        njle        dcb_bogus_dimension           ;    will have to be removed.
else                                            
        njl        dcb_bogus_dimension
        jz        dcb_null_bitmap
endif        ;NONULL

        or        di,di                   ; check y dimension
ifdef        NONULL
        njle        dcb_bogus_dimension
else
        jg        dcb_good_format
        njl        dcb_bogus_dimension

;/*
;** They want a bitmap with a height or width of 0.  Set the special
;** flags for this condition and fall through the rest of the code.
;*/

dcb_null_bitmap:
        and        Usage.lo,not BITMAP_USAGE_TRANSLATE
        and        bmTemp.bm_sd.sd_fb,not SD_NONNULL
endif        ;NONULL


;/*
;** The format looks good.  If the translate option is set, then make sure
;** the bits are in a format we can deal with. If not, we won't attempt to
;** create the bitmap.  If the format is valid, then translating the bits
;** cannot fail and we won't have to worry about backing out of the code
;** once the bitmap is allocated.
;*/

dcb_good_format:
        mov        ds,BitmapData
        assumes ds,Data
        test        Usage.lo,BITMAP_USAGE_TRANSLATE
        jz        dcb_good_translate_data
        push    ax
        push    bx
        push    si
        les        bx,lpInitInfo
        assumes es,nothing
        mov     cx,1                  ; signal to check all entered fields
        call        far ptr far_check_bitmap_info
        pop     si
        pop     bx
        pop     ax
        njcxz        dcb_bogus_format        ;Unknown format for the bits

;/*
;** There's still a possibility of error, if the color encoding is BCE_PALETTE
;** but there isn't a palette selected into the DC (whether or not the bitmap
;** is selected into the DC).
;*/

        push        bx
        mov        bx,lpInitInfo.lo
        CPUMode 386
        cmp        es:[bx].bmi2_cbFix,bmi2_ulColorEncoding
        jbe        dcb_color_encoding_ok
        cmp        es:[bx].bmi2_ulColorEncoding,BCE_PALETTE
        jne        dcb_color_encoding_ok
        CPUMode 286

;/*
;** The color encoding is BCE_PALETTE.  If the DC doesn't have a palette
;** selected, then return an error.
;*/

        mov        bx,hddc.lo
        test        [bx].ddc_fbBelow,DDC_PALETTE
        jnz        dcb_color_encoding_ok
        xor        cx,cx

dcb_color_encoding_ok:
        pop        bx
        njcxz        dcb_bogus_format        ;Unknown format for the bits

dcb_good_translate_data:


;/* 
;**  Get a pointer to the parameter block used for color format and
;**  computing memory requirements:
;*/ 

        mov        ah,bl                        ;AH = Bitcount, AL = planes
        mov        bx,npbmcDev
        or        al,al                        ;Device's format if either
        jz        dcb_have_data_table        ;  bitcount or planes is 0
        or        ah,ah
        jz        dcb_have_data_table
        mov        bx,npbmcMono
        cmp        ax,0101h
        je        dcb_have_data_table        ;1,1 - Monochrome
        mov        bx,npbmcColor                ;?,? - Color
dcb_have_data_table:

;/*
;**  If this is a null bitmap, we had to come this far to pick up the color
;**  format just incase they try a GetBitmapBits on it.  We can skip the
;**  memory calculation for a null bitmap.
;**
;**   Currently:
;**  
;**          CS:BX --> bitmap parameter table
;**          SI = width in pels    (guaranteed < 32K)
;**          DI = height in scans  (guaranteed < 32K)
;*/

        push        CodeBASE
        CPUMode 386
        pop        gs
        assumes gs,Code
        mov        al,gs:[bx].bmc_fbColor
        or        bmTemp.bm_sd.sd_fb,al        ;Flag as color if format is color
        test        bmTemp.bm_sd.sd_fb,SD_NONNULL
        jnz        short dcb_os2_alloc        ;Go allocate memory
        jmp        dcb_os2_alloc_ok        ;No global memory needed

;/*
;**   Compute the size of a single scan of the bitmap, and the size of all
;**   planes of a single scan.
;*/

        public        dcb_os2_alloc
dcb_os2_alloc:
        mov        cl,gs:[bx].bmc_cRound        ;Round to a dword multiple
        xor        ch,ch
        add        si,cx
        not        cx
        and        si,cx
        mov        cl,gs:[bx].bmc_cShr
        shr        si,cl
        mov        bmTemp.bm_sd.sd_cbScan,si
        mov        al,gs:[bx].bmc_cPlanes
        CPUMode 286
        xor        ah,ah
        mul        si
        mov        si,ax
        mov        bmTemp.bm_sd.sd_dScan,ax

;/*
;** Compute the total amount of memory required for the bitmap.  Our hope
;** is that with a single quick multiply we will determine that it isn't
;** a huge bitmap.
;*/

        xor        cx,cx                        ;Want to end up with size in DX:AX
        mul        di
        jno        dcb_have_size
        dec        dx
        jnz        dcb_its_a_biggie
        inc        dx
        or        ax,ax
        jz        dcb_have_size
dcb_its_a_biggie:

;/*
;** The bitmap is a huge bitmap.        We will have to compute how much memory
;** must be allocated for all the scans.        All planes of a scanline must
;** fit within a segment.
;**
;** Currently:
;**        SI = sd_dScan
;**        DI = sd_cy
;*/

dcb_huge_bitmap:
        or        bmTemp.bm_sd.sd_fb,SD_HUGE
        mov     bmTemp.bm_sd.sd_selIncr,DOSHUGEINCR

        xor        ax,ax                        ;Compute how many scans will fit
        cwd                                ;  in a 64K segment.  The remainder
        inc        dx                        ;  is the fill bytes count

;/*
;** This division cannot overflow.  SI cannot be zero since we explicitly
;** tested for a bitcount of zero.  SI is at least 4 since we always allocate
;** to a dword boundary.        Anyway, a GP-Fault here is as good as a firewall.
;*/

        div        si

;/*
;** DX = number of unused bytes per 64K segment.        AX is the number of scans
;** which will fit within a 64K segment.        Dividing the number of scans by AX
;** will give us the number of 64K segments required.  The remainder from
;** this * the number of bytes per scan will give us the number of bytes
;** needed for the last 64K segment.
;*/

        mov        bmTemp.bm_sd.sd_cbFill,dx
        mov        bmTemp.bm_sd.sd_cySeg,ax
        xchg        ax,di
        cwd                                ;Will be zero since max is 32K-1
        div        di                        ;DX = scans for last seg
        xchg        ax,di                        ;Set DI = full 64K segments needed
        xchg        ax,si                        ;Set AX = bytes per scan
        mul        dx                        ;AX is number of bytes for last seg
        mov        dx,di                        ;DX:AX = memory needed

dcb_have_size:

ifndef BITBLT_PIPELINE_WORKS

;/*
;** We'll allocate an extra dword on the end of the bitmap
;** to help prevent a GP-Fault.  Also an extra one at the beginning.
;*/

        or        ax,ax
        jz        @F
        add     ax,SIZE_DWORD+SIZE_DWORD
        jnc        @F
        xor        ax,ax
        inc        dx
@@:

; Don't want to offset start if a hugh bitmap.
        test        bmTemp.bm_sd.sd_fb,SD_HUGE
        jnz     dcb_global_alloc
endif

;/*
;** Decide where are we going to allocate the bits from?
;**   FarHeap if size <= MAX_FAROBJ_SIZE
;**   Global memory otherwise
;*/


        or        dx,dx
        jnz     dcb_global_alloc

ifndef BITBLT_PIPELINE_WORKS
        mov     bmTemp.bm_sd.sd_pBits.off,SIZE_DWORD
endif

        cmp        ax,DOSPAGESIZE
        ja        dcb_global_alloc

dcb_heap_alloc:
        push        ax
        cCall        alloc_far_mem
        pop        bx
        jcxz        dcb_global_alloc_pop        ;We may run out of heap space

        mov     bmTemp.bm_sd.sd_pBits.sel,dx

ifndef BITBLT_PIPELINE_WORKS
        add     bmTemp.bm_sd.sd_pBits.off,ax
else
        mov     bmTemp.bm_sd.sd_pBits.off,ax
endif

        or      bmTemp.bm_sd.sd_fb,SD_HEAPBITS  ;Remember that it is from heap
        jmp     short   dcb_os2_alloc_ok

dcb_global_alloc_pop:
        mov        ax,bx                        ; DX:AX = size to allocate
        assert        dx,E,0                    ; it must have been < 64K
dcb_global_alloc:
        lea     bx,bmTemp.bm_sd.sd_pBits.sel    ;SS:BX = where selector goes
        sub        cx,cx
        call        far_global_alloc        ;Allocate the memory
        jcxz        dcb_os2_alloc_ok        ;Allocate succeeded
        jmp        short dcb_no_memory      ;No selector allocated so far
                                            ;  so we can just fall through

;/*
;** The local memory allocation failed.  Free the global memory and return
;** the error to the caller.  If the global alloc failed or the bitmap is
;** NULL, the selector will be INVALID_SEL.
;*/

dcb_cbm_fail:
        mov     cx,lpBits.hi            ;selector of decomp. bits in lpBits.hi
        cCall   far_private_free

dcb_free_bm:
        xchg    si,di                   ;move hbm to SI
        call    free_bm

dcb_free_global_mem:
        test    bmTemp.bm_sd.sd_fb,SD_HEAPBITS
        jz      dcb_free_global

dcb_free_heap:
        mov     dx,bmTemp.bm_sd.sd_pBits.sel
        mov     ax,bmTemp.bm_sd.sd_pBits.off

ifndef BITBLT_PIPELINE_WORKS

        sub     ax,SIZE_DWORD

endif

        call    free_far_mem
        jmp     short dcb_no_memory

dcb_free_global:
        mov     cx,bmTemp.bm_sd.sd_pBits.sel    ;If NULL bitmap, then the
        inc     cx                              ; selector will be INVALID_SEL
        jz        dcb_no_memory
        .errnz        INVALID_SEL-0FFFFh
        dec        cx
        call        far_global_free         ;Takes selector in CX

dcb_no_memory:
        test    fConvBM,DCBF_CONV_BM
        jnz     dcb_error_exit          ;ConvertBitmapData has its own log error
        mov        ax,PMERR_INSUFFICIENT_MEMORY

dcb_log_error:
        save_error_code

dcb_error_exit:
        xor        ax,ax
        cwd
        jmp        dcb_we_go_home_now


;/*
;** We're half way home.  The global allocation was successful.  Now
;** allocate space for the local bitmap information in our heap and
;** copy the bits into it.
;*/

dcb_os2_alloc_ok:
        call        alloc_bm                ;Allocate the bitmap header
        jcxz        dcb_free_global_mem        ;Allocation failed
        mov        di,ax                        ;--> the real bitmap in our DS
        mov        es,BitmapData
        assumes es,Data
        lea        si,bmTemp
        .errnz        bm_sd
        movs        word ptr es:[di],word ptr ss:[si]
        .errnz        bm_sd.sd_usId
        stosw                                ;Set surface pointer
        inc        si                        ;Skip over surface pointer in temp
        inc        si                        ;  structure
        .errnz        bm_sd.sd_npsd-2         ;Must be second word
        mov        cx,((size BITMAP)/2)-2        ;Already moved two words
        .errnz        (size BITMAP) and 1
        rep        movs word ptr es:[di],word ptr ss:[si]
        sub        di,size BITMAP                ;--> back to the bitmap


;/*
;** We now have a complete bitmap structure, fully valid, in our DS.
;** Now initialize the bitmap if there were bits passed in.
;*/

        test        Usage.lo,BITMAP_USAGE_TRANSLATE
        njz        dcb_initialize_done

;/*
;** We have to check whether the bits is in a compressed form. If so, we
;** have to decompress it prior to the translation.
;*/

        CPUMode 386
        les     bx,lpInitInfo

        .errnz  bmp2_cbFix
        .errnz  bmp2_cx-bmp2_cbFix-4
        .errnz  bmp2_cy-bmp2_cx-4
        .errnz  bmp2_cPlanes-bmp2_cy-4
        .errnz  bmp2_cBitCount-bmp2_cPlanes-2
        .errnz  bmp2_ulCompression-bmp2_cBitCount-2
        .errnz  bmp2_cbImage-bmp2_ulCompression-4
        .errnz  bmp2_cxResolution-bmp2_cbImage-4

        cmp     es:[bx].bmp2_cbFix,bmp2_cxResolution
        jb      dcb_translate_bits      ;compression not supported in old Info
        cmp     es:[bx].bmp2_ulCompression,BCA_UNCOMP
        je      dcb_translate_bits      ;not a compressed bits

dcb_decompress_bits:
        cCall   <far ptr alloc_uncomp_buffer> ;allocate a temporary buffer
        or      ecx,ecx
        jz      dcb_free_bm             ;ECX = 0 if fails to allocate one
        xchg    lpBits.lo,ax            ;make DX:AX  => compressed bits buffer
        xchg    lpBits.hi,dx            ;     lpBits => uncompressed bits buffer
        or      fConvBM,DCBF_CONV_BM    ;we will convert this bitmap

;/*
;** we want to duplicate the bitmapinfo structure from bmp2_cx to bmp2_cBitCount
;** fields
;*/
        push    di                      ;save near ptr to surface
        push    ss
        pop     es
        assumes es,nothing
        lea     bx,bmiDecomp            ;SS:BX => local bitmap info
        mov     di,bx                   ;ES:DI => local bitmap info
        lgs     si,lpInitInfo
        assumes gs,nothing
        mov     cx,bmp2_ulCompression
        shr     cx,2

        .errnz  bmp2_ulCompression and 3

        rep     movs dword ptr es:[di],dword ptr gs:[si];we need information
        mov     ss:[bx].bmp2_cbFix,bmp2_ulCompression   ;upto bmp2_cBitCount
        pop     di                      ;DS:DI => surface

        xor     ecx,ecx
        farPtr  MyCmd,cx,CBD_DECOMPRESSION
        farPtr  MylpCompBits,dx,ax
        farPtr  MylpDecompBmi,ss,bx
        farPtr  MyFunN,cx,off_ConvertBitmapData
        check   ConvertBitmapData,<hdc,ulCmd,ulOption,pbmiSrc,pbBitsSrc,pbmiDst,pbBitsDst,hddc,ulFunN>
        cCall        InnerGreEntry,<hdc,MyCmd,ecx,lpInitInfo,MylpCompBits,MylpDecompBmi,lpBits,ecx,MyFunN>
        or      ax,dx
        jz      dcb_cbm_fail

        CPUMode 286

dcb_translate_bits:
        xor        ax,ax
        farPtr        lcy,<ax>,<[di].bm_sd.sd_cy>
        farPtr        FirstScan,<ax>,<ax>
        arg        di                        ;Handle to the bitmap
        arg        lpInitInfo
        arg        lpBits
        arg        lcy
        arg        FirstScan

ifdef PALMGR
        farPtr        pPal,<[si].devpal_pPalSeg.hi>,<[si].devpal_pPalSeg.lo>
        arg        pPal
        arg        hddc

        mov        si,hddc.lo
        mov        si,[si].ddc_npdevpal
endif
        cCall        bmc_ext_to_int

ifdef FIREWALLS
;/*
;** Since we validated the format of the incoming bits, and we set the
;** start scan and the scan count, this should never have failed.
;*/

        or        dx,dx                        ;Return count must match the number
        jnz        dcb_set_failed                ; of scans we passed in
        cmp        ax,[di].bm_sd.sd_cy
        je        @F
dcb_set_failed:
        rip        text,<DeviceCreateBitmap - Setting bits should not have failed>
@@:
endif

;/*
;** Now we can free the temporary decompressed buffer, if we did conversion.
;*/
        test    fConvBM,DCBF_CONV_BM    ;did we have a conversion?
        jz      dcb_initialize_done
        mov     cx,lpBits.sel           ;selector in lpBits.sel
        cCall   far_private_free

dcb_initialize_done:
        xchg        ax,di                        ;DX:AX - handle to bitmap
        mov        dx,HDBM_IDENT

dcb_we_go_home_now:
        fw_zero <es,cx>

        CPUMode 386
        pop     esi                     ; Restore it
        CPUMode 286

cEnd
page

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceDeleteBitmap
;*
;* DESCRIPTION   = Asks the device driver to delete a bitmap that 
;*                 it created.  The given handle is the one returned 
;*                 from DeviceCreateBitmap. Optionally, the device may 
;*                 be asked to translate the bitmap to a standard format 
;*                 before deleting it.                              
;*                 Registers Preserved:  
;*                 SI,DI,DS,BP           
;*                 Registers Destroyed:  
;*                 AX,BX,CX,DX,ES,FLAGS  
;*
;* INPUT         = None
;* OUTPUT        = None
;*
;* RETURN-NORMAL = DX:AX = 1 
;* RETURN-ERROR  = DX:AX = 0    
;*                 error logged 
;**************************************************************************/

        check        DeviceDeleteBitmap,<hdc,hbm,pdr,flCmd,hddc,ulFunN>

        assumes ds,nothing
        assumes        es,nothing

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

        parmD        hdc
        parmD        dhBitmap
        parmD        lpReturns
        parmD        Usage
        parmD        hddc
        parmD        FunN

        localW        selBits                 ;Selector for returned bits
        localW        selInfo                 ;Selector for return info table
        localW        npInfoData                ;Data for generating BITMAPINFO

cBegin
        cld
        fw_zero <es>

        mov        ds,BitmapData                ;!!!do this to prevent two
        assumes ds,Data                         ;!!! people from deleting the same
        call        far_enter_driver_sem        ;!!! bitmap at the same time
        njc        ddb_exit_no_lock             ; DX:AX = 0 on error

ifdef FIREWALLS

;/*
;** Make sure the bitmap belongs to us.  If not, the engine screwed up.
;*/

        cmp        dhBitmap.hi,HDBM_IDENT
        jne        ddb_bad_handle
        mov        bx,dhBitmap.lo
        cmp        [bx].bm_sd.sd_usId,SURFACE_IDENT
        jne        ddb_bad_handle
        test        [bx].bm_sd.sd_fb,SD_DEVICE
        jnz        ddb_bad_handle

;/*
;** The Engine should never allow us to delete a bitmap which is currently
;** selected into a ddc.        This is an Engine error if it occurs.
;*/

        cmp        [bx].bm_hddc,INVALID_ADDRESS ;Selected into an hDC?
        jne        ddc_bitmap_selected        ;  (we also firewall ourselves
        cmp        [bx].bm_cSelect,0        ;  here also by checking both
        je        ddc_bitmap_free_agent        ;  fields we maintain).

ddc_bitmap_selected:
        rip        text,<DeviceDeleteBitmap - Bitmap currently selected into a ddc>
        xor        ax,ax
        jmp        ddb_we_be_gone

ddb_bad_handle:
        rip        text,<DeviceDeleteBitmap - Invalid bitmap or bitmap handle>
        xor        ax,ax
        jmp        ddb_we_be_gone

ddb_bits_selector_bad:
        rip        text,<DeviceDeleteBitmap - selector to bits is null/not null>
        xor        ax,ax
        jmp        ddb_we_be_gone

;/*
;** As an added FIREWALL, make sure that we have a handle to bits if
;** the bitmap is non-null, and make sure there is no handle if the
;** bitmap is supposed to be null.
;*/

ddc_bitmap_free_agent:
        mov     cx,[bx].bm_sd.sd_pBits.sel  ;Set CX=0 if NULL
        inc        cx
        test        [bx].bm_sd.sd_fb,SD_NONNULL
        jnz        ddb_want_selector
        jcxz        ddc_selector_is_ok
        xor        cx,cx
ddb_want_selector:
        jcxz        ddb_bits_selector_bad
ddc_selector_is_ok:
endif        ; FIREWALLS

        assumes ds,Data
        assumes es,nothing

;/*
;** If the translate option is set, then enough global memory to hold
;** both the bitmap and the information table must be allocated and the
;** bitmap translated into it.  If no memory exists then return an error.
;*/

        mov        si,dhBitmap.lo
        test        Usage.lo,BITMAP_USAGE_TRANSLATE
        jz        v_ddb_xlate_done_if_needed
        mov        selBits,0
        test        [si].bm_sd.sd_fb,SD_NONNULL
        jz        ddb_alloc_info_seg        ;Null bitmap, no global mem needed

;/*
;** The maximum memory needed will be (sd_dScan * sd_cy).  For packed-
;** pixel formats, since we allocated to a double word boundary, this
;** will be an exact fit.  For planer formats, there will be some slop
;** in this calculation, a maximum of (sd_cy * (#planes-1)) bytes.  It
;** makes life easier to just ignore this slop.
;*/

        mov        ax,[si].bm_sd.sd_dScan
        mul        [si].bm_sd.sd_cy
        lea        bx,selBits                ;Selector will be at SS:[BX]
        sub        cx,cx
        call        far_global_alloc        ;Alloc DX:AX bytes of global memory
        or        cx,cx
        jnz        ddb_no_memory                ;Assume no memory for bitmap

ddb_alloc_info_seg:
        mov        di,npbmcColor
        test        [si].bm_sd.sd_fb,SD_COLOR
        jnz        ddb_its_color
        mov        di,npbmcMono
ddb_its_color:
        mov        ax,CodeBASE
        CPUMode 386
        mov        gs,ax
        assumes gs,Code

        mov        ax,gs:[di].bmc_cbInfo
        CPUMode 286
        cwd
        lea        bx,selInfo                ;Allocate info segment
        sub        cx,cx
        call        far_global_alloc        ;Alloc DX:AX bytes of global memory
        jcxz        ddb_have_all_memory
        mov        cx,selBits                ;Don't free bits memory if it
        jcxz        ddb_no_memory                ;  wasn't allocate
        call        far_global_free         ;Takes selector in CX


ddb_no_memory:
        mov        ax,PMERR_INSUFFICIENT_MEMORY

ddb_log_error:
        save_error_code
        xor        ax,ax
        jmp        ddb_we_be_gone

v_ddb_xlate_done_if_needed:
        jmp        ddb_xlate_done_if_needed

;/*
;** We have memory for both the BITMAPINFO structure and for the bits.
;** Set up and call the internal-to-external conversion routine.        We
;** must explicitly request a format for the bits to be returned in.
;** This will be either mono or color based on the bitmap format.
;** We must also return the two pointers to the Engine.
;*/

ddb_have_all_memory:
        mov        ax,CodeBASE
        mov        es,ax
        assumes es,Code

        mov        dl,es:[di].bmc_cBitCount
        xor     dh,dh

        xor        ax,ax
        cld                                ;Fill in the delete/return structure
        mov        cx,selInfo
        mov        bx,selBits
        les        di,lpReturns
        assumes es,nothing
        stosw
        xchg        ax,cx
        stosw
        xchg        ax,cx
        .errnz        dr_pInfo                ;Must be first field
        stosw
        xchg        ax,bx
        stosw
        .errnz        dr_pBits-dr_pInfo-4
;/*
;** BX = 0, AX = lpBits.sel, CX = lpInfo.hi
;*/
        mov        es,cx
        assumes es,nothing
;/*
;** Info structure is at ES:0 (can use that BX = 0)
;*/
        CPUMode 386
        mov     es:[bx].bmi2_cbFix,16
        .errnz  bmi2_cBitCount + (SIZE bmi2_cBitCount) - 16
        mov        es:[bx].bmi2_cPlanes,1        ;Always 1 plane
        mov        es:[bx].bmi2_cBitCount,dx
        CPUMode 286
;/*
;** The scan count depends on whether or not this is a null bitmap
;*/
        xor        cx,cx                       ;put scans to translate into CX
        test        [si].bm_sd.sd_fb,SD_NONNULL
        jz        ddb_xlate_have_scan_count
        mov        cx,[si].bm_sd.sd_cy
ddb_xlate_have_scan_count:

;/*
;**   AX = selector of bits
;**   BX = (don't care)
;**   CX = number of scans
;**   DX = (unused)
;**   DI = ifdef PALMGR hddc.lo else (unused) endif
;**   SI = bitmap
;**   DS = Data
;**   ES = Info selector
;*/

        xor        bx,bx
        mov        di,hddc.lo
        farPtr        MylpInfo,es,bx
        farPtr        lpBits,ax,bx
        farPtr        lcy,bx,cx
        farPtr        FirstScan,bx,bx
        farPtr        pClrTbl,<[di].ddc_pClrTbl.hi>,<[di].ddc_pClrTbl.lo>

        arg        si
        arg        MylpInfo
        arg        lpBits
        arg        lcy
        arg        FirstScan
        arg        pClrTbl
ifdef PALMGR
        arg        di
endif

        cCall        bmc_int_to_ext

ifdef FIREWALLS
        xor        cx,cx                       ;put scans to translate into CX
        test        [si].bm_sd.sd_fb,SD_NONNULL
        jz        @F
        mov        cx,[si].bm_sd.sd_cy
@@:

;/*
;** Since we prepared all the parameters to the conversion routine, the
;** call should never fail.
;*/

        or        dx,dx                        ;Return count must match the number
        jnz        ddb_set_failed                ; of scans we passed in
        cmp        ax,cx
        je        @F
ddb_set_failed:
        rip        text,<DeviceDeleteBitmap - Getting bits should not have failed>
@@:
endif

;/*
;** Any translation has been performed.  Now try and free the bitmap.
;** We've FIREWALLed the bitmap being selected, so we don't need to
;** check that.  We can assume it is now a free agent.
;** !!! we shouldn't call out to OS/2 with the semaphore locked!!!
;*/

ddb_xlate_done_if_needed:
        test    [si].bm_sd.sd_fb,SD_HEAPBITS
        jz      ddb_global_free

ddb_heap_free:
        mov     dx,[si].bm_sd.sd_pBits.sel
        mov     ax,[si].bm_sd.sd_pBits.off

ifndef BITBLT_PIPELINE_WORKS

        sub     ax,SIZE_DWORD

endif

        call    free_far_mem
        jmp     short ddb_free_header

ddb_global_free:
        mov     cx,[si].bm_sd.sd_pBits.sel  ;If no segment, don't free it
        inc        cx
        jz        ddb_free_header
        dec        cx
        call        far_global_free         ;Takes selector in CX
ddb_free_header:
        cCall        free_bm                 ;Takes handle in SI
        mov        ax,1

ddb_we_be_gone:
        cwd
        call        far_leave_driver
ddb_exit_no_lock:
        fw_zero <es,cx>
cEnd
page

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceSelectBitmap
;*
;* DESCRIPTION   = Select a new bitmap into the given ddc. 
;*                 Registers Preserved:  
;*                 SI,DI,DS,BP           
;*                 Registers Destroyed:  
;*                 AX,BX,CX,DX,ES,FLAGS  
;*                 Calls:                
;*                 deselect_bitmap       
;*
;* INPUT         = None
;* OUTPUT        = None
;*
;* RETURN-NORMAL = DX:AX = 1 
;* RETURN-ERROR  = DX:AX = 0 
;*                 error logged 
;**************************************************************************/

        check        DeviceSelectBitmap,<hdc,hbm,hddc,ulFunN>

        assumes ds,nothing
        assumes        es,nothing

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

        parmD        hdc
        parmD        Handle
        parmD        hddc
        parmD        FunN

cBegin
ifdef FIREWALLS
        fw_zero <es>
        mov        ds,BitmapData
        assumes ds,Data
        ddc?        hddc,<MEMORYDDC,SURFACE>
  
;/*
;** If the bitmap handle passed in isn't NULL, then validate the
;** bitmap to make sure it isn't selected into another ddc.  It is
;** valid for it to be selected into this ddc.
;*/

        mov        ax,Handle.hi                ;Null is allowed
        mov        si,Handle.lo
        mov        cx,ax
        or        cx,si
        jz        dsb_fw_ok_so_far
        cmp        ax,HDBM_IDENT
        jne        dsb_bad_handle
        cmp        [si].bm_sd.sd_usId,SURFACE_IDENT
        jne        dsb_bad_handle
        test        [si].bm_sd.sd_fb,SD_DEVICE
        jnz        dsb_bad_handle
        cmp        [si].bm_cSelect,0
        je        dsb_fw_ok_so_far
        mov        ax,hddc.lo
        cmp        [si].bm_hddc,ax
        je        dsb_fw_ok_so_far

dsb_bad_hddc_link:
;Engine should have caught this
        rip        text,<DeviceSelectBitmap - Bitmap in use in different ddc>
        xor        ax,ax
        jmp        short dsb_tour_of_duty_over

dsb_bad_handle:
        rip        text,<DeviceSelectBitmap - Invalid bitmap or bitmap handle>
        xor        ax,ax
        jmp        short dsb_tour_of_duty_over

dsb_fw_ok_so_far:

;/*
;** The bitmap currently selected into the ddc must be linked back to
;** this hddc and have a lock count > 0.        If no bitmap is selected,
;** then ddc_npsd must be FFFF.  This was checked by the SURFACE command
;** to ddc?.  ddc? also checked to make sure there was a selector for
;** a non-null bitmap, or that it was zero for a NULL bitmap.
;*/

        fw_zero <es,ds>
endif

        mov        ds,BitmapData
        assumes ds,Data
        mov        si,hddc.lo                ;si --> ddc
        mov        dx,si
        call        far_enter_driver        ;!!! bitmap at the same time
        jc        dsb_exit_no_lock        ; DX:AX = 0 on error


;/*
;** Unselect the bitmap currently selected into the DC.  The following
;** needs to be performed if there was a bitmap previously selected.
;**
;** In the ddc:
;**
;**        a) clear DDC_PRESENT to show no surface
;**
;**        b) clear DDC_NOTIFY_CLIP to show clipping is invalid
;**
;**        c) clear DDC_VISIBLE to show nothing shows
;**
;**        d) clear ddc_npsd to show no bitmap is selected
;**
;** In the bitmap:
;**
;**        e) decrement the selection count.
;**
;**        f) if the selection count is zero, clear bm_hddc to show
;**           a free bitmap.
;**
;*/

        call        far ptr far_deselect_bitmap            ;Deselect [SI].ddc_npsd


;/*
;** Select the new surface into the ddc.        If there isn't one, then steps
;** a through d from unselecting the surface will have performed all the
;** work necessary.  If there was no surface, then the state of these
;** flags would have been checked by the SURFACE portion of ddc? to make
;** sure that were correct.  If there is a new surface, then:
;**
;** In the bitmap:
;**
;**        a) increment the selection count.
;**
;**        b) Set bm_hddc to be this hddc.
;**
;** In the ddc:
;**
;**        d) Set ddc_npsd to the bitmap's handle
;**
;**        e) copy surface definition into the ddc.
;**
;**        c) Set DDC_PRESENT to show a surface
;**
;**  Currently:
;**         SI --> hddc (ddc_)
;*/

dsb_old_unselected:
        mov        di,Handle.lo                ;Only test .lo since we FIREWALLed
        or        di,di                        ;  the .hi being HDBM_IDENT ;!!! need .errnz that IDENT <> 0
        jz        dsb_new_selected        ;Null handle
        inc        [di].bm_cSelect         ;Show another select
        mov        [di].bm_hddc,si         ;Show owned by this ddc
        mov        [si].ddc_npsd,di        ;--> new surface
        or        [si].ddc_fb,DDC_PRESENT ;Show surface is present

dsb_new_selected:
        mov        ax,1

dsb_tour_of_duty_over:
        cwd
        call        far_leave_driver
        ddc?        hddc,<SURFACE>                ;Make sure surface info is correct
dsb_exit_no_lock:
        fw_zero <es,cx>
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = GetBitmapBits 
;*
;* DESCRIPTION   = This function transfers bitmap data from the specified        
;*                 bitmap to application storage. If hBitmap is NULL then        
;*                 the bitmap currently selected into the DC is used. The        
;*                 DC must be a memory DC, with a bitmap currently selected.     
;*                                                                               
;*                 The format of the source bits is known only by the            
;*                 driver.  The destination format must be one of the            
;*                 formats returned from QueryExternalBitmaps.  Conversion       
;*                 from device dependant format to standard format must          
;*                 occur as the bits are copied. If the form is a non-           
;*                 standard format, then an error will be returned.              
;*                                                                               
;*                 The driver will translate the bitmap into the format          
;*                 requested by BitmapPlanes and BitmapBitcount if it is         
;*                 one of the external formats supported by the driver.          
;*                                                                               
;*                 Registers Preserved:       
;*                        SI,DI,DS,BP         
;*                 Registers Destroyed:       
;*                        AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = None
;* OUTPUT        = None
;*
;* RETURN-NORMAL = DX:AX = number of scans returned 
;* RETURN-ERROR  = DX:AX = -1 if error
;*                 error logged       
;**************************************************************************/

        check        GetBitmapBits,<hdc,hbm,y,cy,pbBits,pbmi,hddc,ulFunN>

        assumes ds,nothing
        assumes        es,nothing

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

        parmD        hdc
        parmD        hBitmap
        parmD        ScanStart
        parmD        ScanCount
        parmD        lpAddress
        parmD        lpInfo
        parmD        hddc
        parmD        FunN

        localD  lpCompBits              ;ptr to caller-supplied bits buffer
        localD  lpCompInfo              ;ptr to caller-supplied bitmap info
        localB  fConvBM                 ;indicate there was a bitmap conversion

        NGBBF_CONV_BM   equ     00000001b   ;indicate a bitmap conversion

cBegin
        fw_zero <es,ds>
        ddc?        hddc,<SURFACE>

        no_path_area        ngbb_log_error,both,error
;/*
;** Must have a memory ddc with a bitmap selected into it
;*/
        mov        ds,BitmapData
        assumes ds,Data
        cmp        hBitmap.lo,0                ;Did he give us a bitmap?
        je        ngbb_check_dc                ;No, go check the DC
        farPtr        MyIndex,0,DI_HBITMAP        ;Yes, translate to a device handle
        cCall        GetDriverInfo,<hBitmap,MyIndex,hdc>
        mov        si,ax                        ;SI = source handle
        and        ax,dx
        inc        ax
        jnz        ngbb_looks_good
        mov        ax,PMERR_INV_HBITMAP

ngbb_log_error:
        save_error_code
        mov        ax,-1
        jmp        ngbb_exit

ngbb_inv_option:
        mov     ax,PMERR_INV_OR_INCOMPAT_OPTIONS
        jmp     short ngbb_log_error
ngbb_inv_info:
        mov     ax,PMERR_INV_INFO_TABLE
        jmp     short ngbb_log_error

ngbb_insuff_mem_II:
        mov     cx,lpInfo.sel
        cCall        far_global_free         ;Takes selector in CX

ngbb_insuff_mem:
        mov     ax,PMERR_INSUFFICIENT_MEMORY
        jmp     short ngbb_log_error

ngbb_check_dc:
        mov        si,hddc.lo
        mov        cl,[si].ddc_fb
        mov        ax,PMERR_INCORRECT_DC_TYPE
        test        cl,DDC_DEVICE
        jnz        ngbb_log_error
        mov        ax,PMERR_BITMAP_NOT_SELECTED
        test        cl,DDC_PRESENT
        jz        ngbb_log_error
        mov        si,[si].ddc_npsd
;/*
;** We have to allocate a temporary buffer if a compressed bitmap is requested.
;*/
        CPUMode 386

ngbb_looks_good:
        mov     fConvBM,0               ;clear the bitmap conversion indicator
        les     di,lpInfo

        .errnz  bmp2_cbFix
        .errnz  bmp2_cx-bmp2_cbFix-4
        .errnz  bmp2_cy-bmp2_cx-4
        .errnz  bmp2_cPlanes-bmp2_cy-4
        .errnz  bmp2_cBitCount-bmp2_cPlanes-2
        .errnz  bmp2_ulCompression-bmp2_cBitCount-2
        .errnz  bmp2_cbImage-bmp2_ulCompression-4
        .errnz  bmp2_cxResolution-bmp2_cbImage-4

        cmp     es:[di].bmp2_cbFix,bmp2_cxResolution
        jb      ngbb_extract_bits       ;compression not supported in old Info
        cmp     es:[di].bmp2_ulCompression,BCA_UNCOMP
        je      ngbb_extract_bits       ;requested for a compressed bits ?
        cmp     es:[di].bmp2_cBitCount,1
        jne     short ngbb_alloc_buff
        mov     ax,ScanCount.lo
        cmp     ax,[si].bm_sd.sd_cy     ;if 1bpp, must be the entire bitmap.
        jb      short ngbb_inv_option

;/*
;** We need to create a local bitmap info structure for uncompressed bits with
;** information from several source:-
;**       bmp2_cx         from    the bitmap width from its surface definition
;**       bmp2_cy         from    the number of scans requested
;**       bmp2_cPlanes    from    the caller-supplied bitmap info structure
;**       bmp2_cBitCount  from    the caller-supplied bitmap info structure
;** But first, we need to allocate a bitmap info structure. The reason why we
;** cannot allocate it on the stack because bmc_int_to_ext will allocate another
;** big chunk of memory for pallette which can sometimes cause stack overflow.
;*/

ngbb_alloc_buff:
        lea     bx,lpInfo.sel           ;SS:BX = where selector goes
        mov     cx,es:[di].bmp2_cBitCount
        mov     ax,1
        shl     ax,cl                   ;AX = # of RGB entries
        shl     ax,2                    ;AX = size of color table
        .errnz  size RGB2 - (1 shl 2)
        add     ax,bmp2_ulCompression
        cwd                             ;DX:AX = bitmap info's size
        sub        cx,cx                   ;CX = buffer flag
        call        far_global_alloc        ;Allocate the memory
        or      cx,cx                   ;if CX = 0, succeed
        jnz     short ngbb_insuff_mem
        xor     bx,bx
        mov     lpInfo.off,bx           ;we start from the beginning of segment

        mov     gs,lpInfo.sel           ;GS:BX => decompressed bitmap info
        mov     gs:[bx].bmp2_cbFix,bmp2_ulCompression ;copy upto color format
        movzx   eax,[si].bm_sd.sd_cx
        mov     gs:[bx].bmp2_cx,eax     ;the bitmap width
        mov     eax,ScanCount
        mov     gs:[bx].bmp2_cy,eax     ;the bitmap height
        mov     eax,dword ptr es:[di].bmp2_cPlanes ;we only need the color format
        mov     dword ptr gs:[bx].bmp2_cPlanes,eax    ;(plane and bitcount)
        mov     lpCompInfo.off,di       ;lpCompInfo points to
        mov     lpCompInfo.sel,es       ;the caller-supplied bitmap info
;/*
;** Allocate a storage for uncompressed bits
;*/
        mov     es,lpInfo.sel           ;we need ES:BX => local bitmap info
        assumes es,nothing
        cCall   <far ptr alloc_uncomp_buffer>     ;allocate a temporary buffer
        or      ecx,ecx
        jz      ngbb_insuff_mem_II      ;ECX = 0 if fails to allocate one

        mov     ecx,lpAddress           ;lpCompBits points to
        mov     lpCompBits,ecx          ;the caller-supplied buffer
        mov     lpAddress.lo,ax         ;lpAddress points to
        mov     lpAddress.hi,dx         ;the locally-allocated buffer
        or      fConvBM,NGBBF_CONV_BM   ;we will do conversion
;/*
;** Extract device-independent bitmap
;*/
ngbb_extract_bits:
        farPtr        pClrTbl,<[di].ddc_pClrTbl.hi>,<[di].ddc_pClrTbl.lo>

        arg        si
        arg        lpInfo
        arg        lpAddress
        arg        ScanCount
        arg        ScanStart
        arg        pClrTbl
ifdef PALMGR
        arg        di
endif
        mov        di,hddc.lo
        cCall        bmc_int_to_ext

ngbb_compress_bits:
        test    fConvBM,NGBBF_CONV_BM   ;did we have a compression requested?
        jz      short ngbb_exit         ;no, we are done!!
        les     di,lpCompInfo           ;ES:DI => caller-supplied bitmap info
        assumes es,nothing
        mov     es:[di].bmp2_cy.lo,ax   ;AX = number of scans extracted

        lgs     bx,lpInfo               ;SS:BX => local bitmap info
        push    gs:[bx].bmp2_cy         ;we have to overwrite this for compression
        mov     gs:[bx].bmp2_cy.lo,ax

        xor     eax,eax
        farPtr  MyCmd,ax,CBD_COMPRESSION
        farPtr  MyFunN,ax,off_ConvertBitmapData
        check   ConvertBitmapData,<hdc,ulCmd,ulOption,pbmiSrc,pbBitsSrc,pbmiDst,pbBitsDst,hddc,ulFunN>
        cCall        InnerGreEntry,<hdc,MyCmd,eax,lpInfo,lpAddress,lpCompInfo,lpCompBits,eax,MyFunN>
        push    ax                      ;save the return value from conversion
        mov     cx,lpAddress.sel        ;selector in lpAddress.sel
        cCall   far_private_free
        mov     cx,lpInfo.sel           ;selector in lpInfo.sel
        cCall        far_global_free         ;Takes selector in CX
        pop     ax

        les     di,lpCompInfo
        assumes es,nothing
        mov     dx,es:[di].bmp2_cy.lo   ;the return value from bmc_int_to_ext
        pop     es:[di].bmp2_cy         ;we overwrote this for compression
        dec     ax
        js      short ngbb_exit         ;sign => compression failed
        mov     ax,dx                   ;value return from bmc_int_to_ext

        CPUMode 286

ngbb_exit:
        cwd
        fw_zero <es,cx>
cEnd
page


;/***************************************************************************
;*
;* FUNCTION NAME = SetBitmapBits
;*
;* DESCRIPTION   = This function transfers bitmap data from application     
;*                 storage to the specified bitmap. If hBitmap is NULL then 
;*                 the bitmap currently selected into the DC is used.  The  
;*                 DC must be a memory DC, with a bitmap currently selected.
;*                                                                          
;*                 The format of the destination bits is known only by the  
;*                 driver. The source format must be one of the formats     
;*                 returned from QueryExternalBitmaps.  Conversion from     
;*                 standard format to device dependant format must occur    
;*                 as the bits are copied.                                  
;* 
;*                 Registers Preserved:        
;*                        SI,DI,DS,BP          
;*                 Registers Destroyed:        
;*                        AX,BX,CX,DX,ES,FLAGS 
;* 
;* INPUT         = None
;* OUTPUT        = None
;*
;* RETURN-NORMAL = DX:AX = 1 
;* RETURN-ERROR  = DX:AX = 0    
;*                 error logged 
;**************************************************************************/

        check        SetBitmapBits,<hdc,hbm,y,cy,pbBits,pbmi,hddc,ulFunN>

        assumes ds,nothing
        assumes        es,nothing

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

        parmD        hdc
        parmD        hBitmap
        parmD        ScanStart
        parmD        ScanCount
        parmD        lpAddress
        parmD        lpInfo
        parmD        hddc
        parmD        FunN

        localD  lpLocalInfo
        localV  bmiDecomp,%(bmp2_ulCompression + (256*size RGB2))
        localB  fConvBM                 ;indicate there was a bitmap conversion

        NSBBF_CONV_BM   equ     00000001b   ;indicate a bitmap conversion
cBegin
        fw_zero <es,ds>
        ddc?        hddc,<SURFACE>

        no_path_area        nsbb_log_error,both,error

;/*
;** Must have a memory ddc with a bitmap selected into it
;*/
        mov        ds,BitmapData
        assumes ds,Data
        cmp        hBitmap.lo,0                ;Did he give us a bitmap?
        je        nsbb_check_dc                 ;No, go check the DC
        farPtr        MyIndex,0,DI_HBITMAP        ;Yes, translate to a device handle
        cCall        GetDriverInfo,<hBitmap,MyIndex,hdc>
        mov        si,ax                        ;SI = source handle
        and        ax,dx
        inc        ax
        jnz        nsbb_looks_good
        mov        ax,PMERR_INV_HBITMAP
nsbb_log_error:
        save_error_code

nsbb_error_exit:
        mov        ax,-1
        jmp        nsbb_exit

nsbb_cbm_fail:
        mov     cx,lpLocalInfo.sel       ;selector of local bitmap info
        cCall   far_private_free
        mov     cx,lpAddress.sel         ;selector of decomp. bits in lpBits.sel
        cCall   far_private_free
        jmp     short nsbb_error_exit

nsbb_insuff_mem_II:
        mov        cx,lpLocalInfo.sel
        cCall        far_global_free          ;Takes selector in CX

nsbb_insuff_mem:
        mov     ax,PMERR_INSUFFICIENT_MEMORY
        jmp     short nsbb_log_error

nsbb_check_dc:
        mov        si,hddc.lo
        mov        cl,[si].ddc_fb
        mov        ax,PMERR_INCORRECT_DC_TYPE
        test    cl,DDC_DEVICE
        jnz        nsbb_log_error
        mov        ax,PMERR_BITMAP_NOT_SELECTED
        test    cl,DDC_PRESENT
        jz        nsbb_log_error
        mov        si,[si].ddc_npsd

;/*
;** Now, we need to verify if the bits are in a compressed form. If so,
;** decompress them before setting them.
;*/

nsbb_looks_good:

        CPUMode 386

        mov     fConvBM,0               ;clear the bitmap conversion indicator
        les     di,lpInfo
        assumes es,nothing

        .errnz  bmp2_cbFix
        .errnz  bmp2_cx-bmp2_cbFix-4
        .errnz  bmp2_cy-bmp2_cx-4
        .errnz  bmp2_cPlanes-bmp2_cy-4
        .errnz  bmp2_cBitCount-bmp2_cPlanes-2
        .errnz  bmp2_ulCompression-bmp2_cBitCount-2
        .errnz  bmp2_cbImage-bmp2_ulCompression-4
        .errnz  bmp2_cxResolution-bmp2_cbImage-4

        cmp     es:[di].bmp2_cbFix,bmp2_cxResolution
        jb      nsbb_set_bits           ;compression not supported in old Info
        cmp     es:[di].bmp2_ulCompression,BCA_UNCOMP
        je      nsbb_set_bits           ;not a compressed bits

;/*
;** We will have to modify the content of the source bitmap info structure,
;** hence create its local copy and use it in place of the source structure.
;*/

nsbb_decompress_bits:
        or      fConvBM,NSBBF_CONV_BM   ;we will do conversion
        lea     bx,lpLocalInfo.sel      ;SS:BX = where selector goes
        mov     cx,es:[di].bmp2_cBitCount
        mov     ax,1
        shl     ax,cl                   ;AX = # of RGB entries
        shl     ax,2                    ;AX = size of color table
        .errnz  size RGB2 - (1 shl 2)
        add     ax,es:[di].bmp2_cbFix.lo
        cwd                             ;DX:AX = bitmap info's size
        mov     di,ax                   ;save the size for future
        sub        cx,cx                   ;CX = buffer flag
        call        far_global_alloc        ;Allocate the memory
        or      cx,cx                   ;if CX = 0, succeed
        jnz     short nsbb_insuff_mem
        xchg    cx,di                   ;DI = size of bmi and CX = 0
        mov     lpLocalInfo.off,di      ;we start from the beginning of segment
        push    si                      ;save near ptr to surface definition
        lgs     si,lpInfo
        assumes gs,nothing
        mov     es,lpLocalInfo.sel
        assumes es,nothing
        mov     ax,cx
        shr     cx,2
        rep     movs dword ptr es:[di],dword ptr gs:[si]
        mov     cx,ax
        and     cx,3
        rep     movs byte ptr es:[di],byte ptr gs:[si]
        sub     si,ax                   ;GS:SI => source bitmap info structure

;/*
;** We want to duplicate the bitmapinfo structure from bmp2_cx to bmp2_cBitCount
;** fields, allocate a buffer for uncompressed bits, and may have to initialize
;** it with the contents of the destination bitmap.
;*/

        push    ss
        pop     es
        assumes es,nothing
        lea     bx,bmiDecomp
        mov     di,bx
        mov     cx,bmp2_ulCompression
        shr     cx,2

        .errnz  bmp2_ulCompression and 3

        rep     movs dword ptr es:[di],dword ptr gs:[si];we need information
        mov     ss:[bx].bmp2_cbFix,bmp2_ulCompression   ;upto bmp2_cBitCount
        mov     eax,ScanCount
        mov     ss:[bx].bmp2_cy,eax     ;and requested height
        pop     si                      ;DS:SI => surface definition

        cCall   <far ptr alloc_uncomp_buffer>     ;allocate a temporary buffer
        or      ecx,ecx
        jz      nsbb_insuff_mem_II      ;ECX = 0 if fails to allocate one
        xchg    lpAddress.off,ax
        xchg    lpAddress.sel,dx

        les     di,lpLocalInfo
        assumes es,nothing
        mov     ecx,es:[di].bmp2_cy     ;ECX = full height of bitmap
        xchg    ecx,ScanCount           ;ScanCount now stores the full height
        mov     es:[di].bmp2_cy,ecx     ;the actual height of bitmap to decomp
        cmp     es:[di].bmp2_ulCompression,BCA_HUFFMAN1D
        je      short nsbb_init_done

        mov        di,hddc.lo
        lea     bx,bmiDecomp
        push    ecx                     ;save # of scans requested
        farPtr        pClrTbl,<[di].ddc_pClrTbl.hi>,<[di].ddc_pClrTbl.lo>
        farPtr  MylpInfo,ss,bx
        arg        si
        arg     MylpInfo
        arg        lpAddress
        arg     ecx                     ;ECX = number of scans requested
        arg        ScanStart
        arg        pClrTbl
ifdef PALMGR
        arg        di
endif
        save    <ax,dx>                 ;save ptr to compressed bits
        cCall        bmc_int_to_ext
        lea     bx,bmiDecomp            ;SS:BX => local bitmap info
        pop     ss:[bx].bmp2_cy         ;restore the number of scans requested

nsbb_init_done:

        xor     ecx,ecx
        farPtr  MyCmd,cx,CBD_DECOMPRESSION
        farPtr  MyOption,cx,CBD_COLOR_CONVERSION
        farPtr  MylpCompBits,dx,ax
        farPtr  MylpDecompBmi,ss,bx
        farPtr  MyFunN,cx,off_ConvertBitmapData
        check   ConvertBitmapData,<hdc,ulCmd,ulOption,pbmiSrc,pbBitsSrc,pbmiDst,pbBitsDst,hddc,ulFunN>
        cCall        InnerGreEntry,<hdc,MyCmd,MyOption,lpLocalInfo,MylpCompBits,MylpDecompBmi,lpAddress,ecx,MyFunN>
        or      ax,dx
        jz      nsbb_cbm_fail           ;if failed, we can get out of here now

        lea     bx,bmiDecomp            ;SS:BX => local bitmap info
        mov     ecx,ScanCount
        xchg    ss:[bx].bmp2_cy,ecx     ;full height in this bitmap info
        mov     ScanCount,ecx           ;# of scan requested in ScanCount
        mov        lpInfo.off,bx                ;then use it to set uncompressed
        mov        lpInfo.sel,ss                ;bitmap

        CPUMode 286

;/*
;** At this point, the bits should be in the decompressed form.
;*/
nsbb_set_bits:
        arg        si
        arg        lpInfo
        arg        lpAddress
        arg        ScanCount
        arg        ScanStart

ifdef PALMGR
        farPtr        pPal,<[di].devpal_pPalSeg.hi>,<[di].devpal_pPalSeg.lo>
        arg        pPal
        arg        hddc

        mov        di,hddc.lo
        mov        di,[di].ddc_npdevpal
endif
        cCall        bmc_ext_to_int                ;Copy bits as needed

;/*
;** Now we can free the temporary decompressed buffer, if any.
;*/
        test    fConvBM,NSBBF_CONV_BM       ;did we do conversion?
        jz      nsbb_exit
        push    ax
        mov     cx,lpLocalInfo.sel          ;selector of local bitmap info
        cCall   far_private_free
        mov     cx,lpAddress.sel            ;selector in lpAddress.sel
        cCall   far_private_free
        pop     ax

nsbb_exit:
        cwd
        fw_zero <es,cx>
cEnd


page

;/***************************************************************************
;*
;* FUNCTION NAME = check_bitmap_info
;*
;* DESCRIPTION   = This function validates various fields of the passed    
;*                 BITMAPINFOHEADER structure, and returns an index based  
;*                 on the format passed.                                   
;*
;*                 Registers Preserved:        
;*                        BX,DX,DI,DS,ES,BP    
;*                 Registers Destroyed:        
;*                        FLAGS,AX,CX,GS,SI    
;*
;* INPUT         = ES:BX   --> BITMAPINFOHEADER or BITMAPINFOHEADER2 struct
;*                 CX <> 0 --> Check all entered fields                          
;*                 CX == 0 --> Check only fields required by GetBitmapBits 
;* OUTPUT        = None
;*
;* RETURN-NORMAL = CX  <> 0 if format recognized                        
;*                 AX = 0 if format is 1 plane,        1 bit-per-pixel  
;*                 AX = 2 if format is 1 plane,        4 bit-per-pixel  
;*                 AX = 4 if format is 1 plane,        8 bit-per-pixel  
;*                 AX = 6 if format is 1 plane, 24 bit-per-pixel        
;*
;* RETURN-ERROR  = CX = 0 if format isn't one of the above 
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing
        assumes gs,nothing

cProc        far_check_bitmap_info,<FAR,PUBLIC>
cBegin
        CPUMode 386
        push    esi                             ; Save it first
        mov     esi,es:[bx].bmi2_cbFix
        cmp     esi,SIZE BITMAPINFOHEADER
        jne     cbmi_new_header
        mov        cx,es:[bx].bmi_cBitCount
        mov     ax,es:[bx].bmi_cPlanes
        jmp     cbmi_check_bitcount_and_planes
cbmi_new_header:
        cmp     esi,SIZE BITMAPINFOHEADER2
        ja      cbmi_invalid_format
        je      cbmi_ulIdentifier
        mov        gs,BitmapData
        assumes gs,Data
        shr     si,1
        jc      cbmi_invalid_format
        add     si,DataOFFSET ok_cbFix
        movzx   si,gs:[si]
        add        si,BitmapOFFSET bmi2_check_point
        movzx   si,cs:[si]
        add        si,BitmapOFFSET cbmi_ulIdentifier
        jmp     si
cbmi_ulIdentifier:
cbmi_ulColorEncoding:
ifdef PALMGR
        cmp     es:[bx].bmi2_ulColorEncoding,BCE_RGB
        je        cbmi_cSize1
        cmp        es:[bx].bmi2_ulColorEncoding,BCE_PALETTE
        jne     cbmi_invalid_format
else
        cmp     es:[bx].bmi2_ulColorEncoding,BCE_RGB
        jne     cbmi_invalid_format
endif
cbmi_cSize1:
cbmi_cSize2:
cbmi_usRendering:
        cmp     es:[bx].bmi2_usRendering,BRH_NOTHALFTONED
        jne     cbmi_invalid_format
cbmi_usRecording:
        cmp     es:[bx].bmi2_usRecording,BRA_BOTTOMUP
        jne     cbmi_invalid_format
cbmi_usReserved:
        cmp     es:[bx].bmi2_usReserved,0
        jne     cbmi_invalid_format
cbmi_usUnits:
        jcxz    cbmi_cBitCount      ; CX must be preserved until here
        cmp     es:[bx].bmi2_usUnits,BRU_METRIC
        jne     cbmi_invalid_format
cbmi_cclrImportant:
        jcxz    cbmi_cBitCount
        mov        cx,es:[bx].bmi2_cBitCount
        mov     eax,1
        shl     eax,cl              ;CL is taken mod 32 by the instruction
        cmp     es:[bx].bmi2_cclrImportant,eax
        ja      cbmi_invalid_format
        jmp     SHORT cbmi_computed_max_colors_already
cbmi_cclrUsed:
        jcxz    cbmi_cBitCount
        mov        cx,es:[bx].bmi2_cBitCount
        mov     eax,1
        shl     eax,cl              ;CL is taken mod 32 by the instruction
cbmi_computed_max_colors_already:
        cmp     es:[bx].bmi2_cclrUsed,eax
        ja      cbmi_invalid_format
cbmi_cyResolution:
cbmi_cxResolution:
cbmi_cbImage:
        cmp     es:[bx].bmi2_ulCompression,BCA_UNCOMP
        je      short cbmi_cBitCount
        .errnz  BCA_UNCOMP
        .errnz  BCA_RLE8-1
        .errnz  BCA_RLE4-2
        .errnz  BCA_HUFFMAN1D-3
        .errnz  BCA_RLE24-4
        cmp     es:[bx].bmi2_ulCompression,BCA_RLE24
        ja      short cbmi_invalid_format
        cmp     es:[bx].bmi2_cbImage,0      ;must be non-zero for compressed
        jne     short cbmi_cBitCount        ;bitmap
        jmp     short cbmi_invalid_format
cbmi_ulCompression:
        cmp     es:[bx].bmi2_ulCompression,BCA_UNCOMP
        jne     short cbmi_invalid_format
cbmi_cBitCount:
        mov        cx,es:[bx].bmi2_cBitCount
        mov     ax,es:[bx].bmi2_cPlanes

cbmi_check_bitcount_and_planes:
        cmp     ax,1
        jne     cbmi_invalid_format
        xor        ax,ax                        ;Index = 0
        cmp        cx,1
        je        cbmi_have_format
        inc        ax                        ;Index = 1
        cmp        cx,4
        je        cbmi_have_format
        inc        ax                        ;Index = 2
        cmp        cx,8
        je        cbmi_have_format
        inc        ax                        ;Index = 3
        cmp        cx,24
        je        cbmi_have_format
cbmi_invalid_format:
        mov        cx,0
cbmi_have_format:
        shl        ax,1                        ;*2 for correct values
cbmi_exit:
        pop     esi                     ; Restore its value
        CPUMode 286
cEnd
page

;/***************************************************************************
;*
;* FUNCTION NAME = deselect_bitmap
;*
;* DESCRIPTION   = This function deselects a bitmap from a ddc if one is         
;*                 selected in. This is used by RestoreDC and SelectBitmap. 
;*                 Registers Preserved:             
;*                        AX,CX,DX,SI,DI,DS,ES,BP   
;*                 Registers Destroyed:             
;*                        BX,FLAGS                  
;*                 In the ddc:                                                     
;*                                                                                 
;*                    a) clear DDC_PRESENT to show no surface                  
;*                                                                             
;*                    b) clear DDC_CLIP_NOTIFY to show clipping is invalid     
;*                                                                             
;*                    c) clear DDC_VISIBLE to show nothing shows               
;*                                                                             
;*                    d) clear ddc_npsd to show no bitmap is selected          
;*                                                                             
;*                 In the bitmap:                                                  
;*                                                                                 
;*                    e) decrement the selection count.                        
;*                                                                             
;*                    f) if the selection count is zero, clear bm_hddc to show 
;*                       a free bitmap.                                        
;*
;* INPUT         = DS:SI --> memory ddc 
;* OUTPUT        = None
;*
;* RETURN-NORMAL = None
;* RETURN-ERROR  = None
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc        far_deselect_bitmap,<FAR,PUBLIC,NODATA,NONWIN>
cBegin
        ddc?        si,<SURFACE,MEMORYDDC>
        mov        bx,INVALID_ADDRESS
        xchg        bx,[si].ddc_npsd
        inc        bx
        jz        dbm_done                ;No bitmap to deselect
        .errnz        INVALID_ADDRESS+1
        dec        bx
        dec        [bx].bm_cSelect
        jnz        dbm_still_owned
        mov        [bx].bm_hddc,INVALID_ADDRESS ;No longer owned
dbm_still_owned:
        and        [si].ddc_fb,not (DDC_PRESENT or DDC_CLIP_NOTIFY or DDC_VISIBLE)
dbm_done:
cEnd

page

;/***************************************************************************
;*
;* FUNCTION NAME = save_bitmap
;*
;* DESCRIPTION   = This function is called from SaveDC to perform whatever 
;*                 operations are necessary to save the bitmap portion of  
;*                 the ddc. The caller has already checked to see if a     
;*                 bitmap is selected into the ddc.                        
;*
;*                 Registers Preserved:             
;*                        AX,CX,DX,SI,DI,DS,ES,BP   
;*                 Registers Destroyed:             
;*                        BX,FLAGS                  
;*
;* INPUT         = DS:SI --> ddc_ 
;* OUTPUT        = None
;*
;* RETURN-NORMAL = None
;* RETURN-ERROR  = None
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc        save_bitmap,<FAR,PUBLIC>
cBegin

ifdef FIREWALLS
        ddc?        si,<MEMORYDDC>
        mov        bx,[si].ddc_npsd
        cmp        [bx].bm_sd.sd_usId,SURFACE_IDENT
        jne        save_bm_bad_surface
        test        [bx].bm_sd.sd_fb,SD_DEVICE
        jz        save_bm_good_surface
save_bm_bad_surface:
        rip        text,<save_bitmap - Surface is not a bitmap>
save_bm_good_surface:
endif

        inc        [bx].bm_cSelect
cEnd

;/***************************************************************************
;*                 
;* FUNCTION NAME = alloc_uncomp_buffer
;*                 
;* DESCRIPTION   = This function is called from DeviceCreateBitmap and
;*                 SetBitmapBits to allocate a buffer to store bits.  
;*                 The dimension is specified in a bitmapInfo structure. 
;*                 
;*                 Registers Preserved:
;*                       DS,ES,SI,DI,BP
;*                 Registers Destroyed:
;*                        AX,BX,ECX,DX,FLAGS
;*                 
;* INPUT         = ES:BX --> bitmapInfo structure 
;*                 DX:AX --> allocated buffer
;*                 ECX       its size (in bytes)
;* OUTPUT        = None
;* RETURN-NORMAL = None
;* RETURN-ERROR  = ECX   =   0
;*                 
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc        alloc_uncomp_buffer,<FAR,PUBLIC>
        localW  lpBuffer
        localD  lSize

cBegin
        CPUMode 386

;/*
;** calculate the bits size from the bitmap dimension
;*/
        mov     ax,es:[bx].bmp2_cx.lo       ;number of pels per scan
        assert  es:[bx].bmp2_cx.hi,E,0
        mul     es:[bx].bmp2_cBitCount      ;DX:AX = number of bits per scan
        add     ax,31
        adc     dx,0
        shrd    ax,dx,5                     ;number of dwords per scan
        shl     ax,2                        ;number of words per scan

ifdef   FIREWALLS
        shr     dx,3                        ;divide by a byte size
        jz      short @F                    ;should be zero
        rip     text,<alloc_uncomp_buffer:scanline is too big.>
@@:
endif;  FIREWALLS

        assert  es:[bx].bmp2_cy.hi,E,0
        mul     es:[bx].bmp2_cy.lo          ;DX:AX = bits size = scansize * height
        mov     lSize.hi,dx
        mov     lSize.lo,ax
        lea     bx,lpBuffer                 ;SS:BX = where the selector returned
        cCall   far_private_alloc
        jcxz    short aub_return            ;CX = 0 if successful
        xor     eax,eax
        mov     lSize,eax                   ;we will return size 0 as failure

aub_return:
        mov     ecx,lSize                   ;return size
        mov     dx,lpBuffer                 ;return selector
        xor     ax,ax                       ;and offset zero
        CPUMode 286

cEnd

sEnd        Bitmap

end
