;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
        PAGE     55,132
        TITLE    AVIO Cell Scanning Functions
        SUBTITLE Header
;/*****************************************************************************
;*
;* SOURCE FILE NAME = CELLSCAN.ASM
;*
;* DESCRIPTIVE NAME = Scan logical Video cells
;*
;*
;* VERSION      V2.0
;*
;* DATE         11/18/91
;*
;* DESCRIPTION  Routines for scanning logical video cells and constructing
;*              pseudo code on the stack for drawing their images.
;*
;*
;* FUNCTIONS    DrawImageRect
;*              LoadCellInfo
;*              ScanFullCells
;*              ScanVerticalBorder
;*
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   11/18/91                     KEZ  Original
;*   11/18/93  @NI1               N.Ichikawa [JL25003@ymtvm4]
;*                                Fix APL font problem.
;*****************************************************************************/
;*****************************************************************************
; Model and processor selection                                              *
;*****************************************************************************

        .386P
        .MODEL FLAT,SYSCALL

;*****************************************************************************
; Included files                                                             *
;*****************************************************************************

INCL_GPIPRIMITIVES  EQU 1
INCL_SAADEFS        EQU 1
        INCLUDE PMGRE.INC

DINCL_BITMAP        EQU 1
DINCL_ENABLE        EQU 1
        INCLUDE DRIVER.INC
        INCLUDE EXTERN.INC
        INCLUDE CELLBLT.INC
DINCL_VIOPS         EQU 1
        INCLUDE PROTOS.INC
ifdef  JTUNE                                                            ;IBMJ
INCL_GRE_STRINGS    EQU 1
        INCLUDE PMDDIM.INC

        INCLUDE BSEMEMF.INC
endif ;JTUNE                                                            ;IBMJ

;*****************************************************************************
; Equates                                                                    *
;*****************************************************************************

ifndef JTUNE                                                            ;IBMJ
PSEUDOSTACKSIZE EQU 256 ;was 100
else  ;JTUNE                                                            ;IBMJ
PSEUDOSTACKSIZE EQU 4096
endif ;JTUNE                                                            ;IBMJ

;*****************************************************************************
; Data                                                                       *
;*****************************************************************************

        .DATA

        ALIGN 4

        PUBLIC  PseudoStack
PseudoStack DWORD PSEUDOSTACKSIZE dup (0)       ; Pseudocode stack

        PUBLIC PseudoStackTop
PseudoStackTop LABEL DWORD                      ; Top of stack

ifdef  JTUNE                                                            ;IBMJ

LVBShadowInfo   STRUCT  4
        Identify                DWORD   0
        pLVBShadow              DWORD   0
        dLVBShadowSize          DWORD   0
        npcpmap                 DWORD   0
        dWindowSize             DWORD   0
        dScrollVar              DWORD   0
        dVertMovement           DWORD   0
LVBShadowInfo   ENDS

ALIGN 4
PrimaryShadow           LVBShadowInfo   < 0, 0, 0, 0, 0, 0, 0 >

pShadowInfo             DWORD   0
LVBShadowOffset         DWORD   0
AvioLVBShadowOffset     DWORD   0
wExtCellInfo            WORD    0

endif ;JTUNE                                                            ;IBMJ

;*****************************************************************************
; Private functions                                                          *
;*****************************************************************************

        .CODE

;*****************************************************************************
; Public functions                                                           *
;*****************************************************************************

        SUBTITLE DrawImageRect
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = DrawImageRect
;*
;* DESCRIPTION   = This routine materializes a rectangular portion of a VIO image
;*                 on the display screen.  The rectangle is denoted by the
;*                 wrectangle at EBX.  The coordinates in that rectangle use the
;*                 bottom left origin mandated by the Graphics Engine specification.
;*                 The CharRect routine above invokes this routine indirectly via
;*                 the enumerate_clip_rects function.  By convention ESI will
;*                 hold the frame pointer for CharRect.
;*
;*                 Registers Destroyed:
;*                       ?
;*                 Registers Preserved:
;*                       BP SI
;*
;* INPUT         = EBX --> A RECTL structure defining the portion of the screen to
;*                         be painted.
;*                 ESI --> The stack frame pointer for CharRect.
;* OUTPUT        =
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

ALIGN 4
define_CharRect_frame DrawImageRect

;/*
;** Here we set up the control logic for displaying LVB characters.  We divide
;** the LVB image rectangle into five subrectangles:
;**
;**   +---+-------------------------------------------------+---+
;**   | L |             Top Border                          | R |
;**   | e +-------------------------------------------------+ i |
;**   | f |                                                 | g |
;**   | t |                                                 | h |
;**   |   |          Full                                   | t |
;**   |   |                                                 |   |
;**   | B |             Cell                                | B |
;**   | o |                                                 | o |
;**   | r |                Region                           | r |
;**   | d |                                                 | d |
;**   | e |                                                 | e |
;**   | r |                                                 | r |
;**   |   |                                                 |   |
;**   |   +-------------------------------------------------+   |
;**   |   |             Bottom Border                       |   |
;**   +---+-------------------------------------------------+---+
;**
;** The Left and Right borders require horizontal clipping (masking) and
;** possibly vertical clipping for the top and bottom characters in the border
;** columns.  These borders are drawn by the ScanVerticalBorder routine.
;**
;** The Top and Bottom borders require vertical clipping, but don't need
;** horizontal clipping (masking).  These borders are drawn by the
;** ScanFullCells routine.
;**
;** The images in the Full Cell region require neither horizontal nor vertical
;** clipping.  They also constitute the majority of the cell images to be drawn.
;** They are also drawn by the ScanFullCells routine.
;**
;** The following code assumes that EBX points to the clip rectangle for a
;** portion of the LVB image to be drawn in the destination bitmap.  The
;** coordinates in the clip rectangle are assumed to be relative to the
;** destination bitmap, with their origin a the bottom left corner.
;**
;** The code computes a set of parameters to drive routines which scan the
;** appropriate LVB cells to generate pseudo code for the drawing functions
;** which will actually materialize the image.
;*/

        PUSH    EBP                             ; Preserve the frame pointer for
                                                ; EnumClipRects.
        MOV     EBP,ESI                         ; Retrieve the frame pointer for Char
        MOV     fSomethingDrawn,ESI             ; Log the fact that we've got a
                                                ; a non-null visible region
        MOV     EAX,[EBX].RECTL.rcl_xLeft       ; Copy the clip rectangle to
                                                ; our stack frame.
        MOV     rClipRect.rcs_xLeft,EAX
        MOV     EAX,[EBX].RECTL.rcl_yBottom
        MOV     rClipRect.rcs_yBottom,EAX
        MOV     EAX,[EBX].RECTL.rcl_xRight
        MOV     rClipRect.rcs_xRight,EAX
        MOV     EAX,[EBX].RECTL.rcl_yTop
        MOV     rClipRect.rcs_yTop,EAX
ifdef  DBCS                                                              ;IBMJ
        MOV     EAX,seg_LVB
        MOV     CellBLTBlock.LowerLimitOfLVB,EAX
        XOR     EAX,EAX
        MOV     AX,wRowCount
        MUL     wColCount
        MOV     CL,byte ptr wCellSizeShift
        SHL     EAX,CL
        MOV     ESI,EAX                 ; ESI = size of LVB, used at -> (*)
        ADD     EAX,CellBLTBlock.LowerLimitOfLVB
        DEC     EAX
        MOV     CellBLTBlock.UpperLimitOfLVB,EAX
endif ;DBCS                                                             ;IBMJ
ifdef JTUNE                                                             ;IBMJ
        call    PrepareLVBShadow        ; (*) <-

        test    swFlags,SW_HAVE_ACCEL
        jz      @F
        PUSH    EBX                     ; So we can reference the original
@@:
endif;JTUNE                             ; clip rect later               ;IBMJ

;/*
;** Since we're dealing with the screen we must first exclude the mouse cursor
;** from the rectangle we'll be drawing.
;*/

        MOVZX   EDI,wDestHeight                 ; So we can flip the
        MOV     EDX,EDI                         ; coordinate origin to the
                                                ; top left corner.
        SUB     EDI,rClipRect.rcs_yBottom       ; ... Bottom ...
        SUB     EDX,rClipRect.rcs_yTop          ; ... Top    ...
        MOV     ECX,rClipRect.rcs_xLeft         ; ... Left   ...
        MOV     ESI,rClipRect.rcs_xRight        ; ... Right  ...

IFNDEF HW_CUR

        CALL    far_exclude

ENDIF; HW_CUR

ifdef  JTUNE                                                            ;IBMJ
        test    swFlags,SW_HAVE_ACCEL
        jz      not_hw_scroll
        test    swFlags,SW_SPRITE
        jnz     @F
        INVOKE  SetScreenBusy, 0        ; don't let cursor interfere
@@:
; The JTUNE flag enables ScrollRect. The reason that it's done here
; is to save space and time. Here we call BitBltCellScroll (celldraw.asm)
; to scroll the requested rect. Then we adjust the cliprect and fall
; into the normal CharRect code to draw the final lines of the scroll.
; If the scroll is unidirectional then we push a 0 on the stack. If we
; are scrolling two directions, we set the clip rect to draw the area
; exposed by the y scroll (area A) and push the cliprect for the area
; exposed by the x scroll (area B), and finally we push a non-zero
; value (1 or -1).
;
;
;           +----------------------------+-+
;           |                            | |
;           |                            | |
;           |                            |A|
;           |                            |r|
;           |        BitBlt'd area       |e|
;           |        (worse case)        |a|
;           |                            | |
;           |                            |B|
;           |                            | |
;           |                            | |
;           +----------------------------+-+
;           |           Area A             |
;           +------------------------------+
;
;
; After the CharRect code has finished displaying it's chars, then
; we pop our value off the stack. If it's non-zero, then we pop
; off a clip rect and jump back up to the top of the char rect
; code and it will fill in the final block.
;
;
; How Our CharRect World is Defined:
;
;       Screen (0,0)
;           o---------------------------------------->
;           |       A
;           |       | wVertLineOffset (signed vector)
;           |       |
;           |<------+-----------------------------+ - - A
;           | wHorzPixelOffset (signed vector)    |     |
;           |       |                             |     |
;           |       |     +----------------+ A    |     |
;           |       |     |                | |    |     |
;           |       |     |    DrawRect    | |    |     |
;           |       |     |     to be      | |RectDepth |nRowCount
;           |       A     |    scrolled    | |    |     |
;           |       |     |                | |    |     |
;           |       |     +----------------+<=StartRow  |
;           |       |                             |     |
;           |       | Logical Video Buffer (LVB)  |     |
;           |       o----------->-----------------+ - - V
;           |    ImageRect (0,0)
;           V
;
; For example, that wVertLineOffset is defined in screen coordinate and
; computed as:
;
;   wVertLineOffset = screen top (=0) - conceptual LVB image rect top
;
; So we can get the top of image rect with following equation:
;
;   image rect top  = -wVertLineOffset            (screen coordinate)
;                   = wDestHeight+wVertLineOffset (our coordinate)
;
;   draw rect top   = -wVertLineOffset
;                     +(nRowCount-(StartRow+RectDepth))*wCellHeight
;                                                 (screen coordinate)
;                   = wDestHeight+wVertLineOffset
;                     -(nRowCount-(StartRow+RectDepth))*wCellHeight
;                                                 (our coordinate)

; If we're hired not for ScrollRect, let CharRect do it.

        cmp     word ptr FunN,NGreScrollRect
        jne     do_charrect

        mov     esi,lpRectDesc          ; get desc. for the rectangle to draw

; If we're redrawing the entire screen, also let CharRect do it.

        mov     ecx,[esi].ScrollRectRef.cellscroll_HorzMovement
                                                        ; rightward scroll
        sub     ecx,[esi].ScrollRectRef.cellscroll_RectWidth
        jz      do_charrect
        mov     ecx,[esi].ScrollRectRef.cellscroll_VertMovement
                                                        ; downward scroll
        sub     ecx,[esi].ScrollRectRef.cellscroll_RectDepth
        jz      do_charrect

        mov     ecx,[esi].ScrollRectRef.cellscroll_HorzMovement
                                                        ; leftward scroll
        add     ecx,[esi].ScrollRectRef.cellscroll_RectWidth
        jz      do_charrect
        mov     ecx,[esi].ScrollRectRef.cellscroll_VertMovement
                                                        ; upward scroll
        add     ecx,[esi].ScrollRectRef.cellscroll_RectDepth
        jz      do_charrect

; If the scrolled result will be all clipped out, we need not to do
; this scroll operation.

        movzx   ebx,wCellHeight         ; keep them for many references
        movzx   ecx,wCellWidth

        mov     eax,[esi].ScrollRectRef.cellscroll_VertMovement
        mul     ebx                     ; * wCellHeight
        AbsVal
        add     eax,rClipRect.rcs_yBottom
        cmp     eax,rClipRect.rcs_yTop
        jns     scrollrect_done

        mov     eax,[esi].ScrollRectRef.cellscroll_HorzMovement
        mul     ecx                     ; * wCellWidth
        AbsVal
        add     eax,rClipRect.rcs_xLeft
        cmp     eax,rClipRect.rcs_xRight
        jns     scrollrect_done


; Okay, we still have to. Make BitBltCellScroll call.

        lea     eax,rClipRect
        push    eax                     ; lpClipRect

        mov     eax,[esi].ScrollRectRef.cellscroll_RectDepth
        mul     ebx                     ; * wCellHeight
        push    eax                     ; height

        mov     eax,[esi].ScrollRectRef.cellscroll_RectWidth
        mul     ecx                     ; * wCellWidth
        push    eax                     ; width

        mov     eax,[esi].ScrollRectRef.cellscroll_VertMovement
        mul     ebx                     ; * wCellHeight
        push    eax                     ; y delta to be scrolled

        mov     eax,[esi].ScrollRectRef.cellscroll_HorzMovement
        mul     ecx                     ; * wCellWidth
        push    eax                     ; x delta to be scrolled

        movzx   eax,wRowCount
        sub     eax,[esi].ScrollRectRef.cellscroll_StartRow
        sub     eax,[esi].ScrollRectRef.cellscroll_RectDepth
        mul     ebx                     ; * wCellHeight
        sub     ax,wVertLineOffset
        movsx   eax,ax
        push    eax                     ; rect upper left y

        mov     eax,[esi].ScrollRectRef.cellscroll_StartColumn
        mul     ecx                     ; * wCellWidth
        sub     ax,wHorzPixelOffset
        movsx   eax,ax
        push    eax                     ; rect upper left x

        mov     eax,hddc
        push    eax
        call    BitBltCellScroll
        add     esp,8*4

;/*
;**   LVB-Shadow Scroll Logic
;*/
        test    swFlags,SW_CT_DISABLE
        jnz     scrollrect_done

        mov     ebx,pShadowInfo
        cmp     [esi].ScrollRectRef.cellscroll_HorzMovement,0
        jne     LVBNotScroll
        cmp     [esi].ScrollRectRef.cellscroll_StartColumn,0
        jne     LVBNotScroll
        mov     eax,[esi].ScrollRectRef.cellscroll_RectWidth
        cmp     ax,wColCount
        jne     LVBNotScroll
        mov     eax,[esi].ScrollRectRef.cellscroll_VertMovement
        cmp     eax,[EBX].LVBShadowInfo.dVertMovement
        jne     LVBNotScroll
        cmp     eax,0
        cmp     [esi].ScrollRectRef.cellscroll_VertMovement,0
        jl      LVBScrollUp

        public  LVBScrollDown
