;*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    60,132
;
;/*********************************************************************/
;/* code to perform the scan through a scanline looking for the       */
;/* presence or absence of a given colour                             */
;/*********************************************************************/
;
;/*********************************************************************/
;/* CT001 - CMVC Defect 73076.  Resolve infinite loop created by      */
;/*         improperly calculating the number of pels scanned.        */
;/*********************************************************************/
;
.386

INCL_GPIBITMAPS EQU     1
INCL_GRE_BITMAPS   EQU 1
include os2.inc
include eddinclt.inc

ifdef FLOOD_FILL

?DF   equ   1
include cmacros.inc
include struc.inc

include missing.inc

_DATA           segment dword use32 public 'DATA'
_DATA           ends

_TEXT   segment use32 dword public 'CODE'
                assume  cs:FLAT, ds:FLAT, es:FLAT


;******************************************************************
; LONG DRIVERCALL bit_scan_forward(ULONG scanbyte)
;
;  Scan forward through the byte passed, looking for a set bit
;  returns -1 if all bits are clear
;******************************************************************
cProc   bit_scan_forward,<PUBLIC,NODATA>

        parmD   scanbyte

cBegin
        mov     edx, scanbyte
        bsf     eax, edx
        jnz     short @F
        mov     eax, -1
@@:

cEnd


;******************************************************************
; LONG DRIVERCALL bit_scan_reverse(ULONG scanbyte)
;
;  Scan backward through the byte passed, looking for a set bit
;  returns -1 if all bits are clear
;******************************************************************
cProc   bit_scan_reverse,<PUBLIC,NODATA>

        parmD   scanbyte

cBegin
        mov     edx, scanbyte
        bsr     eax, edx
        jnz     short @F
        mov     eax, -1
@@:

cEnd


;******************************************************************
; LONG DRIVERCALL scan8_whole_bytes(PBYTE  start_address,
;                                   ULONG  bytes_to_scan,
;                                   ULONG  options,
;                                   ULONG  colour)
;
; scans a scanline in 8 bpp format for the first occurrence of colour (if
; LR_BORDER option) or the first non-occurrence of colour (if not LR_BORDER
; option). Scans either left or right depending on the LR_LEFT / LR_RIGHT
; option - make sure both are not set before calling.
; Returns the byte (pixel) offset from the first byte scanned
; This can range from zero (current pel matched) to bytes_to_scan (no
; pels matched).
;******************************************************************

cProc   scan8_whole_bytes,<PUBLIC,NODATA>,<edi,ecx,ebx>

        parmD   start_address
        parmD   bytes_to_scan
        parmD   options
        parmD   colour

cBegin

        ; scas through memory from low to high by default (scan to right)
        cld

        ; check if scanning to left
        test    options, LR_LEFT
        jz      short @F

        ; move through memory from high to low
        std
@@:
        ; get the scas parameters
        mov     edi, start_address
        mov     ecx, bytes_to_scan
        mov     eax, colour
        mov     ebx, ecx

        ; check if we're looking for a border or the end of an area
        test    options, LR_BORDER
        jz      short @F

        ; scan until we find the colour
        repne   scas byte ptr [edi]
        jne     short s8w_not_found
        jmp     short scan_done

@@:
        ; scan until we find the absence of the colour
        repe    scas byte ptr [edi]
        je      short s8w_not_found

scan_done:
        ; found a byte containing what we were looking for -
        ; calculate the pixel offset from the start point
        sub     ebx, ecx
        dec     ebx

s8w_not_found:
        mov     eax, ebx

s8w_exit:
        cld

cEnd

ifdef BPP24
;******************************************************************
; LONG DRIVERCALL scan24(PBYTE  start_address,
;                        ULONG  pixels_to_scan,
;                        ULONG  options,
;                        ULONG  colour)
;
; scans a scanline in 24 bpp format for the first occurrence of colour (if
; LR_BORDER option) or the first non-occurrence of colour (if not LR_BORDER
; option). Scans either left or right depending on the LR_LEFT / LR_RIGHT
; option - make sure both are not set before calling.
; Returns the pixel offset from the first pixel scanned.
; This can range from zero (current pel matched) to bytes_to_scan (no
; pels matched).
;******************************************************************

cProc   scan24,<PUBLIC,NODATA>,<edi,ecx,ebx,edx,esi>

        parmD   start_address
        parmD   pixels_to_scan
        parmD   options
        parmD   colour

cBegin
        ; scas through memory from low to high by default (scan to right)
        cld
        mov     esi,3

        ; check if scanning to left
        test    options, LR_LEFT
        jz      short @F

        ; move through memory from high to low
        std
        mov     esi,-3

