;*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
;-----------------------------Module-Header-----------------------------;
; Module Name:  FDBITS.ASM
;
;   This module contains bitmap manipulation functions for OS/2J
;   font drivers.
;
; Created: 07-May-1987
; Author:  A. Miyazawa  [TRL/CSI/Multi-media Document Systems]
; Author:  Takashi Itoh [jl03313 @ ymtvm3, IBM Japan]
; Author:  Soh Ohta     [jl09057 @ ymtvm3, IBM Japan]
;
;                       Refer to Copyright Inscruction Form No.G120-2083
;
; Exported Functions:   none
;
; Public Functions:     Bitblt
;
; Public Data:          none
;
; General Description:
;
;-----------------------------------------------------------------------;

        .286p
        .xlist
        include cmacros.inc
        include resmap.inc
        .list

        createSeg   _TEXT, Bitmap, WORD, PUBLIC, CODE


SPECIAL_44      equ     1               ; fixed by Noriko Tsubouch
MAX_BITMAPSIZE  equ     255             ; varid extent: 1..255
MAX_SCALEFACTOR equ     48              ; scaling unit: 1/48
CB_TABLE_ENTRY  equ     (MAX_SCALEFACTOR/8)

POINTER32       struc
off             dw      0               ; offset   part
sel             dw      0               ; selector part
POINTER32       ends


sBegin  Bitmap
        assumes cs,Bitmap

; Scaling logic dispatch table.

horzScaleProc   label   word
                dw      sb_horz_shrink  ; shrink  data in a scanline
                dw      sb_horz_stretch ; stretch data in a scanline
vertScaleProc   label   word
                dw      sb_vert_shrink  ; shrink  scanlines
                dw      sb_vert_stretch ; stretch scanlines


; Scaling logic coded table.
; The first bit of each table entry must be 1 (except 0/48 case).

coded_table     label   byte
        db  00000000b,00000000b,00000000b,00000000b,00000000b,00000000b  ; 0/48
        db  10000000b,00000000b,00000000b,00000000b,00000000b,00000000b  ; 1/48
        db  10000000b,00000000b,00000000b,10000000b,00000000b,00000000b  ; 2/48
        db  10000000b,00000000b,10000000b,00000000b,10000000b,00000000b  ; 3/48
        db  10000000b,00001000b,00000000b,10000000b,00001000b,00000000b  ; 4/48
        db  10000000b,00100000b,00001000b,00000100b,00000001b,00000000b  ; 5/48
        db  10000000b,10000000b,10000000b,10000000b,10000000b,10000000b  ; 6/48
        db  10000001b,00000010b,00000100b,00001000b,00010000b,00100000b  ; 7/48
        db  10000010b,00001000b,00100000b,10000010b,00001000b,00100000b  ; 8/48
        db  10000010b,00010000b,10000010b,00010000b,10000010b,00010000b  ; 9/48
        db  10000100b,00100001b,00001000b,10000100b,00100001b,00001000b  ;10/48
        db  10000100b,01000010b,00100010b,00010001b,00010000b,10001000b  ;11/48
        db  10001000b,10001000b,10001000b,10001000b,10001000b,10001000b  ;12/48
        db  10001000b,10001001b,00010001b,00100010b,00100100b,01000100b  ;13/48
        db  10001001b,00010010b,00100100b,10001001b,00010010b,00100100b  ;14/48
        db  10001001b,00100100b,10001001b,00100100b,10001001b,00100100b  ;15/48
        db  10010010b,01001001b,00100100b,10010010b,01001001b,00100100b  ;16/48
        db  10010010b,01001001b,01001001b,00100100b,10100100b,10010010b  ;17/48
        db  10010010b,10010010b,10010010b,10010010b,10010010b,10010010b  ;18/48
        db  10010010b,10010100b,10100101b,00101001b,01001010b,01010010b  ;19/48
        db  10010100b,10101001b,01001010b,10010100b,10101001b,01001010b  ;20/48
        db  10010101b,00101010b,10010101b,00101010b,10010101b,00101010b  ;21/48
        db  10010101b,01010010b,10101010b,10010101b,01010010b,10101010b  ;22/48
        db  10010101b,01010101b,01010101b,00101010b,10101010b,10101010b  ;23/48
        db  10101010b,10101010b,10101010b,10101010b,10101010b,10101010b  ;24/48
        db  10101010b,10101010b,10101010b,11010101b,01010101b,01010101b  ;25/48
        db  10101010b,10101101b,01010101b,10101010b,10101101b,01010101b  ;26/48
        db  10101010b,11010101b,10101010b,11010101b,10101010b,11010101b  ;27/48
        db  10101011b,01011010b,10110101b,10101011b,01011010b,10110101b  ;28/48
        db  10101101b,01101011b,01011010b,11010110b,10110101b,10101101b  ;29/48
        db  10101101b,10101101b,10101101b,10101101b,10101101b,10101101b  ;30/48
        db  10101101b,10110110b,10110110b,11011011b,01011011b,01101101b  ;31/48
        db  10110110b,11011011b,01101101b,10110110b,11011011b,01101101b  ;32/48
        db  10110110b,11011011b,10110110b,11011011b,10110110b,11011011b  ;33/48
        db  10110110b,11101101b,11011011b,10110110b,11101101b,11011011b  ;34/48
        db  10110111b,01110110b,11101110b,11011101b,11011011b,10111011b  ;35/48
        db  10111011b,10111011b,10111011b,10111011b,10111011b,10111011b  ;36/48
        db  10111011b,10111101b,11011101b,11101110b,11101111b,01110111b  ;37/48
        db  10111011b,11011110b,11110111b,10111011b,11011110b,11110111b  ;38/48
        db  10111101b,11101111b,10111101b,11101111b,10111101b,11101111b  ;39/48
        db  10111110b,11111011b,11101111b,10111110b,11111011b,11101111b  ;40/48
        db  10111110b,11111101b,11111011b,11110111b,11101111b,11011111b  ;41/48
        db  10111111b,10111111b,10111111b,10111111b,10111111b,10111111b  ;42/48
        db  10111111b,11011111b,11110111b,11111011b,11111110b,11111111b  ;43/48
        db  10111111b,11111011b,11111111b,10111111b,11111011b,11111111b  ;44/48
        db  10111111b,11111111b,10111111b,11111111b,10111111b,11111111b  ;45/48
        db  10111111b,11111111b,11111111b,10111111b,11111111b,11111111b  ;46/48
        db  10111111b,11111111b,11111111b,11111111b,11111111b,11111111b  ;47/48
        db  11111111b,11111111b,11111111b,11111111b,11111111b,11111111b  ;48/48