LVBScrollDown::
        push    esi
        mov     eax,[esi].ScrollRectRef.cellscroll_RectDepth
;                  add     eax,[esi].ScrollRectRef.cellscroll_VertMovement
        cmp     ax,wRowCount
        jbe     @F
        movzx   eax,wRowCount
@@:
        sub     eax,[esi].ScrollRectRef.cellscroll_VertMovement
        mul     [esi].ScrollRectRef.cellscroll_RectWidth
        mov     cl,byte ptr wCellSizeShift
        shl     eax,cl
        push    eax                     ; length for copy -> (*)

        mov     eax,[esi].ScrollRectRef.cellscroll_StartRow
        add     eax,[esi].ScrollRectRef.cellscroll_VertMovement
        mul     [esi].ScrollRectRef.cellscroll_RectWidth
        mov     cl,byte ptr wCellSizeShift
        shl     eax,cl
        mov     edi,eax
        add     edi,[EBX].LVBShadowInfo.pLVBShadow

        mov     eax,[esi].ScrollRectRef.cellscroll_StartRow
        mul     [esi].ScrollRectRef.cellscroll_RectWidth
        mov     cl,byte ptr wCellSizeShift
        shl     eax,cl
        mov     esi,eax
        add     esi,[EBX].LVBShadowInfo.pLVBShadow

        pop     edx                     ; (*) <- length for copy
        cld
        mov     ecx,edx
        shr     ecx,2
ifndef TMP
        rep     movsd
else  ;TMP
        mov     eax,-1
        rep     stosd
endif ;TMP
        mov     ecx,edx
        and     ecx,3
ifndef TMP
        rep     movsb
else  ;TMP
        rep     stosb
endif ;TMP

        pop     esi
        jmp     scrollrect_done

        public  LVBScrollUp
LVBScrollUp::
        push    esi
        mov     edi,[esi].ScrollRectRef.cellscroll_StartRow
        add     edi,[esi].ScrollRectRef.cellscroll_VertMovement
        js      @F
        xor     edi,edi
@@:
        mov     eax,[esi].ScrollRectRef.cellscroll_RectDepth
        add     eax,edi
        mul     [esi].ScrollRectRef.cellscroll_RectWidth
        mov     cl,byte ptr wCellSizeShift
        shl     eax,cl
        push    eax                     ; length for copy -> (*)

        mov     eax,[esi].ScrollRectRef.cellscroll_StartRow
        add     eax,[esi].ScrollRectRef.cellscroll_VertMovement
        sub     eax,edi
        mul     [esi].ScrollRectRef.cellscroll_RectWidth
        mov     cl,byte ptr wCellSizeShift
        shl     eax,cl
        xchg    edi,eax
        add     edi,[EBX].LVBShadowInfo.pLVBShadow

        neg     eax
        add     eax,[esi].ScrollRectRef.cellscroll_StartRow
        mul     [esi].ScrollRectRef.cellscroll_RectWidth
        mov     cl,byte ptr wCellSizeShift
        shl     eax,cl
        mov     esi,eax
        add     esi,[EBX].LVBShadowInfo.pLVBShadow

        pop     edx                     ; (*) <- length for copy
        cld
        mov     ecx,edx
        shr     ecx,2
ifndef TMP
        rep     movsd
else  ;TMP
        mov     eax,-1
        rep     stosd
endif ;TMP
        mov     ecx,edx
        and     ecx,3
ifndef TMP
        rep     movsb
else  ;TMP
        rep     stosb
endif ;TMP

        pop     esi
        jmp     scrollrect_done

        public  LVBNotScroll
LVBNotScroll::
        mov     ecx,CellBLTBlock.UpperLimitOfLVB
        sub     ecx,CellBLTBlock.LowerLimitOfLVB
        inc     ecx
        shr     ecx,2
        mov     edi,[EBX].LVBShadowInfo.pLVBShadow
        mov     eax,-1
        cld
        rep     stosd
        mov     eax,[esi].ScrollRectRef.cellscroll_VertMovement
        mov     [EBX].LVBShadowInfo.dVertMovement,eax

scrollrect_done:


; Adjust clip rect for "Area A" from the vertical scroll.

        xor     ecx,ecx                 ; assumes not scrolled vertically
        mov     eax,[esi].ScrollRectRef.cellscroll_VertMovement
        or      eax,eax                 ; check scroll direction up/down
        jz      done_with_vert          ; not scrolled vertically
        js      scrolled_up             ; negative value means scrolled up


; Scrolled Down:
; Somewhere in the bottom of draw rectangle is drawn by bitblt.
; The bottom of clip rectangle may need to be updated.
;
; After scrolled, the bottom of invalidated area (Area A) is to be:
;   1. top of scrolled draw rectangle (when draw.top < clip.top)
;   2. top of scrolled clip rectangle (when clip.top < draw.top)
;      (be sure that here we uses the lower-left originated coordinate)
;
; And also, this bottom of invalidated rect may be clipped by the
; bottom of clip rectangle (when clip.bottom > invalidated.bottom)
;
;
;                           1. draw rectangle
;                           +---------------+<==top
;                           |       |       |
;                           |       |       |
;                           |       V       |
;                           |    downward   |
;                           |    scroll     |
;                           +---------------+
;                                   ||
;                                   VV
;
;   2. clip rectangle        BLT not clipped   or   BLT is clipped
;   +---------------+<==top +---------------+      +---------------+
;   |       |       |       | |             |      | |             |
;   |       |       |       | | invalidated |      | |             |
;   |       V       |  ==>  | V             |      | | invalidated |
;   |    downward   |       |---------------|<=!   | |             |
;   |    scroll     |       |  BLT'ed area  |      | |             |
;   +---------------+       +---------------+      +-V-------------+<=!!
;                                                  +- - - - - - - -+
;                                                  :  BLT'ed area  :
;
; The invalidated area will be drawn by CharRect.
; Currently, AX = es:cellscroll_VertMovement[si].lo (positive value)

scrolled_down:
        mul     wCellHeight                 ; eax = amount of scroll Y in pels
        mov     ebx,rClipRect.rcs_yTop ; top of clip rect
        sub     ebx,eax                     ; bx = scrolled top of clip rect

        mov     di,wDestHeight
        add     di,wVertLineOffset
        movsx   edi,di
        push    eax
        movzx   eax,wRowCount
        sub     eax,[esi].ScrollRectRef.cellscroll_StartRow
        sub     eax,[esi].ScrollRectRef.cellscroll_RectDepth
        mul     wCellHeight
        sub     edi,eax                     ; top of draw rect
        pop     eax
        sub     edi,eax                     ; edi = scrolled top of draw rect

        cmp     ebx,edi                     ; take lower one
        js      @f
        mov     ebx,edi
@@:                                         ; ebx = bottom of invalidated area

        mov     eax,rClipRect.rcs_yBottom ; eax = bottom of clip rect
        SMax    ebx                          ; ebx = max (eax,ebx)
        mov     rClipRect.rcs_yBottom,ebx ; update bottom of clip rect

        mov     ecx,1                        ; note scrolled downward
        jmp     done_with_vert


; Scrolled Up:
; Somewhere in the top of draw rectangle is drawn by bitblt.
; The top of clip rectangle may need to be updated.
;
; After scrolled, the top of invalidated area (Area A) is to be:
;   1. bottom of scrolled draw rectangle (when draw.bot > clip.bot)
;   2. bottom of scrolled clip rectangle (when clip.bot > draw.bot)
;      (be sure that here we uses the lower-left originated coordinate)
;
; And also, this top of invalidated rect may be clipped by the
; top of clip rectangle (when clip.top < invalidated.top)
;
;
;                           1. draw rectangle
;                           +---------------+
;                           |    upward     |
;                           |    scroll     |
;                           |       A       |
;                           |       |       |
;                           |       |       |
;                           +---------------+<==bot
;                                   ||             :  BLT'ed area  :
;                                   VV             +- - - - - - - -+
;   +---------------+       +---------------+      +-A-------------+<=!!
;   |    upward     |       |  BLT'ed area  |      | |             |
;   |    scroll     |       |---------------|<=!   | |             |
;   |       A       |  ==>  | A             |      | | invalidated |
;   |       |       |       | | invalidated |      | |             |
;   |       |       |       | |             |      | |             |
;   +---------------+<==bot +---------------+      +---------------+
;   2. clip rectangle        BLT not clipped   or   BLT is clipped
;
;
; The invalidated area will be drawn by CharRect.
; Currently, AX = es:cellscroll_VertMovement[si].lo (negative value)

scrolled_up:
        mul     wCellHeight            ; eax = -(amount of scroll Y in pels)
        mov     ebx,rClipRect.rcs_yBottom ; bottom of clip rect
        sub     ebx,eax                ; ebx = scrolled bottom of clip rect

        mov     di,wDestHeight
        add     di,wVertLineOffset
        movsx   edi,di
        push    eax
        movzx   eax,wRowCount
        sub     eax,[esi].ScrollRectRef.cellscroll_StartRow
        mul     wCellHeight
        sub     edi,eax                     ; bottom of draw rect
        pop     eax
        sub     edi,eax                ; edi = scrolled bottom of draw rect

        cmp     ebx,edi                     ; take upper one
        jns     @f
        mov     ebx,edi
@@:                                         ; ebx = top of invalidated area

        mov     eax,rClipRect.rcs_yTop ; eax = top of clip rect
        SMin    ebx                          ; ebx = min (eax,ebx)
        mov     rClipRect.rcs_yTop,ebx ; update top of clip rect


        mov     ecx,-1                      ; note scrolled upward
done_with_vert:


; Adjust clip rect for "Area B" from the horizontal scroll.

        mov     eax,[esi].ScrollRectRef.cellscroll_HorzMovement
        or      eax,eax                     ; check scroll direction left/right
        jz      do_charrect                 ; not scrolled horizontally
        js      scrolled_left               ; negative value means scrolled left


; Scrolled Right:
; Somewhere in the right of draw rectangle is drawn by bitblt.
; The right of clip rectangle may need to be updated.
;
; After scrolled, the right of invalidated area (Area B) is to be:
;   1. left of scrolled draw rectangle (when draw.left > clip.left)
;   2. left of scrolled clip rectangle (when clip.left > draw.left)
;      (be sure that here we uses the lower-left originated coordinate)
;
; And also, this right of invalidated rect may be clipped by the
; right of clip rectangle (when clip.right < invalidated.right)
;
;
;                           1. draw rectangle
;                           +---------------+
;                           |               |
;                           |----------->   |
;                           |   rightward   |
;                           |   scroll      |
;                           +---------------+
;                           left    ||
;                                   VV
;
;   2. clip rectangle        BLT not clipped   or   BLT is clipped
;   +---------------+       +-----------+---+      +---------------++---
;   |               |       |           |   |      |               ||
;   |----------->   |  ==>  |---------->|BLT|      |--------------->|BLT
;   |   rightward   |       |invalidated|'ed|      |  invalidated  ||'ed
;   |   scroll      |       |           |   |      |               ||
;   +---------------+       +-----------+---+      +---------------++---
;   left                                !                         !!
;
;
; The invalidated area will be drawn by CharRect.
; Currently, AX = es:cellscroll_HorzMovement[si].lo (positive value)

scrolled_right:
        mul     wCellWidth                  ; eax = amount of scroll X in pels
        mov     ebx,rClipRect.rcs_xLeft ; left of clip rect
        add     ebx,eax                     ; ebx = scrolled left of clip rect

        push    eax
        mov     eax,[esi].ScrollRectRef.cellscroll_StartColumn
        mul     wCellWidth
        sub     ax,wHorzPixelOffset
        movsx   eax,ax
        mov     edi,eax                     ; left of draw rect
        pop     eax
        add     edi,eax                     ; edi = scrolled left of draw rect

        cmp     ebx,edi                     ; take right one
        jns     @f
        mov     ebx,edi
@@:                                         ; ebx = right of invalidated area

        mov     eax,rClipRect.rcs_xRight ; eax = right of clip rect
        SMin    ebx                         ; ebx = min (eax,ebx)
                                            ;    = update right of clip rect

        or      ecx,ecx                     ; also vertically scrolled ?
        jnz     rightclip_modified          ; yes, do it first. save cliprect.
        mov     rClipRect.rcs_xRight,ebx ; no, update clip rect and
        jmp     do_charrect                 ; go through normal pass.


; Scrolled Left:
; Somewhere in the left of draw rectangle is drawn by bitblt.
; The left of clip rectangle may need to be updated.
;
; After scrolled, the left of invalidated area (Area B) is to be:
;   1. right of scrolled draw rectangle (when draw.right < clip.right)
;   2. right of scrolled clip rectangle (when clip.right < draw.right)
;      (be sure that here we uses the lower-left originated coordinate)
;
; And also, this left of invalidated rect may be clipped by the
; left of clip rectangle (when clip.left > invalidated.left)
;
;
;                           1. draw rectangle
;                           +---------------+
;                           |               |
;                           |   <-----------|
;                           |    leftward   |
;                           |    scroll     |
;                           +---------------+
;                                   ||  right
;                                   VV
;
;   2. clip rectangle        BLT not clipped   or       BLT is clipped
;   +---------------+       +---+-----------+      ---++---------------+
;   |               |       |   |           |         ||               |
;   |   <-----------|  ==>  |BLT|<----------|      BLT|<---------------|
;   |    leftward   |       |'ed|invalidated|      'ed||  invalidated  |
;   |    scroll     |       |   |           |         ||               |
;   +---------------+       +---+-----------+      ---++---------------+
;               right           !                      !!
;
;
; The invalidated area will be drawn by CharRect.
; Currently, AX = es:cellscroll_HorzMovement[si].lo (negative value)

scrolled_left:
        mul     wCellWidth                ; eax = -(amount of scroll X in pels)
        mov     ebx,rClipRect.rcs_xRight ; right of clip rect
        add     ebx,eax                   ; ebx = scrolled right of clip rect

        push    eax
        mov     eax,[esi].ScrollRectRef.cellscroll_StartColumn
        add     eax,[esi].ScrollRectRef.cellscroll_RectWidth
        mul     wCellWidth
        sub     ax,wHorzPixelOffset
        movsx   eax,ax
        mov     edi,eax                     ; right of draw rect
        pop     eax
        add     edi,eax                    ; edi = scrolled right of draw rect

        cmp     ebx,edi                     ; take left one
        js      @f
        mov     ebx,edi
@@:                                         ; ebx =left of invalidated area

        mov     eax,rClipRect.rcs_xLeft ; eax = left of clip rect
        SMax    ebx                         ; ebx = max (ax,bx)
                                            ;    = update left of clip rect

        or      ecx,ecx                     ; also vertically scrolled ?
        jnz     leftclip_modified           ; yes, do it first. save cliprect.
        mov     rClipRect.rcs_xLeft,ebx ; no, update clip rect and
        jmp     do_charrect                 ; go through normal pass.