@@:
        ; get the scas parameters
        mov     edi, start_address
        mov     ecx, pixels_to_scan
        mov     eax, colour
        mov     ebx, ecx

        ; change the colour we look for because the bitmap is stored in
        ; motorola format
        ror     eax,8
        ror     ax,8
        ror     eax,16
        ror     ax,8
        ror     eax,16
        and     eax,00ffffffh
        mov     edx,eax

        ; check if we're looking for a border or the end of an area
        test    options, LR_BORDER
        je      short @F

        ; scan until we find the colour
scan_1:
        mov     eax,[edi]
        and     eax,00ffffffh
        add     edi,esi
        cmp     eax,edx
        jz      short scan24_done
        loop    scan_1
        jmp     short s24_not_found

@@:
        ; scan until we find the absence of the colour
scan_2:
        mov     eax,[edi]
        and     eax,00ffffffh
        add     edi,esi
        cmp     eax,edx
        jnz     short scan24_done
        loop    scan_2
        jmp     short s24_not_found

scan24_done:
        ; found a pixel containing what we were looking for -
        ; calculate the pixel offset from the start point
        sub     ebx, ecx

s24_not_found:
        mov     eax, ebx

        ; clear the direction flag
        cld

cEnd

endif   ; BPP24

;******************************************************************
; LONG DRIVERCALL scan16(PBYTE  start_address,
;                        ULONG  pixels_to_scan,
;                        ULONG  options,
;                        ULONG  colour)
;
; scans a scanline in 16 bpp format for the first occurrence of colour (if
; LR_BORDER option) or the first non-occurrence of colour (if not LR_BORDER
; option). Scans either left or right depending on the LR_LEFT / LR_RIGHT
; option - make sure both are not set before calling.
; Returns the pixel offset from the first pixel scanned.
; This can range from zero (current pel matched) to bytes_to_scan (no
; pels matched).
;******************************************************************

cProc   scan16,<PUBLIC,NODATA>,<edi,ecx,ebx>

        parmD   start_address
        parmD   pixels_to_scan
        parmD   options
        parmD   colour


cBegin

        ; scas through memory from low to high by default (scan to right)
        cld

        ; check if scanning to left
        test    options, LR_LEFT
        jz      short @F

        ; move through memory from high to low
        std

@@:
        ; get the scas parameters
        mov     edi, start_address
        mov     ecx, pixels_to_scan
        mov     eax, colour
        mov     ebx, ecx

        ; change the colour we look for because the bitmap is stored in
        ; motorola format
        xchg    ah,al           ; swap the byte ordering
%out Warning: Hardcoded to only work with XGA 16bpp format

        ; check if we're looking for a border or the end of an area
        test    options, LR_BORDER
        je      short @F

        ; scan until we find the colour
        repne   scas word ptr [edi]
        jne     short s16_not_found
        jmp     short scan16_done

@@:
        ; scan until we find the absence of the colour
        repe    scas word ptr [edi]
        je      short s16_not_found

scan16_done:
        ; found a pixel containing what we were looking for -
        ; calculate the pixel offset from the start point
        sub     ebx, ecx
        dec     ebx

s16_not_found:
        mov     eax, ebx

        ; clear the direction flag
        cld

cEnd


;******************************************************************
; LONG DRIVERCALL scan1_whole_bytes(PBYTE  start_address,
;                                   ULONG  pels_to_scan,
;                                   ULONG  options,
;                                   ULONG  colour)
;
; scans a scanline in 1 bpp format for the first non-occurrence of colour.
; Scans either left or right depending on the LR_LEFT / LR_RIGHT option -
; make sure both are not set before calling. Returns the pixel (bit) offset
; from the first bit scanned
;******************************************************************

cProc   scan1_whole_bytes,<PUBLIC,NODATA>, <edi,ecx,ebx>

        parmD   start_address
        parmD   pels_to_scan
        parmD   options
        parmD   colour

cBegin

        ; scas through memory from low to high by default (scan to right)
        cld

        ; check if scanning to left
        test    options, LR_LEFT
        jz      short @F

        ; move through memory from high to low
        std

@@:
        ; get the scas parameters
        mov     edi, start_address
        mov     ecx, pels_to_scan
        add     ecx, 7          ; want the divide to round up
        shr     ecx, 3          ; divide by 8 to get number of bytes
        mov     eax, colour
        mov     ebx, ecx

        ; scan until we find the absence of the colour
        repe    scas byte ptr [edi]
        jne     short s1w_found_it

        ; calculate the bit offset to the leftmost pel in the clip rectangle
        shl     ebx, 3
        dec     ebx
        jmp     short s1w_exit

s1w_found_it:
        ; found a byte containing what we were looking for -
        ; calculate the byte offset from the first byte
        dec     ebx
        sub     ebx, ecx

        ; now find the bit within the byte
        ; check if scanning to left
        xor     edx,edx                 ; clear out all bits of edx
        test    options, LR_LEFT
        jz      short s1w_going_right

        ; if we're looking for a zero, invert the byte so we can use bit scan
        mov     dl, byte ptr [edi+1]
        and     al, al
        jz      short @F
        not     dl