ifdef SPECIAL_44
special44_48    label   byte
        db  11111111b,11101111b,11111110b,11111111b,11101111b,11111110b  ;44/48 M20NT
endif;SPECIAL_44
        .errnz (MAX_SCALEFACTOR - 48)


;---------------------------Public-Routine------------------------------;
; Bitblt
;
; Perform small bitmap bitblt function.
; Both stretching and shrinking are supported.
;
; Entry:
;
;   NPBITSDEF PASCAL Bitblt (NPBITSDEF npDstBmp, NPBITSDEF npSrcBmp);
;
;   typedef struct _BD {    /* bd */
;       NPBYTE          npBits;         // pointer to bitmap bits
;       BYTE            cbScan;         // bitmap width in bytes
;       BYTE            nScans;         // bitmap height in scancount
;       BYTE            x;              // x offset to image mapping rect
;       BYTE            y;              // y offset to image mapping rect
;       BYTE            cx;             // x extent of image mapping rect
;       BYTE            cy;             // y extent of image mapping rect
;   } BITSDEF, NEAR *NPBITSDEF;
;
; Returns:
;   AX = NPBITSDEF which indicates the result bitmap.
;
; Registers Destroyed:
; Registers Preserved:
;       SI,DI,DS
; History:
;   23-Sep-1991 -by-    Soh Ohta [jl09057 @ ymtvm3]
; Massive change.
;-----------------------------------------------------------------------;

BITSDEF_W       struc
bw_npBits       dw      ?               ; pointer to bitmap bits
bw_cbScan       dw      ?               ; bitmap width in bytes
bw_nScans       dw      ?               ; bitmap height in scancount
bw_x            dw      ?               ; x offset to image mapping rect
bw_y            dw      ?               ; y offset to image mapping rect
bw_cx           dw      ?               ; x extent of image mapping rect
bw_cy           dw      ?               ; y extent of image mapping rect
BITSDEF_W       ends

        assumes ds,nothing
        assumes es,nothing

cProc   Bitblt,<NEAR,PUBLIC,PASCAL,NODATA>,<si,di>

        parmW   npDstBmp                ; dst bitmap definition
        parmW   npSrcBmp                ; src bitmap definition

        localW  horzMaxExt              ; largest  extent
        localW  horzMinExt              ; smallest extent
        localW  horzSwitch              ; scaling  type
        localW  vertMaxExt              ; largest  extent
        localW  vertMinExt              ; smallest extent
        localW  vertSwitch              ; scaling  type

        localV  rowCodedBits,%(CB_TABLE_ENTRY)
        localV  colCodedBits,%(CB_TABLE_ENTRY)
        localW  rowIndex                ; current index to rowCodedBits
        localW  colIndex                ; current index to colCodedBits

        localB  nScanSrc                ; scan counter for src bitmap
        localB  nScanDst                ; scan counter for dst bitmap
        localB  nPelSrc                 ; pel  counter for src scanline
        localB  nPelDst                 ; pel  counter for dst scanline
        localB  iniSrcCached            ; initial src pel counter [8..1]
        localB  iniDstCached            ; initial dst pel counter [8..1]

        localB  mStart                  ; mask for start byte
        localB  mLast                   ; mask for last  byte
        localB  cbInner                 ; inner byte count
        localB  nPhase                  ; phase

        localV  srcBmp,%(size BITSDEF_W)
        localV  dstBmp,%(size BITSDEF_W)