; Here we should call CharRect twice (worst case).
;
; We will draw Area A (vertically invalidated area) at first, and the
; modified vertical clip (top/bottom) is already stored in rClipRect.
; ... ready to use for Area A CharRect.
;
; Now we have modified horizontal clip (left/right) in CX. We will
; construct clip rectangle for Area B, which is drawn in the second pass.
; In the second pass:
;
;   vertclip for Area B = ~(vertclip for Area A)
;
; because the portion of (modified vertclip) & (modified horzclip) will
; have been drawn in the first pass.
;
; We will keep the clip rectangle for Area B (horizontally invalidated
; area) onto the stack.
; The value of top of stack (must non 0) indicate that the second pass
; should be performed later (and also indicates the cliprect was saved).

rightclip_modified:
        pop     esi
        push    [esi].RECTL.rcl_xLeft         ; original leftclip
        push    ebx                     ; modified rightclip
        jmp     @f

leftclip_modified:
        pop     esi
        push    ebx                     ; modified leftclip
        push    [esi].RECTL.rcl_xRight        ; original rightclip


@@:     or      ecx,ecx                 ; check scroll direction up/down
        js      topclip_modified        ; negative value means scrolled up


bottomclip_modified:
        push    [esi].RECTL.rcl_yBottom       ; original bottomclip
        push    rClipRect.rcs_yBottom; modified bottomclip as topclip
        jmp     push_cliprect_saved_flag

topclip_modified:
        push    rClipRect.rcs_yTop; modified topclip as bottomclip
        push    [esi].RECTL.rcl_yTop          ; original topclip
        jmp     push_cliprect_saved_flag


; Here we will call CharRect only once.
; Modified (or not modified for simple CharRect case) clip rectangle is
; saved in the rClipRect structure.

do_charrect:
        xor     ecx,ecx                 ; no rClipRect saved on the stack.
        pop     eax                     ; clean up the stack (was clip rect)


        public  push_cliprect_saved_flag
push_cliprect_saved_flag::
        push    ecx                     ; top of stack = cliprect saved flag
not_hw_scroll:
endif ;JTUNE                                                            ;IBMJ

        MOVZX   ESI,wDestHeight                 ; So we can flip the
        MOV     EAX,ESI                         ; coordinate origin to the
                                                ; top left corner.
        SUB     EAX,rClipRect.rcs_yBottom       ; ... Bottom ...
        MOVSX   EDI,wVertLineOffset              ; Convert to LVB image
        ADD     EDI,EAX                         ; coordinates.
        MOV     EAX,EDI
        MOVZX   EBX,wCellHeight
        XOR     EDX,EDX
        DIV     EBX
        MOV     wBotRow,AX                      ; Bottom limit on the LVB row
                                                ; set which is not clipped
                                                ; vertically.  Like
                                                ; RECTS.bottom, this defines
                                                ; a boundary, not an index.
        MOV     ECX,EAX
        MUL     EBX
        SUB     EDI,EAX
        MOV     wBotLines,DI                    ; The number of scan lines in
                                                ; the bottom border below the
                                                ; FULL (i.e., unclipped)
                                                ; region.
        SUB     AX,wVertLineOffset              ; Convert to destination
                                                ; coordinates.
        MOV     wBotFullLine,AX                 ; A boundary line in the sense
                                                ; of RECT.bottom for the LVB
                                                ; image region which is not
                                                ; clipped vertically.
        MOV     EAX,ESI
        SUB     EAX,rClipRect.rcs_yTop          ; ... Top ...
        MOVSX   EDI,wVertLineOffset             ; Convert to LVB image
        ADD     EAX,EDI                         ; coordinates.
        MOV     EDI,EAX
        ADD     EAX,EBX
        DEC     EAX
        DIV     EBX
        MOV     wTopRow,AX                      ; LVB row index for the first
                                                ; row not clipped vertically
        SUB     ECX,EAX
        MOV     wFullRows,CX                    ; The number of rows in the
                                                ; FULL region (possibly zero)
        MUL     EBX
        SUB     EDI,EAX
        NEG     EDI
        MOV     wTopLines,DI                    ; The number of scan lines in
                                                ; the top border above the
                                                ; FULL (i.e., unclipped)
                                                ; region.
        SUB     AX,wVertLineOffset              ; Convert to destination
                                                ; coordinates.
        MOV     wTopFullLine,AX                 ; Image Y coordinate for the
                                                ; top line of the
                                                ; LVB[wBotRow] image
        MOV     EAX,rClipRect.rcs_xRight        ; ... Right ...
        MOVSX   ECX,wHorzPixelOffset            ; Convert to LVB image
        ADD     EAX,ECX                         ; coordinates.
        MOV     ECX,EAX
        PixToCol AX
        MOV     wRightCol,AX                    ; Right limit on the LVB col.
                                                ; set which is not clipped
                                                ; horizontally.  Like
                                                ; RECT.right, this defines a
        MOV     EDI,EAX
        ColToPix AX
        SUB     CX,AX
        MOV     wRightLines,CX                  ; Vertical lines in the right
                                                ; border.
        SUB     AX,wHorzPixelOffset
        MOV     wRightFullLine,AX               ; Boundary line to the right
                                                ; of the full cell region

        MOV     EAX,rClipRect.rcs_xLeft         ; ... Left ...
        MOVSX   ECX,wHorzPixelOffset            ; Convert to LVB image
        ADD     EAX,ECX                         ; coordinates.
        MOV     ECX,EAX
        MOVZX   ESI,wCellWidth
        ADD     EAX,ESI
        DEC     EAX
        PixToCol AX
        MOV     wLeftCol,AX                     ; LVB index of the leftmost
                                                ; column of the LVB which is
                                                ; not clipped horizontally.
        SUB     EDI,EAX
        MOV     ESI,EDI
        MOV     wFullCols,EDI                   ; The number of columns in the
                                                ; FULL region (possibly zero)
        ColToPix AX
        SUB     CX,AX
        NEG     CX
        MOV     wLeftLines,CX                   ; Vertical lines in the left
                                                ; border.
        SUB     AX,wHorzPixelOffset
        MOV     wLeftFullLine,AX                ; Leftmost vertical line in
                                                ; the full cell region
        MOV     CX,wCellSizeShift               ; Shift factor for multiplying
                                                ; by Cell Size
        SHL     ESI,CL                          ; A LVB pointer increment used
        SUB     SI,wLVBRowBytes                 ; to move from the front of an
        MOV     wLVBRowInc,SI                   ; LVB row to the end of the
                                                ; next row above.
        MOV     SI,wCellSize                    ; An LVB address increment for
        SUB     SI,wLVBRowBytes                 ; moving vertically.
        MOVSX   ESI,SI
        MOV     wVertLVBIncr,ESI
        XOR     EDI,EDI                         ; Base offset for the Logical
                                                ; Video Buffer
        MOVZX   EAX,wTopRow
        MOVZX   ESI,wColCount
        MUL     ESI
        MOVZX   EDX,wLeftCol
        ADD     EAX,EDX
        SHL     EAX,CL
        ADD     EAX,EDI
        ADD     EAX,seg_LVB
        MOV     pFirstFullLVBCell,EAX           ; The LVB offset for the top
        MOVZX   EAX,wBotRow                     ; left cell in the FULL region
        DEC     EAX
        MUL     ESI
        MOVSX   EDX,wRightCol
        ADD     EAX,EDX
        SHL     EAX,CL
        ADD     EAX,EDI
        SUB     EAX,2
        ADD     EAX,seg_LVB
        MOV     pLastFullLVBCell,EAX            ; Address of the last LVB WORD
                                                ; at the bottom right corner
                                                ; of the FULL region.

;/*
;** The code below computes a bound on ESP.  It's used to determine how much
;** pseudo code we can push on the stack before we segment the scanning process.
;*/

;;;STACKSTUFF

        PUBLIC  StackCalculations
StackCalculations::
        MOV     EBX,offset PseudoStackTop
        XCHG    EBX,ESP

        PUSH    EBX                            ; And save old ESP
ifndef JFIX                                                             ;IBMJ
        MOV     pStackLimit,OFFSET PseudoStack+cb_variables_len+StackFirewall
else  ;JFIX                                                             ;IBMJ
        MOV     pStackLimit,OFFSET PseudoStack+StackFirewall
endif ;JFIX                                                             ;IBMJ

        MOV     EAX,ESP                 ; Where the return address
        SUB     EAX,StackCallOverhead   ; used by the Scan functions
        MOV     pReturnAddress,EAX      ; will be...

;/*
;** The code below directs the drawing for the image rectangle.  The side
;** effects of the code above are assumed.
;**
;** The rectangle is partitioned into a central region consisting of cell images
;** which don't need to be clipped, and a perimeter of border cell images which
;** must be clipped either horizontally or vertically.  A collection of
;** subfunctions are invoked to process each category of subregion and
;** materialize the image.  Those subfunctions generate pseudo code on the stack
;** and invoke the drawing functions.
;*/

        MOV     wfForceColors,0FFFFh    ; Set a flag to mark the first
                                        ; segment of processing for the
                                        ; current rectangle.
        MOV     ECX,wFullCols           ; Checking width boundary conditions.
        OR      ECX,ECX                 ; When wFullCols is negative, the left
        JS      OneColumn               ; and right borders overlap to form a
        JMP     DoLeftBorder            ; single vertical stripe.

        PUBLIC  OneColumn
ALIGN 4
OneColumn::
        MOV     AX,wLeftFullLine
        MOV     BX,wLeftLines
        SUB     AX,BX
        MOV     xcoordStart,AX
        MOV     AX,wCellWidth
        SUB     AX,BX
        MOV     wLeftLineOffset,AX
        MOV     BX,wRightLines
        SUB     BX,AX
        MOV     wVertLineCount,BX
        MOV     EAX,pFirstFullLVBCell
        SUB     EAX,2

;/*
;** This back-up factor works for both Vio and AVio cells because we always want
;** to point to the last WORD of the cell.  See the routine LoadCellInfo for the
;** reasons.
;*/

        MOV     pFirstLVBCell,EAX
        MOV     EAX,pLastFullLVBCell
        MOVZX   EBX,wCellSize                   ; Adjust to the next cell.
        ADD     EAX,EBX
        MOV     pLastLVBCell,EAX
        CALL    ScanVerticalBorder              ; Use caller's call frame
        JMP     RectDone

ALIGN 4
        PUBLIC  DoLeftBorder
DoLeftBorder::
        MOV     BX,wLeftLines
        OR      BX,BX
        JZ      DoRightBorder
        MOV     AX,wLeftFullLine
        SUB     AX,BX
        MOV     xcoordStart,AX
        MOV     AX,wCellWidth
        SUB     AX,BX
        MOV     wLeftLineOffset,AX
        MOV     wVertLineCount,BX
        MOV     EAX,pFirstFullLVBCell
        SUB     EAX,2                           ; Back up 1 word.

;/*
;** This back-up factor works for both Vio and AVio cells because we always want
;** to point to the last WORD of the cell.  See the routine LoadCellInfo for the
;**reasons.
;*/

        MOV     pFirstLVBCell,EAX
        MOV     EAX,pLastFullLVBCell
        MOV     EBX,wFullCols
        MOV     CX,wCellSizeShift
        SHL     EBX,CL
        SUB     EAX,EBX
        MOV     pLastLVBCell,EAX
        CALL    ScanVerticalBorder              ; Use caller's call frame

        PUBLIC  DoRightBorder
DoRightBorder::
        MOV     AX,wRightLines
        OR      AX,AX
        JZ      DoMiddleColumns

        MOV     wVertLineCount,AX
        MOV     AX,wRightFullLine
        MOV     xcoordStart,AX
        XOR     AX,AX
        MOV     wLeftLineOffset,AX

        MOV     EAX,pFirstFullLVBCell
        MOV     EBX,wFullCols
        MOV     CX,wCellSizeShift
        SHL     EBX,CL
        ADD     EAX,EBX

;/*
;** The adjustment below insures that pFirstLVBCell always points to the last
;** WORD of the LVB cell in question.  See the routine LoadCellInfo for this.
;*/

        MOVZX   ECX,wCellSize
        ADD     EAX,ECX
        SUB     EAX,2
        MOV     pFirstLVBCell,EAX
        MOV     EAX,pLastFullLVBCell
        MOVZX   ECX,wCellSize
        ADD     EAX,ECX
        MOV     pLastLVBCell,EAX
        CALL    ScanVerticalBorder

        PUBLIC  DoMiddleColumns
DoMiddleColumns::
        MOV     ECX,wFullCols
        OR      CX,CX
        JNZ     GotFullCells
        JMP     RectDone

        PUBLIC  GotFullCells
ALIGN 4
GotFullCells::
        MOV     AX,wCellWidth
        MOV     wfForceColors,0FFFFh
        MOV     wVertLineCount,AX
        XOR     AX,AX
        MOV     wLeftLineOffset,AX
        MOV     AX,wLeftFullLine
        MOV     xcoordTopLeft,AX
        MOV     AX,wFullRows
        OR      AX,AX
        JNS     MultipleMiddleRows
        MOV     EAX,pFirstFullLVBCell
        MOVZX   EBX,wLVBRowBytes
        SUB     EAX,EBX
        MOV     pFirstLVBCell,EAX
        MOV     EBX,wFullCols
        MOV     CX,wCellSizeShift
        SHL     EBX,CL
        ADD     EAX,EBX
        SUB     EAX,2
        MOV     pLastLVBCell,EAX
        MOV     ESI,EAX
        MOVZX   EAX,wTopFullLine
        MOVZX   EBX,wTopLines
        SUB     EAX,EBX
        MOV     ycoordTopLeft,AX
        MOVZX   EAX,wCellHeight
        SUB     EAX,EBX
        MOV     wTopLineOffset,EAX
        MOVZX   EBX,wBotLines
        SUB     EBX,EAX
        MOV     wScanLineCount,EBX
        MOV     ECX,wFullCols
        CALL    ScanFullCells
        JMP     RectDone

ALIGN 4
        PUBLIC  MultipleMiddleRows
MultipleMiddleRows::
        MOVZX   EAX,wTopLines
        OR      EAX,EAX
        JZ      DoFullCells
        MOVZX   EBX,wTopFullLine
        SUB     EBX,EAX
        MOV     ycoordTopLeft,BX
        MOVZX   EBX,wCellHeight
        SUB     EBX,EAX
        MOV     wTopLineOffset,EBX
        MOV     wScanLineCount,EAX
        MOV     EAX,pFirstFullLVBCell
        MOVZX   EBX,wLVBRowBytes
        SUB     EAX,EBX
        MOV     pFirstLVBCell,EAX
        MOV     EBX,wFullCols
        MOV     CX,wCellSizeShift
        SHL     EBX,CL
        ADD     EAX,EBX
        SUB     EAX,2
        MOV     pLastLVBCell,EAX
        MOV     ESI,EAX
        MOV     ECX,wFullCols
        CALL    ScanFullCells

        PUBLIC  DoFullCells
DoFullCells::
        MOV     BX,wFullRows
        OR      BX,BX
        JZ      DoBottomBorder
        XOR     EAX,EAX
        MOV     wTopLineOffset,EAX
        MOVZX   EAX,wCellHeight
        MOV     wScanLineCount,EAX
        MOV     AX,wTopFullLine
        MOV     ycoordTopLeft,AX
        DEC     BX
        MOV     ECX,wFullCols
        MOV     CH,BL
        MOV     ESI,pLastFullLVBCell
        CALL    ScanFullCells

        PUBLIC  DoBottomBorder