@@:     bsf     ecx, edx
        jmp     short s1w_do_bit

s1w_going_right:
        mov     dl, byte ptr [edi-1]
        and     al, al
        jz      short @F
        not     dl
@@:     bsr     ecx, edx
        neg     ecx
        add     ecx, 7

s1w_do_bit:
        ; convert the byte offset (ebx) to a bit offset and add in the bit
        ; offset (ecx) within the byte
        shl     ebx, 3
        add     ebx, ecx

s1w_exit:
        mov     eax, ebx
        cld

cEnd


;******************************************************************
; LONG DRIVERCALL scan4_whole_bytes(PBYTE  start_address,
;                                   ULONG  pels_to_scan,
;                                   ULONG  options,
;                                   ULONG  colour)
;
; scans a scanline in 4 bpp format for the first non-occurrence of colour.
; Scans either left or right depending on the LR_LEFT / LR_RIGHT option -
; make sure both are not set before calling. Returns the pixel (bit) offset
; from the first bit scanned
;******************************************************************

cProc   scan4_whole_bytes,<PUBLIC,NODATA>, <esi,edi,ecx,ebx>

        parmD   start_address
        parmD   pels_to_scan
        parmD   options
        parmD   colour

cBegin
        ; scas through memory from low to high by default (scan to right)
        cld

        xor     ebx,ebx

        ; check if scanning to left
        test    options, LR_LEFT
        jz      short @F

        ; move through memory from high to low
        std

@@:
        ; get the scas parameters
        mov     edi, start_address
        mov     ecx, pels_to_scan
        mov     esi, ecx                ; assume we have to scan all the pels
        inc     ecx                     ; want the next divide to round up
        shr     ecx,1                   ; divide by 2 to get number of bytes
        mov     eax, colour

        ; check if we're looking for a border or the end of an area
        test    options, LR_BORDER
        jnz     short @F

        ; scan until we find the absence of the colour
        repe    scas byte ptr [edi]

        je      short s4w_exit
        jmp     short s4w_found

@@:
        ; scan until we find the colour - need to do it byte by byte

        xor     esi, esi          ; zero our pels scanned count

        ; check if scanning to left
        test    options, LR_LEFT
        jnz     short s4w_bord_left

        ; scanning to the right - get the colour to find
        and     al, 0fh

s4w_r_next_byte:
        ; get the next byte to examine and save it for later
        mov     bh, byte ptr [edi]
        inc     edi
        shr     ebx, 4

        ; compare with our colour
        xor     bh, al
        jz      short s4w_exit
        inc     esi      ; we've checked another pel

        ; no match - get our saved data and repeat for the other 4 bits
        shl     ebx, 4
        and     bh, 0fh
        xor     bh, al
        jz      short s4w_exit
        inc     esi      ; we've checked another pel

        ; no match in this byte so get the next one if any
        dec     ecx
        jnz     s4w_r_next_byte

        ; no match found
        jmp     short s4w_exit



s4w_bord_left:

        ; scanning to the left - get the colour to find
        and     al, 0f0h

s4w_l_next_byte:
        ; get the next byte to examine and save it for later
        mov     bl, byte ptr [edi]
        dec     edi
        shl     ebx, 4

        ; compare with our colour
        xor     bl, al
        jz      short s4w_exit
        inc     esi     ; we've checked another pel

        ; no match - get our saved data and repeat for the other 4 bits
        shr     ebx, 4
        and     bl, 0f0h
        xor     bl, al
        jz      short s4w_exit
        inc     esi      ; we've checked another pel

        ; no match in this byte so get the next one if any
        dec     ecx
        jnz     s4w_l_next_byte

        ; no match found
        jmp     short s4w_exit


s4w_found:
        ; found a byte containing what we were looking for -
        ; calculate the byte offset from the first byte
        inc     ecx
        add     ecx, ecx   ; turn a byte counter into a pel counter
        sub     esi, ecx
        inc     esi                                                        ;/*CT001*/
        shr     esi, 1                                                     ;/*CT001*/
        shl     esi, 1                                                     ;/*CT001*/

        ; now find the pel within the byte
        ; check if scanning to left
        test    options, LR_LEFT
        jz      short s4w_going_right

        xor     al, byte ptr [edi+1]
        test    al, 0fh
        jz      short s4w_inc_offset
        jmp     short s4w_exit

s4w_going_right:
        xor     al, byte ptr [edi-1]
        test    al, 0f0h
        jnz     short s4w_exit

s4w_inc_offset:
        inc     esi

s4w_exit:
        mov     eax, esi
        cld

cEnd


_TEXT   ends


endif ; FLOOD_FILL
END