cBegin

        cld

; Compare source and destination bitmap definition.
; If they are exactly equal, no bitblt is to be performed.

        mov     ax,ds
        mov     es,ax                   ; make sure ES == DS
        mov     si,npSrcBmp
        lea     si,[si].bd_cbScan       ; DS:SI --> src bitmap definition
        mov     di,npDstBmp
        lea     di,[di].bd_cbScan       ; ES:DI --> dst bitmap definition
        mov     cx,(SIZE BITSDEF)-bd_cbScan
        repe    cmpsb
        jnz     sb_clear_dst_bits
        jmp     sb_nop_exit             ; bitmap definitions are equal

; Fill destination bitmap with 0's.

sb_clear_dst_bits:
        mov     si,npDstBmp             ; DS:SI --> dst bitmap definition
        mov     di,[si].bd_npBits       ; ES:DI --> dst bitmap bits
        mov     al,[si].bd_cbScan
        mul     byte ptr [si].bd_nScans
        mov     cx,ax                   ; CX = number of bytes in dst bitmap
        xor     al,al
        rep     stosb                   ; clear bitmap!

; Copy source and destination bitmap definition.

        xor     ah,ah                   ; copy src bitmap definition
        mov     si,npSrcBmp
        mov     al,[si].bd_cbScan
        mov     srcBmp.bw_cbScan,ax
        mov     al,[si].bd_nScans
        mov     srcBmp.bw_nScans,ax
        mov     al,[si].bd_x
        mov     srcBmp.bw_x,ax
        mov     al,[si].bd_y
        mov     srcBmp.bw_y,ax
        mov     al,[si].bd_cx
        mov     srcBmp.bw_cx,ax
        mov     al,[si].bd_cy
        mov     srcBmp.bw_cy,ax
        mov     ax,[si].bd_npBits
        mov     srcBmp.bw_npBits,ax

        mov     ax,srcBmp.bw_y          ; normalize definition
        mul     srcBmp.bw_cbScan
        mov     dx,srcBmp.bw_x
        shr     dx,3
        add     ax,dx
        add     srcBmp.bw_npBits,ax
        mov     ax,srcBmp.bw_y
        sub     srcBmp.bw_nScans,ax
        mov     srcBmp.bw_y,0
        and     srcBmp.bw_x,7

        xor     ah,ah                   ; copy dst bitmap definition
        mov     si,npDstBmp
        mov     al,[si].bd_cbScan
        mov     dstBmp.bw_cbScan,ax
        mov     al,[si].bd_nScans
        mov     dstBmp.bw_nScans,ax
        mov     al,[si].bd_x
        mov     dstBmp.bw_x,ax
        mov     al,[si].bd_y
        mov     dstBmp.bw_y,ax
        mov     al,[si].bd_cx
        mov     dstBmp.bw_cx,ax
        mov     al,[si].bd_cy
        mov     dstBmp.bw_cy,ax
        mov     ax,[si].bd_npBits
        mov     dstBmp.bw_npBits,ax

        mov     ax,dstBmp.bw_y          ; normalize definition
        mul     dstBmp.bw_cbScan
        mov     dx,dstBmp.bw_x
        shr     dx,3
        add     ax,dx
        add     dstBmp.bw_npBits,ax
        mov     ax,dstBmp.bw_y
        sub     dstBmp.bw_nScans,ax
        mov     dstBmp.bw_y,0
        and     dstBmp.bw_x,7

; Check bitblt operations between the specified bitmaps.

        xor     cx,cx                   ; scaling flag (0:copy,  1:scale)

        mov     ax,srcBmp.bw_cy
        mov     dx,dstBmp.bw_cy
        xor     bx,bx                   ; scaling type (0:shrnk, 2:strch)
        cmp     dx,ax
        je      sb_have_vert_flags
        mov     cx,1
        jb      sb_have_vert_flags
        xchg    dx,ax
        mov     bx,2
sb_have_vert_flags:
        or      dx,dx
        jz      sb_nop_exit_relay
        mov     vertMaxExt,ax           ; largest  extent
        mov     vertMinExt,dx           ; smallest extent
        mov     vertSwitch,bx           ; scaling  type

        mov     ax,srcBmp.bw_cx
        mov     dx,dstBmp.bw_cx
        xor     bx,bx                   ; scaling type (0:shrnk, 2:strch)
        cmp     dx,ax
        je      sb_have_horz_flags
        mov     cx,1
        jb      sb_have_horz_flags
        xchg    dx,ax
        mov     bx,2