DoBottomBorder::
        MOVZX   EAX,wBotLines
        OR      EAX,EAX
        JZ      RectDone
        MOV     wScanLineCount,EAX
        XOR     EAX,EAX
        MOV     wTopLineOffset,EAX
        MOV     AX,wBotFullLine
        MOV     ycoordTopLeft,AX
        MOV     EAX,pLastFullLVBCell
        MOVZX   ESI,wLVBRowBytes
        ADD     EAX,ESI
        MOV     ESI,EAX
        MOV     pLastLVBCell,EAX
        MOV     EBX,wFullCols
        MOV     CX,wCellSizeShift
        SHL     EBX,CL
        SUB     EAX,EBX
        ADD     EAX,2
        MOV     pFirstLVBCell,EAX
        MOV     ECX,wFullCols
        CALL    ScanFullCells

        PUBLIC  RectDone
RectDone::

        POP     ESP                     ; Restore original stack

ifdef  JTUNE                                                            ;IBMJ

; Check to see if we have another clip rect to do.

        test    swFlags,SW_HAVE_ACCEL
        jz      @F
        pop     eax                     ; get cliprect saved flag
        or      eax,eax                 ; all done if zero
        jz      no_saved_cliprect

        pop     rClipRect.rcs_yTop      ; restore modified cliprect
        pop     rClipRect.rcs_yBottom
        pop     rClipRect.rcs_xRight
        pop     rClipRect.rcs_xLeft
        xor     ecx,ecx                 ; no longer the cliprect is saved...
        jmp     push_cliprect_saved_flag
no_saved_cliprect:
        test    swFlags,SW_SPRITE
        jnz     @F
        INVOKE  SetScreenBusy, 1        ; cursor can interfere again
        or      swFlags,SW_CT_DIS_REQ   ; disable it if divide.
@@:
endif ;JTUNE                                                            ;IBMJ

IFNDEF HW_CUR

        CALL    far_unexclude

ENDIF; HW_CUR


        INVOKE  InnerCheckCursor                ; Actually a CheckCursor call
        MOV     ESI,EBP                         ; Restore ESI and EBP to the
        POP     EBP                             ; values they had on entry.

;/*
;** enumerate_clip_rects requires a non-zero result to keep going.  A zero
;** result stops the enumeration.
;*/

        MOV     EAX,ESP


        RET


ifdef  JTUNE                                                            ;IBMJ
;---------------------------Publice Routine-----------------------------;
; PrepareLVBShadow
;
; Prepare Logical Video Buffer Shadow for fast cell drawing.
;
; Entry:
;       ESI = size of LVB
; Returns:
;       None
; Error Returns:
;       None
; Registers Preserved:
;       EBX,EDX,EBP
; Calls:
;       None
; History:
;  4-Dec-1992      by  Hidemasa Muta [jl25345 at ymtvm3]
; Wrote it!
;-----------------------------------------------------------------------;


        public  PrepareLVBShadow
PrepareLVBShadow::
        push    ebx

;/*
;** If BitBlt or ExtTextOut called after previous CharRect/ScrollRect,
;** There is possibility that this window was moved or resized or switched to
;** another window.
;*/
        test    swFlags,SW_CT_DIS_REQ   ; Request for disable this logic.
        jz      @F
        xor     eax,eax
        mov     PrimaryShadow.Identify,eax
        jmp     CanNotUseShadow
@@:

;/*
;** If this LVB has already backed-up or not ?
;*/
        mov     ebx,lpPS
        mov     eax,[ebx].VioPresentationSpace32.viops_pLVB
        lea     ebx,PrimaryShadow
        cmp     eax,[ebx].LVBShadowInfo.Identify
        je      FoundShadow

;/*
;** Could not find shadow both on Primary and Secondary buffer.
;*/
        lea     ebx,PrimaryShadow
        mov     [ebx].LVBShadowInfo.Identify,eax
        mov     [ebx].LVBShadowInfo.npcpmap,0
        jmp     CanNotUseShadow

FoundShadow:
        mov     pShadowInfo,ebx

;/*
;** Re-allocate shadow if its size is smaller than this LVB.
;*/
        cmp     [ebx].LVBShadowInfo.dLVBShadowSize,esi
        jae     LVBShadowAllocated
        cmp     [ebx].LVBShadowInfo.pLVBShadow,0
        je      @F
        mov     eax,[ebx].LVBShadowInfo.pLVBShadow
        invoke  SSFreeMem, eax
        mov     [ebx].LVBShadowInfo.pLVBShadow,0
@@:
        mov     [ebx].LVBShadowInfo.dLVBShadowSize,0
        lea     eax,[ebx].LVBShadowInfo.pLVBShadow
        invoke  SSAllocMem,
                eax,
                esi,
                fALLOC
        or      eax,eax
        jnz     CanNotUseShadow
        mov     [ebx].LVBShadowInfo.dLVBShadowSize,esi
        mov     [ebx].LVBShadowInfo.npcpmap,0
LVBShadowAllocated:

;/*
;** Calculate offset from LVB to LVB shadow space.
;*/
        mov     eax,[ebx].LVBShadowInfo.pLVBShadow
        sub     eax,CellBLTBlock.LowerLimitOfLVB
        add     eax,2
        mov     LVBShadowOffset,eax
        add     eax,2
        mov     AvioLVBShadowOffset,eax

;/*
;** We should consider scroll-var position movement.
;*/
        mov     eax,lpPS
        mov     cx,[eax].VioPresentationSpace32.viops_WindowOriginRow
        shl     ecx,16
        mov     cx,[eax].VioPresentationSpace32.viops_WindowOriginColumn
        xchg    [ebx].LVBShadowInfo.dScrollVar,ecx

;/*
;** In some case, LVB size is changed before BitBlt call.
;*/
        mov     dx,[eax].VioPresentationSpace32.viops_WindowHeight
        shl     edx,16
        mov     dx,[eax].VioPresentationSpace32.viops_WindowWidth
        xchg    [ebx].LVBShadowInfo.dWindowSize,edx

;/*
;** We also should Refresh LVB Shadow, if code page is changed.
;*/
        mov     eax,npcpmap
        xchg    [ebx].LVBShadowInfo.npcpmap,eax

        or      eax,eax
        jz      RefreshLVBShadow
        cmp     [ebx].LVBShadowInfo.npcpmap,eax
        jne     RefreshLVBShadow
        cmp     [ebx].LVBShadowInfo.dScrollVar,ecx
        jne     RefreshLVBShadow
        cmp     [ebx].LVBShadowInfo.dWindowSize,edx
        jne     RefreshLVBShadow
        jmp     CheckCursorPos

;/*
;** Now, we have to Refresh LVB Shadow.
;*/
        public  RefreshLVBShadow
RefreshLVBShadow::
        mov     ecx,esi
        shr     ecx,2
        mov     edi,[ebx].LVBShadowInfo.pLVBShadow
        mov     eax,-1
        cld
        rep     stosd

;/*
;** We should exclude text-cursor position from LVB Shadow.
;*/
CheckCursorPos:
        and     swFlags,not SW_CT_DISABLE
        mov     esi,lpPS
        movzx   eax,wColCount
        movzx   edx,wRowCount
        movzx   ecx,[esi].VioPresentationSpace32.viops_CursorCol
        movzx   esi,[esi].VioPresentationSpace32.viops_CursorRow
ifdef  TMP
        cmp     eax,ecx
        jb      InvalidCursorPos
        cmp     edx,esi
        jb      InvalidCursorPos
endif ;TMP
        sub     edx,esi
        dec     edx
        mul     edx
        add     eax,ecx
        cmp     wCellSizeShift,2
        je      @F
        shl     eax,1
        add     eax,[ebx].LVBShadowInfo.pLVBShadow
        mov     word ptr [eax],-1
        jmp     CheckLVBShadowExit
@@:
        shl     eax,2
        add     eax,[ebx].LVBShadowInfo.pLVBShadow
        mov     dword ptr [eax],-1
        jmp     CheckLVBShadowExit

ifdef  TMP
InvalidCursorPos:
        jmp     CheckLVBShadowExit
endif ;TMP

;/*
;** This time, disable all LVB shadow logic.
;*/
CanNotUseShadow:
        or      swFlags,SW_CT_DISABLE

CheckLVBShadowExit:
        pop     ebx
        ret
endif ;JTUNE                                                            ;IBMJ

DrawImageRect ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE LoadCellInfo
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = LoadCellInfo
;*
;* DESCRIPTION   = This routine scans a Vio or AVio cell and places image and
;*                 attribute information about that cell in AX and BX.  Cells
;*                 scanning goes from high addresses toward low addresses.
;*
;*                 Registers Destroyed:
;*                       AX
;*                 Registers Preserved:
;*                       None
;*
;* INPUT         = ESI   --> Points to the last WORD of the cell to scan.
;*                 FLAGS  =  STD is assumed.
;* OUTPUT        = EDX  = The offset within the current symbol set of the character
;*                        image referenced by the cell.
;*                 EBX  = The attribute information for the cell.  The bit fields
;*                        therein are given by the masks AVioColorSetMask, etc.
;*                 ESI --> Point to the last WORD of the next cell to scan.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

ALIGN 4
define_CharRect_frame LoadCellInfo

        MOV     EAX,1                           ; Are we scanning an AVio
        CMP     AX,wCellSizeShift               ; logical video buffer?
        JB      LoadAVioInfo
        XOR     EDX,EDX                         ; If not,zero the extra AVio
        LODSW                                   ; attribute bits, and copy
ifndef DBCS                                                             ;IBMJ
        XCHG    DH,AH                           ; over the color information.
else ;DBCS  ; DBCS AVio attribute support                               ;IBMJ
        MOV     DH,AH                   ; the color information. keep AH.
endif;DBCS                                                              ;IBMJ
        JMP     LCI_Exit

ALIGN 4
        PUBLIC  LoadAVioInfo
LoadAVioInfo::
        LODSW                                   ; For an AVio LVB we extract
ifndef DBCS ; DBCS AVio attribute support                               ;IBMJ
        XOR     AH,AH
endif;not DBCS                                                          ;IBMJ
        MOV     EDX,EAX                         ; the attribute information
        LODSW                                   ; and put the extra control
        XCHG    AH,DH                           ; bits in BL.

        PUBLIC  LCI_Exit
LCI_Exit::

        RET

LoadCellInfo ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

ifdef DBCS  ; DBCS AVio attribute support                               ;IBMJ

;--------------------------------Macro----------------------------------;
; VioCheckCellType   (macro version)
; fnVioCheckCellType (proc version)
;
;   Check if the specified cell is DBCS cell or not.
;   Be sure we are scanning PS backwords.
;
; Entry:
;   pstype= 4:AVio, 2:Vio,                         for macro version only.
;   AH:AL = DBCS attribute byte/code point
;   ESI   = current LVB cell - 2
;   EBP   = code page mapping vector (in DGroup)   for macro version only.
;   EBP   = CharRect frame                         for proc  version only.
;   FLAGS = Direction flag must be set.
;   cb_dbcsbits = DBCS bits if current PS supports their definition.
; Returns:
;      AX = SBCS/DBCS code point
;   FLAGS = NC : code point is SBCS
;           CY : code point is DBCS
;   cb_markword = DBCS mark pseudo code for DBCS cells.
; Registers Destroyed:
;   EAX,FLAGS
; Registers Preserved:
;   EBX,ECX,EDX,EBP,ESI,EDI
; Calls:
;   DbcsScanCells (internal proc)
; History:
;   14-Dec-1990 by Soh Ohta [jl09057 at ymtvm3]
; Created.
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; (1) PS Format and DBCS attribute bits definition
;
;       Format              FormatID  DBCS attrbyte   DBCS bits
;       ------------------- --------- --------------- -----------
;       Vio,  CGA           00h       n/a             n/a
;       AVio, Extended CGA  00h       n/a             n/a
;       Vio,  IBM JAPAN     01h       attr 1st byte   000000TDb
;       AVio, Common DBCS   70h       attr 3rd byte   T000000Db
;
;       D bit: DBCS leading/trailing byte - indicator
;       T bit: DBCS trailing byte         - qualifier
;
;       DBCS leading  byte: (attr)&(DBCS bits) != 0
;       DBCS trailing byte: (attr)&(DBCS bits) == DBCS bits
;
;       For the PS format in which the DBCS bits are not defined,
;       we will detect DBCS cells by scanning PS backwords.
;
; (2) Special Cases
;
;                   PS:00
;                 Ú-ÚÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
;                 |?³2³(a)                      ³
;                 À-ÃÄÙ- - - - - - - - - - - -ÚÄ´-¿
;                   ³                      (d)³1³2|
;                 Ú-ÃÄ¿- - - - - - - - - - - -ÀÄ´-Ù
;                 |1³2³(c)                      ³
;                 À-ÃÄÙ- - - - - - - - - - - -ÚÄ´-¿
;                   ³                      (b)³1³?|
;                   ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÙ-Ù
;                                                PS:END
;
;     (a) DBCS trailing byte at PS:00 --- never happend (managed by BVH)
;         If it occurs, we cannot guess the leading byte for this cell,
;         so we will handle it as a SBCS cell.
;
;     (b) DBCS leading byte at PS:END --- never happend (managed by BVH)
;         If it occurs, we cannot guess the trailing byte for this cell,
;         so we will handle it as a SBCS cell.
;
;     (c) DBCS trailing byte at first column in a row
;         We guess the leading byte for this cell is located at the
;         end of column in the row just above.
;
;     (d) DBCS leading byte at last column in a row
;         We guess the trailing byte for this cell is located at the
;         beginning of column in the row just below.
;-----------------------------------------------------------------------;

VioCheckCellType        macro   pstype
        local   do_checkbits,sbcs_cell,dbcs1_cell,dbcs2_cell,end_check

        push    ebx
        push    ecx
        test    CellBLTBlock.cb_fsNls,NLSCA_SBCS
        jnz     sbcs_cell                       ;; SBCS codepage
        and     ah,byte ptr CellBLTBlock.cb_dbcsbits;; DBCS cell ?
        jnz     do_checkbits                    ;; yes...
        cmp     byte ptr CellBLTBlock.cb_dbcsbits,0 ;; DBCS bits defined ?
        jnz     sbcs_cell                       ;; yes, it's SBCS cell

;; This PS format doesn't support DBCS attribute bits.
;; We should perform cell scanning for this row.

        mov     ah,pstype                       ;; AVio=4, Vio=2
        INVOKE  DbcsScanCells                   ;; do scanning cells
        jg      dbcs1_cell                      ;; >0, DBCS leading byte
        jl      dbcs2_cell                      ;; <0, DBCS trailing byte
        jmp     sbcs_cell                       ;; =0, SBCS cell

;; This PS format support DBCS attribute bits. We assumes that these
;; bits are always correct, and do nothing about code-point range check.

do_checkbits:
        cmp     ah,byte ptr CellBLTBlock.cb_dbcsbits    ;; DBCS trailing byte ?
        je      dbcs2_cell                      ;; yes...
dbcs1_cell:
        lea     ebx,[esi][2+pstype]             ;; BX = next cell address
        cmp     ebx,CellBLTBlock.UpperLimitOfLVB ;; exeeds the segment limit ?
        ja      sbcs_cell                       ;; yes, force it SBCS cell
        mov     ah,[ebx]                        ;; get DBCS trailing byte
        xchg    al,ah
        mov     CellBLTBlock.cb_markword,PSEUDO_DBCS_1ST
        stc
        jmp     end_check
dbcs2_cell:
        mov     ebx,esi
        sub     ebx,pstype-2                    ;; lea bx,[si][2-pstype] < 0 ?
        cmp     ebx,CellBLTBlock.LowerLimitOfLVB
        jb      sbcs_cell                       ;; yes, force it SBCS cell
        mov     ah,[ebx]                        ;; get DBCS trailing byte
        mov     CellBLTBlock.cb_markword,PSEUDO_DBCS_2ND
        stc
        jmp     end_check
sbcs_cell:
        xor     ah,ah
        clc
end_check:
        pop     ecx
        pop     ebx
                endm

        SUBTITLE fnVioCheckCellType
        PAGE +

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

ALIGN 4
define_CharRect_frame   fnVioCheckCellType

        push    ebp
        cmp     wCellSizeShift,1        ; avio logical video buffer ?
        ja      vcct_avio               ; yes...
vcct_vio:
        mov     ebp,npcpmap
        VioCheckCellType        2       ; SBCS? DBCS? (4:Avio,2:Vio)
        jmp     vcct_exit
vcct_avio:
        mov     ebp,npcpmap
        VioCheckCellType        4       ; SBCS? DBCS? (4:Avio,2:Vio)
vcct_exit:
        pop     ebp
        ret
fnVioCheckCellType      ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE DbcsScanCells
        PAGE +

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

ALIGN 4
DbcsScanCells   PROC    SYSCALL

; We will a search SBCS cell by scanning PS backwards.
; If we find a SBCS cell, we can detect the type of current cell.
;
;           S D D D D ? = DBCS leading byte, or SBCS cell (by code-point)
;         S D D D D D ? = DBCS trailing byte
;   scan <----------| (?=current cell, D=DBCS, S=SBCS)
;
; This code makes the following assumptions:
;
;       EAX      -- current cell offset in PS (saved original)
;       EBX      -- code point (BH must be 0)
;       ECX      -- work
;       EDX      -- offset to the previous cell
;       EDI      -- mapping vector
;       ESI      -- points to a cell

        push    eax
;       push    ebx                     ; (already saved)
;       push    ecx                     ; (already saved)
        push    edx
        push    esi

        xor     ebx,ebx                 ; EBX = work (must BH=0)
        xor     edx,edx
        mov     dl,ah                   ; DX = offset to the prev cell
        xchg    edi,ebp                 ; EDI --> mapping vector
        add     esi,2                   ; ESI --> current cell
        mov     eax,esi                 ; EAX = current cell
        sub     esi,edx                 ; ESI --> previous cell ?
        cmp     esi,CellBLTBlock.LowerLimitOfLVB
        jns     scan_prev_cell          ; ok, it exists

        add     esi,edx                 ; ESI --> current cell
        jmp     check_cell_type         ; it is the first cell in this PS.

; Search a SBCS cell (or first cell in this PS) by scanning PS backwards.
; On exiting this loop, we point a DBCS leading byte.

scan_prev_cell:
        mov     bl,[esi]
        cmp     [edi].CpMapTable.cmt_DBCSLeading[ebx],0
        je      get_back_to_next        ; SBCS cell
        sub     esi,edx                 ; ESI --> previous cell ?
        cmp     esi,CellBLTBlock.LowerLimitOfLVB
        jns     scan_prev_cell          ; ok, it exists
get_back_to_next:
        add     esi,edx                 ; ESI --> DBCS leading byte

; Now we have DBCS leading byte cell position in ESI.

        mov     ecx,edx                 ; ECX = number of bytes in a cell
        xchg    eax,esi                 ; ESI = current cell
        sub     eax,esi
        neg     eax
        cwd
        div     ecx                     ; AX = number of DBCS leading cells
        shr     eax,1                   ; is it even or odd number ?
        jc      dbcs2_cell              ; odd. current cell is DBCS trailing

; Our cell being checked is just after the DBCS trailing byte.
; We will check this cell's code-point to know if it is SBCS or DBCS.

check_cell_type:
        mov     bl,[esi]
        cmp     [edi].CpMapTable.cmt_DBCSLeading[ebx],0
        je      sbcs_cell
dbcs1_cell:
        cmp     bh,-1                   ; flag:G, DBCS leading byte
        jmp     end_scan
dbcs2_cell:
        cmp     bh,1                    ; flag:L, DBCS trailing byte
        jmp     end_scan
sbcs_cell:
        cmp     bh,0                    ; flag:E, SBCS cell
end_scan:
        xchg    edi,ebp
        pop     esi
        pop     edx
;       pop     ecx                     ; (already saved)
;       pop     ebx                     ; (already saved)
        pop     eax
        ret
DbcsScanCells ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE DbcsCodeToOffset
        PAGE +

;---------------------------Private Routine-----------------------------;
; DbcsCodeToOffset
;
;   Put DBCS code-point to array (cb_adbcschar) and return offset.
;
; Entry:
;      EAX = DBCS code-point
;      FLAGS = DN (std assumed)
; Returns:
;      EAX = offset based cb_adbcschar
;      CY = new entry was consumed
; Registers Destroyed:
;   EAX,FLAGS
; Registers Preserved:
;   EBX,ECX,EDX,EBP,ESI,EDI
; Calls:
; History:
;   07-Feb-1991 by Soh Ohta [jl09057 at ymtvm3]
; Created. I wanna sleep... *sigh*
;-----------------------------------------------------------------------;

ALIGN 4
DbcsCodeToOffset PROC SYSCALL   USES ECX EDI

        movzx   eax,ax
        mov     ecx,CellBLTBlock.cb_cdbcschar
        jcxz    cto_not_found           ; no DBCS code-point put

        mov     edi,ecx
        dec     edi
        lea     edi,CellBLTBlock.cb_adbcschar[edi*4]
                                        ; EDI --> end of code-point array
        repne   scasd                   ; find AX from array (be sure std!)
        jne     cto_not_found

cto_it_found:
        shl     ecx,2
        mov     eax,ecx                 ; EAX = offset if it is found
        clc                             ; clear carry
        jmp     cto_done

cto_not_found:
        mov     edi,CellBLTBlock.cb_cdbcschar
        inc     edi
        xchg    edi,CellBLTBlock.cb_cdbcschar   ; update DBCS char count
        shl     edi,2                   ; DI = offset, newly added
        mov     CellBLTBlock.cb_adbcschar[edi],eax
        mov     eax,edi                 ; AX = offset now added
        stc                             ; set carry

cto_done:
        ret
DbcsCodeToOffset        ENDP

endif;DBCS                                                              ;IBMJ

        SUBTITLE ScanVerticalBorder
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = ScanVerticalBorder
;*
;* DESCRIPTION   = This subroutine coordinates the drawing actions for a set of
;*                 Vio/AVio cells which constitute a vertical border for the
;*                 prospective image.  The images for those cells will be
;*                 clipped horizontally.  Some of those images may also be
;*                 clipped vertically.
;*
;*
;*
;* INPUT         = xcoordStart     -- leftmost image line of the column to be drawn.
;*                 wLeftLineOffset -- number of vertical lines to skip in the
;*                                    glyph images.
;*                 wVertLineCount  -- number of vertical lines to copy from the
;*                                    glyph images to the destination image.
;*                 wTopLines
;*                 wTopFullLine
;*                 wBotLines
;*                 wBotFullLine
;*                 wFullRows
;*                 pFirstLVBCell
;*                 pLastLVBCell
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

ALIGN 4
define_CharRect_frame ScanVerticalBorder

        MOV     AX,wFullRows            ; Check to see if this vertical
        OR      AX,AX                   ; border fits completely into
        JNS     MultipleVStripeRows     ; a single cell.
        STD
        MOV     AX,wTopFullLine
        MOVZX   EBX,wTopLines
        SUB     AX,BX
        MOV     ycoordStart,AX
        MOVZX   EAX,wCellHeight
        SUB     EAX,EBX
        MOV     wTopLineOffset,EAX
        MOVZX   EBX,wBotLines
        SUB     EBX,EAX
        MOV     wScanLineCount,EBX
        PushRet EAX,VStripeDone
        MOV     ESI,pFirstLVBCell
        MOVZX   EBX,wLVBRowBytes
        SUB     ESI,EBX
        CALL    LoadCellInfo
        AND     DX,(NOT AVioUnderscoreMask)     ; Because we know the bottom
                                                ; line is not included in this
                                                ; image
ifdef JFIX                                                              ;IBMJ
        push    ESI
        mov     ESI,AVioLCIDMask
        and     SI,DX
        mov     ESI,wSymbolSetOffsets[ESI*4]
        mov     npcpmap,ESI             ; Get mapping vector for this LCID
        pop     ESI
endif;JFIX                                                              ;IBMJ

ifndef DBCS                                                             ;IBMJ
; EAX contains a code point index which we map to a glyph point index
; via the code page mapping vector at npcpmap.  We push that glyph index
; as part of the pseudo code.

        MOV     ESI,EAX
        SHL     ESI,1
        ADD     ESI,npcpmap
        PUSH    [ESI]
else ;DBCS  ; DBCS AVio attribute support                               ;IBMJ
; AH/AL contains DBCS attribute byte/code point.
; Check if it is a part of DBCS cell or not. If it is, the DBCS mark
; word, which indicates the DBCS leading/trailing byte, is saved and
; carry flag is set.

        call    fnVioCheckCellType      ; SBCS? DBCS?
        jnc     VClipSBCS               ; it's SBCS cell

; AX contains a DBCS code point. Register it into the DBCS code point
; array (cb_adbcschar) , and get the entry offset.
; The pseudo code for DBCS characters are defined as:
; - DBCS leading  byte = entry offset | PSEUDO_DBCS_1ST
; - DBCS trailing byte = entry offset | PSEUDO_DBCS_2ND

VClipDBCS:
        mov     CellBLTBlock.cb_cdbcschar,1
        mov     CellBLTBlock.cb_adbcschar,eax
        push    CellBLTBlock.cb_markword ; offset=0 ... PSEUDO_DBCS_XXX itself
        jmp     VClipCellSaved

; AX contains a code point index which we map to a glyph point index
; via the code page mapping vector at es:npcpmap.  We push that glyph index
; as part of the pseudo code.

VClipSBCS:
        MOV     CellBLTBlock.cb_cdbcschar,0
        MOV     ESI,EAX
        SHL     ESI,1
        ADD     ESI,npcpmap
        PUSH    [ESI]

VClipCellSaved:
endif;DBCS                                                              ;IBMJ
        PUSH    EDX
        NOT     EDX
        MOV     wLastAttributes,DX
        JMP     InterpretAttributes

ALIGN 4
        PUBLIC  MultipleVStripeRows
MultipleVStripeRows::
        MOVZX   EAX,wTopLines                   ; Check for a ragged edge on
        OR      EAX,EAX                         ; the top of the column.
        JZ      DoVStripeMiddle
        STD
        MOV     wScanLineCount,EAX              ; Scan lines to draw.
        MOVZX   EBX,wTopFullLine
        SUB     EBX,EAX
        MOV     ycoordStart,BX
        MOVZX   EBX,wCellHeight
        SUB     EBX,EAX
        MOV     wTopLineOffset,EBX
        PushRet EDX,DoVStripeMiddle             ; Set our return point.
        MOVZX   ESI,wLVBRowBytes                ; Load the image address and
        NEG     ESI                             ; attribute information for
        ADD     ESI,pFirstLVBCell               ; this cell.
        CALL    LoadCellInfo
ifdef JFIX                                                              ;IBMJ
        PUSH    ESI
        MOV     ESI,AVioLCIDMask
        AND     SI,DX
        MOV     ESI,wSymbolSetOffsets[ESI*4]
        MOV     npcpmap,ESI             ; Get mapping vector for this LCID
        POP     ESI
endif;JFIX                                                              ;IBMJ

ifndef DBCS                                                             ;IBMJ
;/*
;** EAX contains a code point index which we map to a glyph point index
;** via the code page mapping vector at npcpmap.  We push that glyph index
;** as part of the pseudo code.
;*/

        XCHG    ESI,EAX
        SHL     ESI,1
        ADD     ESI,npcpmap
        PUSH    [ESI]

else ;DBCS  ; DBCS AVio attribute support                               ;IBMJ

; AH/AL contains DBCS attribute byte/code point.
; Check if it is a part of DBCS cell or not. If it is, the DBCS mark
; word, which indicates the DBCS leading/trailing byte, is saved and
; carry flag is set.

        call    fnVioCheckCellType      ; SBCS? DBCS?
        jnc     VSTopSBCS               ; it's SBCS cell

; AX contains a DBCS code point. Register it into the DBCS code point
; array (cb_adbcschar) , and get the entry offset.
; The pseudo code for DBCS characters are defined as:
; - DBCS leading  byte = entry offset | PSEUDO_DBCS_1ST
; - DBCS trailing byte = entry offset | PSEUDO_DBCS_2ND

VSTopDBCS:
        mov     CellBLTBlock.cb_cdbcschar,1
        mov     CellBLTBlock.cb_adbcschar,eax
        push    CellBLTBlock.cb_markword ; offset=0 ... PSEUDO_DBCS_XXX itself
        jmp     VSTopCellSaved

; AX contains a code point index which we map to a glyph point index
; via the code page mapping vector at es:npcpmap.  We push that glyph index
; as part of the pseudo code.

VSTopSBCS:
        mov     CellBLTBlock.cb_cdbcschar,0
        XCHG    ESI,EAX
        SHL     ESI,1
        ADD     ESI,npcpmap
        PUSH    [ESI]

VSTopCellSaved:

endif;DBCS                                                              ;IBMJ
        PUSH    EDX
        NOT     EDX
        MOV     wLastAttributes,DX
        JMP     InterpretAttributes             ; Draw it!

ALIGN 4
        PUBLIC  DoVStripeMiddle
DoVStripeMiddle::
ifndef JFIX                                                             ;IBMJ
        MOV     AX,wFullRows                    ; Do we have any full-height
else  ;JFIX                                                             ;IBMJ
        MOVZX   EAX,wFullRows                   ; Do we have any full-height
endif ;JFIX                                                             ;IBMJ
        OR      AX,AX                           ; cells in this border?
        JNZ     DoVStripeFC
        JMP     DoVStripeBottom

ALIGN 4
        PUBLIC  DoVStripeFC
DoVStripeFC::
ifdef DBCS  ; DBCS AVio attribute support                               ;IBMJ
        MOV     CellBLTBlock.cb_cdbcschar,0
                                        ; clear cb_adbcschar data length
endif;DBCS                                                              ;IBMJ
        STD
        MOV     ECX,EAX
        MOV     ESI,pLastLVBCell
        MOV     AX,wTopFullLine
        MOV     ycoordStart,AX
        MOVZX   EBX,wCellHeight
        MOV     wScanLineCount,EBX
        MOV     wTopLineOffset,0
        MOV     EBX,ESI
        CALL    LoadCellInfo
ifdef JFIX                                                              ;IBMJ
        mov     ESI,AVioLCIDMask
        and     SI,DX
        mov     ESI,wSymbolSetOffsets[ESI*4]
        mov     npcpmap,ESI             ; Get mapping vector for this LCID