sb_have_horz_flags:
        or      dx,dx
        jz      sb_nop_exit_relay
        mov     horzMaxExt,ax           ; largest  extent
        mov     horzMinExt,dx           ; smallest extent
        mov     horzSwitch,bx           ; scaling  type

        jcxz    sb_copy_bitmap
        jmp     sb_scale_bitmap


;-----------------------------------------------------------------------;
; Copy bitmap without scaling.
;-----------------------------------------------------------------------;

        public  sb_copy_bitmap

sb_copy_bitmap:
        call    sb_comp_scan            ; compute bitblt parameters

        mov     ax,ds
        mov     es,ax                   ; make sure ES == DS
        mov     si,srcBmp.bw_npBits     ; DS:SI --> src bitmap bits
        mov     di,dstBmp.bw_npBits     ; ES:DI --> dst bitmap bits
        mov     dx,dstBmp.bw_cy         ; DX = scanline count
        call    sb_copy_scans           ; do bitblt

sb_exit_relay:
        jmp     sb_exit
sb_nop_exit_relay:
        jmp     sb_nop_exit


;-----------------------------------------------------------------------;
; Copy bitmap with scaling option.
;-----------------------------------------------------------------------;

        public  sb_scale_bitmap

sb_scale_bitmap:

        mov     ax,ss
        mov     es,ax                   ; make sure ES == SS

; Get coded bits for vertical scaling.

        mov     ax,MAX_SCALEFACTOR
        mul     vertMinExt              ; smallest extent
        mov     bx,vertMaxExt           ; largest  extent
        cmp     dx,bx
        jae     sb_nop_exit_relay
        div     bx                      ; AX = scaling ratio (1..47)
        cmp     vertSwitch,0            ; vertical scaling type?
        je      get_row_codedbits       ; shrinking...
        or      dx,dx                   ; stretching, no remainder?
        jz      get_row_codedbits       ;   yes,
        inc     ax                      ;   no, make a little larger
get_row_codedbits:
        imul    si,ax,CB_TABLE_ENTRY
        add     si,CodeOFFSET coded_table
        lea     di,rowCodedBits
        mov     cx,CB_TABLE_ENTRY/2
        rep     movs word ptr es:[di],word ptr cs:[si]

; Get coded bits for horizontal scaling.

        mov     ax,MAX_SCALEFACTOR
        mul     horzMinExt              ; smallest extent
        mov     bx,horzMaxExt           ; largest  extent
        cmp     dx,bx
        jae     sb_nop_exit_relay
        div     bx                      ; AX = scaling ratio (1..47)
        cmp     horzSwitch,0            ; horizontal scaling type?
        je      get_col_codedbits       ; shrinking...
        or      dx,dx                   ; stretching, no remainder?
        jz      get_col_codedbits       ;   yes,
        inc     ax                      ;   no, make a little larger
get_col_codedbits:
ifdef SPECIAL_44
        mov     si,CodeOFFSET special44_48
        cmp     ax,44
        je      @f
endif;SPECIAL_44
        imul    si,ax,CB_TABLE_ENTRY
        add     si,CodeOFFSET coded_table
@@:     lea     di,colCodedBits
        mov     cx,CB_TABLE_ENTRY/2
        rep     movs word ptr es:[di],word ptr cs:[si]

; Compute initial src/dsr pel counter for horizontal scaling.

        mov     cx,0808h
        mov     dl,byte ptr srcBmp.bw_x
        mov     dh,byte ptr dstBmp.bw_x
        and     dx,0707h
        sub     cx,dx
        mov     iniSrcCached,cl         ; initial src pel counter [8..1]
        mov     iniDstCached,ch         ; initial dst pel counter [8..1]


;-----------------------------------------------------------------------;
; Start scaling the bitmap per scanline basis.
;-----------------------------------------------------------------------;

; Prepare parameters for vertical scaling.
;
; Be sure that always 1 scanline is drawn at first in horizontal scaling.
; It is equivarent to:
;   - the first bit of each row codedbits table entry is always 1.
;   - the first row codebit was tested and scanline copy was performed.
;   - cached codebit was consumed and counter was decremented (see (*1)).

        mov     ax,srcBmp.bw_cy
        mov     nScanSrc,al             ; reset scan counter for src bitmap
        mov     ax,dstBmp.bw_cy
        mov     nScanDst,al             ; reset scan counter for dst bitmap
        .errnz  (MAX_BITMAPSIZE ge 256)
        mov     rowIndex,0              ; current index to rowCodedBits
        mov     dh,rowCodedBits[0]      ; DH = row codedbits cache
        mov     dl,8                    ; DL = row codedbit counter [8..1]
        shl     dh,1                    ; (*1)
        dec     dl                      ; (*1)

; Prepare parameters for horizontal scaling, then do it.