endif;JFIX                                                              ;IBMJ
        MOV     ESI,EBX
        MOV     EDI,EDX
        MOV     EBX,npcpmap
        PushRet EAX,DoVStripeBottom

;;;STACKSTUFF
;/*
;** NB: Because this scanning loop is not segmented, the stack must be
;**     large enough to hold the worst case pseudo code for a vertical
;**     column.  Given that a logical video buffer is limited to no more
;**     than 255 rows, that implies a requirement of 764 words (3 words
;**     per row except for the first row).  In reality we won't be dealing
;**    with more than 50 rows.  That means a worst case requirement for
;**     149 words of stack space for pseudo code.
;*/

        PUBLIC  VBScanLoop
VBScanLoop::
        CALL    LoadCellInfo
ifndef DBCS                                                             ;IBMJ
        ADD     ESI,wVertLVBIncr
        CMP     EDI,EDX
        JNE     VBAttributesChanged

        PUBLIC  VBAttributesFixed
VBAttributesFixed::
        XCHG    ESI,EAX
        SHL     ESI,1
        PUSH    [EBX+ESI]
        MOV     ESI,EAX
else ;DBCS  ; DBCS AVio attribute support                               ;IBMJ
        CMP     EDI,EDX
        JNE     VBAttributesChanged

VBAttributesFixed:

; AH/AL contains DBCS attribute byte/code point.
; Check if it is a part of DBCS cell or not. If it is, the DBCS mark
; word, which indicates the DBCS leading/trailing byte, is saved and
; carry flag is set.

        CALL    fnVioCheckCellType      ; SBCS? DBCS?
        JNC     VSMidSBCS               ; it's SBCS cell

; AX contains a DBCS code point. Register it into the DBCS code point
; array (cb_adbcschar) , and get the entry offset.
; The pseudo code for DBCS characters are defined as:
; - DBCS leading  byte = entry offset | PSEUDO_DBCS_1ST
; - DBCS trailing byte = entry offset | PSEUDO_DBCS_2ND

VSMidDBCS:
        INVOKE  DbcsCodeToOffset        ; get entry offset
        OR      EAX,CellBLTBlock.cb_markword    ; construct DBCS markword
        PUSH    EAX
        JMP     VSMidCellSaved

; AX contains a code point index which we map to a glyph point index
; via the code page mapping vector at es:bx.  We push that glyph index
; as part of the pseudo code.

VSMidSBCS:
        XCHG    ESI,EAX
        SHL     ESI,1
        PUSH    [EBX+ESI]
        MOV     ESI,EAX

VSMidCellSaved:
        ADD     ESI,wVertLVBIncr
endif;DBCS                                                              ;IBMJ
        LOOP    VBScanLoop
        PUSH    EDI
        NOT     EDI
        MOV     wLastAttributes,DI
ifdef  JTUNE                                                            ;IBMJ
        or      swFlags,SW_CT_DISABLE
        xor     eax,eax
        mov     PrimaryShadow.Identify,eax
endif ;JTUNE                                                            ;IBMJ
        JMP     InterpretAttributes

ALIGN 4
        PUBLIC  VBAttributesChanged
VBAttributesChanged::
        PUSH    EDI
        PUSHD   -1
ifdef JFIX                                                              ;IBMJ
        xor     edi,edx
        and     edi,AVioLCIDMask        ; Did the LCID index change?
        jz      VBLcidNotChanged

; If the LCID index has changed, we must set BP to point to the code page
; mapping vector for the new LCID

        push    esi
        mov     esi,AVioLCIDMask
        and     si,dx
        mov     esi,wSymbolSetOffsets[esi*4]
        mov     npcpmap,esi             ; Get mapping vector for this LCID
        pop     esi

ifdef DBCS  ; DBCS AVio attribute support                               ;IBMJ

; LCID has been changed. The DBCS version of InterpretAttributes can
; handle only one LCID at once so that we should split vert-border here.

        mov     eax,ecx                 ; Compute cell position
        mul     wCellHeight
        add     ax,wTopFullLine
        mov     ycoordStart,ax

        mov     wSaveCounts,cx          ; Save the registers
        mov     cx,wCellSizeShift
        mov     eax,1
        shl     eax,cl
        add     esi,eax
        mov     pCell,esi

        mov     eax,OFFSET VBLcidChanged
        mov     ebx,pReturnAddress
        mov     [ebx],eax               ; Adjust the return point


        pop     eax                     ; Remove -1 from stack
        pop     eax                     ; Force reset cell attributes
        push    eax
        not     eax
        mov     wLastAttributes,ax

        jmp     InterpretAttributes

VBLcidChanged:
        mov     CellBLTBlock.cb_cdbcschar,0
                                        ; Clear cb_adbcschar data length
        movzx   ecx,wSaveCounts         ; Restore the registers for
        mov     esi,pCell               ; scanning cells
        std                             ; Phase 1 processes cells in
                                        ; reverse order
        PushRet eax,DoVStripeBottom     ; Set the return address
                                        ; optimistically
        mov     ax,wTopFullLine         ; Reset cell start position
        mov     ycoordStart,ax          ; also

        mov     ebx,npcpmap             ; code page mapping vector.

        call    LoadCellInfo

endif;DBCS                                                              ;IBMJ

VBLcidNotChanged:
endif;JFIX                                                              ;IBMJ
        MOV     EDI,EDX
ifndef DBCS                                                             ;IBMJ
        JMP     SHORT VBAttributesFixed
else  ;DBCS                                                             ;IBMJ
        JMP     VBAttributesFixed
endif ;DBCS                                                             ;IBMJ

ALIGN 4
        PUBLIC  DoVStripeBottom
DoVStripeBottom::
        MOVZX   EAX,wBotLines                   ; Check for a ragged edge on
        OR      EAX,EAX                         ; the bottom of the column.
        JZ      VStripeDone
        STD
        MOV     wScanLineCount,EAX
        MOV     wTopLineOffset,0
        MOVZX   EAX,wBotFullLine
        MOV     ycoordStart,AX
        PushRet ECX,VStripeDone
        MOVZX   ESI,wLVBRowBytes
        ADD     ESI,pLastLVBCell
        CALL    LoadCellInfo
        AND     EDX,(NOT AVioUnderscoreMask)    ; Because we know the bottom
                                                ; line is not included in this
                                                ; image
ifdef JFIX                                                              ;IBMJ
        push    esi
        mov     esi,AVioLCIDMask
        and     si,dx
        mov     esi,wSymbolSetOffsets[esi*4]
        mov     npcpmap,esi             ; Get mapping vector for this LCID
        pop     esi
endif;JFIX                                                              ;IBMJ

ifndef DBCS                                                             ;IBMJ
        MOV     ESI,EAX
        SHL     ESI,1
        ADD     ESI,npcpmap
        PUSH    [ESI]

else ;DBCS  ; DBCS AVio attribute support                               ;IBMJ
; AH/AL contains DBCS attribute byte/code point.
; Check if it is a part of DBCS cell or not. If it is, the DBCS mark
; word, which indicates the DBCS leading/trailing byte, is saved and
; carry flag is set.

        call    fnVioCheckCellType      ; SBCS? DBCS?
        jnc     VSBotSBCS               ; it's SBCS cell

; AX contains a DBCS code point. Register it into the DBCS code point
; array (cb_adbcschar) , and get the entry offset.
; The pseudo code for DBCS characters are defined as:
; - DBCS leading  byte = entry offset | PSEUDO_DBCS_1ST
; - DBCS trailing byte = entry offset | PSEUDO_DBCS_2ND

VSBotDBCS:
        mov     CellBLTBlock.cb_cdbcschar,1
        mov     CellBLTBlock.cb_adbcschar,eax
        push    CellBLTBlock.cb_markword ; offset=0 ... PSEUDO_DBCS_XXX itself
        jmp     VSBotCellSaved

; AX contains a code point index which we map to a glyph point index
; via the code page mapping vector at es:npcpmap.  We push that glyph index
; as part of the pseudo code.

VSBotSBCS:
        mov     CellBLTBlock.cb_cdbcschar,0
        mov     esi,eax
        shl     esi,1
        add     esi,npcpmap
        push    [esi]

VSBotCellSaved:

endif;DBCS                                                              ;IBMJ
        PUSH    EDX
        NOT     EDX
        MOV     wLastAttributes,DX
        JMP     InterpretAttributes

ALIGN 4
        PUBLIC  VStripeDone
VStripeDone::

        RET

ScanVerticalBorder ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE ScanFullCells
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = ScanFullCells
;*
;* DESCRIPTION   = This subroutine coordinates the drawing actions for the
;*                 Vio/AVio cells which are to be drawn with no horizontal
;*                 clipping.
;*
;*                 Registers Destroyed:
;*                       AX BX CX DX SI DI DS FLAGS
;*                 Registers Preserved:
;*                       None
;*
;* INPUT         = wTopLineOffset   -- number of scan lines to skip at the top of
;*                                     a cell image.
;*                 wScanLineCount   -- number of scan lines to draw for a cell.
;*
;*                 xcoordTopLeft    -- destination coordinates at which drawing
;*                 ycoordTopLeft       is to be done.
;*
;*                 wLVBRowInc       -- increment for moving SI from row to row.
;*                 pStackLimit      -- limit on the space for Pseudo Code.
;*                 wCellSizeShift   -- 1 => Vio, 2 => AVio
;*                 pReturnAddress   -- Stack address of the return address
;*                                     slot for the Pseudo Code interpreter.
;*
;*                 npcpmap          -- DGroup offset of the code page mapping vector.
;*                 CH  = Rows-1
;*                 CL  = Columns
;*                 ESI --> The last LVB WORD in the row/column rectangle.
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE
ALIGN 4
define_CharRect_frame ScanFullCells

;/*
;** We set up the frame variable npNextCellLabel to denote the CS offset of
;** the cell scanning loop.  Note the separate loops for Vio and AVio cells.
;*/

        MOV     EBX,offset FCNextCell
        MOV     AX,wCellSizeShift
        SHR     AX,1
        JZ      SaveFCCodePointer
        MOV     EBX,offset AVioFCNextCell

        PUBLIC  SaveFCCodePointer
SaveFCCodePointer::
        MOV     npNextCellLabel,EBX

;/*
;** The code below sets up the registers as required by the Phase 1 code which
;** scans the LVB cells.  That code makes the following assumptions:
;**
;**   EAX   --  Will be destroyed.
;**   EBX   --  Previous display attributes.
;**   CH    --  Number of rows remaining to process.
;**   CL    --  Number of columns to process in the current row.
;**   EDX   --  Will hold the current attributes for AVio cells.
;**   ESI   --> An LVB cell.
;**   EDI   --  Lower limit on ESP.
;**             NOTE: This will no longer be true after the port, as the stack
;**             limit need no longer be checked. KEZ 11/18/91
;**   ESP   --> First item in the pseudo code list.
;**   EBP   --> Code page mapping vector (in DGroup).
;**   FLAGS --  Direction flag must be set.
;**
;** The code starts with the bottom right cell in the full cell region and works
;** backwards, going up through a row, then to the rightmost cell in the next
;** row above, and so on until we've either completed pseudo code for the entire
;** region, or we've run out of stack space.
;*/

        JMP     Start_horz_LVB_scan

;/*
;** The code below scans AVio buffer cells.  Its structure parallels that of the
;** code for scan Vio buffer cells below.  The scanning loop has been unrolled
;** for speed.
;*/

ALIGN 4
        PUBLIC  AVioFCAttributeChange
AVioFCAttributeChange::
ifndef DBCS ; DBCS AVio attribute support                               ;IBMJ
        ADD     DX,BX                   ; Undo sub DX,BX
endif;not DBCS                                                          ;IBMJ
        PUSH    EBX                     ; Push the old attributes.
        PUSH    -1                      ; Push a control flag marker.
ifdef JFIX                                                              ;@NI1
        PUSH    EBX                     ; Once again.                   ;@NI1
endif;JFIX                                                              ;@NI1
        XOR     BX,DX                   ; Did the LCID index change?
        AND     BX,AVioLCIDMask
        JZ      LCID_Did_not_change

;/*
;** If the LCID index has changed, we must set EBP to point to the code page
;** mapping vector for the new LCID.
;*/

        PUSH    ESI
        MOV     ESI,AVioLCIDMask
        AND     SI,DX
        MOV     EBP,CellBLTBlock.cb_BPSaveSlot

        MOV     ESI,wSymbolSetOffsets[ESI*4]
        MOV     npcpmap,ESI             ; Remember this mapping vector as
        MOV     EBP,ESI                 ; current map in case EBP trashed
        POP     ESI

ifdef DBCS  ; DBCS AVio attribute support                               ;IBMJ

; LCID has been changed. The DBCS version of InterpretAttributes can
; handle only one LCID at once so that we should split current row here.

ifdef JFIX                                                              ;@NI1
        POP     EBX                     ; EBX <- OldAttributes          ;@NI1
else ;JFIX                                                              ;@NI1
        mov     bx,dx                   ; OldAttributes <- NewAttributes
        xor     dx,dx
endif;JFIX                                                              ;@NI1

ifdef  JTUNE                                                            ;IBMJ
        test    swFlags,SW_CT_DISABLE
        jnz     @F
        add     esi,AvioLVBShadowOffset
        mov     dword ptr [esi-2],-1
        sub     esi,AvioLVBShadowOffset
@@:
endif ;JTUNE                                                            ;IBMJ
        add     esi,4                   ; Undo the LODSW side effects
ifdef JFIX                                                              ;@NI1
        jmp     AVioSplitRow_2                                          ;@NI1
else ;JFIX                                                              ;@NI1
        jmp     AVioSplitRow
endif;JFIX                                                              ;@NI1

endif;DBCS                                                              ;IBMJ
        PUBLIC  LCID_Did_not_change
LCID_Did_not_change::
ifdef JFIX                                                              ;@NI1
        ADD     ESP,SIZE_DWORD          ; Adjust stack pointer.         ;@NI1
endif;JFIX                                                              ;@NI1
        MOV     BX,DX                   ; OldAttributes <- NewAttributes
        XOR     DX,DX

;;;STACKSTUFF
        cmp     esp,edi                   ; If we haven't filled the stack,
        ja      AVioFCAttributesFixed   ; resume the scanning process.
ifdef  JTUNE                                                            ;IBMJ
        test    swFlags,SW_CT_DISABLE
        jnz     @F
        add     esi,AvioLVBShadowOffset
        mov     dword ptr [esi-2],-1
        sub     esi,AvioLVBShadowOffset
@@:
endif ;JTUNE                                                            ;IBMJ
        add     esi,4                    ; Undo the LODSW side effects
        jmp     AVioSplitRow

ALIGN 4
ifndef DBCS                                                             ;IBMJ
        PUBLIC  AVioFCNextCell
AVioFCNextCell::
;;;STACKSTUFF
        CMP     ESP,EDI                 ; Have we run out of stack space?
        JBE     AVioSplitRow            ;  Y - Draw what we have
        LODSW                           ;  N - Get an LVB cell
        MOV     DL,AL                   ; AVio descriptor.
        LODSW                           ; Load the first word.
        XCHG    DH,AH                   ; Make a complete attribute set.
                                        ; and set AH to zero
        SUB     DX,BX                   ; Have the attributes changed?
        JNZ     AVioFCAttributeChange   ; If so make adjustments.

        PUBLIC  AVioFCAttributesFixed