sb_scale_nextscan:
        push    dx                      ; save row codedbits/counter
        mov     ax,srcBmp.bw_cx
        mov     nPelSrc,al              ; reset pel counter for src scanline
        mov     ax,dstBmp.bw_cx
        mov     nPelDst,al              ; reset pel counter for dst scanline
        .errnz  (MAX_BITMAPSIZE ge 256)
        mov     colIndex,0              ; current index to colCodedBits
        mov     dh,colCodedBits[0]      ; DH = col codedbits cache
        mov     dl,8                    ; DL = col codedbit counter [8..1]

        mov     ax,ds
        mov     es,ax                   ; make sure ES == DS
        mov     si,srcBmp.bw_npBits     ; DS:SI --> src bitmap bits
        mov     di,dstBmp.bw_npBits     ; ES:DI --> dst bitmap bits
        call    sb_horz_scale           ; do horizontal scaling
        pop     dx                      ; restore row codedbits/counter

; Do vertical scaling for horizontally scaled scanline.

        mov     bx,vertSwitch
        jmp     cs:vertScaleProc[bx]    ; do vertical scaling
                                        ; --> sb_scale_nextscan or sb_exit

; Exit bitblt. Returns the result bitmap.

sb_nop_exit:
        mov     ax,npSrcBmp             ; return source bitmap
        jmp     short sb_done
sb_exit:
        mov     ax,npDstBmp             ; return destination bitmap
sb_done:
cEnd


;----------------------------Private-Routine----------------------------;
; sb_horz_scale
;
; There are following 5 counters maintained in this scaling logic.
;
;   src scan pel counter  (nPelSrc) : # pels remaining in src scan
;   dst scan pel counter  (nPelDst) : # pels remaining in dst scan
;   src cache pel counter      (CL) : # pels remaining in src pel   cache
;   dst cache pel counter      (CH) : # pels produced  in dst pel   cache
;   codedbit cache counter     (DL) : # bits remaining in codedbits cache
;
; Within the scaling loop:
;       AL: src pel cache (aligned to MSB)
;       AH: dst pel cache (aligned to LSB)
;       BL: src pels in a scan
;       BH: dst pels in a scan
;       CL: src pel counter [8..1] or [7..0]
;       CH: dst pel counter [8..1]
;
; Entry:
;       DS:SI   = src bitmap bits
;       ES:DI   = dst bitmap bits
;       DL      = col codedbit counter
;       DH      = col codedbits cache
; Returns:
;       DS:SI   = next src bitmap bits
;       ES:DI   = next dst bitmap bits
; Registers Destroyed:
; Registers Preserved:
; History:
;   23-Sep-1991 -by-    Soh Ohta [jl09057 @ ymtvm3]
; Massive change.
;-----------------------------------------------------------------------;

        assumes ds,nothing
        assumes es,nothing
        public  sb_horz_scale
        public  sb_horz_shrink
        public  sb_horz_stretch

sb_horz_scale   proc    near

        mov     cl,8
        sub     cl,iniSrcCached         ; number of src pels to be skipped
        lodsb                           ; AL = initial src pel cache
        shl     al,cl                   ;      align: LSB --> MSB
        xor     ah,ah                   ; AH = initial dst pel cache
        mov     cl,iniSrcCached         ; CL = src pel counter [8..1]
        mov     ch,iniDstCached         ; CH = dst pel counter [8..1]
        mov     bx,horzSwitch
        jmp     cs:horzScaleProc[bx]    ; do shrinking or stretching

sb_horz_scale_done:
        cmp     ch,8                    ; dst pel counter < 8?
        jge     @f                      ; no, all dst pels flushed already
        mov     cl,ch                   ; AH = scaled dst pel cache
        shl     ah,cl                   ;      align: LSB --> MSB
        or      es:[di],ah
@@:     ret

;-----------------------------------------------------------------------;
; Horizontally shrinking logic.
;
; On shrinking, the scaling logic must hold the destination pel cache
; even if the cached pel count becomes full.
; This is because when the next source pel is to be shrinked, the pel
; must be OR'ed to that cached pels.
;
; Thus: src pel counter:    8:full .... 1:last1pel (0:fetch)
;       dst pel counter:    8:empty ... 0:full    (-1:flush)
;-----------------------------------------------------------------------;

sb_horz_shrink:
        mov     bl,nPelSrc              ; BL = src pels in a scan
        mov     bh,nPelDst              ; BH = dst pels in a scan

; Horizontally shrinking main loop.

sbh_shr_operation?:
        shl     dh,1                    ; shrink (0)?, copy (1)?
        jnc     sbh_shr_shrink          ; shrink 1 src pel
sbh_shr_dst_full?:
        dec     bh                      ; dst scan full?
        jl      sbh_shr_shrink          ; yes, must be shrink this pel
        dec     ch                      ; dst pel cache full?
        jl      sbh_shr_flush_dst       ; yes, flush dst pel cache