AVioFCAttributesFixed::

;/*
;** AX contains a code point index which we map to a glyph point index
;** via the code page mapping vector at EBP.  We push that glyph index
;** as part of the pseudo code.
;*/

        MOVZX   EAX,AX
        XCHG    EAX,ESI
        SHL     ESI,1
        PUSH    [EBP+ESI]
        MOV     ESI,EAX

AVioFCScanCell  MACRO                   ; To allow unrolling...

        DEC     CL                      ; Have we finished this row?
        JZ      AVioEndOfRow
        LODSW                           ; Same as the code above for
        MOV     DL,AL                   ; loading an AVio descriptor
        LODSW                           ; and processing it.
        XCHG    DH,AH
        SUB     DX,BX
        JNZ     AVioFCAttributeChange

;/*
;** AX contains a code point index which we map to a glyph point index via the
;** code page mapping vector at bp.  We push that glyph index as part of the
;** pseudo code.
;*/
        MOVZX   EAX,AX
        XCHG    EAX,ESI
        SHL     ESI,1
        PUSH    [EBP+ESI]
        MOV     ESI,EAX

        ENDM ; AVioFCScanCell
        REPT    2                       ; Short jumps restrict this
                                        ; code to no more than 2
        AVioFCScanCell                  ; additional clones.

        ENDM

        DEC     CL                      ; Have we finished this row?
        JNZ     AVioFCNextCell

else ;DBCS  ; DBCS AVio attribute support                               ;IBMJ
        public  AVioFCNextCell
AVioFCNextCell::

        cmp     esp,edi                 ; Did we run out of stack space?
        jbe     AVioSplitRow
        cmp     CellBLTBlock.cb_cdbcschar,256   ; max DBCS chars at once
        jae     AVioSplitRow

ifndef JTUNE                                                            ;IBMJ
        lodsw                           ; Load the second word of an
        mov     dx,ax                   ; AVio descriptor.
        lodsw                           ; Load the first word.
        xchg    dh,ah                   ; Make a complete attribute set.
                                        ; and set AH to zero.
else  ;JTUNE                                                            ;IBMJ
        sub     esi,2
        lodsd
        test    swFlags,SW_CT_DISABLE
        jz      AVioFCCheckSameChar
        mov     wExtCellInfo,(EXT_CELL_NOT_SAME_CHAR SHR 16)
AvioFCExtExit:
        add     esi,2
        mov     dx,ax
        shr     eax,16
        xchg    al,dl
endif ;JTUNE                                                            ;IBMJ
        cmp     dx,bx           ;don't sub!     ; Have the attributes changed?
        jnz     AVioFCAttributeChange   ; If so make adjustments.

        public  AVioFCAttributesFixed
AVioFCAttributesFixed::

; AH/AL contains 3rd attributes/code point.
; Check if it is a part of DBCS cell or not. If it is, the DBCS mark
; word, which indicates the DBCS leading/trailing byte, is saved and
; carry flag is set.

        VioCheckCellType        4       ; SBCS? DBCS? (4:Avio,2:Vio)
        jnc     AVioSBCS                ; it's SBCS cell

; AX contains a DBCS code point. Register it into the DBCS code point
; array (cb_adbcschar) , and get the entry offset.
; The pseudo code for DBCS characters are defined as:
; - DBCS leading  byte = entry offset | PSEUDO_DBCS_1ST
; - DBCS trailing byte = entry offset | PSEUDO_DBCS_2ND

AVioDBCS:
        INVOKE  DbcsCodeToOffset        ; get entry offset
        jnc     @f
        add     edi,2                   ; update stack limit
@@:     or      eax,CellBLTBlock.cb_markword    ; construct DBCS markword
        push    eax
ifdef  JTUNE                                                            ;IBMJ
        test    swFlags,SW_CT_DISABLE
        jnz     AVioCellSaved
        add     esi,LVBShadowOffset
        mov     dword ptr [esi],-1
        sub     esi,LVBShadowOffset
endif ;JTUNE                                                            ;IBMJ
        jmp     AVioCellSaved

; AX contains a code point index which we map to a glyph point index
; via the code page mapping vector at es:bp.  We push that glyph index
; as part of the pseudo code.

AVioSBCS:
ifndef JTUNE                                                            ;IBMJ
        shl     eax,1
        push    dword ptr [ebp+eax]
else  ;JTUNE                                                            ;IBMJ
        push    wExtCellInfo
        shl     eax,1
        push    word ptr [ebp+eax]
endif ;JTUNE                                                            ;IBMJ

AVioCellSaved:
        dec     cl                      ; Have we finished this row?
        jnz     AVioFCNextCell
endif;DBCS                                                              ;IBMJ

        PUBLIC  AVioEndOfRow
AVioEndOfRow::
        JMP     End_of_row

ALIGN 4
        PUBLIC  AVioSplitRow
AVioSplitRow::
        JMP     Split_a_row

ifdef JFIX                                                              ;@NI1
        PUBLIC  AVioSplitRow_2                                          ;@NI1
AVioSplitRow_2::                                                        ;@NI1
        JMP     Split_a_row_2                                           ;@NI1
endif;JFIX                                                              ;@NI1

ifdef JTUNE                                                             ;IBMJ
        public  AVioFCNextCell2
AVioFCNextCell2::

        cmp     esp,edi                 ; Did we run out of stack space?
        jbe     AVioSplitRow
        sub     esi,2
        lodsd

AVioFCCheckSameChar:
        add     esi,AvioLVBShadowOffset
        cmp     al,20h                  ; tmp fix
        jb      AVioFCNotSameChar2      ; tmp fix
        cmp     eax,[esi]
        jne     AVioFCNotSameChar

        public  AVioFoundSameChar
AVioFoundSameChar::
        mov     wExtCellInfo,(EXT_CELL_SAME_CHAR SHR 16)

        SUB     esi,AvioLVBShadowOffset
        add     esi,2
        mov     dx,ax
        shr     eax,16
        xchg    al,dl
        cmp     dx,bx           ;don't sub!     ; Have the attributes changed?
        jnz     AVioFCAttributeChange   ; If so make adjustments.
        test    CellBLTBlock.cb_fsNls,NLSCA_SBCS
        jnz     @F
        and     ah,byte ptr CellBLTBlock.cb_dbcsbits;; DBCS cell ?
        jnz     AVioFCAttributesFixed           ;; yes...
        cmp     byte ptr CellBLTBlock.cb_dbcsbits,0
        je      AVioFCAttributesFixed
@@:
ifndef TMP
        push    dword ptr EXT_CELL_SAME_CHAR
else  ;TMP
        push    wExtCellInfo
        shl     eax,1
        push    word ptr [ebp+eax]
endif ;TMP
        dec     cl                      ; Have we finished this row?
        jnz     AVioFCNextCell2
        jmp     AVioEndOfRow

AVioFCNotSameChar2:
        mov     dword ptr [esi],-1
        SUB     esi,AvioLVBShadowOffset
        mov     wExtCellInfo,(EXT_CELL_NOT_SAME_CHAR SHR 16)
        jmp     AvioFCExtExit
AVioFCNotSameChar:
        mov     [esi],eax
        SUB     esi,AvioLVBShadowOffset
        mov     wExtCellInfo,(EXT_CELL_NOT_SAME_CHAR SHR 16)
        jmp     AvioFCExtExit
endif ;JTUNE                                                            ;IBMJ

;/*
;** The code below scans Vio buffer cells.  It should be a bit faster than the
;** AVio scanner since it only has to process two bytes of descriptor
;** information rather than four bytes.  The scanning loop is unrolled for
;** speed.
;*/

ALIGN 4
        PUBLIC  FCAttributeChange
FCAttributeChange::
ifndef DBCS ; DBCS AVio attribute support                               ;IBMJ
        ADD     AH,BH                   ; Undo the sub AH,BH
endif;not DBCS                                                          ;IBMJ
        MOV     AL,BL                   ; Save wLVBRowIncr
        XOR     BL,BL                   ; Zot the AVio attribute bits
        PUSH    EBX                     ; Store the previous attributes
        PUSH    -1                      ; Push a control mark (-1).
        MOV     BX,AX                   ; Save the new color attributes
                                        ; and retrieve wLVBRowIncr
ifdef  JTUNE                                                            ;IBMJ
        test    swFlags,SW_CT_DISABLE
        jnz     @F
        add     esi,LVBShadowOffset
        mov     word ptr [esi],-1
        sub     esi,LVBShadowOffset
@@:
endif ;JTUNE                                                            ;IBMJ
        ADD     ESI,2                   ; Undo the LODSW side effect

ifndef DBCS                                                             ;IBMJ
        PUBLIC  FCNextCell
FCNextCell::
;;;STACKSTUFF
        CMP     ESP,EDI                 ; Have we run out of stack space?
        JBE     VioSplitRow             ;  Y - Go draw it.
        LODSW                           ;  N - Load an LVB cell.
        SUB     AH,BH                   ; Have the attributes changed?
        JNZ     FCAttributeChange       ; If so account for the change.

;/*
;** AX contains a code point index which we map to a glyph point index via the
;** code page mapping vector at bp.  We push that glyph index as part of the
;** pseudo code.
;*/

        MOVZX   EAX,AX
        XCHG    EAX,ESI
        SHL     ESI,1
        PUSH    [EBP+ESI]
        MOV     ESI,EAX

FCScanCell  MACRO                       ; To allow unrolling...

        DEC     CL                      ; Have we finished this row?
        JZ      VioEndOfRow
        LODSW
        SUB     AH,BH
        JNZ     FCAttributeChange

;/*
;** AX contains a code point index which we map to a glyph point index via the
;** code page mapping vector at bp.  We push that glyph index as part of the
;** pseudo code.
;*/

        MOVZX   EAX,AX
        XCHG    EAX,ESI
        SHL     ESI,1
        PUSH    [EBP+ESI]
        MOV     ESI,EAX

            ENDM ; FCScanCell

        REPT    5                       ; Short jumps restrict this
                                        ; code to no more than 5
        FCScanCell                      ; additional clones.

        ENDM

        DEC     CL                      ; Have we finished this row?
        JNZ     FCNextCell

else ;DBCS  ; DBCS AVio attribute support                               ;IBMJ

        mov     al,byte ptr CellBLTBlock.cb_dbcsbits
                                        ; DBCS bits if defined, else 0.
        not     al
        and     bh,al                   ; strip DBCS bits off from attributes.

        public  FCNextCell
FCNextCell::

        cmp     esp,edi                 ; Did we run out of stack space?
        jbe     VioSplitRow
        cmp     CellBLTBlock.cb_cdbcschar,256   ; max DBCS chars at once
        jae     VioSplitRow

        xor     eax,eax
        lodsw                           ; Load an LVB cell.
ifdef JTUNE                                                             ;IBMJ
        test    swFlags,SW_CT_DISABLE
        jz      FCCheckSameChar
        mov     wExtCellInfo,(EXT_CELL_NOT_SAME_CHAR SHR 16)
FCExitExit:
endif;JTUNE                                                             ;IBMJ
        push    eax
        mov     al,byte ptr CellBLTBlock.cb_dbcsbits
                                        ; DBCS bits if defined, else 0.
        not     al
        and     ah,al                   ; strip DBCS bits off from attributes.
        cmp     ah,bh           ;don't sub!     ; Have the attributes changed?
        pop     eax
        jnz     FCAttributeChange       ; If so account for the change.

        public  FCAttributesFixed
FCAttributesFixed::

; AH/AL contains attributes/code point.
; Check if it is a part of DBCS cell or not. If it is, the DBCS mark
; word, which indicates the DBCS leading/trailing byte, is saved and
; carry flag is set.

        VioCheckCellType        2       ; SBCS? DBCS? (4:Avio,2:Vio)
        jnc     VioSBCS                 ; it's SBCS cell

; AX contains a DBCS code point. Register it into the DBCS code point
; array (cb_adbcschar) , and get the entry offset.
; The pseudo code for DBCS characters are defined as:
; - DBCS leading  byte = entry offset | PSEUDO_DBCS_1ST
; - DBCS trailing byte = entry offset | PSEUDO_DBCS_2ND

VioDBCS:
        INVOKE  DbcsCodeToOffset        ; get entry offset
;       jnc     @f
;       add     edi,4                   ; update stack limit
@@:     or      eax,CellBLTBlock.cb_markword    ; construct DBCS markword
        push    eax
ifdef  JTUNE                                                            ;IBMJ
        test    swFlags,SW_CT_DISABLE
        jnz     VioCellSaved
        add     esi,LVBShadowOffset
        mov     word ptr [esi],-1
        sub     esi,LVBShadowOffset
endif ;JTUNE                                                            ;IBMJ
        jmp     VioCellSaved

; AX contains a code point index which we map to a glyph point index
; via the code page mapping vector at es:bp.  We push that glyph index
; as part of the pseudo code.

VioSBCS:
ifndef JTUNE                                                            ;IBMJ
        shl     eax,1
        push    dword ptr [ebp+eax]
else  ;JTUNE                                                            ;IBMJ
        push    wExtCellInfo
        shl     eax,1
        push    word ptr [ebp+eax]
endif ;JTUNE                                                            ;IBMJ

VioCellSaved:
        dec     cl                      ; Have we finished this row?
        jnz     FCNextCell

endif;DBCS                                                              ;IBMJ

        PUBLIC  VioEndOfRow
VioEndOfRow::
        JCXZ    VioSplitRow
        PUSH    -2
        MOV     CL,BL
        DEC     CH
        MOVSX   EDX,DX
        ADD     ESI,EDX
        JMP     FCNextCell

ALIGN 4
        PUBLIC  VioSplitRow
VioSplitRow::
        XOR     BL,BL
        JMP     Split_a_row

ifdef JTUNE                                                             ;IBMJ
        public  FCNextCell2
FCNextCell2::

        cmp     esp,edi                 ; Did we run out of stack space?
        jbe     VioSplitRow
        lodsw                           ; Load an LVB cell.

FCCheckSameChar:
        add     esi,LVBShadowOffset
        cmp     al,20h                  ; tmp fix
        jb      FCNotSameChar2          ; tmp fix
        cmp     ax,[esi]
        jne     FCNotSameChar

        public  FoundSameChar
FoundSameChar::
        mov     wExtCellInfo,(EXT_CELL_SAME_CHAR SHR 16)

        sub     esi,LVBShadowOffset
        test    ah,byte ptr CellBLTBlock.cb_dbcsbits    ;; DBCS cell ?
        jnz     FCExitExit
        cmp     ah,bh           ;don't sub!     ; Have the attributes changed?
        jnz     FCAttributeChange       ; If so account for the change.
        test    CellBLTBlock.cb_fsNls,NLSCA_SBCS
        jnz     @F
        cmp     byte ptr CellBLTBlock.cb_dbcsbits,0
        je      FCAttributesFixed
@@:
ifndef TMP
        push    dword ptr EXT_CELL_SAME_CHAR
else  ;TMP
        push    wExtCellInfo
        xor     ah,ah
        shl     eax,1
        push    word ptr [ebp+eax]
endif ;TMP
        dec     cl                      ; Have we finished this row?
        jnz     FCNextCell2
        jmp     VioEndOfRow

FCNotSameChar2:
        mov     word ptr [esi],-1
        sub     esi,LVBShadowOffset
        mov     wExtCellInfo,(EXT_CELL_NOT_SAME_CHAR SHR 16)
        jmp     FCExitExit
FCNotSameChar:
        mov     [esi],ax
        sub     esi,LVBShadowOffset
        mov     wExtCellInfo,(EXT_CELL_NOT_SAME_CHAR SHR 16)
        jmp     FCExitExit
endif ;JTUNE                                                            ;IBMJ

ScanFullCells ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE SegmentHorizontalScanning
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = SegmentHorizontalScanning
;*
;* DESCRIPTION   = This routine handles the boundary conditions for the horizontal
;*                 scanning functions (ScanHorizontalBorder and ScanFullCells).
;*
;* INPUT         = Start_horz_LVB_scan -- Sets the inital state for scanning.
;*                 Split_a_row         -- Segments the drawing within a row.
;*                 End_of_row          -- Takes of the inter-row pseudocode, may
;*                                        force drawing.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE
ALIGN 4
define_CharRect_frame SegmentHorizontalScanning

        PUBLIC  End_of_row
End_of_row::

;;;STACKSTUFF
;/*
;** NB: Cell drawing is never segmented at the beginning of an image row.
;**     This presumes we always have enough stack space to handle a single
;**     column image.  In the worst case (a single column) that requires
;**     4*cntRows words of stack space.  So if we're supporting 255 rows,
;**     we need a minimum of 1020 words of stack space for pseudo code.
;**     Realistically the longest column we should see will be 60 rows which
;**     requires 240 words of pseudo code stack space.
;*/

        MOV     EBP,CellBLTBlock.cb_BPSaveSlot  ; The code below needs the
                                                ; stack
        JCXZ    Draw_cell_images                ; Have we finished the matrix?
        MOVSX   EAX,wLVBRowInc                  ; Move ESI to the rightmost
        ADD     ESI,EAX                         ; cell of the next LVB
        DEC     CH                              ; Decrement the rows
                                                ; remaining.
        MOV     CL,BYTE PTR wFullCols           ; Set up the column count
                                                ; again.
        PUSH    -2
        MOV     EAX,npNextCellLabel
        MOV     EBP,npcpmap                     ; Set up EBP for the loop,
        JMP     EAX                             ; Then resume scanning.

ifdef JFIX                                                              ;@NI1
ALIGN 4                                                                 ;@NI1
        PUBLIC  Split_a_row_2                                           ;@NI1
Split_a_row_2::                                                         ;@NI1
                                                                        ;@NI1
; We should pass the OLD attributes including LCID to the Interpret-    ;@NI1
; Attributes in case that the LCID index was changed during scanning    ;@NI1
; cells in operation.                                                   ;@NI1
; Overwriting EBX with new attributes is, of course, to be done for     ;@NI1
; the next scanning processes' use.                                     ;@NI1
                                                                        ;@NI1
        MOV     EBP,CellBLTBlock.cb_BPSaveSlot  ; Below needs stack.    ;@NI1
        PUSH    EBX                     ; Push the old attributes.      ;@NI1
        MOV     EBX,EDX                 ; OldAttributes<-NewAttributes  ;@NI1
        JMP     shs_push_attr_done                                      ;@NI1
endif;JFIX                                                              ;@NI1

ALIGN 4
        PUBLIC  Split_a_row
Split_a_row::
        MOV     EBP,CellBLTBlock.cb_BPSaveSlot  ; The code below needs the
                                                ; stack

        PUBLIC  Draw_cell_images
Draw_cell_images::

;/*
;** The phase 2 code makes the following register assumptions:
;**
;**   EAX -- Will be destroyed.
;**   EBX -- Holds the increment to move EDI rightward to one cell image.
;**   EDX -- Holds the scan line increment for EDI.
;**   ESI -- Used to retrieve pseudo code and glyph images.
;**   EDI -- Points to the next destination byte.
;**   ESP -- Points to the first pseudo code syllable to process.
;**   FLAGS -- Direction flag must be reset.
;**
;**     These are no longer meaningful. KEZ 11/19/91
;**       DS      -- holds a selector for the currently active font.
;**       ES      -- holds a selector for the ega bitmap.
;**       SS      -- is the segment selector for the pseudo code list.
;**
;** The register state will be set by the InterpretAttributes routine.
;** The code below only worrys about preserving the registers it needs
;** to resume phase 1.
;**
;** The cell drawing routine(s) will consume the pseudo code constructed
;** by phase 1.  The code will be acted upon in the reverse of the order
;** in which it was constructed -- such is the nature of PUSH/POP logic.
;** That is, cells will be drawn going out one row and then moving to the
;** to the leftmost cell in the next row below.
;*/
        PUSH    EBX                     ; Push the attributes for the
                                        ; first cells in the stream.
ifdef JFIX                                                              ;@NI1
shs_push_attr_done:                                                     ;@NI1
endif;JFIX                                                              ;@NI1

;/*
;** On the first drawing call we set wLastAttributes to be different from
;** the first attributes we'll be using.  That ensures that the drawing
;** code will correctly set up its drawing environment.  Subsequent calls
;** for the same region can presume a coherent environment and need only
;** change the environment if the attributes values change.
;*/
        TEST    wfForceColors,1
        JZ      Set_Dest_Ref
        NOT     BX
        MOV     wLastAttributes,BX
        XOR     EAX,EAX                 ; Zot the flag so we don't do
        MOV     wfForceColors,AX        ; this for any trailing segments.

        PUBLIC  Set_Dest_Ref
Set_Dest_Ref::

;/*
;** We set up the destination coordinates assuming we've processed all
;** the cells we're going to draw.
;*/

        MOV     AX,xcoordTopLeft
        MOV     xcoordStart,AX
        MOV     AX,ycoordTopLeft
        MOV     ycoordStart,AX
        OR      CX,CX                   ; Have we described all rows?
        JNZ     Segmented_drawing       ; If not, make adjustments
                                        ; to resume phase 1.
        JMP     InterpretAttributes

ALIGN 4
        PUBLIC  Segmented_drawing
Segmented_drawing::
        MOV     wSaveCounts,CX          ; Save the registers we'll need
        MOV     pCell,ESI               ; after phase 2.

;/*
;** Here we adjust ycoordStart and xcoordStart to account for the cells
;** we haven't processed.
;*/

        MOV     EAX,wScanLineCount
        MUL     CH
        ADD     ycoordStart,AX
        XOR     AX,AX
        MOV     AL,CL
        MUL     bCellWidth
        ADD     xcoordStart,AX
        MOV     EAX,offset reStart_horz_LVB_scan        ; Adjust the return
        MOV     EBX,pReturnAddress                      ; point for this
        MOV     [EBX],EAX                               ; drawing pass.
        JMP     InterpretAttributes

ALIGN 4
        PUBLIC  reStart_horz_LVB_scan
reStart_horz_LVB_scan::
        MOV     CX,wSaveCounts                  ; Restore the registers for
        MOV     ESI,pCell                       ; phase 1 processing.

        PUBLIC  Start_horz_LVB_scan
Start_horz_LVB_scan::
;;;STACKSTUFF
ifdef DBCS  ; DBCS AVio attribute support                               ;IBMJ
        MOV     CellBLTBlock.cb_cdbcschar,0   ; clear cb_adbcschar data length
endif;DBCS                                                              ;IBMJ
        mov     EDI,pStackLimit                 ; EDI -> Stack limit
        MOV     EBX,[ESI]                       ; Pickup the last WORD of the
                                                ; next cell descriptor
        MOV     AX,wCellSizeShift               ; Determine whether we're
        SHR     AX,1                            ; dealing with a Vio cell or
        JNZ     Restore_AVIO_attr               ; an AVio cell.

;/*
;** Initial conditions for Vio full cells:
;*/

        MOV     BL,BYTE PTR wFullCols
        MOV     DX,wLVBRowInc

        PUBLIC  Resume_scanning
Resume_scanning::
        STD                                     ; Phase 1 processes cells in
                                                ; reverse order.
        PushRet EAX,HorzCellsDrawn              ; Set the return address
                                                ; optimistically
        MOV     EAX,npNextCellLabel
        MOV     EBP,npcpmap                     ; Set up addressablity to the
                                                ; code page mapping vector,
        JMP     EAX                             ; and go back into the fray.

ALIGN 4
        PUBLIC  Restore_AVIO_attr
Restore_AVIO_attr::
ifndef DBCS                                                             ;IBMJ
        MOV     AX,[ESI-2]              ; Retrieve the foreground/background
        MOV     BH,AH                   ; color attributes for an AVio cell.
        XOR     BL,BL                   ; Assume Default LCID - this will
                                        ; force codepage remapping if not
                                        ; default
else ;DBCS  ; DBCS AVio attribute support                               ;IBMJ

; Because we should split row when LCID index is changed, we need to
; prepare mapping vector here to prevent from changing LCID index at
; the beginning of scanning loop, which causes endless loop.

        mov     bx,[esi-1]              ; Retrieve colors and other attributes
        xchg    bl,bh                   ;   which includes LCID index
        mov     eax,esi
        mov     esi,AVioLCIDMask
        and     si,bx
        mov     esi,wSymbolSetOffsets[esi*4]
        mov     npcpmap,esi             ; get mapping vector for this LCID
        mov     esi,eax
endif;DBCS                                                              ;IBMJ
        XOR     DX,DX                   ; Assumed for AVio full cells
        JMP     Resume_scanning

ALIGN 4
        PUBLIC  HorzCellsDrawn
HorzCellsDrawn::        ; All the full cells have been drawn.

        RET

SegmentHorizontalScanning ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

ifdef  JTUNE                                                            ;IBMJ
;---------------------------Publice Routine-----------------------------;
; BitBltCellScroll
;
; Scroll a rectangle on the screen. This is used by CharRect from
; drawimagerect in this module.
;
; Entry:
;       None
; Returns:
;       None
; Error Returns:
;       None
; Registers Preserved:
;       ESI,EDI
; Calls:
;       dev_copyrect
; History:
;  4-Dec-1992      by  Hidemasa Muta [jl25345 at ymtvm3]
; Rewrote it!
;  31-Mar-1991     by  Soh Ohta [jl09057 at ymtvm1]
; Rewrote it!
;  Thursday 02-Feb-1989 Mike Harrington [mikehar]
; Wrote it!
;-----------------------------------------------------------------------;

BitBltCellScroll PROC SYSCALL PUBLIC USES ESI EDI,
                pddc            :DWORD,
                x1              :DWORD,
                y1              :DWORD,
                horzcount       :DWORD,
                vertcount       :DWORD,
                rectwidth       :DWORD,
                rectheight      :DWORD,
                lpClipRect      :DWORD
        LOCAL   lpDestRect      :RECTL,
                psd             :DWORD

        mov     eax,pddc
        mov     eax,[eax].DDC.ddc_npsd            ; => destination surface
        mov     psd,eax

; Make our own little rect.

        mov     edi,lpClipRect        ; given clip rect
        lea     esi,lpDestRect

        mov     eax,x1                  ; make draw rect in screen coordinate.
        mov     [esi].RECTL.rcl_xLeft,eax     ; bottom/right is exclusive.
        add     eax,rectwidth
        mov     [esi].RECTL.rcl_xRight,eax
        mov     ebx,y1
        mov     [esi].RECTL.rcl_yTop,ebx
        add     ebx,rectheight
        mov     [esi].RECTL.rcl_yBottom,ebx

; Intersect our rect with the clip rect.

      ; mov     eax,[esi].RECTL.rcl_xRight    ; get the min right
        mov     ebx,[edi].RECTL.rcl_xRight
        SMin    ebx
        mov     [esi].RECTL.rcl_xRight,ebx

        mov     eax,[esi].RECTL.rcl_xLeft     ; get the max left
        mov     ebx,[edi].RECTL.rcl_xLeft
        SMax    ebx
        mov     [esi].RECTL.rcl_xLeft,ebx

        sub     ebx,[esi].RECTL.rcl_xRight    ; make sure left < right
        jns     dest_is_null

        mov     eax,[esi].RECTL.rcl_yTop      ; get the max top
        mov     ebx,SCREEN_CY
        sub     ebx,[edi].RECTL.rcl_yTop
        SMax    ebx
        mov     [esi].RECTL.rcl_yTop,ebx

        mov     eax,[esi].RECTL.rcl_yBottom   ; get the min bottom
        mov     ebx,SCREEN_CY
        sub     ebx,[edi].RECTL.rcl_yBottom
        SMin    ebx
        mov     [esi].RECTL.rcl_yBottom,ebx

        sub     ebx,[esi].RECTL.rcl_yTop      ; make sure bottom < top
        js      dest_is_null

; Now we have valid drawrect (-->DS:SI) in screen coordinate, which is
; already clipped by given clip rectangle.
; Then we will compute the width/height to be BLT'd, using the amount of
; movement for vertical/horizontal directions.

        mov     ecx,[esi].RECTL.rcl_xRight
        sub     ecx,[esi].RECTL.rcl_xLeft
        mov     eax,horzcount
        AbsVal
        sub     ecx,eax
        jz      dest_is_null
        mov     rectwidth,ecx

        mov     ebx,[esi].RECTL.rcl_yBottom
        sub     ebx,[esi].RECTL.rcl_yTop
        mov     eax,vertcount
        AbsVal
        sub     ebx,eax
        jz      dest_is_null
        mov     rectheight,ebx

; All required parameters are computed in screen coordinate.
; Check BLTing direction and construct arguments, then let copyrect to scroll.

        mov     eax,[esi].RECTL.rcl_yTop
        mov     ebx,vertcount
        or      ebx,ebx                 ; check vertical scrolling direction
        js      scrolling_up            ; negative value means upward scroll

scrolling_down:
      ; mov     eax,[esi].RECTL.rcl_yTop      ; EAX = ySrc
        add     ebx,eax                 ; EBX = yDst
        jmp     short @f

scrolling_up:
      ; mov     eax,[esi].RECTL.rcl_yTop      ; EAX = yDst
        neg     ebx
        add     ebx,eax                 ; EBX = ySrc
        xchg    eax,ebx                 ; EAX = ySrc, EBX = yDst

@@:     mov     ecx,[esi].RECTL.rcl_xLeft
        mov     edx,horzcount
        or      edx,edx                 ; check horizintal scrolling direction
        js      scrolling_left          ; negative value means leftward scroll

scrolling_right:
      ; mov     ecx,[esi].RECTL.rcl_xLeft     ; ECX = xSrc
        add     edx,ecx                 ; EDX = xDst
        jmp     short @f

scrolling_left:
      ; mov     ecx,[esi].RECTL.rcl_xLeft     ; ECX = xDst
        neg     edx
        add     edx,ecx                 ; EDX = xSrc
        xchg    ecx,edx                 ; ECX = xSrc, EDX = xDst

@@:
        test    swFlags,SW_SPRITE
        jnz     @F
        push    eax
        INVOKE  SetScreenBusy, 1
        pop     eax
@@:
        INVOKE  OEMBitblt,
                pddc,
                edx,
                ebx,
                psd,
                ecx,
                eax,
                rectwidth,
                rectheight,
                0cch,
                0,
                0

        test    swFlags,SW_SPRITE
        jnz     @F
        INVOKE  SetScreenBusy, 0
@@:
dest_is_null:
        ret

BitBltCellScroll ENDP
endif ;JTUNE                                                            ;IBMJ

        END