sbh_shr_copy:
        shl     ax,1                    ; copy 1 src pel
sbh_shr_src_empty?:
        dec     bl                      ; src scan empty?
        jz      sb_horz_shrink_done     ; --> end of scaling
        dec     cl                      ; src pel cache empty?
        jz      sbh_shr_fetch_src       ; yes, fetch next src pels
sbh_shr_bit_empty?:
        dec     dl                      ; codedbit cache empty?
        jz      sbh_shr_fetch_bit       ; yes, fetch next codedbits
        jmp     short sbh_shr_operation?

sbh_shr_shrink:
        shl     al,1                    ; shrink 1 pel
        jnc     sbh_shr_src_empty?
        or      ah,1
        jmp     short sbh_shr_src_empty?

; Horizontally shrinking exceptional handlings.

sbh_shr_flush_dst:
        or      es:[di],ah              ; flush dst pel cache
        inc     di
        mov     ch,8-1                  ; reset dst pel counter
        jmp     short sbh_shr_copy      ; ('-1' is for sbh_shr_copy'ed bit)

sbh_shr_fetch_src:
        lodsb                           ; fetch next src pels
        mov     cl,8                    ; reset src pel counter
        jmp     short sbh_shr_bit_empty?

sbh_shr_fetch_bit:
        xchg    si,colIndex
        inc     si                      ; increment table index
        cmp     si,CB_TABLE_ENTRY       ; index reaches the end of table?
        jb      @f                      ; no..
        xor     si,si                   ; reset index to zero
@@:     mov     dh,colCodedBits[si]     ; cache nex codedbits byte
        xchg    si,colIndex
        mov     dl,8                    ; reset codedbit counter
        jmp     short sbh_shr_operation?

sb_horz_shrink_done:
        jmp     sb_horz_scale_done

;-----------------------------------------------------------------------;
; Horizontally stretching logic.
;
; On stretching, we can fetch the next source pels just when the src
; pel cache becomes empty.
; This is because when the next destination pel is to be stretched,
; we can easily get the pel from previously cached pels (still in cache).
;
; Thus: src pel counter:    8:full .... 1:last1pel (0:fetch)
;       dst pel counter:    8:empty ... 1:1pelfree (0:flush)
;-----------------------------------------------------------------------;

sb_horz_stretch:
        mov     bl,nPelSrc              ; BL = src pels in a scan
        mov     bh,nPelDst              ; BH = dst pels in a scan

; Horizontally stretching main loop.

sb_horz_operation?:
        shl     dh,1                    ; shretch (0)?, copy (1)?
        jnc     sbh_str_stretch         ; shretch 1 src pel
sbh_str_copy:
        shl     ax,1                    ; copy 1 src pel
sbh_str_src_empty?:
        dec     bl                      ; src scan empty?
        jz      sb_horz_stretch_done    ; --> end of scaling
        dec     cl                      ; src pel cache empty?
        jz      sbh_str_fetch_src       ; yes, fetch next src pels
sbh_str_dst_full?:
        dec     bh                      ; dst scan full?
        jz      sb_horz_stretch_done    ; --> end of scaling
        dec     ch                      ; dst pel cache full?
        jz      sbh_str_flush_dst       ; yes, flush dst pel cache
sbh_str_bit_empty?:
        dec     dl                      ; codedbit cache empty?
        jz      sbh_str_fetch_bit       ; yes, fetch next codedbits
        jmp     short sb_horz_operation?

sbh_str_stretch:
        ror     ah,1                    ; stretch 1 pel
        rol     ah,1
        adc     ah,ah
        jmp     short sbh_str_dst_full?

; Horizontally stretching exceptional handlings.

sbh_str_flush_dst:
        or      es:[di],ah              ; flush dst pel cache
        inc     di
        mov     ch,8                    ; reset dst pel counter
        jmp     short sbh_str_bit_empty?

sbh_str_fetch_src:
        lodsb                           ; fetch next src pels
        mov     cl,8                    ; reset src pel counter
        jmp     short sbh_str_dst_full?

sbh_str_fetch_bit:
        xchg    si,colIndex
        inc     si                      ; increment table index
        cmp     si,CB_TABLE_ENTRY       ; index reaches the end of table?
        jb      @f                      ; no..
        xor     si,si                   ; reset index to zero
@@:     mov     dh,colCodedBits[si]     ; cache nex codedbits byte
        xchg    si,colIndex
        mov     dl,8                    ; reset codedbit counter
        jmp     short sb_horz_operation?

sb_horz_stretch_done:
        jmp     sb_horz_scale_done

sb_horz_scale   endp


;----------------------------Private-Routine----------------------------;
; sb_vert_scale
;
; Entry:
;       DL      = row codedbit counter  [8:empty .. 0:full]
;       DH      = row codedbits cache
; Returns:
;       none.
; Registers Destroyed:
; Registers Preserved:
; History:
;   23-Sep-1991 -by-    Soh Ohta [jl09057 @ ymtvm3]
; Massive change.
;-----------------------------------------------------------------------;

        assumes ds,nothing
        assumes es,nothing
        public  sb_vert_shrink
        public  sb_vert_stretch

sb_vert_scale   proc    near

;-----------------------------------------------------------------------;
; Vertically shrinking logic.
;-----------------------------------------------------------------------;

sb_vert_shrink:
        dec     nScanSrc                ; another src scan remaining?
        jz      sb_vert_done            ; no, scaling all done
        mov     ax,srcBmp.bw_cbScan
        add     srcBmp.bw_npBits,ax     ; go to the next src scanline
        dec     dl                      ; coded bits run out?
        jz      sbv_shr_get_codedbits   ; yes, get next codedbits byte
sbv_shr_test_scale:
        add     dh,dh                   ; 'C' = codedbit for this src scan
        jnc     sb_vert_nextscan        ; 'NC' means shrink --> next scan
        dec     nScanDst                ; another dst scan remaining?
        jle     sb_vert_nextscan        ; no, shrink anyway
        mov     ax,dstBmp.bw_cbScan
        add     dstBmp.bw_npBits,ax     ; go to the next dst scanline
        jmp     short sb_vert_nextscan

sbv_shr_get_codedbits:
        xchg    si,rowIndex
        inc     si                      ; increment table index
        cmp     si,CB_TABLE_ENTRY       ; index reaches the end of table?
        jb      @f                      ; no..
        xor     si,si                   ; reset index to zero
@@:     mov     dh,rowCodedBits[si]     ; cache nex codedbits byte
        xchg    si,rowIndex
        mov     dl,8                    ; reset codedbit counter
        jmp     short sbv_shr_test_scale

;-----------------------------------------------------------------------;
; Vertically stretching logic.
;-----------------------------------------------------------------------;

sbv_str_stretch:
        mov     si,dstBmp.bw_npBits
        mov     cx,dstBmp.bw_cbScan     ; CX = scanline length in bytes
        sub     si,cx                   ; DS:SI --> previous (drawn) scan
        mov     di,dstBmp.bw_npBits     ; ES:DI --> current  (blank) scan
        rep     movsb
sb_vert_stretch:
        dec     nScanDst                ; another dst scan remaining?
        jz      sb_vert_done            ; no, scaling all done
        mov     ax,dstBmp.bw_cbScan
        add     dstBmp.bw_npBits,ax     ; go to the next dst scanline
        dec     dl                      ; coded bits run out?
        jz      sbv_str_get_codedbits   ; yes, get next codedbits byte
sbv_str_test_scale:
        add     dh,dh                   ; 'C' = codedbit for this src scan
        jnc     sbv_str_stretch         ; 'NC' means stretch
        dec     nScanSrc                ; another src scan remaining?
        jz      sb_vert_done            ; no, scaling all done
        mov     ax,srcBmp.bw_cbScan
        add     srcBmp.bw_npBits,ax     ; go to the next src scanline
        jmp     short sb_vert_nextscan

sbv_str_get_codedbits:
        xchg    si,rowIndex
        inc     si                      ; increment table index
        cmp     si,CB_TABLE_ENTRY       ; index reaches the end of table?
        jb      @f                      ; no..
        xor     si,si                   ; reset index to zero
@@:     mov     dh,rowCodedBits[si]     ; cache nex codedbits byte
        xchg    si,rowIndex
        mov     dl,8                    ; reset codedbit counter
        jmp     short sbv_str_test_scale

sb_vert_nextscan:
        jmp     sb_scale_nextscan
sb_vert_done:
        jmp     sb_exit

sb_vert_scale   endp


;----------------------------Private-Routine----------------------------;
; sb_comp_scan
;
; Compute bitblt parameters for bitblt (sb_copy_scans).
; Cannot handle bitmaps:    width > 255 pels
;
; Entry:
;       srcBmp  = src bitmap definition (normalized)
;       dstBmp  = dst bitmap definition (normalized)
; Returns:
;       mStart  = mask for first byte
;       mLast   = mask for last byte
;       cbInner = inner full byte count
;       nPhase  = phase
; Registers Destroyed:
;       AX,CX,DX,FLAGS
; Registers Preserved:
;       BX,BP,SI,DI,DS,ES
; History:
;   23-Sep-1991 -by-    Soh Ohta [jl09057 @ ymtvm3]
; Wrote it.
;-----------------------------------------------------------------------;

        assumes ds,nothing
        assumes es,nothing
        public  sb_comp_scan

sb_comp_scan    proc    near

        mov     cl,byte ptr dstBmp.bw_x
        mov     ch,byte ptr dstBmp.bw_cx
        .errnz  (MAX_BITMAPSIZE ge 256)
        add     ch,cl

        mov     al,ch
        dec     al
        shr     al,3
        inc     al                      ; AL = number of bytes to copy

; Compute first/last partial byte mask.
; If the mask is full byte, the mask should be zero.

        mov     dx,0ffffh
        shr     dl,cl
        cmp     dl,0ffh                 ; 'C' if DL != 0ffh
        sbb     dl,-1                   ; DL = mask for first byte
        mov     cl,ch
        and     cl,7
        shr     dh,cl
        not     dh                      ; DH = mask for last byte

; Compute inner byte count.
; If inner byte count is to be negative, inner byte count is to be 0,
; and the masks should be combined (1byte scan, lhs/rhs masked case).

        xor     ah,ah
        cmp     ah,dl                   ; 'C' if DL != 0 (first byte exists)
        sbb     al,0
        cmp     ah,dh                   ; 'C' if DH != 0 (last byte exists)
        sbb     al,0
        jnc     sb_comp_scan_done
        and     dl,dh                   ; combine masks
        mov     al,0                    ; no inner bytes
        mov     dh,0                    ; no last byte

sb_comp_scan_done:
        mov     mStart,dl
        mov     mLast,dh
        mov     cbInner,al
        mov     cl,byte ptr dstBmp.bw_x
        sub     cl,byte ptr srcBmp.bw_x
        mov     nPhase,cl
        ret

sb_comp_scan    endp


;----------------------------Private-Routine----------------------------;
; sb_copy_scans
;
; Copy specified numbers of lines from source to destination.
;
; Entry:
;       DS:SI   = src bitmap bits
;       ES:DI   = dst bitmap bits
;       DX      = scanline count
;       srcBmp  = src bitmap definition (normalized)
;       dstBmp  = dst bitmap definition (normalized)
; Returns:
;       DS:SI   = next src bitmap bits
;       ES:DI   = next dst bitmap bits
; Registers Destroyed:
;       AX,CX,DX,FLAGS
; Registers Preserved:
;       BX,BP,SI,DI,DS,ES
; History:
;   23-Sep-1991 -by-    Soh Ohta [jl09057 @ ymtvm3]
; Wrote it.
;-----------------------------------------------------------------------;

        assumes ds,nothing
        assumes es,nothing
        public  sb_copy_scans
        public  sb_copy_full
        public  sb_copy_edge

sb_copy_scans   proc    near

        mov     cl,nPhase               ; CL = phase
sb_copy_one_scan:
        push    si
        push    di

sb_copy_first:
        mov     ch,mStart               ; CH = mask for first byte
        or      ch,ch
        jz      sb_copy_inner
        call    sb_copy_edge
sb_copy_inner:
        mov     ch,cbInner              ; CH = inner byte count
        or      ch,ch
        jz      sb_copy_last
        call    sb_copy_full
sb_copy_last:
        mov     ch,mLast                ; CH = mask for last byte
        or      ch,ch
        jz      sb_copy_done
        call    sb_copy_edge

sb_copy_done:
        pop     di
        pop     si
        add     si,srcBmp.bw_cbScan
        add     di,dstBmp.bw_cbScan
        dec     dx
        jnz     sb_copy_one_scan
        ret

sb_copy_scans   endp


sb_copy_full    proc    near

        cmp     cl,0
        jl      sbcf_neg                ; negative phase
        jg      sbcf_pos                ; positive phase
sbcf_zero:
        xchg    cl,ch                   ; CX = inner byte count
        rep     movsb                   ; copy bytes without phase
        ret                             ; CL = phase (=0)
sbcf_neg:
        mov     ah,[si+1]               ; AH = supply bits
        lodsb                           ; AL = body bits
        ror     ax,cl                   ; rotate left == ror ax,cl(=neg)
        stosb
        dec     ch
        jnz     sbcf_neg
        ret
sbcf_pos:
        mov     ah,[si-1]               ; AH = supply bits
        lodsb                           ; AL = body bits
        ror     ax,cl                   ; rotate right == ror ax,cl(=pos)
        stosb
        dec     ch
        jnz     sbcf_pos
        ret

sb_copy_full    endp


sb_copy_edge    proc    near

        cmp     cl,0
        jl      sbce_neg                ; negative phase
        jg      sbce_pos                ; positive phase
sbce_zero:
        lodsb
        and     al,ch                   ; apply mask
        stosb
        ret
sbce_neg:
        mov     ah,[si+1]               ; AH = supply bits
        lodsb                           ; AL = body bits
        ror     ax,cl                   ; rotate left == ror ax,cl(=neg)
        and     al,ch                   ; apply mask
        stosb
        ret
sbce_pos:
        mov     ah,[si-1]               ; AH = supply bits
        lodsb                           ; AL = body bits
        ror     ax,cl                   ; rotate right == ror ax,cl(=pos)
        and     al,ch                   ; apply mask
        stosb
        ret

sb_copy_edge    endp

sEnd    Bitmap

End
